[automerger skipped] [DO NOT MERGE] Fix clipping issue on adaptive icons skipped: 34973c93e4
Change-Id: I70f0778ed7028f37f59699ed0a80b4d33ae80a4c
diff --git a/.gitignore b/.gitignore
index 7240e48..694b40c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,5 @@
local.properties
gradle/
build/
-gradlew*
\ No newline at end of file
+gradlew*
+.DS_Store
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..c583244
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,31 @@
+// 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.
+
+java_library_static {
+ name: "launcher-aosp-tapl",
+ static_libs: [
+ "androidx.annotation_annotation",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "SystemUISharedLib",
+ ],
+ srcs: [
+ "tests/tapl/**/*.java",
+ "quickstep/src/com/android/quickstep/SwipeUpSetting.java",
+ "src/com/android/launcher3/util/SecureSettingsObserver.java",
+ "src/com/android/launcher3/TestProtocol.java",
+ ],
+ platform_apis: true,
+}
diff --git a/Android.mk b/Android.mk
index 3945746..d9e4641 100644
--- a/Android.mk
+++ b/Android.mk
@@ -28,6 +28,42 @@
LOCAL_SDK_VERSION := current
include $(BUILD_PREBUILT)
+include $(CLEAR_VARS)
+LOCAL_MODULE := libPluginCore
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_SRC_FILES := libs/plugin_core.jar
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_SDK_VERSION := current
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libLauncherProtos
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_SRC_FILES := libs/launcher_protos.jar
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_SDK_VERSION := current
+include $(BUILD_PREBUILT)
+#
+# Build rule for plugin lib (needed to write a plugin).
+#
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT2_ONLY := true
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := libPluginCore
+
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src_plugins)
+
+LOCAL_SDK_VERSION := current
+LOCAL_MIN_SDK_VERSION := 28
+LOCAL_MODULE := LauncherPluginLib
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
#
# Build rule for Launcher3 dependencies lib.
#
@@ -37,9 +73,12 @@
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_ANDROID_LIBRARIES := \
- android-support-v4 \
- android-support-v7-recyclerview \
- android-support-dynamic-animation
+ androidx.recyclerview_recyclerview \
+ androidx.dynamicanimation_dynamicanimation \
+ androidx.preference_preference \
+ iconloader_base
+
+LOCAL_STATIC_JAVA_LIBRARIES := LauncherPluginLib
LOCAL_SRC_FILES := \
$(call all-proto-files-under, protos) \
@@ -71,10 +110,13 @@
LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
+ $(call all-java-files-under, src_shortcuts_overrides) \
$(call all-java-files-under, src_ui_overrides) \
$(call all-java-files-under, src_flags)
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+# Proguard is disable for testing. Derivarive prjects to keep proguard enabled
+LOCAL_PROGUARD_ENABLED := disabled
LOCAL_SDK_VERSION := current
LOCAL_MIN_SDK_VERSION := 21
@@ -99,7 +141,7 @@
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
$(call all-java-files-under, src_ui_overrides) \
- $(call all-java-files-under, go/src_flags)
+ $(call all-java-files-under, go/src)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/go/res
@@ -127,21 +169,27 @@
LOCAL_AAPT2_ONLY := true
LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_JAVA_LIBRARIES := libSharedSystemUI
+ifneq (,$(wildcard frameworks/base))
+ LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano
+ LOCAL_PRIVATE_PLATFORM_APIS := true
+else
+ LOCAL_STATIC_JAVA_LIBRARIES := libSharedSystemUI libLauncherProtos
+ LOCAL_SDK_VERSION := system_current
+ LOCAL_MIN_SDK_VERSION := 26
+endif
+LOCAL_MODULE := Launcher3QuickStepLib
+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_flags)
+ $(call all-java-files-under, src_flags) \
+ $(call all-java-files-under, src_shortcuts_overrides)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_SDK_VERSION := system_current
-LOCAL_MIN_SDK_VERSION := 26
-LOCAL_MODULE := Launcher3QuickStepLib
-LOCAL_PRIVILEGED_MODULE := true
LOCAL_MANIFEST_FILE := quickstep/AndroidManifest.xml
include $(BUILD_STATIC_JAVA_LIBRARY)
@@ -156,8 +204,12 @@
LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3QuickStepLib
LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_SDK_VERSION := system_current
-LOCAL_MIN_SDK_VERSION := 26
+ifneq (,$(wildcard frameworks/base))
+ LOCAL_PRIVATE_PLATFORM_APIS := true
+else
+ LOCAL_SDK_VERSION := system_current
+ LOCAL_MIN_SDK_VERSION := 26
+endif
LOCAL_PACKAGE_NAME := Launcher3QuickStep
LOCAL_PRIVILEGED_MODULE := true
LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3
@@ -181,22 +233,28 @@
LOCAL_USE_AAPT2 := true
LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_JAVA_LIBRARIES := libSharedSystemUI
+ifneq (,$(wildcard frameworks/base))
+ LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano
+ LOCAL_PRIVATE_PLATFORM_APIS := true
+else
+ LOCAL_STATIC_JAVA_LIBRARIES := libSharedSystemUI libLauncherProtos
+ LOCAL_SDK_VERSION := system_current
+ LOCAL_MIN_SDK_VERSION := 26
+endif
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, go/src_flags)
+ $(call all-java-files-under, go/src)
LOCAL_RESOURCE_DIR := \
$(LOCAL_PATH)/quickstep/res \
$(LOCAL_PATH)/go/res
-LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+LOCAL_PROGUARD_ENABLED := full
-LOCAL_SDK_VERSION := system_current
-LOCAL_MIN_SDK_VERSION := 26
LOCAL_PACKAGE_NAME := Launcher3QuickStepGo
LOCAL_PRIVILEGED_MODULE := true
LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3 Launcher3QuickStep
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 211e1ff..1beaea5 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -44,6 +44,28 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
+
+ <!--
+ Permissions required for read/write access to the workspace data. These permission name
+ should not conflict with that defined in other apps, as such an app should embed its package
+ name in the permissions. eq com.mypackage.permission.READ_SETTINGS
+ -->
+ <permission
+ android:name="${packageName}.permission.READ_SETTINGS"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signatureOrSystem"
+ android:label="@string/permlab_read_settings"
+ android:description="@string/permdesc_read_settings"/>
+ <permission
+ android:name="${packageName}.permission.WRITE_SETTINGS"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signatureOrSystem"
+ android:label="@string/permlab_write_settings"
+ android:description="@string/permdesc_write_settings"/>
+
+ <uses-permission android:name="${packageName}.permission.READ_SETTINGS" />
+ <uses-permission android:name="${packageName}.permission.WRITE_SETTINGS" />
+
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
android:fullBackupOnly="true"
@@ -100,7 +122,7 @@
android:value="true" />
<activity android:name="com.android.launcher3.dragndrop.AddItemActivity"
- android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"
+ android:theme="@style/AppItemActivityTheme"
android:excludeFromRecents="true"
android:autoRemoveFromRecents="true"
android:label="@string/action_add_to_workspace" >
@@ -118,5 +140,31 @@
android:name="com.android.launcher3.launcher_dump_provider"
android:value="com.android.launcher3.LauncherProvider" />
+ <!--
+ The settings provider contains Home's data, like the workspace favorites. The permissions
+ should be changed to what is defined above. The authorities should also be changed to
+ represent the package name.
+ -->
+ <provider
+ android:name="com.android.launcher3.LauncherProvider"
+ android:authorities="${packageName}.settings"
+ android:exported="true"
+ android:writePermission="${packageName}.permission.WRITE_SETTINGS"
+ android:readPermission="${packageName}.permission.READ_SETTINGS" />
+
+ <!--
+ The settings activity. To extend point settings_fragment_name to appropriate fragment class
+ -->
+ <activity
+ android:name="com.android.launcher3.settings.SettingsActivity"
+ android:label="@string/settings_button_text"
+ android:theme="@android:style/Theme.DeviceDefault.Settings"
+ android:autoRemoveFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.APPLICATION_PREFERENCES" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
</application>
</manifest>
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3212980..4ac51ab 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -26,29 +26,6 @@
Refer comments around specific entries on how to extend individual components.
-->
- <!--
- Permissions required for read/write access to the workspace data. These permission name
- should not conflict with that defined in other apps, as such an app should embed its package
- name in the permissions. eq com.mypackage.permission.READ_SETTINGS
- -->
- <permission
- android:name="com.android.launcher3.permission.READ_SETTINGS"
- android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="signatureOrSystem"
- android:label="@string/permlab_read_settings"
- android:description="@string/permdesc_read_settings"/>
- <permission
- android:name="com.android.launcher3.permission.WRITE_SETTINGS"
- android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="signatureOrSystem"
- android:label="@string/permlab_write_settings"
- android:description="@string/permdesc_write_settings"/>
-
- <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
- <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />
- <uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
- <uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS" />
-
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
android:fullBackupOnly="true"
@@ -86,31 +63,5 @@
</intent-filter>
</activity>
- <!--
- The settings activity. When extending keep the intent filter present
- -->
- <activity
- android:name="com.android.launcher3.SettingsActivity"
- android:label="@string/settings_button_text"
- android:theme="@android:style/Theme.DeviceDefault.Settings"
- android:autoRemoveFromRecents="true">
- <intent-filter>
- <action android:name="android.intent.action.APPLICATION_PREFERENCES" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
-
- <!--
- The settings provider contains Home's data, like the workspace favorites. The permissions
- should be changed to what is defined above. The authorities should also be changed to
- represent the package name.
- -->
- <provider
- android:name="com.android.launcher3.LauncherProvider"
- android:authorities="com.android.launcher3.settings"
- android:exported="true"
- android:writePermission="com.android.launcher3.permission.WRITE_SETTINGS"
- android:readPermission="com.android.launcher3.permission.READ_SETTINGS" />
-
</application>
</manifest>
diff --git a/build.gradle b/build.gradle
index 4ae6600..33409c5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,19 +4,17 @@
google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.0-alpha12'
- classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.3'
+ classpath GRADLE_CLASS_PATH
+ classpath PROTOBUF_CLASS_PATH
}
}
-final String SUPPORT_LIBS_VERSION = '28.0.0-SNAPSHOT'
-
apply plugin: 'com.android.application'
apply plugin: 'com.google.protobuf'
android {
- compileSdkVersion 28
- buildToolsVersion '28.0.0'
+ compileSdkVersion COMPILE_SDK.toInteger()
+ buildToolsVersion BUILD_TOOLS_VERSION
defaultConfig {
minSdkVersion 21
@@ -24,7 +22,7 @@
versionCode 1
versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
@@ -57,6 +55,8 @@
dimension "default"
applicationId 'com.android.launcher3'
testApplicationId 'com.android.launcher3.tests'
+
+ minSdkVersion 28
}
}
@@ -70,7 +70,7 @@
sourceSets {
main {
res.srcDirs = ['res']
- java.srcDirs = ['src']
+ java.srcDirs = ['src', 'src_shortcuts_overrides']
manifest.srcFile 'AndroidManifest-common.xml'
proto {
srcDir 'protos/'
@@ -84,7 +84,7 @@
androidTest {
res.srcDirs = ['tests/res']
- java.srcDirs = ['tests/src']
+ java.srcDirs = ['tests/src', 'tests/tapl']
manifest.srcFile "tests/AndroidManifest-common.xml"
}
@@ -98,7 +98,7 @@
l3go {
res.srcDirs = ['go/res']
- java.srcDirs = ['go/src_flags', "src_ui_overrides"]
+ java.srcDirs = ['go/src', "src_ui_overrides"]
manifest.srcFile "go/AndroidManifest.xml"
}
@@ -118,10 +118,15 @@
}
dependencies {
- implementation "com.android.support:support-v4:${SUPPORT_LIBS_VERSION}"
- implementation "com.android.support:support-dynamic-animation:${SUPPORT_LIBS_VERSION}"
- implementation "com.android.support:recyclerview-v7:${SUPPORT_LIBS_VERSION}"
- implementation 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7'
+ implementation "androidx.dynamicanimation:dynamicanimation:${ANDROID_X_VERSION}"
+ implementation "androidx.recyclerview:recyclerview:${ANDROID_X_VERSION}"
+ implementation "androidx.preference:preference:${ANDROID_X_VERSION}"
+ implementation PROTOBUF_DEPENDENCY
+ implementation project(':IconLoader')
+
+ // This is already included in sysui_shared
+ aospImplementation fileTree(dir: "libs", include: 'plugin_core.jar')
+ l3goImplementation fileTree(dir: "libs", include: 'plugin_core.jar')
quickstepImplementation fileTree(dir: "quickstep/libs", include: 'sysui_shared.jar')
@@ -132,7 +137,7 @@
androidTestImplementation 'com.android.support.test:runner:1.0.0'
androidTestImplementation 'com.android.support.test:rules:1.0.0'
androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
- androidTestImplementation "com.android.support:support-annotations:${SUPPORT_LIBS_VERSION}"
+ androidTestImplementation "androidx.annotation:annotation:${ANDROID_X_VERSION}"
}
protobuf {
diff --git a/go/AndroidManifest.xml b/go/AndroidManifest.xml
index 0a9ad7b..0080898 100644
--- a/go/AndroidManifest.xml
+++ b/go/AndroidManifest.xml
@@ -36,16 +36,14 @@
android:restoreAnyVersion="true"
android:supportsRtl="true" >
- <!-- Activity for handling PinItemRequest. Only supports shortcuts -->
+ <!-- Activity for handling PinItemRequest is disabled on Android Go. -->
<activity android:name="com.android.launcher3.dragndrop.AddItemActivity"
android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:excludeFromRecents="true"
android:autoRemoveFromRecents="true"
android:label="@string/action_add_to_workspace"
+ android:enabled="false"
tools:node="replace" >
- <intent-filter>
- <action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
- </intent-filter>
</activity>
</application>
diff --git a/go/res/drawable/ic_widget.xml b/go/res/drawable/ic_widget.xml
deleted file mode 100644
index 5336876..0000000
--- a/go/res/drawable/ic_widget.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2017 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M3.9,18.35c2.5-2.49,5.78-3.64,10.14-3.64v3.05c0,0.47,0.57,0.71,0.9,0.37l5.74-5.74c0.41-0.41,0.41-1.08,0-1.49l-5.74-5.74
- c-0.33-0.33-0.9-0.1-0.9,0.37v2.95c-6.32,0.9-9.56,4.9-11.02,9.34C2.86,18.34,3.51,18.74,3.9,18.35z"/>
-</vector>
diff --git a/go/res/layout/widget_cell_content.xml b/go/res/layout/widget_cell_content.xml
deleted file mode 100644
index 49506d9..0000000
--- a/go/res/layout/widget_cell_content.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<merge xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/widget_preview_label_vertical_padding"
- android:paddingBottom="@dimen/widget_preview_label_vertical_padding"
- android:paddingLeft="@dimen/widget_preview_label_horizontal_padding"
- android:paddingRight="@dimen/widget_preview_label_horizontal_padding"
- android:orientation="horizontal">
-
- <!-- The name of the widget. -->
- <TextView
- android:id="@+id/widget_name"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:ellipsize="end"
- android:fadingEdge="horizontal"
- android:fontFamily="sans-serif-condensed"
- android:gravity="center"
- android:singleLine="true"
- android:maxLines="1"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="14sp" />
-
- <!-- The original dimensions of the widget (can't be the same text as above due to different
- style. -->
- <TextView
- android:id="@+id/widget_dims"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="5dp"
- android:layout_marginLeft="5dp"
- android:visibility="gone"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="14sp"
- android:fontFamily="sans-serif-condensed"
- android:alpha="0.8" />
- </LinearLayout>
-
- <!-- The image of the widget. This view does not support padding. Any placement adjustment
- should be done using margins. -->
- <com.android.launcher3.widget.WidgetImageView
- android:id="@+id/widget_preview"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1" />
-</merge>
\ No newline at end of file
diff --git a/go/res/values-af/strings.xml b/go/res/values-af/strings.xml
deleted file mode 100644
index 10ac473..0000000
--- a/go/res/values-af/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Raak en hou om \'n kortpad op te tel."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dubbeltik en hou om \'n kortpad op te tel of gebruik gepasmaakte handelinge."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Kortpaaie"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-kortpaaie"</string>
-</resources>
diff --git a/go/res/values-am/strings.xml b/go/res/values-am/strings.xml
deleted file mode 100644
index b3b253f..0000000
--- a/go/res/values-am/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"አንድ አቋራጭ ለመውሰድ ነክተው ይያዙ"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"አንድ አቋራጭ ለመውሰድ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ አድርገው ይያዙ።"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"አቋራጮች"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> አቋራጮች"</string>
-</resources>
diff --git a/go/res/values-ar/strings.xml b/go/res/values-ar/strings.xml
deleted file mode 100644
index 9888d0f..0000000
--- a/go/res/values-ar/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"المس مع الاستمرار لاختيار اختصار."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"يمكنك النقر مرّتين مع الاستمرار لاختيار اختصار أو استخدام الإجراءات المخصصة."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"الاختصارات"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"اختصارات <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-as/strings.xml b/go/res/values-as/strings.xml
deleted file mode 100644
index 6b5807f..0000000
--- a/go/res/values-as/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"কোনো শ্বৰ্টকাট বাছনি কৰিবলৈ স্পৰ্শ কৰি ৰাখক।"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"কোনো শ্বৰ্টকাট বাছনি কৰিবলৈ দুবাৰ টিপি ৰাখক বা নিজৰ উপযোগিতা অনুসৰি বনোৱা কাৰ্যসমূহ ব্যৱহাৰ কৰক।"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"শ্বৰ্টকাটসমূহ"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> শ্বৰ্টকাটসমূহ"</string>
-</resources>
diff --git a/go/res/values-az-rAZ/strings.xml b/go/res/values-az-rAZ/strings.xml
deleted file mode 100644
index c4b8cb7..0000000
--- a/go/res/values-az-rAZ/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Qısayolu seçmək üçün toxunub saxlayın."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Qısayolu seçmək üçün iki dəfə basıb saxlayın və ya fərdi əməliyyatlardan istifadə edin."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Qısayollar"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> qısayolları"</string>
-</resources>
diff --git a/go/res/values-az/strings.xml b/go/res/values-az/strings.xml
deleted file mode 100644
index c4b8cb7..0000000
--- a/go/res/values-az/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Qısayolu seçmək üçün toxunub saxlayın."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Qısayolu seçmək üçün iki dəfə basıb saxlayın və ya fərdi əməliyyatlardan istifadə edin."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Qısayollar"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> qısayolları"</string>
-</resources>
diff --git a/go/res/values-b+sr+Latn/strings.xml b/go/res/values-b+sr+Latn/strings.xml
deleted file mode 100644
index 0da5699..0000000
--- a/go/res/values-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Dodirnite i zadržite da biste izabrali prečicu."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dvaput dodirnite i zadržite da biste izabrali prečicu ili koristite prilagođene radnje."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Prečice"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Prečice za <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-be-rBY/strings.xml b/go/res/values-be-rBY/strings.xml
deleted file mode 100644
index 4189e35..0000000
--- a/go/res/values-be-rBY/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Дакраніцеся і ўтрымлiвайце ярлык, каб дадаць яго."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Дакраніцеся двойчы і ўтрымлівайце, каб выбраць ярлык або выкарыстоўваць спецыяльныя дзеянні."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Ярлыкі"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Ярлыкі <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-be/strings.xml b/go/res/values-be/strings.xml
deleted file mode 100644
index 4189e35..0000000
--- a/go/res/values-be/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Дакраніцеся і ўтрымлiвайце ярлык, каб дадаць яго."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Дакраніцеся двойчы і ўтрымлівайце, каб выбраць ярлык або выкарыстоўваць спецыяльныя дзеянні."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Ярлыкі"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Ярлыкі <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-bg/strings.xml b/go/res/values-bg/strings.xml
deleted file mode 100644
index 1b85992..0000000
--- a/go/res/values-bg/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Докоснете и задръжте за избор на пряк път."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Докоснете двукратно и задръжте за избор на пряк път или използвайте персонализирани действия."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Преки пътища"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Преки пътища за <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-bn-rBD/strings.xml b/go/res/values-bn-rBD/strings.xml
deleted file mode 100644
index c56c925..0000000
--- a/go/res/values-bn-rBD/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"কোনও শর্টকাট বেছে নিতে টাচ করে ধরে রাখুন।"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"কোনও শর্টকাট বেছে নিতে ডাবল ট্যাপ করে ধরে রাখুন অথবা কাস্টম ক্রিয়াগুলি ব্যবহার করুন।"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"শর্টকাট"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> এর শর্টকাট"</string>
-</resources>
diff --git a/go/res/values-bn/strings.xml b/go/res/values-bn/strings.xml
deleted file mode 100644
index c56c925..0000000
--- a/go/res/values-bn/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"কোনও শর্টকাট বেছে নিতে টাচ করে ধরে রাখুন।"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"কোনও শর্টকাট বেছে নিতে ডাবল ট্যাপ করে ধরে রাখুন অথবা কাস্টম ক্রিয়াগুলি ব্যবহার করুন।"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"শর্টকাট"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> এর শর্টকাট"</string>
-</resources>
diff --git a/go/res/values-bs-rBA/strings.xml b/go/res/values-bs-rBA/strings.xml
deleted file mode 100644
index 3141b9d..0000000
--- a/go/res/values-bs-rBA/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Dodirnite i držite da uzmete prečicu."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dodirnite dvaput i držite da uzmete prečicu ili koristite prilagođene akcije."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Prečice"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Prečice aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-bs/strings.xml b/go/res/values-bs/strings.xml
deleted file mode 100644
index 3141b9d..0000000
--- a/go/res/values-bs/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Dodirnite i držite da uzmete prečicu."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dodirnite dvaput i držite da uzmete prečicu ili koristite prilagođene akcije."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Prečice"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Prečice aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-ca/strings.xml b/go/res/values-ca/strings.xml
deleted file mode 100644
index 3b5c3f7..0000000
--- a/go/res/values-ca/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Mantén premuda una drecera per seleccionar-la."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Fes doble toc i mantén premut per seleccionar una drecera o per utilitzar accions personalitzades."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Dreceres"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Dreceres de l\'aplicació <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-cs/strings.xml b/go/res/values-cs/strings.xml
deleted file mode 100644
index e4018f2..0000000
--- a/go/res/values-cs/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Zkratku vyberete podržením."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dvojitým klepnutím a podržením vyberte zkratku, případně použijte vlastní akce."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Zkratky"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Zkratky aplikace <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-da/strings.xml b/go/res/values-da/strings.xml
deleted file mode 100644
index 821d36a..0000000
--- a/go/res/values-da/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Hold en genvej nede for at samle den op."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Tryk to gange, og hold en genvej nede for at samle den op og bruge tilpassede handlinger."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Genveje"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-genveje"</string>
-</resources>
diff --git a/go/res/values-de/strings.xml b/go/res/values-de/strings.xml
deleted file mode 100644
index 43a1b3a..0000000
--- a/go/res/values-de/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Doppeltippen und halten, um eine Verknüpfung auszuwählen."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Doppeltippen und halten, um eine Verknüpfung auszuwählen oder benutzerdefinierte Aktionen zu nutzen."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Verknüpfungen"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-Verknüpfungen"</string>
-</resources>
diff --git a/go/res/values-el/strings.xml b/go/res/values-el/strings.xml
deleted file mode 100644
index ae59907..0000000
--- a/go/res/values-el/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Αγγίξτε παρατεταμένα για να σηκώσετε μια συντόμευση."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Πατήσετε δύο φορές παρατεταμένα για να σηκώσετε μια συντόμευση ή για να χρησιμοποιήσετε προσαρμοσμένες ενέργειες."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Συντομεύσεις"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Συντομεύσεις <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-en-rAU/strings.xml b/go/res/values-en-rAU/strings.xml
deleted file mode 100644
index 2ee2c26..0000000
--- a/go/res/values-en-rAU/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Touch & hold to pick up a shortcut."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap & hold to pick up a shortcut or use custom actions."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Shortcuts"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shortcuts"</string>
-</resources>
diff --git a/go/res/values-en-rGB/strings.xml b/go/res/values-en-rGB/strings.xml
deleted file mode 100644
index 2ee2c26..0000000
--- a/go/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Touch & hold to pick up a shortcut."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap & hold to pick up a shortcut or use custom actions."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Shortcuts"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shortcuts"</string>
-</resources>
diff --git a/go/res/values-en-rIN/strings.xml b/go/res/values-en-rIN/strings.xml
deleted file mode 100644
index 2ee2c26..0000000
--- a/go/res/values-en-rIN/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Touch & hold to pick up a shortcut."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap & hold to pick up a shortcut or use custom actions."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Shortcuts"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shortcuts"</string>
-</resources>
diff --git a/go/res/values-es-rUS/strings.xml b/go/res/values-es-rUS/strings.xml
deleted file mode 100644
index 5212c03..0000000
--- a/go/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Mantén presionado para elegir un acceso directo."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Presiona dos veces y mantén presionado para elegir un acceso directo o usar acciones personalizadas."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Accesos directos"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Accesos directos de <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-es/strings.xml b/go/res/values-es/strings.xml
deleted file mode 100644
index 3ae4588..0000000
--- a/go/res/values-es/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Mantén pulsado el acceso directo que quieras."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Toca dos veces y mantén pulsado el acceso directo o utiliza acciones personalizadas."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Accesos directos"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Accesos directos de <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-et-rEE/strings.xml b/go/res/values-et-rEE/strings.xml
deleted file mode 100644
index 2513e65..0000000
--- a/go/res/values-et-rEE/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Otsetee valimiseks puudutage seda pikalt."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Topeltpuudutage ja hoidke otsetee valimiseks või kohandatud toimingute kasutamiseks."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Otseteed"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Rakenduse <xliff:g id="NAME">%1$s</xliff:g> otseteed"</string>
-</resources>
diff --git a/go/res/values-et/strings.xml b/go/res/values-et/strings.xml
deleted file mode 100644
index 2513e65..0000000
--- a/go/res/values-et/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Otsetee valimiseks puudutage seda pikalt."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Topeltpuudutage ja hoidke otsetee valimiseks või kohandatud toimingute kasutamiseks."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Otseteed"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Rakenduse <xliff:g id="NAME">%1$s</xliff:g> otseteed"</string>
-</resources>
diff --git a/go/res/values-eu-rES/strings.xml b/go/res/values-eu-rES/strings.xml
deleted file mode 100644
index 9949ef0..0000000
--- a/go/res/values-eu-rES/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Eduki sakatuta lasterbide bat aukeratzeko."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Sakatu birritan eta eduki sakatuta lasterbide bat aukeratzeko edo ekintza pertsonalizatuak erabiltzeko."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Lasterbideak"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioaren lasterbidea"</string>
-</resources>
diff --git a/go/res/values-eu/strings.xml b/go/res/values-eu/strings.xml
deleted file mode 100644
index 9949ef0..0000000
--- a/go/res/values-eu/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Eduki sakatuta lasterbide bat aukeratzeko."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Sakatu birritan eta eduki sakatuta lasterbide bat aukeratzeko edo ekintza pertsonalizatuak erabiltzeko."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Lasterbideak"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioaren lasterbidea"</string>
-</resources>
diff --git a/go/res/values-fa/strings.xml b/go/res/values-fa/strings.xml
deleted file mode 100644
index f1584d9..0000000
--- a/go/res/values-fa/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"برای انتخاب یک میانبر، لمس کنید و نگهدارید."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"برای انتخاب میانبر، دو ضربه سریع بزنید و نگه دارید یا از کنشهای سفارشی استفاده کنید."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"میانبرها"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"میانبرهای <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-fi/strings.xml b/go/res/values-fi/strings.xml
deleted file mode 100644
index da9b0e1..0000000
--- a/go/res/values-fi/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Valitse pikakuvake painamalla sitä pitkään."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Valitse pikakuvake tai käytä muokattuja toimintoja kaksoisnapauttamalla ja painamalla pitkään."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Pikakuvakkeet"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Kohteen <xliff:g id="NAME">%1$s</xliff:g> pikakuvakkeet"</string>
-</resources>
diff --git a/go/res/values-fr-rCA/strings.xml b/go/res/values-fr-rCA/strings.xml
deleted file mode 100644
index c7fd6d6..0000000
--- a/go/res/values-fr-rCA/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Maintenez un doigt sur le raccourci pour l\'ajouter"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Touchez 2x un raccourci et maintenez doigt dessus pour l’aj. ou utiliser des actions personnalisées."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Raccourcis"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Raccourcis : <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-fr/strings.xml b/go/res/values-fr/strings.xml
deleted file mode 100644
index 238fe73..0000000
--- a/go/res/values-fr/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Appui prolongé pour sélectionner raccourci."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Appuyez 2 fois et maintenez pression pour sélectionner raccourci ou utilisez actions personnalisées."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Raccourcis"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Raccourcis <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-gl-rES/strings.xml b/go/res/values-gl-rES/strings.xml
deleted file mode 100644
index 31621d5..0000000
--- a/go/res/values-gl-rES/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Mantén premido un atallo para seleccionalo."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Toca dúas veces e mantén premido para seleccionar un atallo ou utiliza accións personalizadas."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Atallos"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Atallos da aplicación <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-gl/strings.xml b/go/res/values-gl/strings.xml
deleted file mode 100644
index 31621d5..0000000
--- a/go/res/values-gl/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Mantén premido un atallo para seleccionalo."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Toca dúas veces e mantén premido para seleccionar un atallo ou utiliza accións personalizadas."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Atallos"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Atallos da aplicación <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-gu-rIN/strings.xml b/go/res/values-gu-rIN/strings.xml
deleted file mode 100644
index bdb549f..0000000
--- a/go/res/values-gu-rIN/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"એક શૉર્ટકટ ચૂંટવા ટૅપ કરી રાખો."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"એક શૉર્ટકટ ચૂંટવા અથવા કોઈ કસ્ટમ ક્રિયાઓનો ઉપયોગ કરવા માટે બે વાર ટૅપ કરી રાખો."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"શૉર્ટકટ"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> શૉર્ટકટ"</string>
-</resources>
diff --git a/go/res/values-gu/strings.xml b/go/res/values-gu/strings.xml
deleted file mode 100644
index bdb549f..0000000
--- a/go/res/values-gu/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"એક શૉર્ટકટ ચૂંટવા ટૅપ કરી રાખો."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"એક શૉર્ટકટ ચૂંટવા અથવા કોઈ કસ્ટમ ક્રિયાઓનો ઉપયોગ કરવા માટે બે વાર ટૅપ કરી રાખો."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"શૉર્ટકટ"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> શૉર્ટકટ"</string>
-</resources>
diff --git a/go/res/values-hi/strings.xml b/go/res/values-hi/strings.xml
deleted file mode 100644
index 2c1650a..0000000
--- a/go/res/values-hi/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"शॉर्टकट चुनने के लिए छूकर रखें."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"शॉर्टकट चुनने के लिए दो बार छूएं और कुछ देर दबाएं रखें या अपने मुताबिक कार्रवाइयों का इस्तेमाल करें."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"शॉर्टकट"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> शॉर्टकट"</string>
-</resources>
diff --git a/go/res/values-hr/strings.xml b/go/res/values-hr/strings.xml
deleted file mode 100644
index fccdeb5..0000000
--- a/go/res/values-hr/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Dodirnite i zadržite kako biste podigli prečac."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dvaput dodirnite i zadržite pritisak kako biste podigli prečac ili pokušajte prilagođenim radnjama."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Prečaci"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Prečaci za aplikaciju <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-hu/strings.xml b/go/res/values-hu/strings.xml
deleted file mode 100644
index 369c227..0000000
--- a/go/res/values-hu/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Felvételhez tartsa nyomva a parancsikont."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Parancsikon felvételéhez koppintson rá duplán és tartsa nyomva, vagy használjon egyéni műveleteket."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Parancsikonok"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-parancsikonok"</string>
-</resources>
diff --git a/go/res/values-hy-rAM/strings.xml b/go/res/values-hy-rAM/strings.xml
deleted file mode 100644
index 4747f6d..0000000
--- a/go/res/values-hy-rAM/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար։"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար կամ օգտվեք հարմարեցրած գործողություններից:"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Դյուրանցումներ"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> դյուրանցումներ"</string>
-</resources>
diff --git a/go/res/values-hy/strings.xml b/go/res/values-hy/strings.xml
deleted file mode 100644
index 4747f6d..0000000
--- a/go/res/values-hy/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար։"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար կամ օգտվեք հարմարեցրած գործողություններից:"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Դյուրանցումներ"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> դյուրանցումներ"</string>
-</resources>
diff --git a/go/res/values-in/strings.xml b/go/res/values-in/strings.xml
deleted file mode 100644
index c8b9da3..0000000
--- a/go/res/values-in/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Tap lama untuk memilih pintasan."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Tap dua kali & tahan untuk memilih pintasan atau menggunakan tindakan khusus."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Pintasan"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Pintasan <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-is-rIS/strings.xml b/go/res/values-is-rIS/strings.xml
deleted file mode 100644
index b8bb923..0000000
--- a/go/res/values-is-rIS/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Haltu fingri á flýtileið til að grípa hana."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Ýttu tvisvar og haltu fingri á flýtileið til að grípa hana eða notaðu sérsniðnar aðgerðir."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Flýtileiðir"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> flýtileiðir"</string>
-</resources>
diff --git a/go/res/values-is/strings.xml b/go/res/values-is/strings.xml
deleted file mode 100644
index b8bb923..0000000
--- a/go/res/values-is/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Haltu fingri á flýtileið til að grípa hana."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Ýttu tvisvar og haltu fingri á flýtileið til að grípa hana eða notaðu sérsniðnar aðgerðir."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Flýtileiðir"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> flýtileiðir"</string>
-</resources>
diff --git a/go/res/values-it/strings.xml b/go/res/values-it/strings.xml
deleted file mode 100644
index bc5d998..0000000
--- a/go/res/values-it/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Tocca e tieni premuto per scegliere la scorciatoia"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Tocca due volte e tieni premuto per scegliere una scorciatoia o per usare azioni personalizzate."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Scorciatoie"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Scorciatoie di <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-iw/strings.xml b/go/res/values-iw/strings.xml
deleted file mode 100644
index f541d4d..0000000
--- a/go/res/values-iw/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"כדי להוסיף קיצור דרך, מקישים עליו פעמיים ומחזיקים."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"כדי להוסיף קיצור דרך או להשתמש בפעולות מותאמות אישית, מקישים על קיצור הדרך פעמיים ומחזיקים."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"קיצורי דרך"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"קיצורי דרך לאפליקציה <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-ja/strings.xml b/go/res/values-ja/strings.xml
deleted file mode 100644
index 8f02d7f..0000000
--- a/go/res/values-ja/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"ショートカットを追加するには押し続けます。"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ダブルタップ後に押し続けてショートカットを選択するか、カスタム操作を使用してください。"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"ショートカット"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"「<xliff:g id="NAME">%1$s</xliff:g>」のショートカット"</string>
-</resources>
diff --git a/go/res/values-ka-rGE/strings.xml b/go/res/values-ka-rGE/strings.xml
deleted file mode 100644
index 1b46534..0000000
--- a/go/res/values-ka-rGE/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"შეეხეთ და დააყოვნეთ მალსახმობის ასარჩევად."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ორმაგად შეეხეთ და გეჭიროთ მალსახმობის ასარჩევად ან მორგებული მოქმედებების გამოსაყენებლად."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"მალსახმობები"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-ის მალსახმობები"</string>
-</resources>
diff --git a/go/res/values-ka/strings.xml b/go/res/values-ka/strings.xml
deleted file mode 100644
index 1b46534..0000000
--- a/go/res/values-ka/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"შეეხეთ და დააყოვნეთ მალსახმობის ასარჩევად."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ორმაგად შეეხეთ და გეჭიროთ მალსახმობის ასარჩევად ან მორგებული მოქმედებების გამოსაყენებლად."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"მალსახმობები"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-ის მალსახმობები"</string>
-</resources>
diff --git a/go/res/values-kk-rKZ/strings.xml b/go/res/values-kk-rKZ/strings.xml
deleted file mode 100644
index e909818..0000000
--- a/go/res/values-kk-rKZ/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Таңбашаны таңдау үшін оны түртіп, ұстап тұрыңыз."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Таңбашаны таңдау немесе арнаулы әрекеттерді пайдалану үшін екі рет түртіп, ұстап тұрыңыз."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Таңбашалар"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> таңбаша"</string>
-</resources>
diff --git a/go/res/values-kk/strings.xml b/go/res/values-kk/strings.xml
deleted file mode 100644
index e909818..0000000
--- a/go/res/values-kk/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Таңбашаны таңдау үшін оны түртіп, ұстап тұрыңыз."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Таңбашаны таңдау немесе арнаулы әрекеттерді пайдалану үшін екі рет түртіп, ұстап тұрыңыз."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Таңбашалар"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> таңбаша"</string>
-</resources>
diff --git a/go/res/values-km-rKH/strings.xml b/go/res/values-km-rKH/strings.xml
deleted file mode 100644
index 40082a4..0000000
--- a/go/res/values-km-rKH/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"ប៉ះ ហើយចុចឲ្យជាប់ដើម្បីរើសផ្លូវកាត់មួយ។"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ប៉ះពីរដង ហើយចុចឱ្យជាប់ដើម្បីរើសផ្លូវកាត់មួយ ឬប្រើសកម្មភាពផ្ទាល់ខ្លួន។"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"ផ្លូវកាត់"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"ផ្លូវកាត់សម្រាប់ <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-km/strings.xml b/go/res/values-km/strings.xml
deleted file mode 100644
index 40082a4..0000000
--- a/go/res/values-km/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"ប៉ះ ហើយចុចឲ្យជាប់ដើម្បីរើសផ្លូវកាត់មួយ។"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ប៉ះពីរដង ហើយចុចឱ្យជាប់ដើម្បីរើសផ្លូវកាត់មួយ ឬប្រើសកម្មភាពផ្ទាល់ខ្លួន។"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"ផ្លូវកាត់"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"ផ្លូវកាត់សម្រាប់ <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-kn-rIN/strings.xml b/go/res/values-kn-rIN/strings.xml
deleted file mode 100644
index 9c121fd..0000000
--- a/go/res/values-kn-rIN/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ ಆರಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ ಆರಿಸಿಕೊಳ್ಳಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಿ."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"ಶಾರ್ಟ್ಕಟ್ಗಳು"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> ಶಾರ್ಟ್ಕಟ್ಗಳು"</string>
-</resources>
diff --git a/go/res/values-kn/strings.xml b/go/res/values-kn/strings.xml
deleted file mode 100644
index 9c121fd..0000000
--- a/go/res/values-kn/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ ಆರಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ ಆರಿಸಿಕೊಳ್ಳಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಿ."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"ಶಾರ್ಟ್ಕಟ್ಗಳು"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> ಶಾರ್ಟ್ಕಟ್ಗಳು"</string>
-</resources>
diff --git a/go/res/values-ko/strings.xml b/go/res/values-ko/strings.xml
deleted file mode 100644
index 60f925e..0000000
--- a/go/res/values-ko/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"바로가기를 선택하려면 길게 터치하세요."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"바로가기를 선택하려면 두 번 탭한 다음 길게 터치하거나 맞춤 액션을 사용합니다."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"바로가기"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> 바로가기"</string>
-</resources>
diff --git a/go/res/values-ky-rKG/strings.xml b/go/res/values-ky-rKG/strings.xml
deleted file mode 100644
index 4c7e973..0000000
--- a/go/res/values-ky-rKG/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Кыска жолду тандоо үчүн басып туруңуз."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Кыска жолду тандоо үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Кыска жолдор"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> кыска жол"</string>
-</resources>
diff --git a/go/res/values-ky/strings.xml b/go/res/values-ky/strings.xml
deleted file mode 100644
index 4c7e973..0000000
--- a/go/res/values-ky/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Кыска жолду тандоо үчүн басып туруңуз."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Кыска жолду тандоо үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Кыска жолдор"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> кыска жол"</string>
-</resources>
diff --git a/go/res/values-lo-rLA/strings.xml b/go/res/values-lo-rLA/strings.xml
deleted file mode 100644
index 7864884..0000000
--- a/go/res/values-lo-rLA/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"ແຕະຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ ຫຼື ໃຊ້ຄຳສັ່ງແບບກຳນົດເອງ."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"ປຸ່ມລັດ"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"ປຸ່ມລັດ <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-lo/strings.xml b/go/res/values-lo/strings.xml
deleted file mode 100644
index 7864884..0000000
--- a/go/res/values-lo/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"ແຕະຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ ຫຼື ໃຊ້ຄຳສັ່ງແບບກຳນົດເອງ."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"ປຸ່ມລັດ"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"ປຸ່ມລັດ <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-lt/strings.xml b/go/res/values-lt/strings.xml
deleted file mode 100644
index 8f49032..0000000
--- a/go/res/values-lt/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Dukart pal. ir palaik., kad pasir. spart. klav."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dukart palieskite ir palaikykite, kad pasirinkt. spartųjį klavišą ar naudotumėte tinkintus veiksmus."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Spartieji klavišai"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"„<xliff:g id="NAME">%1$s</xliff:g>“ spartieji klavišai"</string>
-</resources>
diff --git a/go/res/values-lv/strings.xml b/go/res/values-lv/strings.xml
deleted file mode 100644
index 04315eb..0000000
--- a/go/res/values-lv/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Lai izvēlētos saīsni, pieskarieties un turiet to."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Lai atlasītu saīsni, veiciet dubultskārienu uz tās un turiet to vai arī veiciet pielāgotas darbības."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Saīsnes"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Lietotnes <xliff:g id="NAME">%1$s</xliff:g> saīsnes"</string>
-</resources>
diff --git a/go/res/values-mk-rMK/strings.xml b/go/res/values-mk-rMK/strings.xml
deleted file mode 100644
index 52d66b5..0000000
--- a/go/res/values-mk-rMK/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Допрете двапати и задржете за да изберете кратенка."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Допрете двапати и задржете за да изберете кратенка или да користите приспособени дејства."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Кратенки"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Кратенки за <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-mk/strings.xml b/go/res/values-mk/strings.xml
deleted file mode 100644
index 52d66b5..0000000
--- a/go/res/values-mk/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Допрете двапати и задржете за да изберете кратенка."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Допрете двапати и задржете за да изберете кратенка или да користите приспособени дејства."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Кратенки"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Кратенки за <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-ml-rIN/strings.xml b/go/res/values-ml-rIN/strings.xml
deleted file mode 100644
index b3c12e1..0000000
--- a/go/res/values-ml-rIN/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"ഒരു കുറുക്കുവഴി ചേർക്കുന്നതിന് അത് സ്പർശിച്ച് പിടിക്കുക."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ഒരു കുറുക്കുവഴി തിരഞ്ഞെടുക്കാനോ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ രണ്ടുതവണ ടാപ്പുചെയ്ത് പിടിക്കുക."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"കുറുക്കുവഴികൾ"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> കുറുക്കുവഴികൾ"</string>
-</resources>
diff --git a/go/res/values-ml/strings.xml b/go/res/values-ml/strings.xml
deleted file mode 100644
index b3c12e1..0000000
--- a/go/res/values-ml/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"ഒരു കുറുക്കുവഴി ചേർക്കുന്നതിന് അത് സ്പർശിച്ച് പിടിക്കുക."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ഒരു കുറുക്കുവഴി തിരഞ്ഞെടുക്കാനോ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ രണ്ടുതവണ ടാപ്പുചെയ്ത് പിടിക്കുക."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"കുറുക്കുവഴികൾ"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> കുറുക്കുവഴികൾ"</string>
-</resources>
diff --git a/go/res/values-mn-rMN/strings.xml b/go/res/values-mn-rMN/strings.xml
deleted file mode 100644
index c89dfd1..0000000
--- a/go/res/values-mn-rMN/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Товчлол авах бол удаан дарна уу."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Товчлол авах болон тохируулсан үйлдлийг ашиглахын тулд хоёр товшоод хүлээнэ үү."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Товчлол"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-н товчлол"</string>
-</resources>
diff --git a/go/res/values-mn/strings.xml b/go/res/values-mn/strings.xml
deleted file mode 100644
index c89dfd1..0000000
--- a/go/res/values-mn/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Товчлол авах бол удаан дарна уу."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Товчлол авах болон тохируулсан үйлдлийг ашиглахын тулд хоёр товшоод хүлээнэ үү."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Товчлол"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-н товчлол"</string>
-</resources>
diff --git a/go/res/values-mr-rIN/strings.xml b/go/res/values-mr-rIN/strings.xml
deleted file mode 100644
index 2c767b4..0000000
--- a/go/res/values-mr-rIN/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"शॉर्टकट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"शॉर्टकट निवडण्यासाठी किंवा कस्टम क्रिया वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"शॉर्टकट"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> शॉर्टकट"</string>
-</resources>
diff --git a/go/res/values-mr/strings.xml b/go/res/values-mr/strings.xml
deleted file mode 100644
index 2c767b4..0000000
--- a/go/res/values-mr/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"शॉर्टकट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"शॉर्टकट निवडण्यासाठी किंवा कस्टम क्रिया वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"शॉर्टकट"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> शॉर्टकट"</string>
-</resources>
diff --git a/go/res/values-ms-rMY/strings.xml b/go/res/values-ms-rMY/strings.xml
deleted file mode 100644
index 42add9a..0000000
--- a/go/res/values-ms-rMY/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Sentuh & tahan untuk mengambil pintasan."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Ketik dua kali & tahan untuk mengambil pintasan atau menggunakan tindakan tersuai."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Pintasan"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Pintasan <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-ms/strings.xml b/go/res/values-ms/strings.xml
deleted file mode 100644
index 42add9a..0000000
--- a/go/res/values-ms/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Sentuh & tahan untuk mengambil pintasan."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Ketik dua kali & tahan untuk mengambil pintasan atau menggunakan tindakan tersuai."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Pintasan"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Pintasan <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-my-rMM/strings.xml b/go/res/values-my-rMM/strings.xml
deleted file mode 100644
index 5784df6..0000000
--- a/go/res/values-my-rMM/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"လက်ကွက်ဖြတ်လမ်းတစ်ခုကို ရွေးရန် ထိပြီး ဖိထားပါ"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"လက်ကွက်ဖြတ်လမ်းကို ရွေးရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန်နှစ်ချက်တို့ပြီး ဖိထားပါ။"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"ဖြတ်လမ်းလင့်ခ်များ"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> ဖြတ်လမ်းလင့်ခ်များ"</string>
-</resources>
diff --git a/go/res/values-my/strings.xml b/go/res/values-my/strings.xml
deleted file mode 100644
index 5784df6..0000000
--- a/go/res/values-my/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"လက်ကွက်ဖြတ်လမ်းတစ်ခုကို ရွေးရန် ထိပြီး ဖိထားပါ"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"လက်ကွက်ဖြတ်လမ်းကို ရွေးရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန်နှစ်ချက်တို့ပြီး ဖိထားပါ။"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"ဖြတ်လမ်းလင့်ခ်များ"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> ဖြတ်လမ်းလင့်ခ်များ"</string>
-</resources>
diff --git a/go/res/values-nb/strings.xml b/go/res/values-nb/strings.xml
deleted file mode 100644
index 2a5ffb6..0000000
--- a/go/res/values-nb/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Trykk og hold for å velge en snarvei."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dobbelttrykk og hold for å velge en snarvei eller bruke tilpassede handlinger."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Snarveier"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-snarveier"</string>
-</resources>
diff --git a/go/res/values-ne-rNP/strings.xml b/go/res/values-ne-rNP/strings.xml
deleted file mode 100644
index 0be0375..0000000
--- a/go/res/values-ne-rNP/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"कुनै सटकर्ट छनौट गर्न छोइराख्नुहोस्।"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"कुनै सर्टकट छनौट गर्न दुईपटक ट्याप गरेर होल्ड गर्नुहोस् वा रोजेका कारबाहीहरू प्रयोग गर्नुहोस्।"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"सर्टकटहरू"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> सर्टकटहरू"</string>
-</resources>
diff --git a/go/res/values-ne/strings.xml b/go/res/values-ne/strings.xml
deleted file mode 100644
index 0be0375..0000000
--- a/go/res/values-ne/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"कुनै सटकर्ट छनौट गर्न छोइराख्नुहोस्।"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"कुनै सर्टकट छनौट गर्न दुईपटक ट्याप गरेर होल्ड गर्नुहोस् वा रोजेका कारबाहीहरू प्रयोग गर्नुहोस्।"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"सर्टकटहरू"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> सर्टकटहरू"</string>
-</resources>
diff --git a/go/res/values-nl/strings.xml b/go/res/values-nl/strings.xml
deleted file mode 100644
index 5bcd016..0000000
--- a/go/res/values-nl/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Tik en houd vast om snelkoppeling toe te voegen."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dubbeltik en houd vast om een snelkoppeling toe te voegen of aangepaste acties te gebruiken."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Snelkoppelingen"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-snelkoppelingen"</string>
-</resources>
diff --git a/go/res/values-or/strings.xml b/go/res/values-or/strings.xml
deleted file mode 100644
index 3ec8a72..0000000
--- a/go/res/values-or/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"ଏକ ଶର୍ଟକଟ୍ ଚୟନ କରିବାକୁ ଦାବି ଧରନ୍ତୁ।"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ଡବଲ୍-ଟାପ୍ କରନ୍ତୁ ଏବଂ ଏକ ଶର୍ଟକଟ୍ ଚୟନ କରିବାକୁ ଧରି ରଖନ୍ତୁ କିମ୍ୱା କଷ୍ଟମ୍ ପ୍ରକ୍ରିୟା ବ୍ୟବହାର କରନ୍ତୁ।"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"ଶର୍ଟକଟ୍"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>ର ଶର୍ଟକଟ୍"</string>
-</resources>
diff --git a/go/res/values-pa-rIN/strings.xml b/go/res/values-pa-rIN/strings.xml
deleted file mode 100644
index c7e4abf..0000000
--- a/go/res/values-pa-rIN/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ ਜਾਂ ਵਿਉਂਂਤੀ ਕਾਰਵਾਈਆਂ ਵਰਤੋ।"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"ਸ਼ਾਰਟਕੱਟ"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> ਸ਼ਾਰਟਕੱਟ"</string>
-</resources>
diff --git a/go/res/values-pa/strings.xml b/go/res/values-pa/strings.xml
deleted file mode 100644
index c7e4abf..0000000
--- a/go/res/values-pa/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ ਜਾਂ ਵਿਉਂਂਤੀ ਕਾਰਵਾਈਆਂ ਵਰਤੋ।"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"ਸ਼ਾਰਟਕੱਟ"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> ਸ਼ਾਰਟਕੱਟ"</string>
-</resources>
diff --git a/go/res/values-pl/strings.xml b/go/res/values-pl/strings.xml
deleted file mode 100644
index 45a1dc2..0000000
--- a/go/res/values-pl/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Kliknij i przytrzymaj, by wybrać skrót."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Kliknij dwukrotnie i przytrzymaj, by wybrać skrót lub użyć działań niestandardowych."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Skróty"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> – skróty"</string>
-</resources>
diff --git a/go/res/values-pt-rPT/strings.xml b/go/res/values-pt-rPT/strings.xml
deleted file mode 100644
index 7a75a05..0000000
--- a/go/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Toque sem soltar para escolher um atalho."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Toque duas vezes sem soltar para escolher um atalho ou utilize ações personalizadas."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Atalhos"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Atalhos da aplicação <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-pt/strings.xml b/go/res/values-pt/strings.xml
deleted file mode 100644
index 53bbfc4..0000000
--- a/go/res/values-pt/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Toque e segure para selecionar um atalho."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Toque duas vezes na tela e segure para selecionar um atalho ou usar ações personalizadas."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Atalhos"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Atalhos do app <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-ro/strings.xml b/go/res/values-ro/strings.xml
deleted file mode 100644
index 75d1796..0000000
--- a/go/res/values-ro/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Atingeți și țineți apăsat pentru a selecta o comandă rapidă."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Atingeți de două ori și țineți apăsat pentru comandă rapidă sau folosiți acțiuni personalizate."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Comenzi rapide"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Comenzi rapide pentru <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-ru/strings.xml b/go/res/values-ru/strings.xml
deleted file mode 100644
index 9c5c8cd..0000000
--- a/go/res/values-ru/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Чтобы выбрать ярлык, нажмите на него и удерживайте."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Чтобы выбрать ярлык или использовать специальные действия, нажмите на него дважды и не отпускайте."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Ярлыки"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>: ярлыки"</string>
-</resources>
diff --git a/go/res/values-si-rLK/strings.xml b/go/res/values-si-rLK/strings.xml
deleted file mode 100644
index 4b25c90..0000000
--- a/go/res/values-si-rLK/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"කෙටි මගක් තෝරා ගැනීමට ස්පර්ශ කර අල්ලාගෙන සිටින්න."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"විජට් එකක් තෝරා ගැනීමට හෝ අභිරුචි භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"කෙටි මං"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"කෙටි මං <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-si/strings.xml b/go/res/values-si/strings.xml
deleted file mode 100644
index 4b25c90..0000000
--- a/go/res/values-si/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"කෙටි මගක් තෝරා ගැනීමට ස්පර්ශ කර අල්ලාගෙන සිටින්න."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"විජට් එකක් තෝරා ගැනීමට හෝ අභිරුචි භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"කෙටි මං"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"කෙටි මං <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-sk/strings.xml b/go/res/values-sk/strings.xml
deleted file mode 100644
index fc02933..0000000
--- a/go/res/values-sk/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Skratku pridáte pridržaním."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Skratku pridáte dvojitým klepnutím a pridržaním alebo pomocou vlastných akcií."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Skratky"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Skratky aplikácie <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-sl/strings.xml b/go/res/values-sl/strings.xml
deleted file mode 100644
index 6ecedfb..0000000
--- a/go/res/values-sl/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Pridržite bližnjico, da jo izberete."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dvakrat se dotaknite bližnjice in jo pridržite, da jo izberete, ali pa uporabite dejanja po meri."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Bližnjice"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Bližnjice za <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-sq-rAL/strings.xml b/go/res/values-sq-rAL/strings.xml
deleted file mode 100644
index bb74db6..0000000
--- a/go/res/values-sq-rAL/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Prek dhe mbaj prekur për të zgjedhur një shkurtore."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Prek dy herë dhe mbaj prekur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Shkurtoret"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shkurtore"</string>
-</resources>
diff --git a/go/res/values-sq/strings.xml b/go/res/values-sq/strings.xml
deleted file mode 100644
index bb74db6..0000000
--- a/go/res/values-sq/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Prek dhe mbaj prekur për të zgjedhur një shkurtore."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Prek dy herë dhe mbaj prekur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Shkurtoret"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shkurtore"</string>
-</resources>
diff --git a/go/res/values-sr/strings.xml b/go/res/values-sr/strings.xml
deleted file mode 100644
index 0b9aea2..0000000
--- a/go/res/values-sr/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Додирните и задржите да бисте изабрали пречицу."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Двапут додирните и задржите да бисте изабрали пречицу или користите прилагођене радње."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Пречице"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Пречице за <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-sv/strings.xml b/go/res/values-sv/strings.xml
deleted file mode 100644
index c3f434c..0000000
--- a/go/res/values-sv/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Tryck länge om du vill ta upp en genväg."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Tryck snabbt två gånger och håll kvar om du vill ta upp en genväg eller använda anpassade åtgärder."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Genvägar"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Genvägar för <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-sw/strings.xml b/go/res/values-sw/strings.xml
deleted file mode 100644
index 13c12e4..0000000
--- a/go/res/values-sw/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Gusa na ushikilie ili uchague njia ya mkato."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Gusa mara mbili na ushikilie ile uchague njia ya mkato au utumie vitendo maalum."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Njia za mkato"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Njia za mkato za <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-ta-rIN/strings.xml b/go/res/values-ta-rIN/strings.xml
deleted file mode 100644
index 50059b6..0000000
--- a/go/res/values-ta-rIN/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"குறுக்குவழியைச் சேர்க்க, தொட்டு பிடித்திருக்கவும்."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"குறுக்குவழியை சேர்க்க, இருமுறை தட்டிப் பிடித்திருக்கவும் அல்லது தனிப்பயன் செயல்களைப் பயன்படுத்தவும்."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"குறுக்குவழிகள்"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> குறுக்குவழிகள்"</string>
-</resources>
diff --git a/go/res/values-ta/strings.xml b/go/res/values-ta/strings.xml
deleted file mode 100644
index 50059b6..0000000
--- a/go/res/values-ta/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"குறுக்குவழியைச் சேர்க்க, தொட்டு பிடித்திருக்கவும்."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"குறுக்குவழியை சேர்க்க, இருமுறை தட்டிப் பிடித்திருக்கவும் அல்லது தனிப்பயன் செயல்களைப் பயன்படுத்தவும்."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"குறுக்குவழிகள்"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> குறுக்குவழிகள்"</string>
-</resources>
diff --git a/go/res/values-te-rIN/strings.xml b/go/res/values-te-rIN/strings.xml
deleted file mode 100644
index 0bdf743..0000000
--- a/go/res/values-te-rIN/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"సత్వరమార్గాన్ని ఎంచుకోవడానికి తాకి & నొక్కి ఉంచండి."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"సత్వరమార్గాన్ని ఎంచుకోవడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కి &ఉంచండి."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"సత్వరమార్గాలు"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> సత్వరమార్గాలు"</string>
-</resources>
diff --git a/go/res/values-te/strings.xml b/go/res/values-te/strings.xml
deleted file mode 100644
index 0bdf743..0000000
--- a/go/res/values-te/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"సత్వరమార్గాన్ని ఎంచుకోవడానికి తాకి & నొక్కి ఉంచండి."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"సత్వరమార్గాన్ని ఎంచుకోవడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కి &ఉంచండి."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"సత్వరమార్గాలు"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> సత్వరమార్గాలు"</string>
-</resources>
diff --git a/go/res/values-th/strings.xml b/go/res/values-th/strings.xml
deleted file mode 100644
index e73d89f..0000000
--- a/go/res/values-th/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"แตะค้างไว้เพื่อเลือกทางลัด"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"แตะสองครั้งค้างไว้เพื่อเลือกทางลัดหรือใช้การกระทำที่กำหนดเอง"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"ทางลัด"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"ทางลัด <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-tl/strings.xml b/go/res/values-tl/strings.xml
deleted file mode 100644
index 8f44ec5..0000000
--- a/go/res/values-tl/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Pindutin nang matagal upang kumuha ng shortcut."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"I-double tap nang matagal upang kumuha ng shortcut o gumamit ng mga custom na pagkilos."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Mga Shortcut"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Mga shortcut sa <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-tr/strings.xml b/go/res/values-tr/strings.xml
deleted file mode 100644
index f0f3cce..0000000
--- a/go/res/values-tr/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Kısayol seçmek için dokunun ve basılı tutun."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Bir kısayolu seçmek veya özel işlemleri kullanmak için iki kez dokunun ve basılı tutun."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Kısayollar"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> kısayolları"</string>
-</resources>
diff --git a/go/res/values-uk/strings.xml b/go/res/values-uk/strings.xml
deleted file mode 100644
index 8d1f583..0000000
--- a/go/res/values-uk/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Натисніть і утримуйте, щоб вибрати ярлик."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Двічі натисніть і утримуйте, щоб вибрати ярлик, або виконайте іншу дію."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Ярлики"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Ярлики додатка <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-ur-rPK/strings.xml b/go/res/values-ur-rPK/strings.xml
deleted file mode 100644
index 46bd823..0000000
--- a/go/res/values-ur-rPK/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"کوئی شارٹ کٹ منتخب کرنے کیلئے ٹچ کریں اور دبائے رکھیں۔"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"کوئی شارٹ کٹ منتخب کرنے یا حسب ضرورت کاروائیاں استعمال کرنے کیلئے دو بار تھپتھپائیں اور دبائے رکھیں۔"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"شارٹ کٹس"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> شارٹ کٹس"</string>
-</resources>
diff --git a/go/res/values-ur/strings.xml b/go/res/values-ur/strings.xml
deleted file mode 100644
index 46bd823..0000000
--- a/go/res/values-ur/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"کوئی شارٹ کٹ منتخب کرنے کیلئے ٹچ کریں اور دبائے رکھیں۔"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"کوئی شارٹ کٹ منتخب کرنے یا حسب ضرورت کاروائیاں استعمال کرنے کیلئے دو بار تھپتھپائیں اور دبائے رکھیں۔"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"شارٹ کٹس"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> شارٹ کٹس"</string>
-</resources>
diff --git a/go/res/values-uz-rUZ/strings.xml b/go/res/values-uz-rUZ/strings.xml
deleted file mode 100644
index 318bc15..0000000
--- a/go/res/values-uz-rUZ/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Yorliqni tanlab olish uchun bosib turing."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Ikki marta bosib va bosib turgan holatda yorliqni tanlang yoki maxsus amaldan foydalaning."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Yorliqlar"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> ilovasi yorliqlari"</string>
-</resources>
diff --git a/go/res/values-uz/strings.xml b/go/res/values-uz/strings.xml
deleted file mode 100644
index 318bc15..0000000
--- a/go/res/values-uz/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Yorliqni tanlab olish uchun bosib turing."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Ikki marta bosib va bosib turgan holatda yorliqni tanlang yoki maxsus amaldan foydalaning."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Yorliqlar"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> ilovasi yorliqlari"</string>
-</resources>
diff --git a/go/res/values-vi/strings.xml b/go/res/values-vi/strings.xml
deleted file mode 100644
index 1197619..0000000
--- a/go/res/values-vi/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Chạm và giữ để chọn lối tắt."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Nhấn đúp và giữ để chọn lối tắt hoặc sử dụng hành động tùy chỉnh."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Lối tắt"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Lối tắt <xliff:g id="NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/go/res/values-zh-rCN/strings.xml b/go/res/values-zh-rCN/strings.xml
deleted file mode 100644
index 57351d3..0000000
--- a/go/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"触摸并按住快捷方式即可选择快捷方式。"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"点按两次并按住快捷方式即可选择快捷方式,您也可以使用自定义操作。"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"快捷方式"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>快捷方式"</string>
-</resources>
diff --git a/go/res/values-zh-rHK/strings.xml b/go/res/values-zh-rHK/strings.xml
deleted file mode 100644
index dea7749..0000000
--- a/go/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"按住捷徑即可選取捷徑。"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"扲兩下然後扲住就可以揀選捷徑,或者用自訂嘅操作。"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"捷徑"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> 捷徑"</string>
-</resources>
diff --git a/go/res/values-zh-rTW/strings.xml b/go/res/values-zh-rTW/strings.xml
deleted file mode 100644
index 07ae2ed..0000000
--- a/go/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"按住捷徑即可選取。"</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"輕觸兩下並按住捷徑即可選取,你也可以使用自訂動作。"</string>
- <string name="widget_button_text" msgid="4221900832360456858">"捷徑"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"「<xliff:g id="NAME">%1$s</xliff:g>」捷徑"</string>
-</resources>
diff --git a/go/res/values-zu/strings.xml b/go/res/values-zu/strings.xml
deleted file mode 100644
index e5051df..0000000
--- a/go/res/values-zu/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="long_press_widget_to_add" msgid="4001616142797446267">"Thinta futhi ubambe ukuze ukhethe isinqamuleli."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Thepha kabulu futhi ubambe ukuze ukhethe isinqamuleli noma usebenzise izenzo zangokwezifiso."</string>
- <string name="widget_button_text" msgid="4221900832360456858">"Izinqamuleli"</string>
- <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> izinqamuleli"</string>
-</resources>
diff --git a/go/res/values/strings.xml b/go/res/values/strings.xml
deleted file mode 100644
index 8ef2e62..0000000
--- a/go/res/values/strings.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- Message to tell the user to press and hold on a shortcut to add it [CHAR_LIMIT=50] -->
- <string name="long_press_widget_to_add">Touch & hold to pick up a shortcut.</string>
- <!-- Accessibility spoken hint message in widget picker, which allows user to add a shortcut. Custom action is the label for additional accessibility actions available in this mode [CHAR_LIMIT=100] -->
- <string name="long_accessible_way_to_add">Double-tap & hold to pick up a shortcut or use custom actions.</string>
- <!-- Text for shortcut add button -->
- <string name="widget_button_text">Shortcuts</string>
-
- <!-- Strings for widgets & more in the popup container/bottom sheet -->
- <!-- Title for a bottom sheet that shows shortcuts for a particular app -->
- <string name="widgets_bottom_sheet_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> shortcuts</string>
-
-</resources>
diff --git a/go/src_flags/com/android/launcher3/config/FeatureFlags.java b/go/src/com/android/launcher3/config/FeatureFlags.java
similarity index 90%
rename from go/src_flags/com/android/launcher3/config/FeatureFlags.java
rename to go/src/com/android/launcher3/config/FeatureFlags.java
index b11bb7c..a90808c 100644
--- a/go/src_flags/com/android/launcher3/config/FeatureFlags.java
+++ b/go/src/com/android/launcher3/config/FeatureFlags.java
@@ -16,12 +16,15 @@
package com.android.launcher3.config;
+import android.content.Context;
+
/**
* Defines a set of flags used to control various launcher behaviors
*/
public final class FeatureFlags extends BaseFlags {
-
- private FeatureFlags() {}
+ private FeatureFlags() {
+ // Prevent instantiation
+ }
// Features to control Launcher3Go behavior
public static final boolean GO_DISABLE_WIDGETS = true;
diff --git a/go/src/com/android/launcher3/model/LoaderResults.java b/go/src/com/android/launcher3/model/LoaderResults.java
new file mode 100644
index 0000000..b82f362
--- /dev/null
+++ b/go/src/com/android/launcher3/model/LoaderResults.java
@@ -0,0 +1,42 @@
+/*
+ * 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.model;
+
+import com.android.launcher3.AllAppsList;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.Callbacks;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Helper class to handle results of {@link com.android.launcher3.model.LoaderTask}.
+ */
+public class LoaderResults extends BaseLoaderResults {
+
+ public LoaderResults(LauncherAppState app, BgDataModel dataModel,
+ AllAppsList allAppsList, int pageToBindFirst, WeakReference<Callbacks> callbacks) {
+ super(app, dataModel, allAppsList, pageToBindFirst, callbacks);
+ }
+
+ @Override
+ public void bindDeepShortcuts() {
+ }
+
+ @Override
+ public void bindWidgets() {
+ }
+}
diff --git a/go/src/com/android/launcher3/model/WidgetsModel.java b/go/src/com/android/launcher3/model/WidgetsModel.java
new file mode 100644
index 0000000..18f3f9d
--- /dev/null
+++ b/go/src/com/android/launcher3/model/WidgetsModel.java
@@ -0,0 +1,67 @@
+/*
+ * 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.model;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+import com.android.launcher3.icons.ComponentWithLabel;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.widget.WidgetListRowEntry;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Widgets data model that is used by the adapters of the widget views and controllers.
+ *
+ * <p> The widgets and shortcuts are organized using package name as its index.
+ */
+public class WidgetsModel {
+ private static final ArrayList<WidgetListRowEntry> EMPTY_WIDGET_LIST = new ArrayList<>();
+
+ /**
+ * Returns a list of {@link WidgetListRowEntry}. All {@link WidgetItem} in a single row
+ * are sorted (based on label and user), but the overall list of {@link WidgetListRowEntry}s
+ * is not sorted. This list is sorted at the UI when using
+ * {@link com.android.launcher3.widget.WidgetsDiffReporter}
+ *
+ * @see com.android.launcher3.widget.WidgetsListAdapter#setWidgets(ArrayList)
+ */
+ public synchronized ArrayList<WidgetListRowEntry> getWidgetsList(Context context) {
+ return EMPTY_WIDGET_LIST;
+ }
+
+ /**
+ * @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise
+ * only widgets and shortcuts associated with the package/user are.
+ */
+ public List<ComponentWithLabel> update(LauncherAppState app,
+ @Nullable PackageUserKey packageUser) {
+ return Collections.emptyList();
+ }
+
+
+ public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user,
+ LauncherAppState app) {
+ }
+}
\ No newline at end of file
diff --git a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
new file mode 100644
index 0000000..ff0c907
--- /dev/null
+++ b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
@@ -0,0 +1,124 @@
+/*
+ * 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.shortcuts;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import com.android.launcher3.ItemInfo;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Performs operations related to deep shortcuts, such as querying for them, pinning them, etc.
+ */
+public class DeepShortcutManager {
+ private static DeepShortcutManager sInstance;
+ private static final Object sInstanceLock = new Object();
+
+ public static DeepShortcutManager getInstance(Context context) {
+ synchronized (sInstanceLock) {
+ if (sInstance == null) {
+ sInstance = new DeepShortcutManager(context.getApplicationContext());
+ }
+ return sInstance;
+ }
+ }
+
+ private DeepShortcutManager(Context context) {
+ }
+
+ public static boolean supportsShortcuts(ItemInfo info) {
+ return false;
+ }
+
+ public boolean wasLastCallSuccess() {
+ return false;
+ }
+
+ public void onShortcutsChanged(List<ShortcutInfoCompat> shortcuts) {
+ }
+
+ /**
+ * Queries for the shortcuts with the package name and provided ids.
+ *
+ * This method is intended to get the full details for shortcuts when they are added or updated,
+ * because we only get "key" fields in onShortcutsChanged().
+ */
+ public List<ShortcutInfoCompat> queryForFullDetails(String packageName,
+ List<String> shortcutIds, UserHandle user) {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Gets all the manifest and dynamic shortcuts associated with the given package and user,
+ * to be displayed in the shortcuts container on long press.
+ */
+ public List<ShortcutInfoCompat> queryForShortcutsContainer(ComponentName activity,
+ UserHandle user) {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Removes the given shortcut from the current list of pinned shortcuts.
+ * (Runs on background thread)
+ */
+ public void unpinShortcut(final ShortcutKey key) {
+ }
+
+ /**
+ * Adds the given shortcut to the current list of pinned shortcuts.
+ * (Runs on background thread)
+ */
+ public void pinShortcut(final ShortcutKey key) {
+ }
+
+ public void startShortcut(String packageName, String id, Rect sourceBounds,
+ Bundle startActivityOptions, UserHandle user) {
+ }
+
+ public Drawable getShortcutIconDrawable(ShortcutInfoCompat shortcutInfo, int density) {
+ return null;
+ }
+
+ /**
+ * Returns the id's of pinned shortcuts associated with the given package and user.
+ *
+ * If packageName is null, returns all pinned shortcuts regardless of package.
+ */
+ public List<ShortcutInfoCompat> queryForPinnedShortcuts(String packageName, UserHandle user) {
+ return Collections.emptyList();
+ }
+
+ public List<ShortcutInfoCompat> queryForPinnedShortcuts(String packageName,
+ List<String> shortcutIds, UserHandle user) {
+ return Collections.emptyList();
+ }
+
+ public List<ShortcutInfoCompat> queryForAllShortcuts(UserHandle user) {
+ return Collections.emptyList();
+ }
+
+ public boolean hasHostPermission() {
+ return false;
+ }
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..b299cfe
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,13 @@
+# Until all the dependencies move to android X
+android.useAndroidX = true
+android.enableJetifier = true
+
+ANDROID_X_VERSION=1.0.0-beta01
+
+GRADLE_CLASS_PATH=com.android.tools.build:gradle:3.2.0-rc03
+
+PROTOBUF_CLASS_PATH=com.google.protobuf:protobuf-gradle-plugin:0.8.6
+PROTOBUF_DEPENDENCY=com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7
+
+BUILD_TOOLS_VERSION=28.0.3
+COMPILE_SDK=28
\ No newline at end of file
diff --git a/iconloaderlib/Android.bp b/iconloaderlib/Android.bp
new file mode 100644
index 0000000..f12d16e
--- /dev/null
+++ b/iconloaderlib/Android.bp
@@ -0,0 +1,44 @@
+// 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.
+
+android_library {
+ name: "iconloader_base",
+ sdk_version: "28",
+ min_sdk_version: "21",
+ static_libs: [
+ "androidx.core_core",
+ ],
+ resource_dirs: [
+ "res",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+}
+
+android_library {
+ name: "iconloader",
+ sdk_version: "system_current",
+ min_sdk_version: "21",
+ static_libs: [
+ "androidx.core_core",
+ ],
+ resource_dirs: [
+ "res",
+ ],
+ srcs: [
+ "src/**/*.java",
+ "src_full_lib/**/*.java",
+ ],
+}
diff --git a/res/layout/all_apps_button.xml b/iconloaderlib/AndroidManifest.xml
similarity index 76%
copy from res/layout/all_apps_button.xml
copy to iconloaderlib/AndroidManifest.xml
index 4bc780a..b30258d 100644
--- a/res/layout/all_apps_button.xml
+++ b/iconloaderlib/AndroidManifest.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!--
+ 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.
@@ -14,4 +15,6 @@
limitations under the License.
-->
-<TextView style="@style/BaseIcon" />
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.launcher3.icons">
+</manifest>
diff --git a/iconloaderlib/build.gradle b/iconloaderlib/build.gradle
new file mode 100644
index 0000000..f6a820a
--- /dev/null
+++ b/iconloaderlib/build.gradle
@@ -0,0 +1,55 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ google()
+ }
+ dependencies {
+ classpath GRADLE_CLASS_PATH
+ }
+}
+
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion COMPILE_SDK.toInteger()
+ buildToolsVersion BUILD_TOOLS_VERSION
+ publishNonDefault true
+
+ defaultConfig {
+ minSdkVersion 21
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+ }
+
+ sourceSets {
+ main {
+ java.srcDirs = ['src', 'src_full_lib']
+ manifest.srcFile 'AndroidManifest.xml'
+ res.srcDirs = ['res']
+ }
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ tasks.withType(JavaCompile) {
+ options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+
+repositories {
+ mavenCentral()
+ google()
+}
+
+dependencies {
+ implementation "androidx.core:core:${ANDROID_X_VERSION}"
+}
diff --git a/res/drawable-v26/adaptive_icon_drawable_wrapper.xml b/iconloaderlib/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
similarity index 93%
rename from res/drawable-v26/adaptive_icon_drawable_wrapper.xml
rename to iconloaderlib/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
index 2d78b69..9f13cf5 100644
--- a/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
+++ b/iconloaderlib/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
@@ -17,6 +17,6 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/legacy_icon_background"/>
<foreground>
- <com.android.launcher3.graphics.FixedScaleDrawable />
+ <com.android.launcher3.icons.FixedScaleDrawable />
</foreground>
</adaptive-icon>
diff --git a/res/drawable/ic_instant_app_badge.xml b/iconloaderlib/res/drawable/ic_instant_app_badge.xml
similarity index 93%
rename from res/drawable/ic_instant_app_badge.xml
rename to iconloaderlib/res/drawable/ic_instant_app_badge.xml
index cc53230..b74317e 100644
--- a/res/drawable/ic_instant_app_badge.xml
+++ b/iconloaderlib/res/drawable/ic_instant_app_badge.xml
@@ -21,23 +21,19 @@
<path
android:fillColor="@android:color/black"
- android:fillType="evenOdd"
android:strokeWidth="1"
android:pathData="M 9 0 C 13.9705627485 0 18 4.02943725152 18 9 C 18 13.9705627485 13.9705627485 18 9 18 C 4.02943725152 18 0 13.9705627485 0 9 C 0 4.02943725152 4.02943725152 0 9 0 Z" />
<path
android:fillColor="@android:color/white"
- android:fillType="evenOdd"
android:strokeWidth="1"
android:pathData="M 9 0 C 13.9705627485 0 18 4.02943725152 18 9 C 18 13.9705627485 13.9705627485 18 9 18 C 4.02943725152 18 0 13.9705627485 0 9 C 0 4.02943725152 4.02943725152 0 9 0 Z" />
<path
android:fillColor="@android:color/white"
- android:fillType="evenOdd"
android:strokeWidth="1"
android:pathData="M 9 0 C 13.9705627485 0 18 4.02943725152 18 9 C 18 13.9705627485 13.9705627485 18 9 18 C 4.02943725152 18 0 13.9705627485 0 9 C 0 4.02943725152 4.02943725152 0 9 0 Z" />
<path
android:fillColor="@android:color/black"
android:fillAlpha="0.87"
- android:fillType="evenOdd"
android:strokeWidth="1"
android:pathData="M 6 10.4123279 L 8.63934949 10.4123279 L 8.63934949 15.6 L 12.5577168 7.84517705 L 9.94547194 7.84517705 L 9.94547194 2 Z" />
-</vector>
\ No newline at end of file
+</vector>
diff --git a/iconloaderlib/res/values/colors.xml b/iconloaderlib/res/values/colors.xml
new file mode 100644
index 0000000..873b2fc
--- /dev/null
+++ b/iconloaderlib/res/values/colors.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+<resources>
+ <color name="legacy_icon_background">#FFFFFF</color>
+</resources>
diff --git a/iconloaderlib/res/values/config.xml b/iconloaderlib/res/values/config.xml
new file mode 100644
index 0000000..68c2d2e
--- /dev/null
+++ b/iconloaderlib/res/values/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+<resources>
+
+ <!-- Various configurations to control the simple cache implementation -->
+
+ <dimen name="default_icon_bitmap_size">56dp</dimen>
+ <bool name="simple_cache_enable_im_memory">false</bool>
+ <string name="cache_db_name" translatable="false">app_icons.db</string>
+
+</resources>
\ No newline at end of file
diff --git a/res/layout/all_apps_button.xml b/iconloaderlib/res/values/dimens.xml
similarity index 81%
copy from res/layout/all_apps_button.xml
copy to iconloaderlib/res/values/dimens.xml
index 4bc780a..e8c0c44 100644
--- a/res/layout/all_apps_button.xml
+++ b/iconloaderlib/res/values/dimens.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- 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.
@@ -14,4 +14,6 @@
limitations under the License.
-->
-<TextView style="@style/BaseIcon" />
+<resources>
+ <dimen name="profile_badge_size">24dp</dimen>
+</resources>
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
new file mode 100644
index 0000000..a318574
--- /dev/null
+++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -0,0 +1,344 @@
+package com.android.launcher3.icons;
+
+import static android.graphics.Paint.DITHER_FLAG;
+import static android.graphics.Paint.FILTER_BITMAP_FLAG;
+
+import static com.android.launcher3.icons.ShadowGenerator.BLUR_FACTOR;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Process;
+import android.os.UserHandle;
+
+/**
+ * This class will be moved to androidx library. There shouldn't be any dependency outside
+ * this package.
+ */
+public class BaseIconFactory implements AutoCloseable {
+
+ private static final String TAG = "BaseIconFactory";
+ private static final int DEFAULT_WRAPPER_BACKGROUND = Color.WHITE;
+ static final boolean ATLEAST_OREO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
+ static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
+
+ private final Rect mOldBounds = new Rect();
+ protected final Context mContext;
+ private final Canvas mCanvas;
+ private final PackageManager mPm;
+ private final ColorExtractor mColorExtractor;
+ private boolean mDisableColorExtractor;
+
+ protected final int mFillResIconDpi;
+ protected final int mIconBitmapSize;
+
+ private IconNormalizer mNormalizer;
+ private ShadowGenerator mShadowGenerator;
+
+ private Drawable mWrapperIcon;
+ private int mWrapperBackgroundColor;
+
+ protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) {
+ mContext = context.getApplicationContext();
+
+ mFillResIconDpi = fillResIconDpi;
+ mIconBitmapSize = iconBitmapSize;
+
+ mPm = mContext.getPackageManager();
+ mColorExtractor = new ColorExtractor();
+
+ mCanvas = new Canvas();
+ mCanvas.setDrawFilter(new PaintFlagsDrawFilter(DITHER_FLAG, FILTER_BITMAP_FLAG));
+ }
+
+ protected void clear() {
+ mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
+ mDisableColorExtractor = false;
+ }
+
+ public ShadowGenerator getShadowGenerator() {
+ if (mShadowGenerator == null) {
+ mShadowGenerator = new ShadowGenerator(mIconBitmapSize);
+ }
+ return mShadowGenerator;
+ }
+
+ public IconNormalizer getNormalizer() {
+ if (mNormalizer == null) {
+ mNormalizer = new IconNormalizer(mContext, mIconBitmapSize);
+ }
+ return mNormalizer;
+ }
+
+ @SuppressWarnings("deprecation")
+ public BitmapInfo createIconBitmap(Intent.ShortcutIconResource iconRes) {
+ try {
+ Resources resources = mPm.getResourcesForApplication(iconRes.packageName);
+ if (resources != null) {
+ final int id = resources.getIdentifier(iconRes.resourceName, null, null);
+ // do not stamp old legacy shortcuts as the app may have already forgotten about it
+ return createBadgedIconBitmap(
+ resources.getDrawableForDensity(id, mFillResIconDpi),
+ Process.myUserHandle() /* only available on primary user */,
+ false /* do not apply legacy treatment */);
+ }
+ } catch (Exception e) {
+ // Icon not found.
+ }
+ return null;
+ }
+
+ public BitmapInfo createIconBitmap(Bitmap icon) {
+ if (mIconBitmapSize == icon.getWidth() && mIconBitmapSize == icon.getHeight()) {
+ return BitmapInfo.fromBitmap(icon);
+ }
+ return BitmapInfo.fromBitmap(
+ createIconBitmap(new BitmapDrawable(mContext.getResources(), icon), 1f));
+ }
+
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ boolean shrinkNonAdaptiveIcons) {
+ return createBadgedIconBitmap(icon, user, shrinkNonAdaptiveIcons, false, null);
+ }
+
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ boolean shrinkNonAdaptiveIcons, boolean isInstantApp) {
+ return createBadgedIconBitmap(icon, user, shrinkNonAdaptiveIcons, isInstantApp, null);
+ }
+
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ int iconAppTargetSdk) {
+ return createBadgedIconBitmap(icon, user, iconAppTargetSdk, false);
+ }
+
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ int iconAppTargetSdk, boolean isInstantApp) {
+ return createBadgedIconBitmap(icon, user, iconAppTargetSdk, isInstantApp, null);
+ }
+
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ int iconAppTargetSdk, boolean isInstantApp, float[] scale) {
+ boolean shrinkNonAdaptiveIcons = ATLEAST_P ||
+ (ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O);
+ return createBadgedIconBitmap(icon, user, shrinkNonAdaptiveIcons, isInstantApp, scale);
+ }
+
+ public Bitmap createScaledBitmapWithoutShadow(Drawable icon, int iconAppTargetSdk) {
+ boolean shrinkNonAdaptiveIcons = ATLEAST_P ||
+ (ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O);
+ return createScaledBitmapWithoutShadow(icon, shrinkNonAdaptiveIcons);
+ }
+
+ /**
+ * Creates bitmap using the source drawable and various parameters.
+ * The bitmap is visually normalized with other icons and has enough spacing to add shadow.
+ *
+ * @param icon source of the icon
+ * @param user info can be used for a badge
+ * @param shrinkNonAdaptiveIcons {@code true} if non adaptive icons should be treated
+ * @param isInstantApp info can be used for a badge
+ * @param scale returns the scale result from normalization
+ * @return a bitmap suitable for disaplaying as an icon at various system UIs.
+ */
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
+ boolean shrinkNonAdaptiveIcons, boolean isInstantApp, float[] scale) {
+ if (scale == null) {
+ scale = new float[1];
+ }
+ icon = normalizeAndWrapToAdaptiveIcon(icon, shrinkNonAdaptiveIcons, null, scale);
+ Bitmap bitmap = createIconBitmap(icon, scale[0]);
+ if (ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
+ mCanvas.setBitmap(bitmap);
+ getShadowGenerator().recreateIcon(Bitmap.createBitmap(bitmap), mCanvas);
+ mCanvas.setBitmap(null);
+ }
+
+ final Bitmap result;
+ if (user != null && !Process.myUserHandle().equals(user)) {
+ BitmapDrawable drawable = new FixedSizeBitmapDrawable(bitmap);
+ Drawable badged = mPm.getUserBadgedIcon(drawable, user);
+ if (badged instanceof BitmapDrawable) {
+ result = ((BitmapDrawable) badged).getBitmap();
+ } else {
+ result = createIconBitmap(badged, 1f);
+ }
+ } else if (isInstantApp) {
+ badgeWithDrawable(bitmap, mContext.getDrawable(R.drawable.ic_instant_app_badge));
+ result = bitmap;
+ } else {
+ result = bitmap;
+ }
+ return BitmapInfo.fromBitmap(result, mDisableColorExtractor ? null : mColorExtractor);
+ }
+
+ public Bitmap createScaledBitmapWithoutShadow(Drawable icon, boolean shrinkNonAdaptiveIcons) {
+ RectF iconBounds = new RectF();
+ float[] scale = new float[1];
+ icon = normalizeAndWrapToAdaptiveIcon(icon, shrinkNonAdaptiveIcons, iconBounds, scale);
+ return createIconBitmap(icon,
+ Math.min(scale[0], ShadowGenerator.getScaleForBounds(iconBounds)));
+ }
+
+ /**
+ * Sets the background color used for wrapped adaptive icon
+ */
+ public void setWrapperBackgroundColor(int color) {
+ mWrapperBackgroundColor = (Color.alpha(color) < 255) ? DEFAULT_WRAPPER_BACKGROUND : color;
+ }
+
+ /**
+ * Disables the dominant color extraction for all icons loaded.
+ */
+ public void disableColorExtraction() {
+ mDisableColorExtractor = true;
+ }
+
+ private Drawable normalizeAndWrapToAdaptiveIcon(Drawable icon, boolean shrinkNonAdaptiveIcons,
+ RectF outIconBounds, float[] outScale) {
+ float scale = 1f;
+
+ if (shrinkNonAdaptiveIcons && ATLEAST_OREO) {
+ if (mWrapperIcon == null) {
+ mWrapperIcon = mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper)
+ .mutate();
+ }
+ AdaptiveIconDrawable dr = (AdaptiveIconDrawable) mWrapperIcon;
+ dr.setBounds(0, 0, 1, 1);
+ scale = getNormalizer().getScale(icon, outIconBounds);
+ if (!(icon instanceof AdaptiveIconDrawable)) {
+ FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground());
+ fsd.setDrawable(icon);
+ fsd.setScale(scale);
+ icon = dr;
+ scale = getNormalizer().getScale(icon, outIconBounds);
+
+ ((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor);
+ }
+ } else {
+ scale = getNormalizer().getScale(icon, outIconBounds);
+ }
+
+ outScale[0] = scale;
+ return icon;
+ }
+
+ /**
+ * Adds the {@param badge} on top of {@param target} using the badge dimensions.
+ */
+ public void badgeWithDrawable(Bitmap target, Drawable badge) {
+ mCanvas.setBitmap(target);
+ badgeWithDrawable(mCanvas, badge);
+ mCanvas.setBitmap(null);
+ }
+
+ /**
+ * Adds the {@param badge} on top of {@param target} using the badge dimensions.
+ */
+ public void badgeWithDrawable(Canvas target, Drawable badge) {
+ int badgeSize = mContext.getResources().getDimensionPixelSize(R.dimen.profile_badge_size);
+ badge.setBounds(mIconBitmapSize - badgeSize, mIconBitmapSize - badgeSize,
+ mIconBitmapSize, mIconBitmapSize);
+ badge.draw(target);
+ }
+
+ /**
+ * @param scale the scale to apply before drawing {@param icon} on the canvas
+ */
+ private Bitmap createIconBitmap(Drawable icon, float scale) {
+ Bitmap bitmap = Bitmap.createBitmap(mIconBitmapSize, mIconBitmapSize,
+ Bitmap.Config.ARGB_8888);
+ mCanvas.setBitmap(bitmap);
+ mOldBounds.set(icon.getBounds());
+
+ if (ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
+ int offset = Math.max((int) Math.ceil(BLUR_FACTOR * mIconBitmapSize),
+ Math.round(mIconBitmapSize * (1 - scale) / 2 ));
+ icon.setBounds(offset, offset, mIconBitmapSize - offset, mIconBitmapSize - offset);
+ icon.draw(mCanvas);
+ } else {
+ if (icon instanceof BitmapDrawable) {
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
+ Bitmap b = bitmapDrawable.getBitmap();
+ if (bitmap != null && b.getDensity() == Bitmap.DENSITY_NONE) {
+ bitmapDrawable.setTargetDensity(mContext.getResources().getDisplayMetrics());
+ }
+ }
+ int width = mIconBitmapSize;
+ int height = mIconBitmapSize;
+
+ int intrinsicWidth = icon.getIntrinsicWidth();
+ int intrinsicHeight = icon.getIntrinsicHeight();
+ if (intrinsicWidth > 0 && intrinsicHeight > 0) {
+ // Scale the icon proportionally to the icon dimensions
+ final float ratio = (float) intrinsicWidth / intrinsicHeight;
+ if (intrinsicWidth > intrinsicHeight) {
+ height = (int) (width / ratio);
+ } else if (intrinsicHeight > intrinsicWidth) {
+ width = (int) (height * ratio);
+ }
+ }
+ final int left = (mIconBitmapSize - width) / 2;
+ final int top = (mIconBitmapSize - height) / 2;
+ icon.setBounds(left, top, left + width, top + height);
+ mCanvas.save();
+ mCanvas.scale(scale, scale, mIconBitmapSize / 2, mIconBitmapSize / 2);
+ icon.draw(mCanvas);
+ mCanvas.restore();
+
+ }
+ icon.setBounds(mOldBounds);
+ mCanvas.setBitmap(null);
+ return bitmap;
+ }
+
+ @Override
+ public void close() {
+ clear();
+ }
+
+ public BitmapInfo makeDefaultIcon(UserHandle user) {
+ return createBadgedIconBitmap(getFullResDefaultActivityIcon(mFillResIconDpi),
+ user, Build.VERSION.SDK_INT);
+ }
+
+ public static Drawable getFullResDefaultActivityIcon(int iconDpi) {
+ return Resources.getSystem().getDrawableForDensity(
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+ ? android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon,
+ iconDpi);
+ }
+
+ /**
+ * An extension of {@link BitmapDrawable} which returns the bitmap pixel size as intrinsic size.
+ * This allows the badging to be done based on the action bitmap size rather than
+ * the scaled bitmap size.
+ */
+ private static class FixedSizeBitmapDrawable extends BitmapDrawable {
+
+ public FixedSizeBitmapDrawable(Bitmap bitmap) {
+ super(null, bitmap);
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return getBitmap().getWidth();
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return getBitmap().getWidth();
+ }
+ }
+}
diff --git a/src/com/android/launcher3/graphics/BitmapInfo.java b/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java
similarity index 65%
rename from src/com/android/launcher3/graphics/BitmapInfo.java
rename to iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java
index ab906e2..245561e 100644
--- a/src/com/android/launcher3/graphics/BitmapInfo.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BitmapInfo.java
@@ -13,31 +13,37 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.graphics;
+package com.android.launcher3.icons;
import android.graphics.Bitmap;
-
-import com.android.launcher3.ItemInfoWithIcon;
+import android.graphics.Bitmap.Config;
public class BitmapInfo {
+ public static final Bitmap LOW_RES_ICON = Bitmap.createBitmap(1, 1, Config.ALPHA_8);
+
public Bitmap icon;
public int color;
- public void applyTo(ItemInfoWithIcon info) {
- info.iconBitmap = icon;
- info.iconColor = color;
- }
-
public void applyTo(BitmapInfo info) {
info.icon = icon;
info.color = color;
}
+ public final boolean isLowRes() {
+ return LOW_RES_ICON == icon;
+ }
+
public static BitmapInfo fromBitmap(Bitmap bitmap) {
+ return fromBitmap(bitmap, null);
+ }
+
+ public static BitmapInfo fromBitmap(Bitmap bitmap, ColorExtractor dominantColorExtractor) {
BitmapInfo info = new BitmapInfo();
info.icon = bitmap;
- info.color = ColorExtractor.findDominantColorByHue(bitmap);
+ info.color = dominantColorExtractor != null
+ ? dominantColorExtractor.findDominantColorByHue(bitmap)
+ : 0;
return info;
}
}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BitmapRenderer.java b/iconloaderlib/src/com/android/launcher3/icons/BitmapRenderer.java
new file mode 100644
index 0000000..a66b929
--- /dev/null
+++ b/iconloaderlib/src/com/android/launcher3/icons/BitmapRenderer.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 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.icons;
+
+import android.annotation.TargetApi;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Picture;
+import android.os.Build;
+
+/**
+ * Interface representing a bitmap draw operation.
+ */
+public interface BitmapRenderer {
+
+ boolean USE_HARDWARE_BITMAP = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
+
+ static Bitmap createSoftwareBitmap(int width, int height, BitmapRenderer renderer) {
+ Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ renderer.draw(new Canvas(result));
+ return result;
+ }
+
+ @TargetApi(Build.VERSION_CODES.P)
+ static Bitmap createHardwareBitmap(int width, int height, BitmapRenderer renderer) {
+ if (!USE_HARDWARE_BITMAP) {
+ return createSoftwareBitmap(width, height, renderer);
+ }
+
+ Picture picture = new Picture();
+ renderer.draw(picture.beginRecording(width, height));
+ picture.endRecording();
+ return Bitmap.createBitmap(picture);
+ }
+
+ void draw(Canvas out);
+}
diff --git a/src/com/android/launcher3/graphics/ColorExtractor.java b/iconloaderlib/src/com/android/launcher3/icons/ColorExtractor.java
similarity index 79%
rename from src/com/android/launcher3/graphics/ColorExtractor.java
rename to iconloaderlib/src/com/android/launcher3/icons/ColorExtractor.java
index e9d72b7..87bda82 100644
--- a/src/com/android/launcher3/graphics/ColorExtractor.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/ColorExtractor.java
@@ -13,27 +13,37 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.graphics;
+package com.android.launcher3.icons;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.util.SparseArray;
+import java.util.Arrays;
/**
* Utility class for extracting colors from a bitmap.
*/
public class ColorExtractor {
- public static int findDominantColorByHue(Bitmap bitmap) {
- return findDominantColorByHue(bitmap, 20);
+ private final int NUM_SAMPLES = 20;
+ private final float[] mTmpHsv = new float[3];
+ private final float[] mTmpHueScoreHistogram = new float[360];
+ private final int[] mTmpPixels = new int[NUM_SAMPLES];
+ private final SparseArray<Float> mTmpRgbScores = new SparseArray<>();
+
+ /**
+ * This picks a dominant color, looking for high-saturation, high-value, repeated hues.
+ * @param bitmap The bitmap to scan
+ */
+ public int findDominantColorByHue(Bitmap bitmap) {
+ return findDominantColorByHue(bitmap, NUM_SAMPLES);
}
/**
* This picks a dominant color, looking for high-saturation, high-value, repeated hues.
* @param bitmap The bitmap to scan
- * @param samples The approximate max number of samples to use.
*/
- public static int findDominantColorByHue(Bitmap bitmap, int samples) {
+ public int findDominantColorByHue(Bitmap bitmap, int samples) {
final int height = bitmap.getHeight();
final int width = bitmap.getWidth();
int sampleStride = (int) Math.sqrt((height * width) / samples);
@@ -42,15 +52,18 @@
}
// This is an out-param, for getting the hsv values for an rgb
- float[] hsv = new float[3];
+ float[] hsv = mTmpHsv;
+ Arrays.fill(hsv, 0);
// First get the best hue, by creating a histogram over 360 hue buckets,
// where each pixel contributes a score weighted by saturation, value, and alpha.
- float[] hueScoreHistogram = new float[360];
+ float[] hueScoreHistogram = mTmpHueScoreHistogram;
+ Arrays.fill(hueScoreHistogram, 0);
float highScore = -1;
int bestHue = -1;
- int[] pixels = new int[samples];
+ int[] pixels = mTmpPixels;
+ Arrays.fill(pixels, 0);
int pixelCount = 0;
for (int y = 0; y < height; y += sampleStride) {
@@ -82,7 +95,8 @@
}
}
- SparseArray<Float> rgbScores = new SparseArray<>();
+ SparseArray<Float> rgbScores = mTmpRgbScores;
+ rgbScores.clear();
int bestColor = 0xff000000;
highScore = -1;
// Go back over the RGB colors that match the winning hue,
diff --git a/src/com/android/launcher3/graphics/FixedScaleDrawable.java b/iconloaderlib/src/com/android/launcher3/icons/FixedScaleDrawable.java
similarity index 97%
rename from src/com/android/launcher3/graphics/FixedScaleDrawable.java
rename to iconloaderlib/src/com/android/launcher3/icons/FixedScaleDrawable.java
index 0f0e424..e594f47 100644
--- a/src/com/android/launcher3/graphics/FixedScaleDrawable.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/FixedScaleDrawable.java
@@ -1,4 +1,4 @@
-package com.android.launcher3.graphics;
+package com.android.launcher3.icons;
import android.annotation.TargetApi;
import android.content.res.Resources;
diff --git a/iconloaderlib/src/com/android/launcher3/icons/GraphicsUtils.java b/iconloaderlib/src/com/android/launcher3/icons/GraphicsUtils.java
new file mode 100644
index 0000000..11d5eef
--- /dev/null
+++ b/iconloaderlib/src/com/android/launcher3/icons/GraphicsUtils.java
@@ -0,0 +1,63 @@
+/*
+ * 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.icons;
+
+import android.graphics.Bitmap;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import androidx.annotation.ColorInt;
+
+public class GraphicsUtils {
+
+ private static final String TAG = "GraphicsUtils";
+
+ /**
+ * Set the alpha component of {@code color} to be {@code alpha}. Unlike the support lib version,
+ * it bounds the alpha in valid range instead of throwing an exception to allow for safer
+ * interpolation of color animations
+ */
+ @ColorInt
+ public static int setColorAlphaBound(int color, int alpha) {
+ if (alpha < 0) {
+ alpha = 0;
+ } else if (alpha > 255) {
+ alpha = 255;
+ }
+ return (color & 0x00ffffff) | (alpha << 24);
+ }
+
+ /**
+ * Compresses the bitmap to a byte array for serialization.
+ */
+ public static byte[] flattenBitmap(Bitmap bitmap) {
+ // Try go guesstimate how much space the icon will take when serialized
+ // to avoid unnecessary allocations/copies during the write (4 bytes per pixel).
+ int size = bitmap.getWidth() * bitmap.getHeight() * 4;
+ ByteArrayOutputStream out = new ByteArrayOutputStream(size);
+ try {
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
+ out.flush();
+ out.close();
+ return out.toByteArray();
+ } catch (IOException e) {
+ Log.w(TAG, "Could not write bitmap");
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/graphics/IconNormalizer.java b/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java
similarity index 69%
rename from src/com/android/launcher3/graphics/IconNormalizer.java
rename to iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java
index a2a0801..05908df 100644
--- a/src/com/android/launcher3/graphics/IconNormalizer.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java
@@ -14,32 +14,22 @@
* limitations under the License.
*/
-package com.android.launcher3.graphics;
+package com.android.launcher3.icons;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.util.Log;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
import java.nio.ByteBuffer;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
public class IconNormalizer {
private static final String TAG = "IconNormalizer";
@@ -57,9 +47,6 @@
private static final int MIN_VISIBLE_ALPHA = 40;
- // Shape detection related constants
- private static final float BOUND_RATIO_MARGIN = .05f;
- private static final float PIXEL_DIFF_PERCENTAGE_THRESHOLD = 0.005f;
private static final float SCALE_NOT_INITIALIZED = 0;
// Ratio of the diameter of an normalized circular icon to the actual icon size.
@@ -68,8 +55,6 @@
private final int mMaxSize;
private final Bitmap mBitmap;
private final Canvas mCanvas;
- private final Paint mPaintMaskShape;
- private final Paint mPaintMaskShapeOutline;
private final byte[] mPixels;
private final Rect mAdaptiveIconBounds;
@@ -79,13 +64,11 @@
private final float[] mLeftBorder;
private final float[] mRightBorder;
private final Rect mBounds;
- private final Path mShapePath;
- private final Matrix mMatrix;
/** package private **/
- IconNormalizer(Context context) {
+ IconNormalizer(Context context, int iconBitmapSize) {
// Use twice the icon size as maximum size to avoid scaling down twice.
- mMaxSize = LauncherAppState.getIDP(context).iconBitmapSize * 2;
+ mMaxSize = iconBitmapSize * 2;
mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);
mCanvas = new Canvas(mBitmap);
mPixels = new byte[mMaxSize * mMaxSize];
@@ -94,89 +77,10 @@
mBounds = new Rect();
mAdaptiveIconBounds = new Rect();
- mPaintMaskShape = new Paint();
- mPaintMaskShape.setColor(Color.RED);
- mPaintMaskShape.setStyle(Paint.Style.FILL);
- mPaintMaskShape.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
-
- mPaintMaskShapeOutline = new Paint();
- mPaintMaskShapeOutline.setStrokeWidth(2 * context.getResources().getDisplayMetrics().density);
- mPaintMaskShapeOutline.setStyle(Paint.Style.STROKE);
- mPaintMaskShapeOutline.setColor(Color.BLACK);
- mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
-
- mShapePath = new Path();
- mMatrix = new Matrix();
mAdaptiveIconScale = SCALE_NOT_INITIALIZED;
}
/**
- * Returns if the shape of the icon is same as the path.
- * For this method to work, the shape path bounds should be in [0,1]x[0,1] bounds.
- */
- private boolean isShape(Path maskPath) {
- // Condition1:
- // If width and height of the path not close to a square, then the icon shape is
- // not same as the mask shape.
- float iconRatio = ((float) mBounds.width()) / mBounds.height();
- if (Math.abs(iconRatio - 1) > BOUND_RATIO_MARGIN) {
- if (DEBUG) {
- Log.d(TAG, "Not same as mask shape because width != height. " + iconRatio);
- }
- return false;
- }
-
- // Condition 2:
- // Actual icon (white) and the fitted shape (e.g., circle)(red) XOR operation
- // should generate transparent image, if the actual icon is equivalent to the shape.
-
- // Fit the shape within the icon's bounding box
- mMatrix.reset();
- mMatrix.setScale(mBounds.width(), mBounds.height());
- mMatrix.postTranslate(mBounds.left, mBounds.top);
- maskPath.transform(mMatrix, mShapePath);
-
- // XOR operation
- mCanvas.drawPath(mShapePath, mPaintMaskShape);
-
- // DST_OUT operation around the mask path outline
- mCanvas.drawPath(mShapePath, mPaintMaskShapeOutline);
-
- // Check if the result is almost transparent
- return isTransparentBitmap();
- }
-
- /**
- * Used to determine if certain the bitmap is transparent.
- */
- private boolean isTransparentBitmap() {
- ByteBuffer buffer = ByteBuffer.wrap(mPixels);
- buffer.rewind();
- mBitmap.copyPixelsToBuffer(buffer);
-
- int y = mBounds.top;
- // buffer position
- int index = y * mMaxSize;
- // buffer shift after every row, width of buffer = mMaxSize
- int rowSizeDiff = mMaxSize - mBounds.right;
-
- int sum = 0;
- for (; y < mBounds.bottom; y++) {
- index += mBounds.left;
- for (int x = mBounds.left; x < mBounds.right; x++) {
- if ((mPixels[index] & 0xFF) > MIN_VISIBLE_ALPHA) {
- sum++;
- }
- index++;
- }
- index += rowSizeDiff;
- }
-
- float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height());
- return percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD;
- }
-
- /**
* Returns the amount by which the {@param d} should be scaled (in both dimensions) so that it
* matches the design guidelines for a launcher icon.
*
@@ -190,19 +94,14 @@
*
* @param outBounds optional rect to receive the fraction distance from each edge.
*/
- public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds,
- @Nullable Path path, @Nullable boolean[] outMaskShape) {
- if (Utilities.ATLEAST_OREO && d instanceof AdaptiveIconDrawable) {
+ public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds) {
+ if (BaseIconFactory.ATLEAST_OREO && d instanceof AdaptiveIconDrawable) {
if (mAdaptiveIconScale != SCALE_NOT_INITIALIZED) {
if (outBounds != null) {
outBounds.set(mAdaptiveIconBounds);
}
return mAdaptiveIconScale;
}
- if (d instanceof FolderAdaptiveIcon) {
- // Since we just want the scale, avoid heavy drawing operations
- d = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK), null);
- }
}
int width = d.getIntrinsicWidth();
int height = d.getIntrinsicHeight();
@@ -306,14 +205,10 @@
1 - ((float) mBounds.right) / width,
1 - ((float) mBounds.bottom) / height);
}
-
- if (outMaskShape != null && outMaskShape.length > 0) {
- outMaskShape[0] = isShape(path);
- }
float areaScale = area / (width * height);
// Use sqrt of the final ratio as the images is scaled across both width and height.
float scale = areaScale > scaleRequired ? (float) Math.sqrt(scaleRequired / areaScale) : 1;
- if (Utilities.ATLEAST_OREO && d instanceof AdaptiveIconDrawable &&
+ if (BaseIconFactory.ATLEAST_OREO && d instanceof AdaptiveIconDrawable &&
mAdaptiveIconScale == SCALE_NOT_INITIALIZED) {
mAdaptiveIconScale = scale;
mAdaptiveIconBounds.set(mBounds);
diff --git a/src/com/android/launcher3/graphics/ShadowGenerator.java b/iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java
similarity index 91%
rename from src/com/android/launcher3/graphics/ShadowGenerator.java
rename to iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java
index 88da853..455c58c 100644
--- a/src/com/android/launcher3/graphics/ShadowGenerator.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/ShadowGenerator.java
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.launcher3.graphics;
+package com.android.launcher3.icons;
-import android.content.Context;
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BlurMaskFilter;
@@ -27,23 +28,18 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
-import android.support.v4.graphics.ColorUtils;
-
-import com.android.launcher3.LauncherAppState;
/**
* Utility class to add shadows to bitmaps.
*/
public class ShadowGenerator {
-
- // Percent of actual icon size
- private static final float HALF_DISTANCE = 0.5f;
public static final float BLUR_FACTOR = 0.5f/48;
// Percent of actual icon size
public static final float KEY_SHADOW_DISTANCE = 1f/48;
private static final int KEY_SHADOW_ALPHA = 61;
-
+ // Percent of actual icon size
+ private static final float HALF_DISTANCE = 0.5f;
private static final int AMBIENT_SHADOW_ALPHA = 30;
private final int mIconSize;
@@ -52,8 +48,8 @@
private final Paint mDrawPaint;
private final BlurMaskFilter mDefaultBlurMaskFilter;
- public ShadowGenerator(Context context) {
- mIconSize = LauncherAppState.getIDP(context).iconBitmapSize;
+ public ShadowGenerator(int iconSize) {
+ mIconSize = iconSize;
mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
mDefaultBlurMaskFilter = new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL);
@@ -120,7 +116,7 @@
}
public Builder setupBlurForSize(int height) {
- shadowBlur = height * 1f / 32;
+ shadowBlur = height * 1f / 24;
keyShadowDistance = height * 1f / 16;
return this;
}
@@ -146,12 +142,12 @@
// Key shadow
p.setShadowLayer(shadowBlur, 0, keyShadowDistance,
- ColorUtils.setAlphaComponent(Color.BLACK, keyShadowAlpha));
+ setColorAlphaBound(Color.BLACK, keyShadowAlpha));
c.drawRoundRect(bounds, radius, radius, p);
// Ambient shadow
p.setShadowLayer(shadowBlur, 0, 0,
- ColorUtils.setAlphaComponent(Color.BLACK, ambientShadowAlpha));
+ setColorAlphaBound(Color.BLACK, ambientShadowAlpha));
c.drawRoundRect(bounds, radius, radius, p);
if (Color.alpha(color) < 255) {
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
new file mode 100644
index 0000000..63820f6
--- /dev/null
+++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
@@ -0,0 +1,569 @@
+/*
+ * 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.icons.cache;
+
+import static com.android.launcher3.icons.BaseIconFactory.getFullResDefaultActivityIcon;
+import static com.android.launcher3.icons.BitmapInfo.LOW_RES_ICON;
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
+import android.content.ComponentName;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Process;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.launcher3.icons.BaseIconFactory;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.icons.GraphicsUtils;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.Provider;
+import com.android.launcher3.util.SQLiteCacheHelper;
+
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import androidx.annotation.NonNull;
+
+public abstract class BaseIconCache {
+
+ private static final String TAG = "BaseIconCache";
+ private static final boolean DEBUG = false;
+
+ private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
+
+ // Empty class name is used for storing package default entry.
+ public static final String EMPTY_CLASS_NAME = ".";
+
+ public static class CacheEntry extends BitmapInfo {
+ public CharSequence title = "";
+ public CharSequence contentDescription = "";
+ }
+
+ private final HashMap<UserHandle, BitmapInfo> mDefaultIcons = new HashMap<>();
+
+ protected final Context mContext;
+ protected final PackageManager mPackageManager;
+
+ private final Map<ComponentKey, CacheEntry> mCache;
+ protected final Handler mWorkerHandler;
+
+ protected int mIconDpi;
+ protected IconDB mIconDb;
+ protected String mSystemState = "";
+
+ private final String mDbFileName;
+ private final BitmapFactory.Options mDecodeOptions;
+ private final Looper mBgLooper;
+
+ public BaseIconCache(Context context, String dbFileName, Looper bgLooper,
+ int iconDpi, int iconPixelSize, boolean inMemoryCache) {
+ mContext = context;
+ mDbFileName = dbFileName;
+ mPackageManager = context.getPackageManager();
+ mBgLooper = bgLooper;
+ mWorkerHandler = new Handler(mBgLooper);
+
+ if (inMemoryCache) {
+ mCache = new HashMap<>(INITIAL_ICON_CACHE_CAPACITY);
+ } else {
+ // Use a dummy cache
+ mCache = new AbstractMap<ComponentKey, CacheEntry>() {
+ @Override
+ public Set<Entry<ComponentKey, CacheEntry>> entrySet() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public CacheEntry put(ComponentKey key, CacheEntry value) {
+ return value;
+ }
+ };
+ }
+
+ if (BitmapRenderer.USE_HARDWARE_BITMAP && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ mDecodeOptions = new BitmapFactory.Options();
+ mDecodeOptions.inPreferredConfig = Bitmap.Config.HARDWARE;
+ } else {
+ mDecodeOptions = null;
+ }
+
+ updateSystemState();
+ mIconDpi = iconDpi;
+ mIconDb = new IconDB(context, dbFileName, iconPixelSize);
+ }
+
+ /**
+ * Returns the persistable serial number for {@param user}. Subclass should implement proper
+ * caching strategy to avoid making binder call every time.
+ */
+ protected abstract long getSerialNumberForUser(UserHandle user);
+
+ /**
+ * Return true if the given app is an instant app and should be badged appropriately.
+ */
+ protected abstract boolean isInstantApp(ApplicationInfo info);
+
+ /**
+ * Opens and returns an icon factory. The factory is recycled by the caller.
+ */
+ protected abstract BaseIconFactory getIconFactory();
+
+ public void updateIconParams(int iconDpi, int iconPixelSize) {
+ mWorkerHandler.post(() -> updateIconParamsBg(iconDpi, iconPixelSize));
+ }
+
+ private synchronized void updateIconParamsBg(int iconDpi, int iconPixelSize) {
+ mIconDpi = iconDpi;
+ mDefaultIcons.clear();
+
+ mIconDb.close();
+ mIconDb = new IconDB(mContext, mDbFileName, iconPixelSize);
+ mCache.clear();
+ }
+
+ private Drawable getFullResIcon(Resources resources, int iconId) {
+ if (resources != null && iconId != 0) {
+ try {
+ return resources.getDrawableForDensity(iconId, mIconDpi);
+ } catch (Resources.NotFoundException e) { }
+ }
+ return getFullResDefaultActivityIcon(mIconDpi);
+ }
+
+ public Drawable getFullResIcon(String packageName, int iconId) {
+ try {
+ return getFullResIcon(mPackageManager.getResourcesForApplication(packageName), iconId);
+ } catch (PackageManager.NameNotFoundException e) { }
+ return getFullResDefaultActivityIcon(mIconDpi);
+ }
+
+ public Drawable getFullResIcon(ActivityInfo info) {
+ try {
+ return getFullResIcon(mPackageManager.getResourcesForApplication(info.applicationInfo),
+ info.getIconResource());
+ } catch (PackageManager.NameNotFoundException e) { }
+ return getFullResDefaultActivityIcon(mIconDpi);
+ }
+
+ private BitmapInfo makeDefaultIcon(UserHandle user) {
+ try (BaseIconFactory li = getIconFactory()) {
+ return li.makeDefaultIcon(user);
+ }
+ }
+
+ /**
+ * Remove any records for the supplied ComponentName.
+ */
+ public synchronized void remove(ComponentName componentName, UserHandle user) {
+ mCache.remove(new ComponentKey(componentName, user));
+ }
+
+ /**
+ * Remove any records for the supplied package name from memory.
+ */
+ private void removeFromMemCacheLocked(String packageName, UserHandle user) {
+ HashSet<ComponentKey> forDeletion = new HashSet<>();
+ for (ComponentKey key: mCache.keySet()) {
+ if (key.componentName.getPackageName().equals(packageName)
+ && key.user.equals(user)) {
+ forDeletion.add(key);
+ }
+ }
+ for (ComponentKey condemned: forDeletion) {
+ mCache.remove(condemned);
+ }
+ }
+
+ /**
+ * Removes the entries related to the given package in memory and persistent DB.
+ */
+ public synchronized void removeIconsForPkg(String packageName, UserHandle user) {
+ removeFromMemCacheLocked(packageName, user);
+ long userSerial = getSerialNumberForUser(user);
+ mIconDb.delete(
+ IconDB.COLUMN_COMPONENT + " LIKE ? AND " + IconDB.COLUMN_USER + " = ?",
+ new String[]{packageName + "/%", Long.toString(userSerial)});
+ }
+
+ public IconCacheUpdateHandler getUpdateHandler() {
+ updateSystemState();
+ return new IconCacheUpdateHandler(this);
+ }
+
+ /**
+ * Refreshes the system state definition used to check the validity of the cache. It
+ * incorporates all the properties that can affect the cache like locale and system-version.
+ */
+ private void updateSystemState() {
+ final String locale;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ locale = mContext.getResources().getConfiguration().getLocales().toLanguageTags();
+ } else {
+ locale = Locale.getDefault().toString();
+ }
+
+ mSystemState = locale + "," + Build.VERSION.SDK_INT;
+ }
+
+ protected String getIconSystemState(String packageName) {
+ return mSystemState;
+ }
+
+ /**
+ * Adds an entry into the DB and the in-memory cache.
+ * @param replaceExisting if true, it will recreate the bitmap even if it already exists in
+ * the memory. This is useful then the previous bitmap was created using
+ * old data.
+ * package private
+ */
+ protected synchronized <T> void addIconToDBAndMemCache(T object, CachingLogic<T> cachingLogic,
+ PackageInfo info, long userSerial, boolean replaceExisting) {
+ UserHandle user = cachingLogic.getUser(object);
+ ComponentName componentName = cachingLogic.getComponent(object);
+
+ final ComponentKey key = new ComponentKey(componentName, user);
+ CacheEntry entry = null;
+ if (!replaceExisting) {
+ entry = mCache.get(key);
+ // We can't reuse the entry if the high-res icon is not present.
+ if (entry == null || entry.icon == null || entry.isLowRes()) {
+ entry = null;
+ }
+ }
+ if (entry == null) {
+ entry = new CacheEntry();
+ cachingLogic.loadIcon(mContext, object, entry);
+ }
+ entry.title = cachingLogic.getLabel(object);
+ entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user);
+ mCache.put(key, entry);
+
+ ContentValues values = newContentValues(entry, entry.title.toString(),
+ componentName.getPackageName());
+ addIconToDB(values, componentName, info, userSerial);
+ }
+
+ /**
+ * Updates {@param values} to contain versioning information and adds it to the DB.
+ * @param values {@link ContentValues} containing icon & title
+ */
+ private void addIconToDB(ContentValues values, ComponentName key,
+ PackageInfo info, long userSerial) {
+ values.put(IconDB.COLUMN_COMPONENT, key.flattenToString());
+ values.put(IconDB.COLUMN_USER, userSerial);
+ values.put(IconDB.COLUMN_LAST_UPDATED, info.lastUpdateTime);
+ values.put(IconDB.COLUMN_VERSION, info.versionCode);
+ mIconDb.insertOrReplace(values);
+ }
+
+ public synchronized BitmapInfo getDefaultIcon(UserHandle user) {
+ if (!mDefaultIcons.containsKey(user)) {
+ mDefaultIcons.put(user, makeDefaultIcon(user));
+ }
+ return mDefaultIcons.get(user);
+ }
+
+ public boolean isDefaultIcon(Bitmap icon, UserHandle user) {
+ return getDefaultIcon(user).icon == icon;
+ }
+
+ /**
+ * Retrieves the entry from the cache. If the entry is not present, it creates a new entry.
+ * This method is not thread safe, it must be called from a synchronized method.
+ */
+ protected <T> CacheEntry cacheLocked(
+ @NonNull ComponentName componentName, @NonNull UserHandle user,
+ @NonNull Provider<T> infoProvider, @NonNull CachingLogic<T> cachingLogic,
+ boolean usePackageIcon, boolean useLowResIcon) {
+ return cacheLocked(componentName, user, infoProvider, cachingLogic, usePackageIcon,
+ useLowResIcon, true);
+ }
+
+ protected <T> CacheEntry cacheLocked(
+ @NonNull ComponentName componentName, @NonNull UserHandle user,
+ @NonNull Provider<T> infoProvider, @NonNull CachingLogic<T> cachingLogic,
+ boolean usePackageIcon, boolean useLowResIcon, boolean addToMemCache) {
+ assertWorkerThread();
+ ComponentKey cacheKey = new ComponentKey(componentName, user);
+ CacheEntry entry = mCache.get(cacheKey);
+ if (entry == null || (entry.isLowRes() && !useLowResIcon)) {
+ entry = new CacheEntry();
+ if (addToMemCache) {
+ mCache.put(cacheKey, entry);
+ }
+
+ // Check the DB first.
+ T object = null;
+ boolean providerFetchedOnce = false;
+
+ if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) {
+ object = infoProvider.get();
+ providerFetchedOnce = true;
+
+ if (object != null) {
+ cachingLogic.loadIcon(mContext, object, entry);
+ } else {
+ if (usePackageIcon) {
+ CacheEntry packageEntry = getEntryForPackageLocked(
+ componentName.getPackageName(), user, false);
+ if (packageEntry != null) {
+ if (DEBUG) Log.d(TAG, "using package default icon for " +
+ componentName.toShortString());
+ packageEntry.applyTo(entry);
+ entry.title = packageEntry.title;
+ entry.contentDescription = packageEntry.contentDescription;
+ }
+ }
+ if (entry.icon == null) {
+ if (DEBUG) Log.d(TAG, "using default icon for " +
+ componentName.toShortString());
+ getDefaultIcon(user).applyTo(entry);
+ }
+ }
+ }
+
+ if (TextUtils.isEmpty(entry.title)) {
+ if (object == null && !providerFetchedOnce) {
+ object = infoProvider.get();
+ providerFetchedOnce = true;
+ }
+ if (object != null) {
+ entry.title = cachingLogic.getLabel(object);
+ entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user);
+ }
+ }
+ }
+ return entry;
+ }
+
+ public synchronized void clear() {
+ assertWorkerThread();
+ mIconDb.clear();
+ }
+
+ /**
+ * Adds a default package entry in the cache. This entry is not persisted and will be removed
+ * when the cache is flushed.
+ */
+ public synchronized void cachePackageInstallInfo(String packageName, UserHandle user,
+ Bitmap icon, CharSequence title) {
+ removeFromMemCacheLocked(packageName, user);
+
+ ComponentKey cacheKey = getPackageKey(packageName, user);
+ CacheEntry entry = mCache.get(cacheKey);
+
+ // For icon caching, do not go through DB. Just update the in-memory entry.
+ if (entry == null) {
+ entry = new CacheEntry();
+ }
+ if (!TextUtils.isEmpty(title)) {
+ entry.title = title;
+ }
+ if (icon != null) {
+ BaseIconFactory li = getIconFactory();
+ li.createIconBitmap(icon).applyTo(entry);
+ li.close();
+ }
+ if (!TextUtils.isEmpty(title) && entry.icon != null) {
+ mCache.put(cacheKey, entry);
+ }
+ }
+
+ private static ComponentKey getPackageKey(String packageName, UserHandle user) {
+ ComponentName cn = new ComponentName(packageName, packageName + EMPTY_CLASS_NAME);
+ return new ComponentKey(cn, user);
+ }
+
+ /**
+ * Gets an entry for the package, which can be used as a fallback entry for various components.
+ * This method is not thread safe, it must be called from a synchronized method.
+ */
+ protected CacheEntry getEntryForPackageLocked(String packageName, UserHandle user,
+ boolean useLowResIcon) {
+ assertWorkerThread();
+ ComponentKey cacheKey = getPackageKey(packageName, user);
+ CacheEntry entry = mCache.get(cacheKey);
+
+ if (entry == null || (entry.isLowRes() && !useLowResIcon)) {
+ entry = new CacheEntry();
+ boolean entryUpdated = true;
+
+ // Check the DB first.
+ if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) {
+ try {
+ int flags = Process.myUserHandle().equals(user) ? 0 :
+ PackageManager.GET_UNINSTALLED_PACKAGES;
+ PackageInfo info = mPackageManager.getPackageInfo(packageName, flags);
+ ApplicationInfo appInfo = info.applicationInfo;
+ if (appInfo == null) {
+ throw new NameNotFoundException("ApplicationInfo is null");
+ }
+
+ BaseIconFactory li = getIconFactory();
+ // Load the full res icon for the application, but if useLowResIcon is set, then
+ // only keep the low resolution icon instead of the larger full-sized icon
+ BitmapInfo iconInfo = li.createBadgedIconBitmap(
+ appInfo.loadIcon(mPackageManager), user, appInfo.targetSdkVersion,
+ isInstantApp(appInfo));
+ li.close();
+
+ entry.title = appInfo.loadLabel(mPackageManager);
+ entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user);
+ entry.icon = useLowResIcon ? LOW_RES_ICON : iconInfo.icon;
+ entry.color = iconInfo.color;
+
+ // Add the icon in the DB here, since these do not get written during
+ // package updates.
+ ContentValues values = newContentValues(
+ iconInfo, entry.title.toString(), packageName);
+ addIconToDB(values, cacheKey.componentName, info, getSerialNumberForUser(user));
+
+ } catch (NameNotFoundException e) {
+ if (DEBUG) Log.d(TAG, "Application not installed " + packageName);
+ entryUpdated = false;
+ }
+ }
+
+ // Only add a filled-out entry to the cache
+ if (entryUpdated) {
+ mCache.put(cacheKey, entry);
+ }
+ }
+ return entry;
+ }
+
+ private boolean getEntryFromDB(ComponentKey cacheKey, CacheEntry entry, boolean lowRes) {
+ Cursor c = null;
+ try {
+ c = mIconDb.query(
+ lowRes ? IconDB.COLUMNS_LOW_RES : IconDB.COLUMNS_HIGH_RES,
+ IconDB.COLUMN_COMPONENT + " = ? AND " + IconDB.COLUMN_USER + " = ?",
+ new String[]{
+ cacheKey.componentName.flattenToString(),
+ Long.toString(getSerialNumberForUser(cacheKey.user))});
+ if (c.moveToNext()) {
+ // Set the alpha to be 255, so that we never have a wrong color
+ entry.color = setColorAlphaBound(c.getInt(0), 255);
+ entry.title = c.getString(1);
+ if (entry.title == null) {
+ entry.title = "";
+ entry.contentDescription = "";
+ } else {
+ entry.contentDescription = mPackageManager.getUserBadgedLabel(
+ entry.title, cacheKey.user);
+ }
+
+ if (lowRes) {
+ entry.icon = LOW_RES_ICON;
+ } else {
+ byte[] data = c.getBlob(2);
+ try {
+ entry.icon = BitmapFactory.decodeByteArray(data, 0, data.length,
+ mDecodeOptions);
+ } catch (Exception e) { }
+ }
+ return true;
+ }
+ } catch (SQLiteException e) {
+ Log.d(TAG, "Error reading icon cache", e);
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ return false;
+ }
+
+ static final class IconDB extends SQLiteCacheHelper {
+ private final static int RELEASE_VERSION = 25;
+
+ public final static String TABLE_NAME = "icons";
+ public final static String COLUMN_ROWID = "rowid";
+ public final static String COLUMN_COMPONENT = "componentName";
+ public final static String COLUMN_USER = "profileId";
+ public final static String COLUMN_LAST_UPDATED = "lastUpdated";
+ public final static String COLUMN_VERSION = "version";
+ public final static String COLUMN_ICON = "icon";
+ public final static String COLUMN_ICON_COLOR = "icon_color";
+ public final static String COLUMN_LABEL = "label";
+ public final static String COLUMN_SYSTEM_STATE = "system_state";
+
+ public final static String[] COLUMNS_HIGH_RES = new String[] {
+ IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL, IconDB.COLUMN_ICON };
+ public final static String[] COLUMNS_LOW_RES = new String[] {
+ IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL };
+
+ public IconDB(Context context, String dbFileName, int iconPixelSize) {
+ super(context, dbFileName, (RELEASE_VERSION << 16) + iconPixelSize, TABLE_NAME);
+ }
+
+ @Override
+ protected void onCreateTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" +
+ COLUMN_COMPONENT + " TEXT NOT NULL, " +
+ COLUMN_USER + " INTEGER NOT NULL, " +
+ COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, " +
+ COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, " +
+ COLUMN_ICON + " BLOB, " +
+ COLUMN_ICON_COLOR + " INTEGER NOT NULL DEFAULT 0, " +
+ COLUMN_LABEL + " TEXT, " +
+ COLUMN_SYSTEM_STATE + " TEXT, " +
+ "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ") " +
+ ");");
+ }
+ }
+
+ private ContentValues newContentValues(BitmapInfo bitmapInfo, String label, String packageName) {
+ ContentValues values = new ContentValues();
+ values.put(IconDB.COLUMN_ICON,
+ bitmapInfo.isLowRes() ? null : GraphicsUtils.flattenBitmap(bitmapInfo.icon));
+ values.put(IconDB.COLUMN_ICON_COLOR, bitmapInfo.color);
+
+ values.put(IconDB.COLUMN_LABEL, label);
+ values.put(IconDB.COLUMN_SYSTEM_STATE, getIconSystemState(packageName));
+
+ return values;
+ }
+
+ private void assertWorkerThread() {
+ if (Looper.myLooper() != mBgLooper) {
+ throw new IllegalStateException("Cache accessed on wrong thread " + Looper.myLooper());
+ }
+ }
+}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java
new file mode 100644
index 0000000..addb51f
--- /dev/null
+++ b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java
@@ -0,0 +1,33 @@
+/*
+ * 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.icons.cache;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.UserHandle;
+
+import com.android.launcher3.icons.BitmapInfo;
+
+public interface CachingLogic<T> {
+
+ ComponentName getComponent(T object);
+
+ UserHandle getUser(T object);
+
+ CharSequence getLabel(T object);
+
+ void loadIcon(Context context, T object, BitmapInfo target);
+}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java b/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java
new file mode 100644
index 0000000..ee52934
--- /dev/null
+++ b/iconloaderlib/src/com/android/launcher3/icons/cache/HandlerRunnable.java
@@ -0,0 +1,67 @@
+/*
+ * 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.icons.cache;
+
+import android.os.Handler;
+
+/**
+ * A runnable that can be posted to a {@link Handler} which can be canceled.
+ */
+public abstract class HandlerRunnable implements Runnable {
+
+ private final Handler mHandler;
+ private final Runnable mEndRunnable;
+
+ private boolean mEnded = false;
+ private boolean mCanceled = false;
+
+ public HandlerRunnable(Handler handler, Runnable endRunnable) {
+ mHandler = handler;
+ mEndRunnable = endRunnable;
+ }
+
+ /**
+ * Cancels this runnable from being run, only if it has not already run.
+ */
+ public void cancel() {
+ mHandler.removeCallbacks(this);
+ // TODO: This can actually cause onEnd to be called twice if the handler is already running
+ // this runnable
+ // NOTE: This is currently run on whichever thread the caller is run on.
+ mCanceled = true;
+ onEnd();
+ }
+
+ /**
+ * @return whether this runnable was canceled.
+ */
+ protected boolean isCanceled() {
+ return mCanceled;
+ }
+
+ /**
+ * To be called by the implemention of this runnable. The end callback is done on whichever
+ * thread the caller is calling from.
+ */
+ public void onEnd() {
+ if (!mEnded) {
+ mEnded = true;
+ if (mEndRunnable != null) {
+ mEndRunnable.run();
+ }
+ }
+ }
+}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java
new file mode 100644
index 0000000..3c71bd0
--- /dev/null
+++ b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java
@@ -0,0 +1,303 @@
+/*
+ * 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.icons.cache;
+
+import android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseBooleanArray;
+
+import com.android.launcher3.icons.cache.BaseIconCache.IconDB;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * Utility class to handle updating the Icon cache
+ */
+public class IconCacheUpdateHandler {
+
+ private static final String TAG = "IconCacheUpdateHandler";
+
+ /**
+ * In this mode, all invalid icons are marked as to-be-deleted in {@link #mItemsToDelete}.
+ * This mode is used for the first run.
+ */
+ private static final boolean MODE_SET_INVALID_ITEMS = true;
+
+ /**
+ * In this mode, any valid icon is removed from {@link #mItemsToDelete}. This is used for all
+ * subsequent runs, which essentially acts as set-union of all valid items.
+ */
+ private static final boolean MODE_CLEAR_VALID_ITEMS = false;
+
+ private static final Object ICON_UPDATE_TOKEN = new Object();
+
+ private final HashMap<String, PackageInfo> mPkgInfoMap;
+ private final BaseIconCache mIconCache;
+
+ private final HashMap<UserHandle, Set<String>> mPackagesToIgnore = new HashMap<>();
+
+ private final SparseBooleanArray mItemsToDelete = new SparseBooleanArray();
+ private boolean mFilterMode = MODE_SET_INVALID_ITEMS;
+
+ IconCacheUpdateHandler(BaseIconCache cache) {
+ mIconCache = cache;
+
+ mPkgInfoMap = new HashMap<>();
+
+ // Remove all active icon update tasks.
+ mIconCache.mWorkerHandler.removeCallbacksAndMessages(ICON_UPDATE_TOKEN);
+
+ createPackageInfoMap();
+ }
+
+ public void setPackagesToIgnore(UserHandle userHandle, Set<String> packages) {
+ mPackagesToIgnore.put(userHandle, packages);
+ }
+
+ private void createPackageInfoMap() {
+ PackageManager pm = mIconCache.mPackageManager;
+ for (PackageInfo info :
+ pm.getInstalledPackages(PackageManager.MATCH_UNINSTALLED_PACKAGES)) {
+ mPkgInfoMap.put(info.packageName, info);
+ }
+ }
+
+ /**
+ * Updates the persistent DB, such that only entries corresponding to {@param apps} remain in
+ * the DB and are updated.
+ * @return The set of packages for which icons have updated.
+ */
+ public <T> void updateIcons(List<T> apps, CachingLogic<T> cachingLogic,
+ OnUpdateCallback onUpdateCallback) {
+ // Filter the list per user
+ HashMap<UserHandle, HashMap<ComponentName, T>> userComponentMap = new HashMap<>();
+ int count = apps.size();
+ for (int i = 0; i < count; i++) {
+ T app = apps.get(i);
+ UserHandle userHandle = cachingLogic.getUser(app);
+ HashMap<ComponentName, T> componentMap = userComponentMap.get(userHandle);
+ if (componentMap == null) {
+ componentMap = new HashMap<>();
+ userComponentMap.put(userHandle, componentMap);
+ }
+ componentMap.put(cachingLogic.getComponent(app), app);
+ }
+
+ for (Entry<UserHandle, HashMap<ComponentName, T>> entry : userComponentMap.entrySet()) {
+ updateIconsPerUser(entry.getKey(), entry.getValue(), cachingLogic, onUpdateCallback);
+ }
+
+ // From now on, clear every valid item from the global valid map.
+ mFilterMode = MODE_CLEAR_VALID_ITEMS;
+ }
+
+ /**
+ * Updates the persistent DB, such that only entries corresponding to {@param apps} remain in
+ * the DB and are updated.
+ * @return The set of packages for which icons have updated.
+ */
+ @SuppressWarnings("unchecked")
+ private <T> void updateIconsPerUser(UserHandle user, HashMap<ComponentName, T> componentMap,
+ CachingLogic<T> cachingLogic, OnUpdateCallback onUpdateCallback) {
+ Set<String> ignorePackages = mPackagesToIgnore.get(user);
+ if (ignorePackages == null) {
+ ignorePackages = Collections.emptySet();
+ }
+ long userSerial = mIconCache.getSerialNumberForUser(user);
+
+ Stack<T> appsToUpdate = new Stack<>();
+
+ try (Cursor c = mIconCache.mIconDb.query(
+ new String[]{IconDB.COLUMN_ROWID, IconDB.COLUMN_COMPONENT,
+ IconDB.COLUMN_LAST_UPDATED, IconDB.COLUMN_VERSION,
+ IconDB.COLUMN_SYSTEM_STATE},
+ IconDB.COLUMN_USER + " = ? ",
+ new String[]{Long.toString(userSerial)})) {
+
+ final int indexComponent = c.getColumnIndex(IconDB.COLUMN_COMPONENT);
+ final int indexLastUpdate = c.getColumnIndex(IconDB.COLUMN_LAST_UPDATED);
+ final int indexVersion = c.getColumnIndex(IconDB.COLUMN_VERSION);
+ final int rowIndex = c.getColumnIndex(IconDB.COLUMN_ROWID);
+ final int systemStateIndex = c.getColumnIndex(IconDB.COLUMN_SYSTEM_STATE);
+
+ while (c.moveToNext()) {
+ String cn = c.getString(indexComponent);
+ ComponentName component = ComponentName.unflattenFromString(cn);
+ PackageInfo info = mPkgInfoMap.get(component.getPackageName());
+
+ int rowId = c.getInt(rowIndex);
+ if (info == null) {
+ if (!ignorePackages.contains(component.getPackageName())) {
+
+ if (mFilterMode == MODE_SET_INVALID_ITEMS) {
+ mIconCache.remove(component, user);
+ mItemsToDelete.put(rowId, true);
+ }
+ }
+ continue;
+ }
+ if ((info.applicationInfo.flags & ApplicationInfo.FLAG_IS_DATA_ONLY) != 0) {
+ // Application is not present
+ continue;
+ }
+
+ long updateTime = c.getLong(indexLastUpdate);
+ int version = c.getInt(indexVersion);
+ T app = componentMap.remove(component);
+ if (version == info.versionCode && updateTime == info.lastUpdateTime &&
+ TextUtils.equals(c.getString(systemStateIndex),
+ mIconCache.getIconSystemState(info.packageName))) {
+
+ if (mFilterMode == MODE_CLEAR_VALID_ITEMS) {
+ mItemsToDelete.put(rowId, false);
+ }
+ continue;
+ }
+ if (app == null) {
+ if (mFilterMode == MODE_SET_INVALID_ITEMS) {
+ mIconCache.remove(component, user);
+ mItemsToDelete.put(rowId, true);
+ }
+ } else {
+ appsToUpdate.add(app);
+ }
+ }
+ } catch (SQLiteException e) {
+ Log.d(TAG, "Error reading icon cache", e);
+ // Continue updating whatever we have read so far
+ }
+
+ // Insert remaining apps.
+ if (!componentMap.isEmpty() || !appsToUpdate.isEmpty()) {
+ Stack<T> appsToAdd = new Stack<>();
+ appsToAdd.addAll(componentMap.values());
+ new SerializedIconUpdateTask(userSerial, user, appsToAdd, appsToUpdate, cachingLogic,
+ onUpdateCallback).scheduleNext();
+ }
+ }
+
+ /**
+ * Commits all updates as part of the update handler to disk. Not more calls should be made
+ * to this class after this.
+ */
+ public void finish() {
+ // Commit all deletes
+ int deleteCount = 0;
+ StringBuilder queryBuilder = new StringBuilder()
+ .append(IconDB.COLUMN_ROWID)
+ .append(" IN (");
+
+ int count = mItemsToDelete.size();
+ for (int i = 0; i < count; i++) {
+ if (mItemsToDelete.valueAt(i)) {
+ if (deleteCount > 0) {
+ queryBuilder.append(", ");
+ }
+ queryBuilder.append(mItemsToDelete.keyAt(i));
+ deleteCount++;
+ }
+ }
+ queryBuilder.append(')');
+
+ if (deleteCount > 0) {
+ mIconCache.mIconDb.delete(queryBuilder.toString(), null);
+ }
+ }
+
+
+ /**
+ * A runnable that updates invalid icons and adds missing icons in the DB for the provided
+ * LauncherActivityInfo list. Items are updated/added one at a time, so that the
+ * worker thread doesn't get blocked.
+ */
+ private class SerializedIconUpdateTask<T> implements Runnable {
+ private final long mUserSerial;
+ private final UserHandle mUserHandle;
+ private final Stack<T> mAppsToAdd;
+ private final Stack<T> mAppsToUpdate;
+ private final CachingLogic<T> mCachingLogic;
+ private final HashSet<String> mUpdatedPackages = new HashSet<>();
+ private final OnUpdateCallback mOnUpdateCallback;
+
+ SerializedIconUpdateTask(long userSerial, UserHandle userHandle,
+ Stack<T> appsToAdd, Stack<T> appsToUpdate, CachingLogic<T> cachingLogic,
+ OnUpdateCallback onUpdateCallback) {
+ mUserHandle = userHandle;
+ mUserSerial = userSerial;
+ mAppsToAdd = appsToAdd;
+ mAppsToUpdate = appsToUpdate;
+ mCachingLogic = cachingLogic;
+ mOnUpdateCallback = onUpdateCallback;
+ }
+
+ @Override
+ public void run() {
+ if (!mAppsToUpdate.isEmpty()) {
+ T app = mAppsToUpdate.pop();
+ String pkg = mCachingLogic.getComponent(app).getPackageName();
+ PackageInfo info = mPkgInfoMap.get(pkg);
+ mIconCache.addIconToDBAndMemCache(
+ app, mCachingLogic, info, mUserSerial, true /*replace existing*/);
+ mUpdatedPackages.add(pkg);
+
+ if (mAppsToUpdate.isEmpty() && !mUpdatedPackages.isEmpty()) {
+ // No more app to update. Notify callback.
+ mOnUpdateCallback.onPackageIconsUpdated(mUpdatedPackages, mUserHandle);
+ }
+
+ // Let it run one more time.
+ scheduleNext();
+ } else if (!mAppsToAdd.isEmpty()) {
+ T app = mAppsToAdd.pop();
+ PackageInfo info = mPkgInfoMap.get(mCachingLogic.getComponent(app).getPackageName());
+ // We do not check the mPkgInfoMap when generating the mAppsToAdd. Although every
+ // app should have package info, this is not guaranteed by the api
+ if (info != null) {
+ mIconCache.addIconToDBAndMemCache(app, mCachingLogic, info,
+ mUserSerial, false /*replace existing*/);
+ }
+
+ if (!mAppsToAdd.isEmpty()) {
+ scheduleNext();
+ }
+ }
+ }
+
+ public void scheduleNext() {
+ mIconCache.mWorkerHandler.postAtTime(this, ICON_UPDATE_TOKEN,
+ SystemClock.uptimeMillis() + 1);
+ }
+ }
+
+ public interface OnUpdateCallback {
+
+ void onPackageIconsUpdated(HashSet<String> updatedPackages, UserHandle user);
+ }
+}
diff --git a/src/com/android/launcher3/util/ComponentKey.java b/iconloaderlib/src/com/android/launcher3/util/ComponentKey.java
similarity index 93%
rename from src/com/android/launcher3/util/ComponentKey.java
rename to iconloaderlib/src/com/android/launcher3/util/ComponentKey.java
index d478ffa..34bed94 100644
--- a/src/com/android/launcher3/util/ComponentKey.java
+++ b/iconloaderlib/src/com/android/launcher3/util/ComponentKey.java
@@ -29,8 +29,9 @@
private final int mHashCode;
public ComponentKey(ComponentName componentName, UserHandle user) {
- Preconditions.assertNotNull(componentName);
- Preconditions.assertNotNull(user);
+ if (componentName == null || user == null) {
+ throw new NullPointerException();
+ }
this.componentName = componentName;
this.user = user;
mHashCode = Arrays.hashCode(new Object[] {componentName, user});
diff --git a/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java b/iconloaderlib/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java
similarity index 93%
rename from src/com/android/launcher3/util/NoLocaleSQLiteHelper.java
rename to iconloaderlib/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java
index 05a7d27..fe864a2 100644
--- a/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java
+++ b/iconloaderlib/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java
@@ -18,8 +18,6 @@
import static android.database.sqlite.SQLiteDatabase.NO_LOCALIZED_COLLATORS;
-import static com.android.launcher3.Utilities.ATLEAST_P;
-
import android.content.Context;
import android.content.ContextWrapper;
import android.database.DatabaseErrorHandler;
@@ -27,6 +25,7 @@
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteDatabase.OpenParams;
import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Build;
/**
* Extension of {@link SQLiteOpenHelper} which avoids creating default locale table by
@@ -34,6 +33,9 @@
*/
public abstract class NoLocaleSQLiteHelper extends SQLiteOpenHelper {
+ private static final boolean ATLEAST_P =
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
+
public NoLocaleSQLiteHelper(Context context, String name, int version) {
super(ATLEAST_P ? context : new NoLocalContext(context), name, null, version);
if (ATLEAST_P) {
diff --git a/src/com/android/launcher3/util/Provider.java b/iconloaderlib/src/com/android/launcher3/util/Provider.java
similarity index 76%
rename from src/com/android/launcher3/util/Provider.java
rename to iconloaderlib/src/com/android/launcher3/util/Provider.java
index 1cdd8d6..4a54c0f 100644
--- a/src/com/android/launcher3/util/Provider.java
+++ b/iconloaderlib/src/com/android/launcher3/util/Provider.java
@@ -19,20 +19,15 @@
/**
* Utility class to allow lazy initialization of objects.
*/
-public abstract class Provider<T> {
+public interface Provider<T> {
/**
* Initializes and returns the object. This may contain expensive operations not suitable
* to UI thread.
*/
- public abstract T get();
+ T get();
- public static <T> Provider<T> of (final T value) {
- return new Provider<T>() {
- @Override
- public T get() {
- return value;
- }
- };
+ static <T> Provider<T> of (T value) {
+ return() -> value;
}
}
diff --git a/src/com/android/launcher3/util/SQLiteCacheHelper.java b/iconloaderlib/src/com/android/launcher3/util/SQLiteCacheHelper.java
similarity index 92%
rename from src/com/android/launcher3/util/SQLiteCacheHelper.java
rename to iconloaderlib/src/com/android/launcher3/util/SQLiteCacheHelper.java
index 44c1762..49de4bd 100644
--- a/src/com/android/launcher3/util/SQLiteCacheHelper.java
+++ b/iconloaderlib/src/com/android/launcher3/util/SQLiteCacheHelper.java
@@ -9,9 +9,6 @@
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
-
/**
* An extension of {@link SQLiteOpenHelper} with utility methods for a single table cache DB.
* Any exception during write operations are ignored, and any version change causes a DB reset.
@@ -19,8 +16,7 @@
public abstract class SQLiteCacheHelper {
private static final String TAG = "SQLiteCacheHelper";
- private static final boolean NO_ICON_CACHE = FeatureFlags.IS_DOGFOOD_BUILD &&
- Utilities.isPropertyEnabled(LogConfig.MEMORY_ONLY_ICON_CACHE);
+ private static final boolean IN_MEMORY_CACHE = false;
private final String mTableName;
private final MySQLiteOpenHelper mOpenHelper;
@@ -28,7 +24,7 @@
private boolean mIgnoreWrites;
public SQLiteCacheHelper(Context context, String name, int version, String tableName) {
- if (NO_ICON_CACHE) {
+ if (IN_MEMORY_CACHE) {
name = null;
}
mTableName = tableName;
@@ -87,6 +83,10 @@
mOpenHelper.clearDB(mOpenHelper.getWritableDatabase());
}
+ public void close() {
+ mOpenHelper.close();
+ }
+
protected abstract void onCreateTable(SQLiteDatabase db);
/**
diff --git a/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java b/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java
new file mode 100644
index 0000000..48f11fd
--- /dev/null
+++ b/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java
@@ -0,0 +1,89 @@
+/*
+ * 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.icons;
+
+import android.content.Context;
+
+/**
+ * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
+ * that are threadsafe.
+ */
+public class IconFactory extends BaseIconFactory {
+
+ private static final Object sPoolSync = new Object();
+ private static IconFactory sPool;
+ private static int sPoolId = 0;
+
+ /**
+ * Return a new Message instance from the global pool. Allows us to
+ * avoid allocating new objects in many cases.
+ */
+ public static IconFactory obtain(Context context) {
+ int poolId;
+ synchronized (sPoolSync) {
+ if (sPool != null) {
+ IconFactory m = sPool;
+ sPool = m.next;
+ m.next = null;
+ return m;
+ }
+ poolId = sPoolId;
+ }
+
+ return new IconFactory(context,
+ context.getResources().getConfiguration().densityDpi,
+ context.getResources().getDimensionPixelSize(R.dimen.default_icon_bitmap_size),
+ poolId);
+ }
+
+ public static void clearPool() {
+ synchronized (sPoolSync) {
+ sPool = null;
+ sPoolId++;
+ }
+ }
+
+ private final int mPoolId;
+
+ private IconFactory next;
+
+ private IconFactory(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) {
+ super(context, fillResIconDpi, iconBitmapSize);
+ mPoolId = poolId;
+ }
+
+ /**
+ * Recycles a LauncherIcons that may be in-use.
+ */
+ public void recycle() {
+ synchronized (sPoolSync) {
+ if (sPoolId != mPoolId) {
+ return;
+ }
+ // Clear any temporary state variables
+ clear();
+
+ next = sPool;
+ sPool = this;
+ }
+ }
+
+ @Override
+ public void close() {
+ recycle();
+ }
+}
diff --git a/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java b/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java
new file mode 100644
index 0000000..1337975
--- /dev/null
+++ b/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java
@@ -0,0 +1,114 @@
+/*
+ * 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.icons;
+
+import static android.content.Intent.ACTION_MANAGED_PROFILE_ADDED;
+import static android.content.Intent.ACTION_MANAGED_PROFILE_REMOVED;
+
+import android.annotation.TargetApi;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.SparseLongArray;
+
+import com.android.launcher3.icons.cache.BaseIconCache;
+
+/**
+ * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
+ * that are threadsafe.
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class SimpleIconCache extends BaseIconCache {
+
+ private static SimpleIconCache sIconCache = null;
+ private static final Object CACHE_LOCK = new Object();
+
+ private final SparseLongArray mUserSerialMap = new SparseLongArray(2);
+ private final UserManager mUserManager;
+
+ public SimpleIconCache(Context context, String dbFileName, Looper bgLooper, int iconDpi,
+ int iconPixelSize, boolean inMemoryCache) {
+ super(context, dbFileName, bgLooper, iconDpi, iconPixelSize, inMemoryCache);
+ mUserManager = context.getSystemService(UserManager.class);
+
+ // Listen for user cache changes.
+ IntentFilter filter = new IntentFilter(ACTION_MANAGED_PROFILE_ADDED);
+ filter.addAction(ACTION_MANAGED_PROFILE_REMOVED);
+ context.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ resetUserCache();
+ }
+ }, filter, null, new Handler(bgLooper), 0);
+ }
+
+ @Override
+ protected long getSerialNumberForUser(UserHandle user) {
+ synchronized (mUserSerialMap) {
+ int index = mUserSerialMap.indexOfKey(user.getIdentifier());
+ if (index >= 0) {
+ return mUserSerialMap.valueAt(index);
+ }
+ long serial = mUserManager.getSerialNumberForUser(user);
+ mUserSerialMap.put(user.getIdentifier(), serial);
+ return serial;
+ }
+ }
+
+ private void resetUserCache() {
+ synchronized (mUserSerialMap) {
+ mUserSerialMap.clear();
+ }
+ }
+
+ @Override
+ protected boolean isInstantApp(ApplicationInfo info) {
+ return info.isInstantApp();
+ }
+
+ @Override
+ protected BaseIconFactory getIconFactory() {
+ return IconFactory.obtain(mContext);
+ }
+
+ public static SimpleIconCache getIconCache(Context context) {
+ synchronized (CACHE_LOCK) {
+ if (sIconCache != null) {
+ return sIconCache;
+ }
+ boolean inMemoryCache =
+ context.getResources().getBoolean(R.bool.simple_cache_enable_im_memory);
+ String dbFileName = context.getString(R.string.cache_db_name);
+
+ HandlerThread bgThread = new HandlerThread("simple-icon-cache");
+ bgThread.start();
+
+ sIconCache = new SimpleIconCache(context.getApplicationContext(), dbFileName,
+ bgThread.getLooper(), context.getResources().getConfiguration().densityDpi,
+ context.getResources().getDimensionPixelSize(R.dimen.default_icon_bitmap_size),
+ inMemoryCache);
+ return sIconCache;
+ }
+ }
+}
diff --git a/libs/README.txt b/libs/README.txt
new file mode 100644
index 0000000..9109592
--- /dev/null
+++ b/libs/README.txt
@@ -0,0 +1,8 @@
+These jar are compiled in the frameworks/base of the platform tree.
+
+launcher_protos.jar is defined as launcherprotosnano in the following file:
+frameworks/base/core/protos/android/stats/launcher/Android.bp
+
+plugin_core.jar is defined as PluginCoreLib in the following file:
+frameworks/base/packages/SystemUI/plugin/Android.bp
+
diff --git a/libs/launcher_protos.jar b/libs/launcher_protos.jar
new file mode 100644
index 0000000..c043936
--- /dev/null
+++ b/libs/launcher_protos.jar
Binary files differ
diff --git a/libs/plugin_core.jar b/libs/plugin_core.jar
new file mode 100644
index 0000000..dd27f86
--- /dev/null
+++ b/libs/plugin_core.jar
Binary files differ
diff --git a/proguard.flags b/proguard.flags
index e401116..272ab7a 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -2,80 +2,6 @@
*;
}
--keep class com.android.launcher3.allapps.AllAppsBackgroundDrawable {
- public void setAlpha(int);
- public int getAlpha();
-}
-
--keep class com.android.launcher3.BaseRecyclerViewFastScrollBar {
- public void setThumbWidth(int);
- public int getThumbWidth();
- public void setTrackWidth(int);
- public int getTrackWidth();
-}
-
--keep class com.android.launcher3.BaseRecyclerViewFastScrollPopup {
- public void setAlpha(float);
- public float getAlpha();
-}
-
--keep class com.android.launcher3.ButtonDropTarget {
- public int getTextColor();
-}
-
--keep class com.android.launcher3.CellLayout {
- public float getBackgroundAlpha();
- public void setBackgroundAlpha(float);
-}
-
--keep class com.android.launcher3.CellLayout$LayoutParams {
- public void setWidth(int);
- public int getWidth();
- public void setHeight(int);
- public int getHeight();
- public void setX(int);
- public int getX();
- public void setY(int);
- public int getY();
-}
-
--keep class com.android.launcher3.views.BaseDragLayer$LayoutParams {
- public void setWidth(int);
- public int getWidth();
- public void setHeight(int);
- public int getHeight();
- public void setX(int);
- public int getX();
- public void setY(int);
- public int getY();
-}
-
--keep class com.android.launcher3.FastBitmapDrawable {
- public void setDesaturation(float);
- public float getDesaturation();
- public void setBrightness(float);
- public float getBrightness();
-}
-
--keep class com.android.launcher3.MemoryDumpActivity {
- *;
-}
-
--keep class com.android.launcher3.PreloadIconDrawable {
- public float getAnimationProgress();
- public void setAnimationProgress(float);
-}
-
--keep class com.android.launcher3.pageindicators.CaretDrawable {
- public float getCaretProgress();
- public void setCaretProgress(float);
-}
-
--keep class com.android.launcher3.Workspace {
- public float getBackgroundAlpha();
- public void setBackgroundAlpha(float);
-}
-
# Proguard will strip new callbacks in LauncherApps.Callback from
# WrappedCallback if compiled against an older SDK. Don't let this happen.
-keep class com.android.launcher3.compat.** {
@@ -95,32 +21,21 @@
# next row when focus is on the last item of last row when using a RecyclerView
# Keep optimized and shrunk proguard to prevent issues like this when using
# support jar.
--keep class android.support.v7.widget.RecyclerView { *; }
+-keep class androidx.recyclerview.widget.RecyclerView { *; }
-# LauncherAppTransitionManager
--keep class com.android.launcher3.LauncherAppTransitionManagerImpl {
+# Preference fragments
+-keep class ** extends android.app.Fragment {
public <init>(...);
}
-# InstantAppResolver
--keep class com.android.quickstep.InstantAppResolverImpl {
- public <init>(...);
-}
-
-# MainProcessInitializer
--keep class com.android.quickstep.QuickstepProcessInitializer {
- public <init>(...);
-}
-
-# UserEventDispatcherExtension
--keep class com.android.quickstep.logging.UserEventDispatcherExtension {
+## Prevent obfuscating various overridable objects
+-keep class ** implements com.android.launcher3.util.ResourceBasedOverride {
public <init>(...);
}
-keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** {
*;
}
-
-keep interface com.android.launcher3.model.nano.LauncherDumpProto.** {
*;
}
@@ -135,3 +50,4 @@
-dontwarn android.app.**
-dontwarn android.view.**
-dontwarn android.os.**
+-dontwarn android.graphics.**
\ No newline at end of file
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index 06e6a92..4129ae8 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -112,6 +112,8 @@
CANCEL_TARGET = 14;
TASK_PREVIEW = 15;
SPLIT_SCREEN_TARGET = 16;
+ REMOTE_ACTION_SHORTCUT = 17;
+ APP_USAGE_SETTINGS = 18;
}
enum TipType {
@@ -184,8 +186,8 @@
optional int64 elapsed_container_millis = 5;
optional int64 elapsed_session_millis = 6;
- optional bool is_in_multi_window_mode = 7;
- optional bool is_in_landscape_mode = 8;
+ optional bool is_in_multi_window_mode = 7 [deprecated = true];
+ optional bool is_in_landscape_mode = 8 [deprecated = true];
optional LauncherEventExtension extension = 9;
}
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index cb74855..74e0b1e 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -24,6 +24,7 @@
<uses-sdk android:targetSdkVersion="28" android:minSdkVersion="28"/>
<uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
+
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
android:fullBackupOnly="true"
@@ -59,10 +60,10 @@
android:resumeWhilePausing="true"
android:taskAffinity="" />
- <!-- Content provider to settings search -->
+ <!-- Content provider to settings search. The autority should be same as the packageName -->
<provider
android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
- android:authorities="com.android.launcher3"
+ android:authorities="${packageName}"
android:grantUriPermissions="true"
android:multiprocess="true"
android:permission="android.permission.READ_SEARCH_INDEXABLES"
@@ -72,7 +73,6 @@
</intent-filter>
</provider>
-
<service
android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
tools:node="remove" />
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 27de1e9..5810e8b 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/res/layout/task_menu.xml b/quickstep/res/layout/task_menu.xml
index bf55ece..098b34f 100644
--- a/quickstep/res/layout/task_menu.xml
+++ b/quickstep/res/layout/task_menu.xml
@@ -24,11 +24,19 @@
android:orientation="vertical"
android:visibility="invisible">
+ <com.android.quickstep.views.IconView
+ android:id="@+id/task_icon"
+ android:layout_width="@dimen/task_thumbnail_icon_size"
+ android:layout_height="@dimen/task_thumbnail_icon_size"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_marginBottom="@dimen/deep_shortcut_drawable_padding"
+ android:focusable="false"
+ android:importantForAccessibility="no" />
+
<TextView
- android:id="@+id/task_icon_and_name"
+ android:id="@+id/task_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:drawablePadding="@dimen/deep_shortcut_drawable_padding"
android:gravity="center_horizontal"
android:layout_marginBottom="16dp"
android:textSize="12sp"/>
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 8ae493f..fb82cc6 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Oorsig"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Geen onlangse items nie"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Maak toe"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programgebruikinstellings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Vee alles uit"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Onlangse programme"</string>
</resources>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 4ca0c67..d5ce08d 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ማጠቃለያ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ምንም የቅርብ ጊዜ ንጥሎች የሉም"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"ዝጋ"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"የመተግበሪያ አጠቃቀም ቅንብሮች"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ሁሉንም አጽዳ"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"የቅርብ ጊዜ መተግበሪያዎች"</string>
</resources>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index c04b618..c203a4f 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"نظرة عامة"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ليست هناك عناصر تم استخدامها مؤخرًا"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"إغلاق"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"إعدادات استخدام التطبيق"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"محو الكل"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"التطبيقات التي تمّ استخدامها مؤخرًا"</string>
</resources>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 812a246..76b7326 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"অৱলোকন"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"কোনো শেহতীয়া বস্তু নাই"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"বন্ধ কৰক"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"এপে ব্যৱহাৰ কৰা ডেটাৰ ছেটিংসমূহ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"সকলো মচক"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"শেহতীয়া এপসমূহ"</string>
</resources>
diff --git a/quickstep/res/values-az-rAZ/strings.xml b/quickstep/res/values-az-rAZ/strings.xml
deleted file mode 100644
index 0546f46..0000000
--- a/quickstep/res/values-az-rAZ/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Bölünmüş ekran"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Sancın"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"İcmal"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Son elementlər yoxdur"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Bağlayın"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Hamısını silin"</string>
-</resources>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 832ed8c..d7315f5 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"İcmal"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Son elementlər yoxdur"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Bağlayın"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tətbiq istifadə ayarları"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hamısını silin"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Son tətbiqlər"</string>
</resources>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index fc4c8c0..9429765 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Pregled"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Zatvori"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Podešavanja korišćenja aplikacije"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
</resources>
diff --git a/quickstep/res/values-be-rBY/strings.xml b/quickstep/res/values-be-rBY/strings.xml
deleted file mode 100644
index 1e60dd3..0000000
--- a/quickstep/res/values-be-rBY/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Падзяліць экран"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Замацаваць"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Агляд"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Няма новых элементаў"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Закрыць"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Ачысціць усё"</string>
-</resources>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index c5d03d4..002583f 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Агляд"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Няма новых элементаў"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Закрыць"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Налады выкарыстання праграмы"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Ачысціць усё"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Нядаўнія праграмы"</string>
</resources>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 2672b83..e9337fb 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Общ преглед"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Няма скорошни елементи"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Затваряне"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки за използването на приложенията"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Изчистване на всички"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Скорошни приложения"</string>
</resources>
diff --git a/quickstep/res/values-bn-rBD/strings.xml b/quickstep/res/values-bn-rBD/strings.xml
deleted file mode 100644
index a0605d8..0000000
--- a/quickstep/res/values-bn-rBD/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"স্ক্রিন স্প্লিট করুন"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"পিন করুন"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"এক নজরে"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"কোনো সাম্প্রতিক আইটেম নেই"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"বন্ধ করুন"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"সবকিছু খালি করুন"</string>
-</resources>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 0a824c2..ff82c9b 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"এক নজরে"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"কোনো সাম্প্রতিক আইটেম নেই"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"বন্ধ করুন"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"অ্যাপ ব্যবহারের সেটিংস"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"সবকিছু খালি করুন"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"সম্প্রতি ব্যবহৃত অ্যাপ"</string>
</resources>
diff --git a/quickstep/res/values-bs-rBA/strings.xml b/quickstep/res/values-bs-rBA/strings.xml
deleted file mode 100644
index 9ffa848..0000000
--- a/quickstep/res/values-bs-rBA/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Način rada podijeljenog ekrana"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Pregled"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Zatvaranje"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
-</resources>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 6bf38eb..328e187 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Pregled"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Zatvaranje"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke korištenja aplikacije"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
</resources>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 2d51703..f59077a 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Aplicacions recents"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hi ha cap element recent"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Tanca"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuració d\'ús d\'aplicacions"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Esborra-ho tot"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicacions recents"</string>
</resources>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index a178df0..79b818d 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Přehled"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Žádné nedávné položky"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Zavřít"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavení využití aplikací"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Vymazat vše"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Poslední aplikace"</string>
</resources>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index d0d629f..17dfafb 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -19,11 +19,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Delt skærm"</string>
+ <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Opdel skærm"</string>
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fastgør"</string>
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Oversigt"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ingen nye elementer"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Luk"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Indstillinger for appforbrug"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Ryd alt"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Seneste apps"</string>
</resources>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index aee8b85..ee357b5 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -19,11 +19,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Bildschirm teilen"</string>
+ <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Splitscreen"</string>
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixieren"</string>
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Übersicht"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Keine kürzlich verwendeten Elemente"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Schließen"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Einstellungen zur App-Nutzung"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Alle Apps schließen"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Zuletzt aktive Apps"</string>
</resources>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 7364b82..7c11681 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Επισκόπηση"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Δεν υπάρχουν πρόσφατα στοιχεία"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Κλείσιμο"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ρυθμίσεις χρήσης εφαρμογής"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Διαγραφή όλων"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Πρόσφατες εφαρμογές"</string>
</resources>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index d0dc1e8..29a202c 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Overview"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Close"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
</resources>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index d0dc1e8..29a202c 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Overview"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Close"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
</resources>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index d0dc1e8..29a202c 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Overview"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Close"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
</resources>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 83e9d96..b2f8172 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Recientes"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hay elementos recientes"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Cerrar"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración de uso de la app"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Apps recientes"</string>
</resources>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index e076df5..66df093 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Aplicaciones recientes"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hay elementos recientes"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Cerrar"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ajustes de uso de la aplicación"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicaciones recientes"</string>
</resources>
diff --git a/quickstep/res/values-et-rEE/strings.xml b/quickstep/res/values-et-rEE/strings.xml
deleted file mode 100644
index efa68f9..0000000
--- a/quickstep/res/values-et-rEE/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Jagatud ekraan"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Kinnita"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ülevaade"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Hiljutisi üksusi pole"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Sule"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Sule kõik"</string>
-</resources>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 85de9c0..514448f 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ülevaade"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Hiljutisi üksusi pole"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Sule"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Rakenduse kasutuse seaded"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Sule kõik"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Hiljutised rakendused"</string>
</resources>
diff --git a/quickstep/res/values-eu-rES/strings.xml b/quickstep/res/values-eu-rES/strings.xml
deleted file mode 100644
index d22242e..0000000
--- a/quickstep/res/values-eu-rES/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Zatitu pantaila"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Ainguratu"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ikuspegi orokorra"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Ez dago azkenaldi honetako ezer"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Itxi"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Garbitu guztiak"</string>
-</resources>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 60943cc..76664a1 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ikuspegi orokorra"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ez dago azkenaldi honetako ezer"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Itxi"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Aplikazioen erabileraren ezarpenak"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Garbitu guztiak"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Azken aplikazioak"</string>
</resources>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 4a30daa..0a7e74c 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"نمای کلی"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"بدون موارد اخیر"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"بستن"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"تنظیمات استفاده از برنامه"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"پاک کردن همه"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"برنامههای اخیر"</string>
</resources>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 8f41350..18475e7 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Viimeisimmät"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ei viimeaikaisia kohteita"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Sulje"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Sovelluksen käyttöasetukset"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Poista kaikki"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Viimeisimmät sovellukset"</string>
</resources>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 7177996..7951177 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Aperçu"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Fermer"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres d\'utilisation de l\'application"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Applications récentes"</string>
</resources>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 0deb00b..2427dc4 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Aperçu"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Fermer"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres de consommation de l\'application"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Applications récentes"</string>
</resources>
diff --git a/quickstep/res/values-gl-rES/strings.xml b/quickstep/res/values-gl-rES/strings.xml
deleted file mode 100644
index 8efc773..0000000
--- a/quickstep/res/values-gl-rES/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Pantalla dividida"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Visión xeral"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Non hai elementos recentes"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Pecha a aplicación"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
-</resources>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 8c217eb..72d9a90 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Visión xeral"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Non hai elementos recentes"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Pecha a aplicación"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración do uso de aplicacións"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicacións recentes"</string>
</resources>
diff --git a/quickstep/res/values-gu-rIN/strings.xml b/quickstep/res/values-gu-rIN/strings.xml
deleted file mode 100644
index cdae86f..0000000
--- a/quickstep/res/values-gu-rIN/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"સ્ક્રીનને વિભાજિત કરો"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"પિન કરો"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ઝલક"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"તાજેતરની કોઈ આઇટમ નથી"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"બંધ કરો"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"બધું સાફ કરો"</string>
-</resources>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 8b9a538..d474a44 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ઝલક"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"તાજેતરની કોઈ આઇટમ નથી"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"બંધ કરો"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ઍપ વપરાશનું સેટિંગ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"બધું સાફ કરો"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"તાજેતરની ઍપ"</string>
</resources>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 83c31e7..26a75a7 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"खास जानकारी"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"हाल ही में इस्तेमाल किया गया कोई ऐप्लिकेशन नहीं है"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"बंद करें"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ऐप्लिकेशन इस्तेमाल की सेटिंग"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"सभी ऐप्लिकेशन बंद करें"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"हाल ही में इस्तेमाल किए गए एेप्लिकेशन"</string>
</resources>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index baa8d85..fbc3e48 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Pregled"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Zatvori"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke upotrebe aplikacija"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Izbriši sve"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
</resources>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index d971374..6f00587 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Áttekintés"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nincsenek mostanában használt elemek"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Bezárás"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Alkalmazáshasználati beállítások"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Összes törlése"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Legutóbbi alkalmazások"</string>
</resources>
diff --git a/quickstep/res/values-hy-rAM/strings.xml b/quickstep/res/values-hy-rAM/strings.xml
deleted file mode 100644
index 4afae7d..0000000
--- a/quickstep/res/values-hy-rAM/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Տրոհել էկրանը"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Ամրացնել"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ընդհանուր տեղեկություններ"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Վերջին տարրեր չկան"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Փակել"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Փակել բոլորը"</string>
-</resources>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index b4b9b98..dfc1224 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ընդհանուր տեղեկություններ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Վերջին տարրեր չկան"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Փակել"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Հավելվածի օգտագործման կարգավորումներ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Փակել բոլորը"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Վերջին օգտագործած հավելվածները"</string>
</resources>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 787c143..8d6551e 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ringkasan"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Tidak ada item yang baru dibuka"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Tutup"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setelan penggunaan aplikasi"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hapus semua"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplikasi baru-baru ini"</string>
</resources>
diff --git a/quickstep/res/values-is-rIS/strings.xml b/quickstep/res/values-is-rIS/strings.xml
deleted file mode 100644
index 88a92ed..0000000
--- a/quickstep/res/values-is-rIS/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Skipta skjá"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Festa"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Yfirlit"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Engin nýleg atriði"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Loka"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Hreinsa allt"</string>
-</resources>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index 1aface0..3c10a3d 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Yfirlit"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Engin nýleg atriði"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Loka"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Notkunarstillingar forrits"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hreinsa allt"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nýleg forrit"</string>
</resources>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 192ec44..eda8363 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Panoramica"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nessun elemento recente"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Chiudi"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Impostazioni di utilizzo delle app"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Cancella tutto"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"App recenti"</string>
</resources>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 64c35ec..15909b8 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"מסכים אחרונים"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"אין פריטים אחרונים"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"סגירה"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"הגדרות שימוש באפליקציה"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ניקוי הכול"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"אפליקציות אחרונות"</string>
</resources>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 558112c..4d0c75f 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"概要"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近のアイテムはありません"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"閉じる"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"アプリの使用状況の設定"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"すべてクリア"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"最近使ったアプリ"</string>
</resources>
diff --git a/quickstep/res/values-ka-rGE/strings.xml b/quickstep/res/values-ka-rGE/strings.xml
deleted file mode 100644
index 6de8ed9..0000000
--- a/quickstep/res/values-ka-rGE/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"ეკრანის გაყოფა"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"ჩამაგრება"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"მიმოხილვა"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"ბოლოს გამოყენებული ერთეულები არ არის"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"დახურვა"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"ყველას გასუფთავება"</string>
-</resources>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 5f061de..2b102ca 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"მიმოხილვა"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ბოლოს გამოყენებული ერთეულები არ არის"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"დახურვა"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"აპების გამოყენების პარამეტრები"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ყველას გასუფთავება"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ბოლოდროინდელი აპები"</string>
</resources>
diff --git a/quickstep/res/values-kk-rKZ/strings.xml b/quickstep/res/values-kk-rKZ/strings.xml
deleted file mode 100644
index ddd4a77..0000000
--- a/quickstep/res/values-kk-rKZ/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Экранды бөлу"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Бекіту"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Шолу"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Соңғы элементтер жоқ"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Жабу"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Барлығын өшіру"</string>
-</resources>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 3e72130..5cca69b 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Шолу"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Соңғы элементтер жоқ"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Жабу"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Қолданбаны пайдалану параметрлері"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Барлығын өшіру"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Соңғы пайдаланылған қолданбалар"</string>
</resources>
diff --git a/quickstep/res/values-km-rKH/strings.xml b/quickstep/res/values-km-rKH/strings.xml
deleted file mode 100644
index 65c1dcc..0000000
--- a/quickstep/res/values-km-rKH/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"មុខងារបំបែកអេក្រង់"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"ដៅ"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ទិដ្ឋភាពរួម"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"មិនមានធាតុថ្មីៗទេ"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"បិទ"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"សម្អាតទាំងអស់"</string>
-</resources>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 6ae9482..245493a 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ទិដ្ឋភាពរួម"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"មិនមានធាតុថ្មីៗទេ"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"បិទ"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ការកំណត់ការប្រើប្រាស់កម្មវិធី"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"សម្អាតទាំងអស់"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"កម្មវិធីថ្មីៗ"</string>
</resources>
diff --git a/quickstep/res/values-kn-rIN/strings.xml b/quickstep/res/values-kn-rIN/strings.xml
deleted file mode 100644
index 55ccbb0..0000000
--- a/quickstep/res/values-kn-rIN/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"ಪರದೆಯನ್ನು ಬೇರ್ಪಡಿಸಿ"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"ಪಿನ್ ಮಾಡಿ"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ಅವಲೋಕನ"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"ಮುಚ್ಚಿ"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string>
-</resources>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 591418b..de0ca04 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ಅವಲೋಕನ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"ಮುಚ್ಚಿ"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ಆ್ಯಪ್ ಬಳಕೆಯ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ಇತ್ತೀಚಿನ ಅಪ್ಲಿಕೇಶನ್ಗಳು"</string>
</resources>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 5b1ecbd..d4c93f9 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"최근 사용"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"최근 항목이 없습니다."</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"닫기"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"앱 사용 설정"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"모두 삭제"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"최근 앱"</string>
</resources>
diff --git a/quickstep/res/values-ky-rKG/strings.xml b/quickstep/res/values-ky-rKG/strings.xml
deleted file mode 100644
index b788693..0000000
--- a/quickstep/res/values-ky-rKG/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Экранды бөлүү"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Кадап коюу"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Сереп салуу"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Акыркы колдонмолор жок"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Жабуу"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Баарын тазалоо"</string>
-</resources>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 9f84037..c2c1dda 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Сереп салуу"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Акыркы колдонмолор жок"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Жабуу"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Колдонмону пайдалануу жөндөөлөрү"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Баарын тазалоо"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Акыркы колдонмолор"</string>
</resources>
diff --git a/quickstep/res/values-lo-rLA/strings.xml b/quickstep/res/values-lo-rLA/strings.xml
deleted file mode 100644
index a83743a..0000000
--- a/quickstep/res/values-lo-rLA/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"ແບ່ງໜ້າຈໍ"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"ປັກໝຸດ"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ພາບຮວມ"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"ບໍ່ມີລາຍການຫຼ້າສຸດ"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"ປິດ"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"ລຶບລ້າງທັງໝົດ"</string>
-</resources>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index ed1cb6e..278224a 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ພາບຮວມ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ບໍ່ມີລາຍການຫຼ້າສຸດ"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"ປິດ"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ການຕັ້ງຄ່າການນຳໃຊ້ແອັບ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ລຶບລ້າງທັງໝົດ"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ແອັບຫຼ້າສຸດ"</string>
</resources>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index c16fc56..182bc01 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Apžvalga"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nėra jokių naujausių elementų"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Uždaryti"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programos naudojimo nustatymai"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Išvalyti viską"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Naujausios programos"</string>
</resources>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 2dee41c..9e09f74 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Pārskats"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nav nesenu vienumu."</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Aizvērt"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Lietotņu izmantošanas iestatījumi"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Notīrīt visu"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Pēdējās izmantotās lietotnes"</string>
</resources>
diff --git a/quickstep/res/values-mk-rMK/strings.xml b/quickstep/res/values-mk-rMK/strings.xml
deleted file mode 100644
index e428b4e..0000000
--- a/quickstep/res/values-mk-rMK/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Поделен екран"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Прикачување"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Преглед"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Нема неодамнешни ставки"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Затвори"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Исчисти ги сите"</string>
-</resources>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index ff16cea..b068136 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Преглед"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Нема неодамнешни ставки"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Затвори"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Поставки за користење на апликациите"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Исчисти ги сите"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Неодамнешни апликации"</string>
</resources>
diff --git a/quickstep/res/values-ml-rIN/strings.xml b/quickstep/res/values-ml-rIN/strings.xml
deleted file mode 100644
index 4cca447..0000000
--- a/quickstep/res/values-ml-rIN/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"സ്ക്രീൻ വിഭജിക്കുക"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"പിൻ ചെയ്യുക"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"അവലോകനം"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"അവസാനിപ്പിക്കുക"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"എല്ലാം മായ്ക്കുക"</string>
-</resources>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 624aded..629909d 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"അവലോകനം"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"അവസാനിപ്പിക്കുക"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ആപ്പ് ഉപയോഗ ക്രമീകരണം"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"എല്ലാം മായ്ക്കുക"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"സമീപകാല ആപ്പുകൾ"</string>
</resources>
diff --git a/quickstep/res/values-mn-rMN/strings.xml b/quickstep/res/values-mn-rMN/strings.xml
deleted file mode 100644
index f40f69e..0000000
--- a/quickstep/res/values-mn-rMN/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Дэлгэцийг хуваах"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Тогтоох"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Тойм"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Сүүлийн үеийн зүйл алга"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Хаах"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Бүгдийг устгах"</string>
-</resources>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index f902125..ffb26fa 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Тойм"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Сүүлийн үеийн зүйл алга"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Хаах"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Апп ашиглалтын тохиргоо"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Бүгдийг устгах"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Саяхны аппууд"</string>
</resources>
diff --git a/quickstep/res/values-mr-rIN/strings.xml b/quickstep/res/values-mr-rIN/strings.xml
deleted file mode 100644
index 938363d..0000000
--- a/quickstep/res/values-mr-rIN/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"विभाजित स्क्रीन"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करा"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"अवलोकन"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"कोणतेही अलीकडील आयटम नाहीत"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"बंद"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"सर्व साफ करा"</string>
-</resources>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 7a669dd..72f41de 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"अवलोकन"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"कोणतेही अलीकडील आयटम नाहीत"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"बंद"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"अॅप वापर सेटिंग्ज"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"सर्व साफ करा"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"अलीकडील अॅप्स"</string>
</resources>
diff --git a/quickstep/res/values-ms-rMY/strings.xml b/quickstep/res/values-ms-rMY/strings.xml
deleted file mode 100644
index 236fab2..0000000
--- a/quickstep/res/values-ms-rMY/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Skrin pisah"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Semat"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ikhtisar"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Tiada item terbaharu"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Tutup"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Kosongkan semua"</string>
-</resources>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 6995863..839cf14 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ikhtisar"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Tiada item terbaharu"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Tutup"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tetapan penggunaan apl"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Kosongkan semua"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Apl terbaharu"</string>
</resources>
diff --git a/quickstep/res/values-my-rMM/strings.xml b/quickstep/res/values-my-rMM/strings.xml
deleted file mode 100644
index e44b904..0000000
--- a/quickstep/res/values-my-rMM/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"ပင်ထိုးခြင်း"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"အနှစ်ချုပ်"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"ပိတ်ရန်"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"အားလုံးကို ရှင်းရန်"</string>
-</resources>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index ae6dc7d..d89ddc7 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"အနှစ်ချုပ်"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"ပိတ်ရန်"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"အက်ပ်အသုံးပြုမှု ဆက်တင်များ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"အားလုံးကို ရှင်းရန်"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"လတ်တလောသုံး အက်ပ်များ"</string>
</resources>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index cb8ee10..dd0d8cd 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Oversikt"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ingen nylige elementer"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Lukk"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Innstillinger for appbruk"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Fjern alt"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nylige apper"</string>
</resources>
diff --git a/quickstep/res/values-ne-rNP/strings.xml b/quickstep/res/values-ne-rNP/strings.xml
deleted file mode 100644
index bf52604..0000000
--- a/quickstep/res/values-ne-rNP/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"स्क्रिन विभाजन गर्नुहोस्"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"पिन गर्नुहोस्"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"परिदृश्य"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"हालसालैको कुनै पनि वस्तु छैन"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"बन्द गर्नुहोस्"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"सबै खाली गर्नुहोस्"</string>
-</resources>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 4efae7b..17e4185 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"परिदृश्य"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"हालसालैको कुनै पनि वस्तु छैन"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"बन्द गर्नुहोस्"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"अनुप्रयोगको उपयोगका सेटिङहरू"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"सबै खाली गर्नुहोस्"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"हालसालैका अनुप्रयोगहरू"</string>
</resources>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 8ef2a5d..7dd3abd 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Overzicht"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Geen recente items"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Sluiten"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Instellingen voor app-gebruik"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Alles wissen"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recente apps"</string>
</resources>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 6895ef5..e45b3c9 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ସଂକ୍ଷିପ୍ତ ବିବରଣ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"କୌଣସି ସାମ୍ପ୍ରତିକ ଆଇଟମ୍ ନାହିଁ"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ଆପ୍ ବ୍ୟବହାର ସେଟିଂସ୍"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ସବୁ ଖାଲି କରନ୍ତୁ"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ସାମ୍ପ୍ରତିକ ଆପ୍"</string>
</resources>
diff --git a/quickstep/res/values-pa-rIN/strings.xml b/quickstep/res/values-pa-rIN/strings.xml
deleted file mode 100644
index bc044c8..0000000
--- a/quickstep/res/values-pa-rIN/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"ਪਿੰਨ ਕਰੋ"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ਰੂਪ-ਰੇਖਾ"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮਾਂ ਨਹੀਂ"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"ਬੰਦ ਕਰੋ"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
-</resources>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 4159c30..a8031c8 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ਰੂਪ-ਰੇਖਾ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮਾਂ ਨਹੀਂ"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"ਬੰਦ ਕਰੋ"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ਐਪ ਵਰਤੋਂ ਦੀਆਂ ਸੈਟਿੰਗਾਂ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ਹਾਲੀਆ ਐਪਾਂ"</string>
</resources>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index cf15abd..107cf44 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Przegląd"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Brak ostatnich elementów"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Zamknij"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ustawienia użycia aplikacji"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Wyczyść wszystko"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Ostatnie aplikacje"</string>
</resources>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 36c7e3c..15d3b52 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Vista geral"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Fechar"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Definições de utilização de aplicações"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Limpar tudo"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicações recentes"</string>
</resources>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 41f53f0..2a15a04 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Visão geral"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Fechar"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configurações de uso do app"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Limpar tudo"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Apps recentes"</string>
</resources>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 032d886..60581c0 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -19,11 +19,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Ecran divizat"</string>
+ <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Ecran împărțit"</string>
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixați"</string>
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Recente"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Niciun element recent"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Închideți"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setări de utilizare a aplicației"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Ștergeți tot"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicații recente"</string>
</resources>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 6a218fc..ae3bfa0 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Обзор"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Здесь пока ничего нет."</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Закрыть"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки использования приложения"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Очистить все"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Недавние приложения"</string>
</resources>
diff --git a/quickstep/res/values-si-rLK/strings.xml b/quickstep/res/values-si-rLK/strings.xml
deleted file mode 100644
index 61bb8ba..0000000
--- a/quickstep/res/values-si-rLK/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"බෙදුම් තිරය"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"අමුණන්න"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"දළ විශ්ලේෂණය"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"මෑත අයිතම නැත"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"වසන්න"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"සියල්ල හිස් කරන්න"</string>
-</resources>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index c01211a..44bb3c9 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"දළ විශ්ලේෂණය"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"මෑත අයිතම නැත"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"වසන්න"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"යෙදුම් භාවිත සැකසීම්"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"සියල්ල හිස් කරන්න"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"මෑත යෙදුම්"</string>
</resources>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 2cd3942..adbe83f 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Prehľad"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Žiadne nedávne položky"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Zavrieť"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavenia využívania aplikácie"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Vymazať všetko"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedávne aplikácie"</string>
</resources>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 06eb95d..33da937 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Pregled"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ni nedavnih elementov"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Zapri"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavitve uporabe aplikacij"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Počisti vse"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
</resources>
diff --git a/quickstep/res/values-sq-rAL/strings.xml b/quickstep/res/values-sq-rAL/strings.xml
deleted file mode 100644
index a0c3d78..0000000
--- a/quickstep/res/values-sq-rAL/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Ekrani i ndarë"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Gozhdo"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Përmbledhja"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Nuk ka asnjë artikull të fundit"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Mbyll"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Pastroji të gjitha"</string>
-</resources>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 00231e1..91d0067 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Përmbledhja"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nuk ka asnjë artikull të fundit"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Mbyll"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cilësimet e përdorimit të aplikacionit"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Pastroji të gjitha"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplikacionet e fundit"</string>
</resources>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 0077ee2..ee2550c 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Преглед"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Нема недавних ставки"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Затвори"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Подешавања коришћења апликације"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Обриши све"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Недавне апликације"</string>
</resources>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index f05d79f..17c64bb 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Översikt"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Listan med de senaste åtgärderna är tom"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Stäng"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Inställningar för appanvändning"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Rensa alla"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Senaste apparna"</string>
</resources>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index e6ce953..4be292c 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Muhtasari"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Hakuna vipengee vya hivi karibuni"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Funga"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mipangilio ya matumizi ya programu"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Ondoa zote"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Programu za hivi karibuni"</string>
</resources>
diff --git a/quickstep/res/values-ta-rIN/strings.xml b/quickstep/res/values-ta-rIN/strings.xml
deleted file mode 100644
index 0c800ca..0000000
--- a/quickstep/res/values-ta-rIN/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"திரைப் பிரிப்பு"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"பின் செய்தல்"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"மேலோட்டப் பார்வை"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"சமீபத்தியவை எதுவுமில்லை"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"மூடும்"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"எல்லாம் அழி"</string>
-</resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 19518e1..49de608 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"மேலோட்டப் பார்வை"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"சமீபத்தியவை எதுவுமில்லை"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"மூடும்"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ஆப்ஸ் உபயோக அமைப்புகள்"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"எல்லாம் அழி"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"சமீபத்திய ஆப்ஸ்"</string>
</resources>
diff --git a/quickstep/res/values-te-rIN/strings.xml b/quickstep/res/values-te-rIN/strings.xml
deleted file mode 100644
index 416fbb8..0000000
--- a/quickstep/res/values-te-rIN/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"స్క్రీన్ని విభజించు"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"పిన్ చేయి"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"అవలోకనం"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"ఇటీవలి అంశాలు ఏవీ లేవు"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"మూసివేయండి"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"అన్నీ తీసివేయండి"</string>
-</resources>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 4c0e5ac..cc3f70b 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"అవలోకనం"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ఇటీవలి అంశాలు ఏవీ లేవు"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"మూసివేయండి"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"యాప్ వినియోగ సెట్టింగ్లు"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"అన్నీ తీసివేయండి"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ఇటీవలి యాప్లు"</string>
</resources>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 8dfda24..16553a4 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ภาพรวม"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ไม่มีรายการล่าสุด"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"ปิด"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"การตั้งค่าการใช้แอป"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ล้างทั้งหมด"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"แอปล่าสุด"</string>
</resources>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index ab3cac9..ad140bf 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Overview"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Walang kamakailang item"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Isara"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mga setting ng paggamit ng app"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"I-clear lahat"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Mga kamakailang app"</string>
</resources>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 9693413..af2d0162 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Genel bakış"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Yeni öğe yok"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Kapat"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Uygulama kullanım ayarları"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Tümünü temizle"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Son uygulamalar"</string>
</resources>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 2afcb31..c9e0508 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Огляд"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Немає нещодавніх додатків"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Закрити"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Налаштування використання додатка"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Очистити все"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Нещодавні додатки"</string>
</resources>
diff --git a/quickstep/res/values-ur-rPK/strings.xml b/quickstep/res/values-ur-rPK/strings.xml
deleted file mode 100644
index 0a546fd..0000000
--- a/quickstep/res/values-ur-rPK/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"اسپلٹ اسکرین وضع"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"پن کریں"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"مجموعی جائزہ"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"کوئی حالیہ آئٹم نہیں"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"بند کریں"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"سبھی کو صاف کریں"</string>
-</resources>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index f493a2f..34e32c0 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"مجموعی جائزہ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"کوئی حالیہ آئٹم نہیں"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"بند کریں"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ایپ کے استعمال کی ترتیبات"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"سبھی کو صاف کریں"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"حالیہ ایپس"</string>
</resources>
diff --git a/quickstep/res/values-uz-rUZ/strings.xml b/quickstep/res/values-uz-rUZ/strings.xml
deleted file mode 100644
index efea341..0000000
--- a/quickstep/res/values-uz-rUZ/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Ekranni ikkiga ajratish"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Mahkamlash"</string>
- <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Nazar"</string>
- <string name="recents_empty_message" msgid="7040467240571714191">"Yaqinda ishlatilgan ilovalar yo‘q"</string>
- <string name="accessibility_close_task" msgid="5354563209433803643">"Yopish"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"Hammasini tozalash"</string>
-</resources>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 4911925..449f28e 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Nazar"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Yaqinda ishlatilgan ilovalar yo‘q"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Yopish"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ilovadan foydalanish sozlamalari"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hammasini tozalash"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Yaqinda ishlatilgan ilovalar"</string>
</resources>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 406faf5..6f6f822 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Tổng quan"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Không có mục gần đây nào"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Đóng"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cài đặt mức sử dụng ứng dụng"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Xóa tất cả"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Ứng dụng gần đây"</string>
</resources>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 71ac114..3aef813 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"概览"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"近期没有任何内容"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"关闭"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"应用使用设置"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"最近用过的应用"</string>
</resources>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index ab29a91..70bdd04 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"概覽"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"關閉"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"最近使用的應用程式"</string>
</resources>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 1a9448c..e1f89ca 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"總覽"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"關閉"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"最近使用的應用程式"</string>
</resources>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 3d4f372..5669619 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -24,6 +24,7 @@
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Buka konke"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Azikho izinto zakamuva"</string>
<string name="accessibility_close_task" msgid="5354563209433803643">"Vala"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Izilungiselelo zokusetshenziswa kohlelo lokusebenza"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Sula konke"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Izinhlelo zokusebenza zakamuva"</string>
</resources>
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index c294376..3fbfcdd 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -19,4 +19,11 @@
<string name="overview_callbacks_class" translatable="false"></string>
<string name="user_event_dispatcher_class" translatable="false">com.android.quickstep.logging.UserEventDispatcherExtension</string>
+
+ <string name="stats_log_manager_class" translatable="false">com.android.quickstep.logging.StatsLogCompatManager</string>
+
+ <!-- The number of thumbnails and icons to keep in the cache. The thumbnail cache size also
+ determines how many thumbnails will be fetched in the background. -->
+ <integer name="recentsThumbnailCacheSize">3</integer>
+ <integer name="recentsIconCacheSize">12</integer>
</resources>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index a76899d..c712703 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -36,6 +36,9 @@
<!-- Content description for the recent apps's accessibility option that closes it. [CHAR LIMIT=NONE] -->
<string name="accessibility_close_task">Close</string>
+ <!-- Content description for the recent apps's accessibility option that opens its usage settings. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_app_usage_settings">App usage settings</string>
+
<!-- Recents: Title of a button that clears the task list, i.e. closes all tasks. [CHAR LIMIT=30] -->
<string name="recents_clear_all">Clear all</string>
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index e346310..78f6ffa 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -17,7 +17,8 @@
import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
import static com.android.launcher3.Utilities.postAsyncCallback;
-import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
+import static com.android.systemui.shared.recents.utilities.Utilities
+ .postAtFrontOfQueueAsynchronously;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -25,12 +26,13 @@
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Handler;
-import android.support.annotation.BinderThread;
-import android.support.annotation.UiThread;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import androidx.annotation.BinderThread;
+import androidx.annotation.UiThread;
+
@TargetApi(Build.VERSION_CODES.P)
public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 14633af..9e85469 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -178,6 +178,14 @@
@Override
public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
if (hasControlRemoteAppTransitionPermission()) {
+ boolean fromRecents = mLauncher.getStateManager().getState().overviewUi
+ && findTaskViewToLaunch(launcher, v, null) != null;
+ RecentsView recentsView = mLauncher.getOverviewPanel();
+ if (fromRecents && recentsView.getQuickScrubController().isQuickSwitch()) {
+ return ActivityOptions.makeCustomAnimation(mLauncher, R.anim.no_anim,
+ R.anim.no_anim);
+ }
+
RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler,
true /* startAtFrontOfQueue */) {
@@ -218,8 +226,6 @@
}
};
- boolean fromRecents = mLauncher.getStateManager().getState().overviewUi
- && findTaskViewToLaunch(launcher, v, null) != null;
int duration = fromRecents
? RECENTS_LAUNCH_DURATION
: APP_LAUNCH_DURATION;
@@ -414,7 +420,10 @@
mLauncher.getWorkspace().getPageIndicator().pauseAnimations();
mDragLayer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- endListener = this::resetContentView;
+ endListener = () -> {
+ resetContentView();
+ mDragLayer.getScrim().hideSysUiScrim(false);
+ };
}
return new Pair<>(launcherAnimator, endListener);
}
@@ -427,8 +436,8 @@
mFloatingView = new View(mLauncher);
if (isBubbleTextView && v.getTag() instanceof ItemInfoWithIcon ) {
// Create a copy of the app icon
- mFloatingView.setBackground(
- DrawableFactory.get(mLauncher).newIcon((ItemInfoWithIcon) v.getTag()));
+ mFloatingView.setBackground(DrawableFactory.INSTANCE.get(mLauncher)
+ .newIcon(v.getContext(), (ItemInfoWithIcon) v.getTag()));
}
// Position the floating view exactly on top of the original
@@ -537,6 +546,9 @@
@Override
public void onAnimationEnd(Animator animation) {
// Reset launcher to normal state
+ if (isBubbleTextView) {
+ ((BubbleTextView) v).setStayPressed(false);
+ }
v.setVisibility(View.VISIBLE);
((ViewGroup) mDragLayer.getParent()).removeView(mFloatingView);
}
@@ -785,8 +797,6 @@
workspaceAnimator.setDuration(333);
workspaceAnimator.setInterpolator(Interpolators.DEACCEL_1_7);
- mDragLayer.getScrim().hideSysUiScrim(true);
-
// Pause page indicator animations as they lead to layer trashing.
mLauncher.getWorkspace().getPageIndicator().pauseAnimations();
mDragLayer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
@@ -806,7 +816,6 @@
mDragLayerAlpha.setValue(1f);
mDragLayer.setLayerType(View.LAYER_TYPE_NONE, null);
mDragLayer.setTranslationY(0f);
- mDragLayer.getScrim().hideSysUiScrim(false);
}
private boolean hasControlRemoteAppTransitionPermission() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
index 1eaa8bc..1906286 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.uioverrides;
+import static com.android.launcher3.AbstractFloatingView.TYPE_QUICKSTEP_PREVIEW;
import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
@@ -44,7 +45,7 @@
@Override
public void onStateEnabled(Launcher launcher) {
- AbstractFloatingView.closeAllOpenViews(launcher);
+ AbstractFloatingView.closeAllOpenViewsExcept(launcher, TYPE_QUICKSTEP_PREVIEW);
dispatchWindowStateChanged(launcher);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java
index 722f51b..693ae60 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java
@@ -35,7 +35,7 @@
public BackButtonAlphaHandler(Launcher launcher) {
mLauncher = launcher;
- mOverviewInteractionState = OverviewInteractionState.getInstance(mLauncher);
+ mOverviewInteractionState = OverviewInteractionState.INSTANCE.get(mLauncher);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/BackgroundAppState.java
new file mode 100644
index 0000000..fdb13b1
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/BackgroundAppState.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import android.os.RemoteException;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.quickstep.QuickScrubController;
+import com.android.quickstep.RecentsModel;
+import com.android.quickstep.util.LayoutUtils;
+import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.recents.ISystemUiProxy;
+
+/**
+ * State indicating that the Launcher is behind an app
+ */
+public class BackgroundAppState extends OverviewState {
+
+ private static final int STATE_FLAGS =
+ FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_DISABLE_ACCESSIBILITY;
+
+ public BackgroundAppState(int id) {
+ super(id, QuickScrubController.QUICK_SCRUB_FROM_HOME_START_DURATION, STATE_FLAGS);
+ }
+
+ @Override
+ public float getVerticalProgress(Launcher launcher) {
+ if (launcher.getDeviceProfile().isVerticalBarLayout()) {
+ return super.getVerticalProgress(launcher);
+ }
+ int transitionLength = LayoutUtils.getShelfTrackingDistance(launcher.getDeviceProfile());
+ AllAppsTransitionController controller = launcher.getAllAppsController();
+ float scrollRange = Math.max(controller.getShiftRange(), 1);
+ float progressDelta = (transitionLength / scrollRange);
+ return super.getVerticalProgress(launcher) + progressDelta;
+ }
+
+ @Override
+ public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
+ // Initialize the recents view scale to what it would be when starting swipe up/quickscrub
+ RecentsView recentsView = launcher.getOverviewPanel();
+ recentsView.getTaskSize(sTempRect);
+ int appWidth = launcher.getDragLayer().getWidth();
+ if (recentsView.shouldUseMultiWindowTaskSizeStrategy()) {
+ ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(launcher).getSystemUiProxy();
+ if (sysUiProxy != null) {
+ try {
+ // Try to use the actual non-minimized app width (launcher will be resized to
+ // the non-minimized bounds, which differs from the app width in landscape
+ // multi-window mode
+ appWidth = sysUiProxy.getNonMinimizedSplitScreenSecondaryBounds().width();
+ } catch (RemoteException e) {
+ // Ignore, fall back to just using the drag layer width
+ }
+ }
+ }
+ float scale = (float) appWidth / sTempRect.width();
+ return new float[] { scale, 0f };
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
index 2645302..1d65a54 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
@@ -35,6 +35,7 @@
* Vertical transition of the task previews relative to the full container.
*/
public static final float OVERVIEW_TRANSLATION_FACTOR = 0.4f;
+ public static final float OVERVIEW_CENTERED_TRANSLATION_FACTOR = 0.5f;
private static final int STATE_FLAGS = FLAG_DISABLE_RESTORE | FLAG_DISABLE_INTERACTION
| FLAG_OVERVIEW_UI | FLAG_HIDE_BACK_BUTTON | FLAG_DISABLE_ACCESSIBILITY;
@@ -60,12 +61,17 @@
RecentsView recentsView = launcher.getOverviewPanel();
recentsView.getTaskSize(sTempRect);
- return new float[] {getOverviewScale(launcher.getDeviceProfile(), sTempRect, launcher),
- OVERVIEW_TRANSLATION_FACTOR};
+ boolean isQuickSwitch = recentsView.getQuickScrubController().isQuickSwitch();
+ float translationYFactor = isQuickSwitch
+ ? OVERVIEW_CENTERED_TRANSLATION_FACTOR
+ : OVERVIEW_TRANSLATION_FACTOR;
+ return new float[] {getOverviewScale(launcher.getDeviceProfile(), sTempRect, launcher,
+ isQuickSwitch), translationYFactor};
}
- public static float getOverviewScale(DeviceProfile dp, Rect taskRect, Context context) {
- if (dp.isVerticalBarLayout()) {
+ public static float getOverviewScale(DeviceProfile dp, Rect taskRect, Context context,
+ boolean isQuickSwitch) {
+ if (dp.isVerticalBarLayout() && !isQuickSwitch) {
return 1f;
}
@@ -73,6 +79,10 @@
float usedHeight = taskRect.height() + res.getDimension(R.dimen.task_thumbnail_top_margin);
float usedWidth = taskRect.width() + 2 * (res.getDimension(R.dimen.recents_page_spacing)
+ res.getDimension(R.dimen.quickscrub_adjacent_visible_width));
+ if (isQuickSwitch) {
+ usedWidth = taskRect.width();
+ return Math.max(dp.availableHeightPx / usedHeight, dp.availableWidthPx / usedWidth);
+ }
return Math.min(Math.min(dp.availableHeightPx / usedHeight,
dp.availableWidthPx / usedWidth), MAX_PREVIEW_SCALE_UP);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
index 6d10619..fd4bf9b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
@@ -73,7 +73,7 @@
protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
super.onSwipeInteractionCompleted(targetState, logAction);
if (mStartState == NORMAL && targetState == OVERVIEW) {
- RecentsModel.getInstance(mLauncher).onOverviewShown(true, TAG);
+ RecentsModel.INSTANCE.get(mLauncher).onOverviewShown(true, TAG);
}
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 7f956f8..8f1d46c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -15,10 +15,12 @@
*/
package com.android.launcher3.uioverrides;
+import static com.android.launcher3.AbstractFloatingView.TYPE_QUICKSTEP_PREVIEW;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
+import android.graphics.Rect;
import android.view.View;
import com.android.launcher3.AbstractFloatingView;
@@ -31,12 +33,15 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
/**
* Definition for overview state
*/
public class OverviewState extends LauncherState {
+ protected static final Rect sTempRect = new Rect();
+
private static final int STATE_FLAGS = FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
| FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_DISABLE_ACCESSIBILITY;
@@ -70,14 +75,14 @@
public void onStateEnabled(Launcher launcher) {
RecentsView rv = launcher.getOverviewPanel();
rv.setOverviewStateEnabled(true);
- AbstractFloatingView.closeAllOpenViews(launcher);
+ AbstractFloatingView.closeAllOpenViewsExcept(launcher, TYPE_QUICKSTEP_PREVIEW);
}
@Override
public void onStateDisabled(Launcher launcher) {
RecentsView rv = launcher.getOverviewPanel();
rv.setOverviewStateEnabled(false);
- RecentsModel.getInstance(launcher).resetAssistCache();
+ RecentsModel.INSTANCE.get(launcher).resetAssistCache();
}
@Override
@@ -130,4 +135,14 @@
DeviceProfile dp = launcher.getDeviceProfile();
return dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
}
+
+ @Override
+ public void onBackPressed(Launcher launcher) {
+ TaskView taskView = launcher.<RecentsView>getOverviewPanel().getRunningTaskView();
+ if (taskView != null) {
+ taskView.launchTask(true);
+ } else {
+ super.onBackPressed(launcher);
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
index 0eead88..8684c58 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.uioverrides;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -45,6 +46,7 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.TouchInteractionService;
+import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -96,11 +98,17 @@
}
return false;
}
+ RecentsView recentsView = mLauncher.getOverviewPanel();
if (mLauncher.isInState(ALL_APPS)) {
// In all-apps only listen if the container cannot scroll itself
if (!mLauncher.getAppsView().shouldContainerScroll(ev)) {
return false;
}
+ } else if (mLauncher.isInState(OVERVIEW) && recentsView.getChildCount() > 0) {
+ // Allow swiping up in the gap between the hotseat and overview.
+ if (ev.getY() < recentsView.getChildAt(0).getBottom()) {
+ return false;
+ }
} else {
// For all other states, only listen if the event originated below the hotseat height
DeviceProfile dp = mLauncher.getDeviceProfile();
@@ -109,7 +117,7 @@
return false;
}
}
- if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ if (AbstractFloatingView.getTopOpenViewWithType(mLauncher, TYPE_ACCESSIBLE) != null) {
return false;
}
return true;
@@ -196,7 +204,7 @@
// Reset the state manager, when changing the interaction mode
mLauncher.getStateManager().goToState(OVERVIEW, false /* animate */);
mPendingAnimation = recentsView.createTaskLauncherAnimation(taskView, maxAccuracy);
- mPendingAnimation.anim.setInterpolator(Interpolators.ZOOM_IN);
+ mPendingAnimation.anim.setInterpolator(Interpolators.LINEAR);
Runnable onCancelRunnable = () -> {
cancelPendingAnim();
@@ -205,6 +213,7 @@
mCurrentAnimation = AnimatorPlaybackController.wrap(mPendingAnimation.anim, maxAccuracy,
onCancelRunnable);
mLauncher.getStateManager().setCurrentUserControlledAnimation(mCurrentAnimation);
+ totalShift = LayoutUtils.getShelfTrackingDistance(mLauncher.getDeviceProfile());
} else {
mCurrentAnimation = mLauncher.getStateManager()
.createAnimationToNewWorkspace(mToState, builder, maxAccuracy, this::clearState,
@@ -255,7 +264,7 @@
protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
super.onSwipeInteractionCompleted(targetState, logAction);
if (mStartState == NORMAL && targetState == OVERVIEW) {
- RecentsModel.getInstance(mLauncher).onOverviewShown(true, TAG);
+ RecentsModel.INSTANCE.get(mLauncher).onOverviewShown(true, TAG);
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java
new file mode 100644
index 0000000..8f33e40
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java
@@ -0,0 +1,123 @@
+/*
+ * 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;
+
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.touch.TouchEventTranslator;
+import com.android.launcher3.util.TouchController;
+import com.android.quickstep.RecentsModel;
+import com.android.systemui.shared.recents.ISystemUiProxy;
+
+/**
+ * TouchController for handling touch events that get sent to the StatusBar. Once the
+ * Once the event delta y passes the touch slop, the events start getting forwarded.
+ * All events are offset by initial Y value of the pointer.
+ */
+public class StatusBarTouchController implements TouchController {
+
+ private static final String TAG = "StatusBarController";
+
+ protected final Launcher mLauncher;
+ protected final TouchEventTranslator mTranslator;
+ private final float mTouchSlop;
+ private ISystemUiProxy mSysUiProxy;
+
+ /* If {@code false}, this controller should not handle the input {@link MotionEvent}.*/
+ private boolean mCanIntercept;
+
+ public StatusBarTouchController(Launcher l) {
+ mLauncher = l;
+ // Guard against TAPs by increasing the touch slop.
+ mTouchSlop = 2 * ViewConfiguration.get(l).getScaledTouchSlop();
+ mTranslator = new TouchEventTranslator((MotionEvent ev)-> dispatchTouchEvent(ev));
+ }
+
+ private void dispatchTouchEvent(MotionEvent ev) {
+ try {
+ if (mSysUiProxy != null) {
+ mSysUiProxy.onStatusBarMotionEvent(ev);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Remote exception on sysUiProxy.", e);
+ }
+ }
+
+ @Override
+ public final boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ int action = ev.getActionMasked();
+ if (action == ACTION_DOWN) {
+ mCanIntercept = canInterceptTouch(ev);
+ if (!mCanIntercept) {
+ return false;
+ }
+ mTranslator.reset();
+ mTranslator.setDownParameters(0, ev);
+ } else if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
+ // Check!! should only set it only when threshold is not entered.
+ mTranslator.setDownParameters(ev.getActionIndex(), ev);
+ }
+ if (!mCanIntercept) {
+ return false;
+ }
+ if (action == ACTION_MOVE) {
+ float dy = ev.getY() - mTranslator.getDownY();
+ float dx = ev.getX() - mTranslator.getDownX();
+ if (dy > mTouchSlop && dy > Math.abs(dx)) {
+ mTranslator.dispatchDownEvents(ev);
+ mTranslator.processMotionEvent(ev);
+ return true;
+ }
+ if (Math.abs(dx) > mTouchSlop) {
+ mCanIntercept = false;
+ }
+ }
+ return false;
+ }
+
+
+ @Override
+ public final boolean onControllerTouchEvent(MotionEvent ev) {
+ mTranslator.processMotionEvent(ev);
+ return true;
+ }
+
+ private boolean canInterceptTouch(MotionEvent ev) {
+ if (!mLauncher.isInState(LauncherState.NORMAL) ||
+ AbstractFloatingView.getTopOpenViewWithType(mLauncher,
+ AbstractFloatingView.TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW) != null) {
+ return false;
+ } else {
+ // For NORMAL state, only listen if the event originated above the navbar height
+ DeviceProfile dp = mLauncher.getDeviceProfile();
+ if (ev.getY() > (mLauncher.getDragLayer().getHeight() - dp.getInsets().bottom)) {
+ return false;
+ }
+ }
+ mSysUiProxy = RecentsModel.INSTANCE.get(mLauncher).getSystemUiProxy();
+ return mSysUiProxy != null;
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
index cfd4119..54269f09 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.uioverrides;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
@@ -79,7 +80,7 @@
// If we are already animating from a previous state, we can intercept.
return true;
}
- if (AbstractFloatingView.getTopOpenView(mActivity) != null) {
+ if (AbstractFloatingView.getTopOpenViewWithType(mActivity, TYPE_ACCESSIBLE) != null) {
return false;
}
return isRecentsInteractive();
@@ -120,7 +121,7 @@
if (mRecentsView.isTaskViewVisible(view) && mActivity.getDragLayer()
.isEventOverView(view, ev)) {
mTaskBeingDragged = view;
- if (!OverviewInteractionState.getInstance(mActivity)
+ if (!OverviewInteractionState.INSTANCE.get(mActivity)
.isSwipeUpGestureEnabled()) {
// Don't allow swipe down to open if we don't support swipe up
// to enter overview.
@@ -219,7 +220,7 @@
}
@Override
- public boolean onDrag(float displacement, float velocity) {
+ public boolean onDrag(float displacement) {
float totalDisplacement = displacement + mDisplacementShift;
boolean isGoingUp =
totalDisplacement == 0 ? mCurrentAnimationIsGoingUp : totalDisplacement < 0;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 2d0946b..4e79fed 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -42,6 +42,7 @@
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.OverviewInteractionState;
import com.android.quickstep.RecentsModel;
@@ -52,35 +53,37 @@
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.zip.Deflater;
public class UiFactory {
public static TouchController[] createTouchControllers(Launcher launcher) {
- boolean swipeUpEnabled = OverviewInteractionState.getInstance(launcher)
+ boolean swipeUpEnabled = OverviewInteractionState.INSTANCE.get(launcher)
.isSwipeUpGestureEnabled();
- if (!swipeUpEnabled) {
- return new TouchController[] {
- launcher.getDragController(),
- new OverviewToAllAppsTouchController(launcher),
- new LauncherTaskViewController(launcher)};
+ ArrayList<TouchController> list = new ArrayList<>();
+ list.add(launcher.getDragController());
+
+ if (!swipeUpEnabled || launcher.getDeviceProfile().isVerticalBarLayout()) {
+ list.add(new OverviewToAllAppsTouchController(launcher));
}
+
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
- return new TouchController[] {
- launcher.getDragController(),
- new OverviewToAllAppsTouchController(launcher),
- new LandscapeEdgeSwipeController(launcher),
- new LauncherTaskViewController(launcher)};
+ list.add(new LandscapeEdgeSwipeController(launcher));
} else {
- return new TouchController[] {
- launcher.getDragController(),
- new PortraitStatesTouchController(launcher),
- new LauncherTaskViewController(launcher)};
+ list.add(new PortraitStatesTouchController(launcher));
}
+ if (FeatureFlags.PULL_DOWN_STATUS_BAR && Utilities.IS_DEBUG_DEVICE
+ && !launcher.getDeviceProfile().isMultiWindowMode
+ && !launcher.getDeviceProfile().isVerticalBarLayout()) {
+ list.add(new StatusBarTouchController(launcher));
+ }
+ list.add(new LauncherTaskViewController(launcher));
+ return list.toArray(new TouchController[list.size()]);
}
public static void setOnTouchControllersChangedListener(Context context, Runnable listener) {
- OverviewInteractionState.getInstance(context).setOnSwipeUpSettingChangedListener(listener);
+ OverviewInteractionState.INSTANCE.get(context).setOnSwipeUpSettingChangedListener(listener);
}
public static StateHandler[] getStateHandler(Launcher launcher) {
@@ -100,7 +103,7 @@
shouldBackButtonBeHidden = AbstractFloatingView.getTopOpenViewWithType(launcher,
TYPE_ALL & ~TYPE_HIDE_BACK_BUTTON) == null;
}
- OverviewInteractionState.getInstance(launcher)
+ OverviewInteractionState.INSTANCE.get(launcher)
.setBackButtonAlpha(shouldBackButtonBeHidden ? 0 : 1, true /* animate */);
}
@@ -114,6 +117,7 @@
launcher.getStateManager().addStateListener(new LauncherStateManager.StateListener() {
@Override
public void onStateSetImmediately(LauncherState state) {
+ onStateTransitionComplete(state);
}
@Override
@@ -122,7 +126,7 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
- boolean swipeUpEnabled = OverviewInteractionState.getInstance(launcher)
+ boolean swipeUpEnabled = OverviewInteractionState.INSTANCE.get(launcher)
.isSwipeUpGestureEnabled();
LauncherState prevState = launcher.getStateManager().getLastState();
@@ -139,6 +143,7 @@
launcher.getStateManager().addStateListener(new LauncherStateManager.StateListener() {
@Override
public void onStateSetImmediately(LauncherState state) {
+ onStateTransitionComplete(state);
}
@Override
@@ -158,28 +163,23 @@
}
}
- public static void onStart(Context context) {
- RecentsModel model = RecentsModel.getInstance(context);
- if (model != null) {
- model.onStart();
- }
- }
-
public static void onEnterAnimationComplete(Context context) {
// After the transition to home, enable the high-res thumbnail loader if it wasn't enabled
// as a part of quickstep/scrub, so that high-res thumbnails can load the next time we
// enter overview
- RecentsModel.getInstance(context).getRecentsTaskLoader()
- .getHighResThumbnailLoader().setVisible(true);
+ RecentsModel.INSTANCE.get(context).getThumbnailCache()
+ .getHighResLoadingState().setVisible(true);
}
public static void onLauncherStateOrResumeChanged(Launcher launcher) {
LauncherState state = launcher.getStateManager().getState();
- DeviceProfile profile = launcher.getDeviceProfile();
- WindowManagerWrapper.getInstance().setShelfHeight(
- (state == NORMAL || state == OVERVIEW) && launcher.isUserActive()
- && !profile.isVerticalBarLayout(),
- profile.hotseatBarSizePx);
+ if (!OverviewInteractionState.INSTANCE.get(launcher).swipeGestureInitializing()) {
+ DeviceProfile profile = launcher.getDeviceProfile();
+ WindowManagerWrapper.getInstance().setShelfHeight(
+ (state == NORMAL || state == OVERVIEW) && launcher.isUserActive()
+ && !profile.isVerticalBarLayout(),
+ profile.hotseatBarSizePx);
+ }
if (state == NORMAL) {
launcher.<RecentsView>getOverviewPanel().setSwipeDownShouldLaunchApp(false);
@@ -187,7 +187,7 @@
}
public static void onTrimMemory(Context context, int level) {
- RecentsModel model = RecentsModel.getInstance(context);
+ RecentsModel model = RecentsModel.INSTANCE.get(context);
if (model != null) {
model.onTrimMemory(level);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java
new file mode 100644
index 0000000..eaf4183
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java
@@ -0,0 +1,59 @@
+/*
+ * 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 android.content.ComponentName;
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import com.android.launcher3.Utilities;
+import com.android.systemui.shared.plugins.PluginEnabler;
+
+import androidx.preference.PreferenceDataStore;
+
+public class PluginEnablerImpl extends PreferenceDataStore implements PluginEnabler {
+
+ private static final String PREFIX_PLUGIN_ENABLED = "PLUGIN_ENABLED_";
+
+ final private SharedPreferences mSharedPrefs;
+
+ public PluginEnablerImpl(Context context) {
+ mSharedPrefs = Utilities.getDevicePrefs(context);
+ }
+
+ @Override
+ public void setEnabled(ComponentName component, boolean enabled) {
+ putBoolean(pluginEnabledKey(component), enabled);
+ }
+
+ @Override
+ public boolean isEnabled(ComponentName component) {
+ return getBoolean(pluginEnabledKey(component), true);
+ }
+
+ @Override
+ public void putBoolean(String key, boolean value) {
+ mSharedPrefs.edit().putBoolean(key, value).apply();
+ }
+
+ @Override
+ public boolean getBoolean(String key, boolean defValue) {
+ return mSharedPrefs.getBoolean(key, defValue);
+ }
+
+ static String pluginEnabledKey(ComponentName cn) {
+ return PREFIX_PLUGIN_ENABLED + cn.flattenToString();
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java
new file mode 100644
index 0000000..910fa0d
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java
@@ -0,0 +1,46 @@
+/*
+ * 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 android.content.Context;
+import android.os.Looper;
+
+import com.android.launcher3.LauncherModel;
+import com.android.systemui.shared.plugins.PluginInitializer;
+
+public class PluginInitializerImpl implements PluginInitializer {
+ @Override
+ public Looper getBgLooper() {
+ return LauncherModel.getWorkerLooper();
+ }
+
+ @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() {
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
new file mode 100644
index 0000000..6e7c087
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
@@ -0,0 +1,78 @@
+/*
+ * 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 android.content.ComponentName;
+import android.content.Context;
+
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.shared.plugins.PluginManagerImpl;
+import com.android.systemui.shared.plugins.PluginPrefs;
+
+import java.util.Set;
+
+public class PluginManagerWrapper {
+
+ public static final MainThreadInitializedObject<PluginManagerWrapper> INSTANCE =
+ new MainThreadInitializedObject<>(PluginManagerWrapper::new);
+
+ public static final String PLUGIN_CHANGED = PluginManager.PLUGIN_CHANGED;
+
+ private final Context mContext;
+ private final PluginManager mPluginManager;
+ private final PluginEnablerImpl mPluginEnabler;
+
+ private PluginManagerWrapper(Context c) {
+ mContext = c;
+ PluginInitializerImpl pluginInitializer = new PluginInitializerImpl();
+ mPluginManager = new PluginManagerImpl(c, pluginInitializer);
+ mPluginEnabler = pluginInitializer.getPluginEnabler(c);
+ }
+
+ public PluginEnablerImpl getPluginEnabler() {
+ return mPluginEnabler;
+ }
+
+ public void addPluginListener(PluginListener<? extends Plugin> listener, Class<?> pluginClass) {
+ addPluginListener(listener, pluginClass, false);
+ }
+
+ public void addPluginListener(PluginListener<? extends Plugin> listener, Class<?> pluginClass,
+ boolean allowMultiple) {
+ mPluginManager.addPluginListener(listener, pluginClass, allowMultiple);
+ }
+
+ public void removePluginListener(PluginListener<? extends Plugin> listener) {
+ mPluginManager.removePluginListener(listener);
+ }
+
+ public Set<String> getPluginActions() {
+ return new PluginPrefs(mContext).getPluginList();
+ }
+
+ /**
+ * Returns the string key used to store plugin enabled/disabled setting
+ */
+ public static String pluginEnabledKey(ComponentName cn) {
+ return PluginEnablerImpl.pluginEnabledKey(cn);
+ }
+
+ public static boolean hasPlugins(Context context) {
+ return PluginPrefs.hasPlugins(context);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index ced8754..02af0d6 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -16,19 +16,19 @@
package com.android.quickstep;
import static android.view.View.TRANSLATION_Y;
-
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_ROTATION;
-
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
@@ -38,13 +38,13 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
-import android.support.annotation.Nullable;
-import android.support.annotation.UiThread;
import android.view.View;
-
+import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
@@ -52,10 +52,12 @@
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
+import com.android.launcher3.TestProtocol;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
-import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.uioverrides.FastOverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -87,7 +89,7 @@
* Updates the UI to indicate quick interaction.
*/
void onQuickInteractionStart(T activity, @Nullable RunningTaskInfo taskInfo,
- boolean activityVisible);
+ boolean activityVisible, TouchInteractionLog touchInteractionLog);
float getTranslationYForQuickScrub(TransformedRect targetRect, DeviceProfile dp,
Context context);
@@ -102,7 +104,7 @@
void onSwipeUpComplete(T activity);
AnimationFactory prepareRecentsUI(T activity, boolean activityVisible,
- Consumer<AnimatorPlaybackController> callback);
+ boolean animateActivity, Consumer<AnimatorPlaybackController> callback);
ActivityInitListener createActivityInitListener(BiPredicate<T, Boolean> onInitListener);
@@ -133,7 +135,7 @@
/**
* Must return a non-null controller is supportsLongSwipe was true.
*/
- LongSwipeHelper getLongSwipeController(T activity, RemoteAnimationTargetSet targetSet);
+ LongSwipeHelper getLongSwipeController(T activity, int runningTaskId);
/**
* Used for containerType in {@link com.android.launcher3.logging.UserEventDispatcher}
@@ -149,13 +151,31 @@
@Override
public void onQuickInteractionStart(Launcher activity, RunningTaskInfo taskInfo,
- boolean activityVisible) {
+ boolean activityVisible, TouchInteractionLog touchInteractionLog) {
LauncherState fromState = activity.getStateManager().getState();
- activity.getStateManager().goToState(FAST_OVERVIEW, activityVisible);
-
QuickScrubController controller = activity.<RecentsView>getOverviewPanel()
.getQuickScrubController();
- controller.onQuickScrubStart(activityVisible && !fromState.overviewUi, this);
+ boolean isQuickSwitch = controller.isQuickSwitch();
+ boolean animate = activityVisible;
+ if (isQuickSwitch && fromState == FAST_OVERVIEW && !animate) {
+ // We can already be in FAST_OVERVIEW if createActivityController() was called
+ // before us. This could happen, for instance, when launcher is slow to load when
+ // starting quick switch, causing us to call onQuickScrubStart() on the background
+ // thread. In this case, we also hadn't set isQuickSwitch = true before setting
+ // FAST_OVERVIEW, so we need to reapply FAST_OVERVIEW to take that into account.
+ activity.getStateManager().reapplyState();
+ } else {
+ activity.getStateManager().goToState(FAST_OVERVIEW, animate);
+ }
+
+ controller.onQuickScrubStart(activityVisible && !fromState.overviewUi, this,
+ touchInteractionLog);
+
+ if (!activityVisible) {
+ // For the duration of the gesture, lock the screen orientation to ensure that we
+ // do not rotate mid-quickscrub
+ activity.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK);
+ }
}
@Override
@@ -180,16 +200,15 @@
@InteractionType int interactionType, TransformedRect outRect) {
LayoutUtils.calculateLauncherTaskSize(context, dp, outRect.rect);
if (interactionType == INTERACTION_QUICK_SCRUB) {
- outRect.scale = FastOverviewState.getOverviewScale(dp, outRect.rect, context);
+ outRect.scale = FastOverviewState.getOverviewScale(dp, outRect.rect, context,
+ FeatureFlags.QUICK_SWITCH.get());
}
if (dp.isVerticalBarLayout()) {
Rect targetInsets = dp.getInsets();
int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
return dp.hotseatBarSizePx + hotseatInset;
} else {
- int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
- // Track slightly below the top of the shelf (between top and content).
- return shelfHeight - dp.edgeMarginPx * 2;
+ return LayoutUtils.getShelfTrackingDistance(dp);
}
}
@@ -208,7 +227,7 @@
@Override
public AnimationFactory prepareRecentsUI(Launcher activity, boolean activityVisible,
- Consumer<AnimatorPlaybackController> callback) {
+ boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
final LauncherState startState = activity.getStateManager().getState();
LauncherState resetState = startState;
@@ -217,21 +236,28 @@
}
activity.getStateManager().setRestState(resetState);
+ final LauncherState fromState;
if (!activityVisible) {
// Since the launcher is not visible, we can safely reset the scroll position.
// This ensures then the next swipe up to all-apps starts from scroll 0.
activity.getAppsView().reset(false /* animate */);
- activity.getStateManager().goToState(OVERVIEW, false);
+ fromState = animateActivity ? BACKGROUND_APP : OVERVIEW;
+ activity.getStateManager().goToState(fromState, false);
// Optimization, hide the all apps view to prevent layout while initializing
activity.getAppsView().getContentView().setVisibility(View.GONE);
+
+ AccessibilityManagerCompat.sendEventToTest(
+ activity, TestProtocol.SWITCHED_TO_STATE_MESSAGE);
+ } else {
+ fromState = startState;
}
return new AnimationFactory() {
@Override
public void createActivityController(long transitionLength,
@InteractionType int interactionType) {
- createActivityControllerInternal(activity, activityVisible, startState,
+ createActivityControllerInternal(activity, activityVisible, fromState,
transitionLength, interactionType, callback);
}
@@ -243,7 +269,7 @@
}
private void createActivityControllerInternal(Launcher activity, boolean wasVisible,
- LauncherState startState, long transitionLength,
+ LauncherState fromState, long transitionLength,
@InteractionType int interactionType,
Consumer<AnimatorPlaybackController> callback) {
LauncherState endState = interactionType == INTERACTION_QUICK_SCRUB
@@ -252,53 +278,60 @@
DeviceProfile dp = activity.getDeviceProfile();
long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
callback.accept(activity.getStateManager()
- .createAnimationToNewWorkspace(startState, endState, accuracy));
+ .createAnimationToNewWorkspace(fromState, endState, accuracy));
+ return;
+ }
+ if (fromState == endState) {
return;
}
AnimatorSet anim = new AnimatorSet();
-
if (!activity.getDeviceProfile().isVerticalBarLayout()) {
AllAppsTransitionController controller = activity.getAllAppsController();
- float scrollRange = Math.max(controller.getShiftRange(), 1);
- float progressDelta = (transitionLength / scrollRange);
-
- float endProgress = endState.getVerticalProgress(activity);
- float startProgress = endProgress + progressDelta;
- ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(
- controller, ALL_APPS_PROGRESS, startProgress, endProgress);
+ ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(controller, ALL_APPS_PROGRESS,
+ fromState.getVerticalProgress(activity),
+ endState.getVerticalProgress(activity));
shiftAnim.setInterpolator(LINEAR);
anim.play(shiftAnim);
-
- // Since we are changing the start position of the UI, reapply the state, at the end
- anim.addListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationSuccess(Animator animator) {
- activity.getStateManager().reapplyState();
- }
- });
}
if (interactionType == INTERACTION_NORMAL) {
- playScaleDownAnim(anim, activity);
+ playScaleDownAnim(anim, activity, endState);
}
anim.setDuration(transitionLength * 2);
activity.getStateManager().setCurrentAnimation(anim);
- callback.accept(AnimatorPlaybackController.wrap(anim, transitionLength * 2));
+ AnimatorPlaybackController controller =
+ AnimatorPlaybackController.wrap(anim, transitionLength * 2);
+
+ // Since we are changing the start position of the UI, reapply the state, at the end
+ controller.setEndAction(() ->
+ activity.getStateManager().goToState(
+ controller.getProgressFraction() > 0.5 ? endState : fromState, false));
+ callback.accept(controller);
}
/**
* Scale down recents from the center task being full screen to being in overview.
*/
- private void playScaleDownAnim(AnimatorSet anim, Launcher launcher) {
+ private void playScaleDownAnim(AnimatorSet anim, Launcher launcher,
+ LauncherState endState) {
RecentsView recentsView = launcher.getOverviewPanel();
TaskView v = recentsView.getTaskViewAt(recentsView.getCurrentPage());
if (v == null) {
return;
}
+
+ // Setup the clip animation helper source/target rects in the final transformed state
+ // of the recents view (a scale may be applied prior to this animation starting to
+ // line up the side pages during swipe up)
+ float prevRvScale = recentsView.getScaleX();
+ float targetRvScale = endState.getOverviewScaleAndTranslationYFactor(launcher)[0];
+ SCALE_PROPERTY.set(recentsView, targetRvScale);
ClipAnimationHelper clipHelper = new ClipAnimationHelper();
clipHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(), null);
+ SCALE_PROPERTY.set(recentsView, prevRvScale);
+
if (!clipHelper.getSourceRect().isEmpty() && !clipHelper.getTargetRect().isEmpty()) {
float fromScale = clipHelper.getSourceRect().width()
/ clipHelper.getTargetRect().width();
@@ -382,12 +415,11 @@
}
@Override
- public LongSwipeHelper getLongSwipeController(Launcher activity,
- RemoteAnimationTargetSet targetSet) {
+ public LongSwipeHelper getLongSwipeController(Launcher activity, int runningTaskId) {
if (activity.getDeviceProfile().isVerticalBarLayout()) {
return null;
}
- return new LongSwipeHelper(activity, targetSet);
+ return new LongSwipeHelper(activity, runningTaskId);
}
@Override
@@ -414,14 +446,14 @@
@Override
public void onQuickInteractionStart(RecentsActivity activity, RunningTaskInfo taskInfo,
- boolean activityVisible) {
+ boolean activityVisible, TouchInteractionLog touchInteractionLog) {
QuickScrubController controller = activity.<RecentsView>getOverviewPanel()
.getQuickScrubController();
// TODO: match user is as well
boolean startingFromHome = !activityVisible &&
(taskInfo == null || Objects.equals(taskInfo.topActivity, mHomeComponent));
- controller.onQuickScrubStart(startingFromHome, this);
+ controller.onQuickScrubStart(startingFromHome, this, touchInteractionLog);
if (activityVisible) {
mUiHandler.postDelayed(controller::onFinishedTransitionToQuickScrub,
OVERVIEW_TRANSITION_MS);
@@ -464,7 +496,7 @@
@Override
public AnimationFactory prepareRecentsUI(RecentsActivity activity, boolean activityVisible,
- Consumer<AnimatorPlaybackController> callback) {
+ boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
if (activityVisible) {
return (transitionLength, interactionType) -> { };
}
@@ -515,6 +547,9 @@
@Override
public void finish() { }
+
+ @Override
+ public void update(boolean shouldFinish, boolean isLongSwipe, RectF currentRect) { }
};
}
@@ -569,8 +604,7 @@
}
@Override
- public LongSwipeHelper getLongSwipeController(RecentsActivity activity,
- RemoteAnimationTargetSet targetSet) {
+ public LongSwipeHelper getLongSwipeController(RecentsActivity activity, int runningTaskId) {
return null;
}
@@ -592,6 +626,8 @@
void setHandler(WindowTransformSwipeHandler handler);
void finish();
+
+ void update(boolean shouldFinish, boolean isLongSwipe, RectF currentRect);
}
interface ActivityInitListener {
diff --git a/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java
index 8e83bd0..5996df7 100644
--- a/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java
@@ -49,8 +49,8 @@
}
@Override
- public void updateTouchTracking(int interactionType) {
- mTarget.updateTouchTracking(interactionType);
+ public void onQuickScrubStart() {
+ mTarget.onQuickScrubStart();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/LongSwipeHelper.java b/quickstep/src/com/android/quickstep/LongSwipeHelper.java
index 6b66ec8..16214dd 100644
--- a/quickstep/src/com/android/quickstep/LongSwipeHelper.java
+++ b/quickstep/src/com/android/quickstep/LongSwipeHelper.java
@@ -26,7 +26,6 @@
import android.view.animation.Interpolator;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -41,7 +40,6 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.FlingBlockCheck;
-import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -56,15 +54,15 @@
Math.min(1 / MIN_PROGRESS_TO_ALL_APPS, 1 / (1 - MIN_PROGRESS_TO_ALL_APPS));
private final Launcher mLauncher;
- private final RemoteAnimationTargetSet mTargetSet;
+ private final int mRunningTaskId;
private float mMaxSwipeDistance = 1;
private AnimatorPlaybackController mAnimator;
private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
- LongSwipeHelper(Launcher launcher, RemoteAnimationTargetSet targetSet) {
+ LongSwipeHelper(Launcher launcher, int runningTaskId) {
mLauncher = launcher;
- mTargetSet = targetSet;
+ mRunningTaskId = runningTaskId;
init();
}
@@ -151,10 +149,16 @@
}
private void onSwipeAnimationComplete(boolean toAllApps, boolean isFling, Runnable callback) {
+ RecentsView rv = mLauncher.getOverviewPanel();
+ if (!toAllApps) {
+ rv.setIgnoreResetTask(mRunningTaskId);
+ }
+
mLauncher.getStateManager().goToState(toAllApps ? ALL_APPS : OVERVIEW, false);
if (!toAllApps) {
DiscoveryBounce.showForOverviewIfNeeded(mLauncher);
- mLauncher.<RecentsView>getOverviewPanel().setSwipeDownShouldLaunchApp(true);
+ rv.animateUpRunningTaskIconScale();
+ rv.setSwipeDownShouldLaunchApp(true);
}
mLauncher.getUserEventDispatcher().logStateChangeAction(
@@ -165,12 +169,4 @@
callback.run();
}
-
- public float getTargetAlpha(RemoteAnimationTargetCompat app, Float expectedAlpha) {
- if (!(app.isNotInRecents
- || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME)) {
- return 0;
- }
- return expectedAlpha;
- }
}
diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java
index f73be6c..8a598a3 100644
--- a/quickstep/src/com/android/quickstep/MotionEventQueue.java
+++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java
@@ -146,7 +146,7 @@
if (event.getActionMasked() == ACTION_VIRTUAL) {
switch (event.getAction()) {
case ACTION_QUICK_SCRUB_START:
- mConsumer.updateTouchTracking(INTERACTION_QUICK_SCRUB);
+ mConsumer.onQuickScrubStart();
break;
case ACTION_QUICK_SCRUB_PROGRESS:
mConsumer.onQuickScrubProgress(event.getX());
@@ -162,7 +162,7 @@
break;
case ACTION_SHOW_OVERVIEW_FROM_ALT_TAB:
mConsumer.onShowOverviewFromAltTab();
- mConsumer.updateTouchTracking(INTERACTION_QUICK_SCRUB);
+ mConsumer.onQuickScrubStart();
break;
case ACTION_QUICK_STEP:
mConsumer.onQuickStep(event);
diff --git a/quickstep/src/com/android/quickstep/MultiStateCallback.java b/quickstep/src/com/android/quickstep/MultiStateCallback.java
index bda3d06..98d723f 100644
--- a/quickstep/src/com/android/quickstep/MultiStateCallback.java
+++ b/quickstep/src/com/android/quickstep/MultiStateCallback.java
@@ -17,20 +17,23 @@
import android.util.SparseArray;
+import com.android.launcher3.Utilities.Consumer;
+
/**
* Utility class to help manage multiple callbacks based on different states.
*/
public class MultiStateCallback {
private final SparseArray<Runnable> mCallbacks = new SparseArray<>();
+ private final SparseArray<Consumer<Boolean>> mStateChangeHandlers = new SparseArray<>();
private int mState = 0;
/**
* Adds the provided state flags to the global state and executes any callbacks as a result.
- * @param stateFlag
*/
public void setState(int stateFlag) {
+ int oldState = mState;
mState = mState | stateFlag;
int count = mCallbacks.size();
@@ -46,6 +49,30 @@
}
}
}
+ notifyStateChangeHandlers(oldState);
+ }
+
+ /**
+ * Adds the provided state flags to the global state and executes any change handlers
+ * as a result.
+ */
+ public void clearState(int stateFlag) {
+ int oldState = mState;
+ mState = mState & ~stateFlag;
+ notifyStateChangeHandlers(oldState);
+ }
+
+ private void notifyStateChangeHandlers(int oldState) {
+ int count = mStateChangeHandlers.size();
+ for (int i = 0; i < count; i++) {
+ int state = mStateChangeHandlers.keyAt(i);
+ boolean wasOn = (state & oldState) == state;
+ boolean isOn = (state & mState) == state;
+
+ if (wasOn != isOn) {
+ mStateChangeHandlers.valueAt(i).accept(isOn);
+ }
+ }
}
/**
@@ -56,6 +83,13 @@
mCallbacks.put(stateMask, callback);
}
+ /**
+ * Sets the handler to be called when the provided states are enabled or disabled.
+ */
+ public void addChangeHandler(int stateMask, Consumer<Boolean> handler) {
+ mStateChangeHandlers.put(stateMask, handler);
+ }
+
public int getState() {
return mState;
}
diff --git a/quickstep/src/com/android/quickstep/NormalizedIconLoader.java b/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
index f875bb7..bd6204a 100644
--- a/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
+++ b/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
@@ -28,9 +28,9 @@
import android.util.SparseArray;
import com.android.launcher3.FastBitmapDrawable;
-import com.android.launcher3.graphics.BitmapInfo;
+import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.graphics.DrawableFactory;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.systemui.shared.recents.model.IconLoader;
import com.android.systemui.shared.recents.model.TaskKeyLruCache;
@@ -42,12 +42,14 @@
private final SparseArray<BitmapInfo> mDefaultIcons = new SparseArray<>();
private final DrawableFactory mDrawableFactory;
- private LauncherIcons mLauncherIcons;
+ private final boolean mDisableColorExtraction;
public NormalizedIconLoader(Context context, TaskKeyLruCache<Drawable> iconCache,
- LruCache<ComponentName, ActivityInfo> activityInfoCache) {
+ LruCache<ComponentName, ActivityInfo> activityInfoCache,
+ boolean disableColorExtraction) {
super(context, iconCache, activityInfoCache);
- mDrawableFactory = DrawableFactory.get(context);
+ mDrawableFactory = DrawableFactory.INSTANCE.get(context);
+ mDisableColorExtraction = disableColorExtraction;
}
@Override
@@ -70,16 +72,18 @@
false));
}
- private synchronized BitmapInfo getBitmapInfo(Drawable drawable, int userId,
+ private BitmapInfo getBitmapInfo(Drawable drawable, int userId,
int primaryColor, boolean isInstantApp) {
- if (mLauncherIcons == null) {
- mLauncherIcons = LauncherIcons.obtain(mContext);
- }
+ try (LauncherIcons la = LauncherIcons.obtain(mContext)) {
+ if (mDisableColorExtraction) {
+ la.disableColorExtraction();
+ }
+ la.setWrapperBackgroundColor(primaryColor);
- mLauncherIcons.setWrapperBackgroundColor(primaryColor);
- // User version code O, so that the icon is always wrapped in an adaptive icon container.
- return mLauncherIcons.createBadgedIconBitmap(drawable, UserHandle.of(userId),
- Build.VERSION_CODES.O, isInstantApp);
+ // User version code O, so that the icon is always wrapped in an adaptive icon container
+ return la.createBadgedIconBitmap(drawable, UserHandle.of(userId),
+ Build.VERSION_CODES.O, isInstantApp);
+ }
}
@Override
@@ -90,6 +94,6 @@
userId,
desc.getPrimaryColor(),
activityInfo.applicationInfo.isInstantApp());
- return mDrawableFactory.newIcon(bitmapInfo, activityInfo);
+ return mDrawableFactory.newIcon(mContext, bitmapInfo, activityInfo);
}
}
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 0e811f7..b11260e 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -52,6 +52,7 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.AssistDataReceiver;
import com.android.systemui.shared.system.BackgroundExecutor;
+import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.NavigationBarCompat;
import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
@@ -79,6 +80,8 @@
private final Choreographer mBackgroundThreadChoreographer;
private final OverviewCallbacks mOverviewCallbacks;
private final TaskOverlayFactory mTaskOverlayFactory;
+ private final TouchInteractionLog mTouchInteractionLog;
+ private final InputConsumerController mInputConsumer;
private final boolean mIsDeferredDownTarget;
private final PointF mDownPos = new PointF();
@@ -100,7 +103,8 @@
RecentsModel recentsModel, Intent homeIntent, ActivityControlHelper activityControl,
MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer,
@HitTarget int downHitTarget, OverviewCallbacks overviewCallbacks,
- TaskOverlayFactory taskOverlayFactory, VelocityTracker velocityTracker) {
+ TaskOverlayFactory taskOverlayFactory, InputConsumerController inputConsumer,
+ VelocityTracker velocityTracker, TouchInteractionLog touchInteractionLog) {
super(base);
mRunningTask = runningTaskInfo;
@@ -113,6 +117,9 @@
mIsDeferredDownTarget = activityControl.deferStartingActivity(downHitTarget);
mOverviewCallbacks = overviewCallbacks;
mTaskOverlayFactory = taskOverlayFactory;
+ mTouchInteractionLog = touchInteractionLog;
+ mTouchInteractionLog.setTouchConsumer(this);
+ mInputConsumer = inputConsumer;
}
@Override
@@ -125,6 +132,7 @@
if (mVelocityTracker == null) {
return;
}
+ mTouchInteractionLog.addMotionEvent(ev);
switch (ev.getActionMasked()) {
case ACTION_DOWN: {
TraceHelper.beginSection("TouchInt");
@@ -215,13 +223,16 @@
}
private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
+ mTouchInteractionLog.startRecentsAnimation();
+
// Create the shared handler
RecentsAnimationState animationState = new RecentsAnimationState();
final WindowTransformSwipeHandler handler = new WindowTransformSwipeHandler(
- animationState.id, mRunningTask, this, touchTimeMs, mActivityControlHelper);
+ animationState.id, mRunningTask, this, touchTimeMs, mActivityControlHelper,
+ mInputConsumer, mTouchInteractionLog);
// Preload the plan
- mRecentsModel.loadTasks(mRunningTask.id, null);
+ mRecentsModel.getTasks(null);
mInteractionHandler = handler;
handler.setGestureEndCallback(mEventQueue::reset);
@@ -315,7 +326,13 @@
}
@Override
- public void updateTouchTracking(int interactionType) {
+ public Choreographer getIntrimChoreographer(MotionEventQueue queue) {
+ mEventQueue = queue;
+ return mBackgroundThreadChoreographer;
+ }
+
+ @Override
+ public void onQuickScrubStart() {
if (!mPassedInitialSlop && mIsDeferredDownTarget && mInteractionHandler == null) {
// If we deferred starting the window animation on touch down, then
// start tracking now
@@ -323,20 +340,16 @@
mPassedInitialSlop = true;
}
+ mTouchInteractionLog.startQuickScrub();
if (mInteractionHandler != null) {
- mInteractionHandler.updateInteractionType(interactionType);
+ mInteractionHandler.onQuickScrubStart();
}
notifyGestureStarted();
}
@Override
- public Choreographer getIntrimChoreographer(MotionEventQueue queue) {
- mEventQueue = queue;
- return mBackgroundThreadChoreographer;
- }
-
- @Override
public void onQuickScrubEnd() {
+ mTouchInteractionLog.endQuickScrub("onQuickScrubEnd");
if (mInteractionHandler != null) {
mInteractionHandler.onQuickScrubEnd();
}
@@ -344,6 +357,7 @@
@Override
public void onQuickScrubProgress(float progress) {
+ mTouchInteractionLog.setQuickScrubProgress(progress);
if (mInteractionHandler != null) {
mInteractionHandler.onQuickScrubProgress(progress);
}
@@ -351,6 +365,7 @@
@Override
public void onQuickStep(MotionEvent ev) {
+ mTouchInteractionLog.startQuickStep();
if (mIsDeferredDownTarget) {
// Deferred gesture, start the animation and gesture tracking once we pass the actual
// touch slop
diff --git a/quickstep/src/com/android/quickstep/OverviewCallbacks.java b/quickstep/src/com/android/quickstep/OverviewCallbacks.java
index ac4a40b..ef9c5c0 100644
--- a/quickstep/src/com/android/quickstep/OverviewCallbacks.java
+++ b/quickstep/src/com/android/quickstep/OverviewCallbacks.java
@@ -18,20 +18,20 @@
import android.content.Context;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.ResourceBasedOverride;
/**
* Callbacks related to overview/quicksteps.
*/
-public class OverviewCallbacks {
+public class OverviewCallbacks implements ResourceBasedOverride {
private static OverviewCallbacks sInstance;
public static OverviewCallbacks get(Context context) {
Preconditions.assertUIThread();
if (sInstance == null) {
- sInstance = Utilities.getOverrideObject(OverviewCallbacks.class,
+ sInstance = Overrides.getObject(OverviewCallbacks.class,
context.getApplicationContext(), R.string.overview_callbacks_class);
}
return sInstance;
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index eff94fc..f8f0905 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -49,7 +49,6 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
-import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.logging.UserEventDispatcher;
@@ -112,7 +111,7 @@
mContext = context;
mAM = ActivityManagerWrapper.getInstance();
mMainThreadExecutor = new MainThreadExecutor();
- mRecentsModel = RecentsModel.getInstance(mContext);
+ mRecentsModel = RecentsModel.INSTANCE.get(mContext);
Intent myHomeIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
@@ -197,14 +196,8 @@
}
public void onTip(int actionType, int viewType) {
- mMainThreadExecutor.execute(new Runnable() {
- @Override
- public void run() {
- UserEventDispatcher.newInstance(mContext,
- new InvariantDeviceProfile(mContext).getDeviceProfile(mContext))
- .logActionTip(actionType, viewType);
- }
- });
+ mMainThreadExecutor.execute(() ->
+ UserEventDispatcher.newInstance(mContext).logActionTip(actionType, viewType));
}
public ActivityControlHelper getActivityControlHelper() {
@@ -234,10 +227,10 @@
public RecentsActivityCommand() {
mHelper = getActivityControlHelper();
mCreateTime = SystemClock.elapsedRealtime();
- mRunningTaskId = mAM.getRunningTask().id;
+ mRunningTaskId = RecentsModel.getRunningTaskId();
// Preload the plan
- mRecentsModel.loadTasks(mRunningTaskId, null);
+ mRecentsModel.getTasks(null);
}
@Override
@@ -276,7 +269,7 @@
activity.<RecentsView>getOverviewPanel().setCurrentTask(mRunningTaskId);
AbstractFloatingView.closeAllOpenViews(activity, wasVisible);
AnimationFactory factory = mHelper.prepareRecentsUI(activity, wasVisible,
- (controller) -> {
+ false /* animate activity */, (controller) -> {
controller.dispatchOnStart();
ValueAnimator anim = controller.getAnimationPlayer()
.setDuration(RECENTS_LAUNCH_DURATION);
@@ -284,12 +277,9 @@
anim.start();
});
factory.onRemoteAnimationReceived(null);
- if (wasVisible) {
- factory.createActivityController(RECENTS_LAUNCH_DURATION, INTERACTION_NORMAL);
- }
+ factory.createActivityController(RECENTS_LAUNCH_DURATION, INTERACTION_NORMAL);
mActivity = activity;
mRecentsView = mActivity.getOverviewPanel();
- mRecentsView.setRunningTaskIconScaledDown(true /* isScaledDown */, false /* animate */);
if (!mUserEventLogged) {
activity.getUserEventDispatcher().logActionCommand(Action.Command.RECENTS_BUTTON,
mHelper.getContainerType(), ContainerType.TASKSWITCHER);
@@ -307,13 +297,15 @@
if (mListener != null) {
mListener.unregister();
}
+ if (mRecentsView != null) {
+ mRecentsView.setRunningTaskIconScaledDown(true);
+ }
AnimatorSet anim = new AnimatorSet();
anim.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
if (mRecentsView != null) {
- mRecentsView.setRunningTaskIconScaledDown(false /* isScaledDown */,
- true /* animate */);
+ mRecentsView.animateUpRunningTaskIconScale();
}
}
});
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index 922a7ff..27f1399 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -15,30 +15,25 @@
*/
package com.android.quickstep;
+import static com.android.quickstep.SwipeUpSetting.newSwipeUpSettingsObserver;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_QUICK_SCRUB;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
-import static com.android.systemui.shared.system.SettingsCompat.SWIPE_UP_SETTING_NAME;
-import android.content.ContentResolver;
import android.content.Context;
-import android.content.res.Resources;
-import android.database.ContentObserver;
import android.os.Handler;
-import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
-import android.provider.Settings;
-import android.support.annotation.WorkerThread;
import android.util.Log;
-import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.DiscoveryBounce;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SecureSettingsObserver;
import com.android.launcher3.util.UiThreadHelper;
import com.android.systemui.shared.recents.ISystemUiProxy;
-import java.util.concurrent.ExecutionException;
+import androidx.annotation.WorkerThread;
/**
* Sets overview interaction flags, such as:
@@ -54,40 +49,23 @@
private static final String TAG = "OverviewFlags";
private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once";
- private static final String SWIPE_UP_SETTING_AVAILABLE_RES_NAME =
- "config_swipe_up_gesture_setting_available";
- private static final String SWIPE_UP_ENABLED_DEFAULT_RES_NAME =
- "config_swipe_up_gesture_default";
// We do not need any synchronization for this variable as its only written on UI thread.
- private static OverviewInteractionState INSTANCE;
-
- public static OverviewInteractionState getInstance(final Context context) {
- if (INSTANCE == null) {
- if (Looper.myLooper() == Looper.getMainLooper()) {
- INSTANCE = new OverviewInteractionState(context.getApplicationContext());
- } else {
- try {
- return new MainThreadExecutor().submit(
- () -> OverviewInteractionState.getInstance(context)).get();
- } catch (InterruptedException|ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
- }
- return INSTANCE;
- }
+ public static final MainThreadInitializedObject<OverviewInteractionState> INSTANCE =
+ new MainThreadInitializedObject<>((c) -> new OverviewInteractionState(c));
private static final int MSG_SET_PROXY = 200;
private static final int MSG_SET_BACK_BUTTON_ALPHA = 201;
private static final int MSG_SET_SWIPE_UP_ENABLED = 202;
- private final SwipeUpGestureEnabledSettingObserver mSwipeUpSettingObserver;
+ private final SecureSettingsObserver mSwipeUpSettingObserver;
private final Context mContext;
private final Handler mUiHandler;
private final Handler mBgHandler;
+ private boolean mSwipeGestureInitializing = false;
+
// These are updated on the background thread
private ISystemUiProxy mISystemUiProxy;
private boolean mSwipeUpEnabled = true;
@@ -104,13 +82,15 @@
mUiHandler = new Handler(this::handleUiMessage);
mBgHandler = new Handler(UiThreadHelper.getBackgroundLooper(), this::handleBgMessage);
- if (getSystemBooleanRes(SWIPE_UP_SETTING_AVAILABLE_RES_NAME)) {
- mSwipeUpSettingObserver = new SwipeUpGestureEnabledSettingObserver(mUiHandler,
- context.getContentResolver());
+ if (SwipeUpSetting.isSwipeUpSettingAvailable()) {
+ mSwipeUpSettingObserver =
+ newSwipeUpSettingsObserver(context, this::notifySwipeUpSettingChanged);
mSwipeUpSettingObserver.register();
+ mSwipeUpEnabled = mSwipeUpSettingObserver.getValue();
+ resetHomeBounceSeenOnQuickstepEnabledFirstTime();
} else {
mSwipeUpSettingObserver = null;
- mSwipeUpEnabled = getSystemBooleanRes(SWIPE_UP_ENABLED_DEFAULT_RES_NAME);
+ mSwipeUpEnabled = SwipeUpSetting.isSwipeUpEnabledDefaultValue();
}
}
@@ -197,47 +177,19 @@
}
}
- private class SwipeUpGestureEnabledSettingObserver extends ContentObserver {
- private Handler mHandler;
- private ContentResolver mResolver;
- private final int defaultValue;
-
- SwipeUpGestureEnabledSettingObserver(Handler handler, ContentResolver resolver) {
- super(handler);
- mHandler = handler;
- mResolver = resolver;
- defaultValue = getSystemBooleanRes(SWIPE_UP_ENABLED_DEFAULT_RES_NAME) ? 1 : 0;
- }
-
- public void register() {
- mResolver.registerContentObserver(Settings.Secure.getUriFor(SWIPE_UP_SETTING_NAME),
- false, this);
- mSwipeUpEnabled = getValue();
- resetHomeBounceSeenOnQuickstepEnabledFirstTime();
- }
-
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
- mHandler.removeMessages(MSG_SET_SWIPE_UP_ENABLED);
- mHandler.obtainMessage(MSG_SET_SWIPE_UP_ENABLED, getValue() ? 1 : 0, 0).sendToTarget();
- }
-
- private boolean getValue() {
- return Settings.Secure.getInt(mResolver, SWIPE_UP_SETTING_NAME, defaultValue) == 1;
- }
+ @WorkerThread
+ public void setSwipeGestureInitializing(boolean swipeGestureInitializing) {
+ mSwipeGestureInitializing = swipeGestureInitializing;
}
- private boolean getSystemBooleanRes(String resName) {
- Resources res = Resources.getSystem();
- int resId = res.getIdentifier(resName, "bool", "android");
+ public boolean swipeGestureInitializing() {
+ return mSwipeGestureInitializing;
+ }
- if (resId != 0) {
- return res.getBoolean(resId);
- } else {
- Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
- return false;
- }
+ public void notifySwipeUpSettingChanged(boolean swipeUpEnabled) {
+ mUiHandler.removeMessages(MSG_SET_SWIPE_UP_ENABLED);
+ mUiHandler.obtainMessage(MSG_SET_SWIPE_UP_ENABLED, swipeUpEnabled ? 1 : 0, 0).
+ sendToTarget();
}
private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java
index cbc7a67..c44ccd3 100644
--- a/quickstep/src/com/android/quickstep/QuickScrubController.java
+++ b/quickstep/src/com/android/quickstep/QuickScrubController.java
@@ -16,8 +16,18 @@
package com.android.quickstep;
+import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.util.FloatProperty;
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.animation.Interpolator;
@@ -37,8 +47,10 @@
* The behavior is to evenly divide the progress into sections, each of which scrolls one page.
* The first and last section set an alarm to auto-advance backwards or forwards, respectively.
*/
+@TargetApi(Build.VERSION_CODES.P)
public class QuickScrubController implements OnAlarmListener {
+ public static final int QUICK_SWITCH_FROM_APP_START_DURATION = 0;
public static final int QUICK_SCRUB_FROM_APP_START_DURATION = 240;
public static final int QUICK_SCRUB_FROM_HOME_START_DURATION = 200;
// We want the translation y to finish faster than the rest of the animation.
@@ -52,6 +64,19 @@
0.05f, 0.20f, 0.35f, 0.50f, 0.65f, 0.80f, 0.95f
};
+ private static final FloatProperty<QuickScrubController> PROGRESS
+ = new FloatProperty<QuickScrubController>("progress") {
+ @Override
+ public void setValue(QuickScrubController quickScrubController, float progress) {
+ quickScrubController.onQuickScrubProgress(progress);
+ }
+
+ @Override
+ public Float get(QuickScrubController quickScrubController) {
+ return quickScrubController.mEndProgress;
+ }
+ };
+
private static final String TAG = "QuickScrubController";
private static final boolean ENABLE_AUTO_ADVANCE = true;
private static final long AUTO_ADVANCE_DELAY = 500;
@@ -67,8 +92,17 @@
private int mQuickScrubSection;
private boolean mStartedFromHome;
private boolean mFinishedTransitionToQuickScrub;
+ private int mLaunchingTaskId;
private Runnable mOnFinishedTransitionToQuickScrubRunnable;
private ActivityControlHelper mActivityControlHelper;
+ private TouchInteractionLog mTouchInteractionLog;
+
+ private boolean mIsQuickSwitch;
+ private float mStartProgress;
+ private float mEndProgress;
+ private float mPrevProgressDelta;
+ private float mPrevPrevProgressDelta;
+ private boolean mShouldSwitchToNext;
public QuickScrubController(BaseActivity activity, RecentsView recentsView) {
mActivity = activity;
@@ -79,13 +113,26 @@
}
}
- public void onQuickScrubStart(boolean startingFromHome, ActivityControlHelper controlHelper) {
+ public void onQuickScrubStart(boolean startingFromHome, ActivityControlHelper controlHelper,
+ TouchInteractionLog touchInteractionLog) {
prepareQuickScrub(TAG);
mInQuickScrub = true;
mStartedFromHome = startingFromHome;
mQuickScrubSection = 0;
mFinishedTransitionToQuickScrub = false;
mActivityControlHelper = controlHelper;
+ mTouchInteractionLog = touchInteractionLog;
+
+ if (mIsQuickSwitch) {
+ mShouldSwitchToNext = true;
+ mPrevProgressDelta = 0;
+ if (mRecentsView.getTaskViewCount() > 0) {
+ mRecentsView.getTaskViewAt(0).setFullscreen(true);
+ }
+ if (mRecentsView.getTaskViewCount() > 1) {
+ mRecentsView.getTaskViewAt(1).setFullscreen(true);
+ }
+ }
snapToNextTaskIfAvailable();
mActivity.getUserEventDispatcher().resetActionDurationMillis();
@@ -93,15 +140,16 @@
public void onQuickScrubEnd() {
mInQuickScrub = false;
- if (ENABLE_AUTO_ADVANCE) {
- mAutoAdvanceAlarm.cancelAlarm();
- }
- int page = mRecentsView.getNextPage();
+
Runnable launchTaskRunnable = () -> {
+ int page = mRecentsView.getPageNearestToCenterOfScreen();
TaskView taskView = mRecentsView.getTaskViewAt(page);
if (taskView != null) {
mWaitingForTaskLaunch = true;
+ mTouchInteractionLog.launchTaskStart();
+ mLaunchingTaskId = taskView.getTask().key.id;
taskView.launchTask(true, (result) -> {
+ mTouchInteractionLog.launchTaskEnd(result);
if (!result) {
taskView.notifyTaskLaunchFailed(TAG);
breakOutOfQuickScrub();
@@ -111,12 +159,49 @@
TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key));
}
mWaitingForTaskLaunch = false;
+ if (mIsQuickSwitch) {
+ mIsQuickSwitch = false;
+ if (mRecentsView.getTaskViewCount() > 0) {
+ mRecentsView.getTaskViewAt(0).setFullscreen(false);
+ }
+ if (mRecentsView.getTaskViewCount() > 1) {
+ mRecentsView.getTaskViewAt(1).setFullscreen(false);
+ }
+ }
+
}, taskView.getHandler());
} else {
breakOutOfQuickScrub();
}
mActivityControlHelper = null;
};
+
+ if (mIsQuickSwitch) {
+ float progressVelocity = mPrevPrevProgressDelta / SINGLE_FRAME_MS;
+ // Move to the next frame immediately, then start the animation from the
+ // following frame since it starts a frame later.
+ float singleFrameProgress = progressVelocity * SINGLE_FRAME_MS;
+ float fromProgress = mEndProgress + singleFrameProgress;
+ onQuickScrubProgress(fromProgress);
+ fromProgress += singleFrameProgress;
+ float toProgress = mShouldSwitchToNext ? 1 : 0;
+ int duration = (int) Math.abs((toProgress - fromProgress) / progressVelocity);
+ duration = Utilities.boundToRange(duration, 80, 300);
+ Animator anim = ObjectAnimator.ofFloat(this, PROGRESS, fromProgress, toProgress);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ launchTaskRunnable.run();
+ }
+ });
+ anim.setDuration(duration).start();
+ return;
+ }
+
+ if (ENABLE_AUTO_ADVANCE) {
+ mAutoAdvanceAlarm.cancelAlarm();
+ }
+ int page = mRecentsView.getNextPage();
int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
* QUICKSCRUB_END_SNAP_DURATION_PER_PAGE;
if (mRecentsView.getChildCount() > 0 && mRecentsView.snapToPage(page, snapDuration)) {
@@ -141,21 +226,31 @@
mActivityControlHelper = null;
mOnFinishedTransitionToQuickScrubRunnable = null;
mRecentsView.setNextPageSwitchRunnable(null);
+ mLaunchingTaskId = 0;
+ }
+
+ public boolean prepareQuickScrub(String tag) {
+ return prepareQuickScrub(tag, mIsQuickSwitch);
}
/**
* Initializes the UI for quick scrub, returns true if success.
*/
- public boolean prepareQuickScrub(String tag) {
+ public boolean prepareQuickScrub(String tag, boolean isQuickSwitch) {
if (mWaitingForTaskLaunch || mInQuickScrub) {
Log.d(tag, "Waiting for last scrub to finish, will skip this interaction");
return false;
}
mOnFinishedTransitionToQuickScrubRunnable = null;
mRecentsView.setNextPageSwitchRunnable(null);
+ mIsQuickSwitch = isQuickSwitch;
return true;
}
+ public boolean isQuickSwitch() {
+ return mIsQuickSwitch;
+ }
+
public boolean isWaitingForTaskLaunch() {
return mWaitingForTaskLaunch;
}
@@ -171,6 +266,40 @@
}
public void onQuickScrubProgress(float progress) {
+ if (mIsQuickSwitch) {
+ TaskView currentPage = mRecentsView.getTaskViewAt(0);
+ TaskView nextPage = mRecentsView.getTaskViewAt(1);
+ if (currentPage == null || nextPage == null) {
+ return;
+ }
+ if (!mFinishedTransitionToQuickScrub) {
+ mStartProgress = mEndProgress = progress;
+ } else {
+ float progressDelta = progress - mEndProgress;
+ mEndProgress = progress;
+ progress = Utilities.boundToRange(progress, mStartProgress, 1);
+ progress = Utilities.mapToRange(progress, mStartProgress, 1, 0, 1, LINEAR);
+ if (mInQuickScrub) {
+ mShouldSwitchToNext = mPrevProgressDelta > 0.007f || progressDelta > 0.007f
+ || progress >= 0.5f;
+ }
+ mPrevPrevProgressDelta = mPrevProgressDelta;
+ mPrevProgressDelta = progressDelta;
+ float scrollDiff = nextPage.getWidth() + mRecentsView.getPageSpacing();
+ int scrollDir = mRecentsView.isRtl() ? -1 : 1;
+ int linearScrollDiff = (int) (progress * scrollDiff * scrollDir);
+ float accelScrollDiff = ACCEL.getInterpolation(progress) * scrollDiff * scrollDir;
+ currentPage.setZoomScale(1 - DEACCEL_3.getInterpolation(progress)
+ * TaskView.EDGE_SCALE_DOWN_FACTOR);
+ currentPage.setTranslationX(linearScrollDiff + accelScrollDiff);
+ nextPage.setTranslationZ(1);
+ nextPage.setTranslationY(currentPage.getTranslationY());
+ int startScroll = mRecentsView.isRtl() ? mRecentsView.getMaxScrollX() : 0;
+ mRecentsView.setScrollX(startScroll + linearScrollDiff);
+ }
+ return;
+ }
+
int quickScrubSection = 0;
for (float threshold : QUICK_SCRUB_THRESHOLDS) {
if (progress < threshold) {
@@ -206,11 +335,28 @@
}
}
+ public void onTaskRemoved(int taskId) {
+ if (mLaunchingTaskId == taskId) {
+ // The task has been removed mid-launch, break out of quickscrub and return the user
+ // to where they were before (and notify the launch failed)
+ TaskView taskView = mRecentsView.getTaskView(taskId);
+ if (taskView != null) {
+ taskView.notifyTaskLaunchFailed(TAG);
+ }
+ breakOutOfQuickScrub();
+ }
+ }
+
public void snapToNextTaskIfAvailable() {
if (mInQuickScrub && mRecentsView.getChildCount() > 0) {
- int duration = mStartedFromHome ? QUICK_SCRUB_FROM_HOME_START_DURATION
- : QUICK_SCRUB_FROM_APP_START_DURATION;
- int pageToGoTo = mStartedFromHome ? 0 : mRecentsView.getNextPage() + 1;
+ int duration = mIsQuickSwitch
+ ? QUICK_SWITCH_FROM_APP_START_DURATION
+ : mStartedFromHome
+ ? QUICK_SCRUB_FROM_HOME_START_DURATION
+ : QUICK_SCRUB_FROM_APP_START_DURATION;
+ int pageToGoTo = mStartedFromHome || mIsQuickSwitch
+ ? 0
+ : mRecentsView.getNextPage() + 1;
goToPageWithHaptic(pageToGoTo, duration, true /* forceHaptic */,
QUICK_SCRUB_START_INTERPOLATOR);
}
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
new file mode 100644
index 0000000..fec38bf
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.Process;
+import android.util.SparseBooleanArray;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.BackgroundExecutor;
+import com.android.systemui.shared.system.KeyguardManagerCompat;
+import com.android.systemui.shared.system.RecentTaskInfoCompat;
+import com.android.systemui.shared.system.TaskDescriptionCompat;
+import com.android.systemui.shared.system.TaskStackChangeListener;
+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.
+ */
+public class RecentTasksList extends TaskStackChangeListener {
+
+ private final KeyguardManagerCompat mKeyguardManager;
+ private final MainThreadExecutor mMainThreadExecutor;
+ private final BackgroundExecutor mBgThreadExecutor;
+
+ // The list change id, increments as the task list changes in the system
+ private int mChangeId;
+ // The last change id when the list was last loaded completely, must be <= the list change id
+ private int mLastLoadedId;
+
+ ArrayList<Task> mTasks = new ArrayList<>();
+
+ public RecentTasksList(Context context) {
+ mMainThreadExecutor = new MainThreadExecutor();
+ mBgThreadExecutor = BackgroundExecutor.get();
+ mKeyguardManager = new KeyguardManagerCompat(context);
+ mChangeId = 1;
+ }
+
+ /**
+ * Asynchronously fetches the list of recent tasks.
+ *
+ * @param numTasks The maximum number of tasks to fetch
+ * @param loadKeysOnly Whether to load other associated task data, or just the key
+ * @param callback The callback to receive the list of recent tasks
+ * @return The change id of the current task list
+ */
+ public synchronized int getTasks(int numTasks, boolean loadKeysOnly,
+ Consumer<ArrayList<Task>> callback) {
+ final int requestLoadId = mChangeId;
+ final int numLoadTasks = numTasks > 0
+ ? numTasks
+ : Integer.MAX_VALUE;
+
+ if (mLastLoadedId == mChangeId) {
+ // The list is up to date, callback with the same list
+ mMainThreadExecutor.execute(() -> {
+ if (callback != null) {
+ callback.accept(mTasks);
+ }
+ });
+ }
+
+ // Kick off task loading in the background
+ mBgThreadExecutor.submit(() -> {
+ ArrayList<Task> tasks = loadTasksInBackground(numLoadTasks,
+ loadKeysOnly);
+
+ mMainThreadExecutor.execute(() -> {
+ mTasks = tasks;
+ mLastLoadedId = requestLoadId;
+
+ if (callback != null) {
+ callback.accept(tasks);
+ }
+ });
+ });
+
+ return requestLoadId;
+ }
+
+ /**
+ * @return Whether the provided {@param changeId} is the latest recent tasks list id.
+ */
+ public synchronized boolean isTaskListValid(int changeId) {
+ return mChangeId == changeId;
+ }
+
+ @Override
+ public synchronized void onTaskStackChanged() {
+ mChangeId++;
+ }
+
+ @Override
+ public synchronized void onActivityPinned(String packageName, int userId, int taskId,
+ int stackId) {
+ mChangeId++;
+ }
+
+ @Override
+ public synchronized void onActivityUnpinned() {
+ mChangeId++;
+ }
+
+ /**
+ * Loads and creates a list of all the recent tasks.
+ */
+ private ArrayList<Task> loadTasksInBackground(int numTasks,
+ boolean loadKeysOnly) {
+ int currentUserId = Process.myUserHandle().getIdentifier();
+ ArrayList<Task> allTasks = new ArrayList<>();
+ List<ActivityManager.RecentTaskInfo> rawTasks =
+ ActivityManagerWrapper.getInstance().getRecentTasks(numTasks, currentUserId);
+ // The raw tasks are given in most-recent to least-recent order, we need to reverse it
+ Collections.reverse(rawTasks);
+
+ SparseBooleanArray tmpLockedUsers = new SparseBooleanArray() {
+ @Override
+ public boolean get(int key) {
+ if (indexOfKey(key) < 0) {
+ // Fill the cached locked state as we fetch
+ put(key, mKeyguardManager.isDeviceLocked(key));
+ }
+ return super.get(key);
+ }
+ };
+
+ int taskCount = rawTasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ ActivityManager.RecentTaskInfo rawTask = rawTasks.get(i);
+ RecentTaskInfoCompat t = new RecentTaskInfoCompat(rawTask);
+ Task.TaskKey taskKey = new Task.TaskKey(rawTask);
+ Task task;
+ if (!loadKeysOnly) {
+ ActivityManager.TaskDescription rawTd = t.getTaskDescription();
+ TaskDescriptionCompat td = new TaskDescriptionCompat(rawTd);
+ boolean isLocked = tmpLockedUsers.get(t.getUserId());
+ task = new Task(taskKey, td.getPrimaryColor(), td.getBackgroundColor(),
+ t.supportsSplitScreenMultiWindow(), isLocked, rawTd, t.getTopActivity());
+ } else {
+ task = new Task(taskKey);
+ }
+ allTasks.add(task);
+ }
+
+ return allTasks;
+ }
+}
\ 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 1d7c066..ef735e1 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -42,7 +42,6 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAnimationRunner;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.badge.BadgeInfo;
@@ -131,21 +130,13 @@
}
private void initDeviceProfile() {
- // In case we are reusing IDP, create a copy so that we dont conflict with Launcher
+ DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
+
+ // In case we are reusing IDP, create a copy so that we don't conflict with Launcher
// activity.
- LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
- if (isInMultiWindowModeCompat()) {
- InvariantDeviceProfile idp = appState == null
- ? new InvariantDeviceProfile(this) : appState.getInvariantDeviceProfile();
- DeviceProfile dp = idp.getDeviceProfile(this);
- mDeviceProfile = mRecentsRootView == null ? dp.copy(this)
- : dp.getMultiWindowProfile(this, mRecentsRootView.getLastKnownSize());
- } else {
- // If we are reusing the Invariant device profile, make a copy.
- mDeviceProfile = appState == null
- ? new InvariantDeviceProfile(this).getDeviceProfile(this)
- : appState.getInvariantDeviceProfile().getDeviceProfile(this).copy(this);
- }
+ mDeviceProfile = (mRecentsRootView != null) && isInMultiWindowModeCompat()
+ ? dp.getMultiWindowProfile(this, mRecentsRootView.getLastKnownSize())
+ : dp.copy(this);
onDeviceProfileInitiated();
}
@@ -228,7 +219,6 @@
// onActivityStart callback.
mFallbackRecentsView.setContentAlpha(1);
super.onStart();
- UiFactory.onStart(this);
mFallbackRecentsView.resetTaskVisuals();
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
index b0313fc..2f3cb5f 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -15,14 +15,23 @@
*/
package com.android.quickstep;
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_UP;
+
+import android.view.MotionEvent;
+
+import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.util.UiThreadHelper;
import com.android.quickstep.util.RemoteAnimationTargetSet;
+import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
+import java.util.function.Supplier;
/**
* Wrapper around RecentsAnimationController to help with some synchronization
@@ -43,6 +52,21 @@
private final ExecutorService mExecutorService =
new LooperExecutor(UiThreadHelper.getBackgroundLooper());
+ private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
+ private final InputConsumerController mInputConsumer;
+ private final Supplier<TouchConsumer> mTouchProxySupplier;
+
+ private TouchConsumer mTouchConsumer;
+ private boolean mTouchInProgress;
+
+ private boolean mFinishPending;
+
+ public RecentsAnimationWrapper(InputConsumerController inputConsumer,
+ Supplier<TouchConsumer> touchProxySupplier) {
+ mInputConsumer = inputConsumer;
+ mTouchProxySupplier = touchProxySupplier;
+ }
+
public synchronized void setController(
RecentsAnimationControllerCompat controller, RemoteAnimationTargetSet targetSet) {
TraceHelper.partitionSection("RecentsController", "Set controller " + controller);
@@ -77,21 +101,38 @@
* on the background thread.
*/
public void finish(boolean toHome, Runnable onFinishComplete) {
- mExecutorService.submit(() -> {
- RecentsAnimationControllerCompat controller = mController;
- mController = null;
- TraceHelper.endSection("RecentsController",
- "Finish " + controller + ", toHome=" + toHome);
- if (controller != null) {
- controller.setInputConsumerEnabled(false);
- controller.finish(toHome);
+ if (!toHome) {
+ mExecutorService.submit(() -> finishBg(false, onFinishComplete));
+ return;
+ }
+
+ mMainThreadExecutor.execute(() -> {
+ if (mTouchInProgress) {
+ mFinishPending = true;
+ // Execute the callback
if (onFinishComplete != null) {
onFinishComplete.run();
}
+ } else {
+ mExecutorService.submit(() -> finishBg(true, onFinishComplete));
}
});
}
+ protected void finishBg(boolean toHome, Runnable onFinishComplete) {
+ RecentsAnimationControllerCompat controller = mController;
+ mController = null;
+ TraceHelper.endSection("RecentsController", "Finish " + controller + ", toHome=" + toHome);
+ if (controller != null) {
+ controller.setInputConsumerEnabled(false);
+ controller.finish(toHome);
+
+ if (onFinishComplete != null) {
+ onFinishComplete.run();
+ }
+ }
+ }
+
public void enableInputConsumer() {
mInputConsumerEnabled = true;
if (mInputConsumerEnabled) {
@@ -106,6 +147,34 @@
}
}
+ public void enableTouchProxy() {
+ mMainThreadExecutor.execute(this::enableTouchProxyUi);
+ }
+
+ private void enableTouchProxyUi() {
+ mInputConsumer.setTouchListener(this::onInputConsumerTouch);
+ }
+
+ private boolean onInputConsumerTouch(MotionEvent ev) {
+ int action = ev.getAction();
+ if (action == ACTION_DOWN) {
+ mTouchInProgress = true;
+ mTouchConsumer = mTouchProxySupplier.get();
+ } else if (action == ACTION_CANCEL || action == ACTION_UP) {
+ // Finish any pending actions
+ mTouchInProgress = false;
+ if (mFinishPending) {
+ mFinishPending = false;
+ mExecutorService.submit(() -> finishBg(true, null));
+ }
+ }
+ if (mTouchConsumer != null) {
+ mTouchConsumer.accept(ev);
+ }
+
+ return true;
+ }
+
public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) {
if (mBehindSystemBars == behindSystemBars) {
return;
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 0b97f01..2e4d4d2 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -20,167 +20,144 @@
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.ComponentCallbacks2;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
-import android.os.Looper;
+import android.os.HandlerThread;
+import android.os.Process;
import android.os.RemoteException;
-import android.os.UserHandle;
-import android.support.annotation.WorkerThread;
import android.util.Log;
-import android.util.LruCache;
import android.util.SparseArray;
-import android.view.accessibility.AccessibilityManager;
-
import com.android.launcher3.MainThreadExecutor;
-import com.android.launcher3.R;
+import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
import com.android.systemui.shared.recents.ISystemUiProxy;
-import com.android.systemui.shared.recents.model.IconLoader;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.PreloadOptions;
-import com.android.systemui.shared.recents.model.RecentsTaskLoader;
-import com.android.systemui.shared.recents.model.TaskKeyLruCache;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.BackgroundExecutor;
import com.android.systemui.shared.system.TaskStackChangeListener;
-
import java.util.ArrayList;
-import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
+import androidx.annotation.WorkerThread;
+
/**
* Singleton class to load and manage recents model.
*/
@TargetApi(Build.VERSION_CODES.O)
public class RecentsModel extends TaskStackChangeListener {
// We do not need any synchronization for this variable as its only written on UI thread.
- private static RecentsModel INSTANCE;
-
- public static RecentsModel getInstance(final Context context) {
- if (INSTANCE == null) {
- if (Looper.myLooper() == Looper.getMainLooper()) {
- INSTANCE = new RecentsModel(context.getApplicationContext());
- } else {
- try {
- return new MainThreadExecutor().submit(
- () -> RecentsModel.getInstance(context)).get();
- } catch (InterruptedException|ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
- }
- return INSTANCE;
- }
+ public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
+ new MainThreadInitializedObject<>(c -> new RecentsModel(c));
private final SparseArray<Bundle> mCachedAssistData = new SparseArray<>(1);
private final ArrayList<AssistDataListener> mAssistDataListeners = new ArrayList<>();
private final Context mContext;
- private final RecentsTaskLoader mRecentsTaskLoader;
private final MainThreadExecutor mMainThreadExecutor;
- private RecentsTaskLoadPlan mLastLoadPlan;
- private int mLastLoadPlanId;
- private int mTaskChangeId;
private ISystemUiProxy mSystemUiProxy;
private boolean mClearAssistCacheOnStackChange = true;
- private final boolean mIsLowRamDevice;
- private boolean mPreloadTasksInBackground;
- private final AccessibilityManager mAccessibilityManager;
+
+ private final RecentTasksList mTaskList;
+ private final TaskIconCache mIconCache;
+ private final TaskThumbnailCache mThumbnailCache;
private RecentsModel(Context context) {
mContext = context;
- ActivityManager activityManager =
- (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
- mIsLowRamDevice = activityManager.isLowRamDevice();
mMainThreadExecutor = new MainThreadExecutor();
- Resources res = context.getResources();
- mRecentsTaskLoader = new RecentsTaskLoader(mContext,
- res.getInteger(R.integer.config_recentsMaxThumbnailCacheSize),
- res.getInteger(R.integer.config_recentsMaxIconCacheSize), 0) {
-
- @Override
- protected IconLoader createNewIconLoader(Context context,
- TaskKeyLruCache<Drawable> iconCache,
- LruCache<ComponentName, ActivityInfo> activityInfoCache) {
- return new NormalizedIconLoader(context, iconCache, activityInfoCache);
- }
- };
- mRecentsTaskLoader.startLoader(mContext);
+ HandlerThread loaderThread = new HandlerThread("TaskThumbnailIconCache",
+ Process.THREAD_PRIORITY_BACKGROUND);
+ loaderThread.start();
+ mTaskList = new RecentTasksList(context);
+ mIconCache = new TaskIconCache(context, loaderThread.getLooper());
+ mThumbnailCache = new TaskThumbnailCache(context, loaderThread.getLooper());
ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
-
- mTaskChangeId = 1;
- loadTasks(-1, null);
- mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
}
- public RecentsTaskLoader getRecentsTaskLoader() {
- return mRecentsTaskLoader;
+ public TaskIconCache getIconCache() {
+ return mIconCache;
+ }
+
+ public TaskThumbnailCache getThumbnailCache() {
+ return mThumbnailCache;
}
/**
- * Preloads the task plan
- * @param taskId The running task id or -1
+ * Fetches the list of recent tasks.
+ *
* @param callback The callback to receive the task plan once its complete or null. This is
* always called on the UI thread.
* @return the request id associated with this call.
*/
- public int loadTasks(int taskId, Consumer<RecentsTaskLoadPlan> callback) {
- final int requestId = mTaskChangeId;
+ public int getTasks(Consumer<ArrayList<Task>> callback) {
+ return mTaskList.getTasks(-1, false /* loadKeysOnly */, callback);
+ }
- // Fail fast if nothing has changed.
- if (mLastLoadPlanId == mTaskChangeId) {
- if (callback != null) {
- final RecentsTaskLoadPlan plan = mLastLoadPlan;
- mMainThreadExecutor.execute(() -> callback.accept(plan));
+ /**
+ * @return The task id of the running task, or -1 if there is no current running task.
+ */
+ public static int getRunningTaskId() {
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
+ return runningTask != null ? runningTask.id : -1;
+ }
+
+ /**
+ * @return Whether the provided {@param changeId} is the latest recent tasks list id.
+ */
+ public boolean isTaskListValid(int changeId) {
+ return mTaskList.isTaskListValid(changeId);
+ }
+
+ /**
+ * Finds and returns the task key associated with the given task id.
+ *
+ * @param callback The callback to receive the task key if it is found or null. This is always
+ * called on the UI thread.
+ */
+ public void findTaskWithId(int taskId, Consumer<Task.TaskKey> callback) {
+ mTaskList.getTasks(-1, true /* loadKeysOnly */, (tasks) -> {
+ for (Task task : tasks) {
+ if (task.key.id == taskId) {
+ callback.accept(task.key);
+ return;
+ }
}
- return requestId;
+ callback.accept(null);
+ });
+ }
+
+ @Override
+ public void onTaskStackChangedBackground() {
+ if (!mThumbnailCache.isPreloadingEnabled()) {
+ // Skip if we aren't preloading
+ return;
}
- BackgroundExecutor.get().submit(() -> {
- // Preload the plan
- RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(mContext);
- PreloadOptions opts = new PreloadOptions();
- opts.loadTitles = mAccessibilityManager.isEnabled();
- loadPlan.preloadPlan(opts, mRecentsTaskLoader, taskId, UserHandle.myUserId());
- // Set the load plan on UI thread
- mMainThreadExecutor.execute(() -> {
- mLastLoadPlan = loadPlan;
- mLastLoadPlanId = requestId;
+ int currentUserId = Process.myUserHandle().getIdentifier();
+ if (!checkCurrentOrManagedUserId(currentUserId, mContext)) {
+ // Skip if we are not the current user
+ return;
+ }
- if (callback != null) {
- callback.accept(loadPlan);
+ // Keep the cache up to date with the latest thumbnails
+ int runningTaskId = RecentsModel.getRunningTaskId();
+ mTaskList.getTasks(mThumbnailCache.getCacheSize(), true /* keysOnly */, (tasks) -> {
+ for (Task task : tasks) {
+ if (task.key.id == 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);
+ }
});
- return requestId;
- }
-
- public void setPreloadTasksInBackground(boolean preloadTasksInBackground) {
- mPreloadTasksInBackground = preloadTasksInBackground && !mIsLowRamDevice;
- }
-
- @Override
- public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
- mTaskChangeId++;
- }
-
- @Override
- public void onActivityUnpinned() {
- mTaskChangeId++;
}
@Override
public void onTaskStackChanged() {
- mTaskChangeId++;
-
Preconditions.assertUIThread();
if (mClearAssistCacheOnStackChange) {
mCachedAssistData.clear();
@@ -189,39 +166,6 @@
}
}
- @Override
- public void onTaskStackChangedBackground() {
- int userId = UserHandle.myUserId();
- if (!mPreloadTasksInBackground || !checkCurrentOrManagedUserId(userId, mContext)) {
- // TODO: Only register this for the current user
- return;
- }
-
- // Preload a fixed number of task icons/thumbnails in the background
- ActivityManager.RunningTaskInfo runningTaskInfo =
- ActivityManagerWrapper.getInstance().getRunningTask();
- RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
- RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
- launchOpts.runningTaskId = runningTaskInfo != null ? runningTaskInfo.id : -1;
- launchOpts.numVisibleTasks = 2;
- launchOpts.numVisibleTaskThumbnails = 2;
- launchOpts.onlyLoadForCache = true;
- launchOpts.onlyLoadPausedActivities = true;
- launchOpts.loadThumbnails = true;
- PreloadOptions preloadOpts = new PreloadOptions();
- preloadOpts.loadTitles = mAccessibilityManager.isEnabled();
- plan.preloadPlan(preloadOpts, mRecentsTaskLoader, -1, userId);
- mRecentsTaskLoader.loadTasks(plan, launchOpts);
- }
-
- public boolean isLoadPlanValid(int resultId) {
- return mTaskChangeId == resultId;
- }
-
- public RecentsTaskLoadPlan getLastLoadPlan() {
- return mLastLoadPlan;
- }
-
public void setSystemUiProxy(ISystemUiProxy systemUiProxy) {
mSystemUiProxy = systemUiProxy;
}
@@ -230,16 +174,15 @@
return mSystemUiProxy;
}
- public void onStart() {
- mRecentsTaskLoader.startLoader(mContext);
- }
-
public void onTrimMemory(int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
- // We already stop the loader in UI_HIDDEN, so stop the high res loader as well
- mRecentsTaskLoader.getHighResThumbnailLoader().setVisible(false);
+ mThumbnailCache.getHighResLoadingState().setVisible(false);
}
- mRecentsTaskLoader.onTrimMemory(level);
+ if (level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) {
+ // Clear everything once we reach a low-mem situation
+ mThumbnailCache.clear();
+ mIconCache.clear();
+ }
}
public void onOverviewShown(boolean fromHome, String tag) {
diff --git a/quickstep/src/com/android/quickstep/SwipeUpSetting.java b/quickstep/src/com/android/quickstep/SwipeUpSetting.java
new file mode 100644
index 0000000..381ab9f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/SwipeUpSetting.java
@@ -0,0 +1,62 @@
+/*
+ * 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.quickstep;
+
+import static com.android.systemui.shared.system.SettingsCompat.SWIPE_UP_SETTING_NAME;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+
+import com.android.launcher3.util.SecureSettingsObserver;
+import com.android.launcher3.util.SecureSettingsObserver.OnChangeListener;
+
+public final class SwipeUpSetting {
+ private static final String TAG = "SwipeUpSetting";
+
+ private static final String SWIPE_UP_SETTING_AVAILABLE_RES_NAME =
+ "config_swipe_up_gesture_setting_available";
+
+ private static final String SWIPE_UP_ENABLED_DEFAULT_RES_NAME =
+ "config_swipe_up_gesture_default";
+
+ private static boolean getSystemBooleanRes(String resName) {
+ Resources res = Resources.getSystem();
+ int resId = res.getIdentifier(resName, "bool", "android");
+
+ if (resId != 0) {
+ return res.getBoolean(resId);
+ } else {
+ Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
+ return false;
+ }
+ }
+
+ public static boolean isSwipeUpSettingAvailable() {
+ return getSystemBooleanRes(SWIPE_UP_SETTING_AVAILABLE_RES_NAME);
+ }
+
+ public static boolean isSwipeUpEnabledDefaultValue() {
+ return getSystemBooleanRes(SWIPE_UP_ENABLED_DEFAULT_RES_NAME);
+ }
+
+ public static SecureSettingsObserver newSwipeUpSettingsObserver(Context context,
+ OnChangeListener listener) {
+ return new SecureSettingsObserver(context.getContentResolver(), listener,
+ SWIPE_UP_SETTING_NAME, isSwipeUpEnabledDefaultValue() ? 1 : 0);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
new file mode 100644
index 0000000..612c00e
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -0,0 +1,151 @@
+/*
+ * 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.quickstep;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.LruCache;
+import android.view.accessibility.AccessibilityManager;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.icons.cache.HandlerRunnable;
+import com.android.launcher3.util.Preconditions;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskKeyLruCache;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import java.util.function.Consumer;
+
+/**
+ * Manages the caching of task icons and related data.
+ * TODO: This class should later be merged into IconCache.
+ */
+public class TaskIconCache {
+
+ private final Handler mBackgroundHandler;
+ private final MainThreadExecutor mMainThreadExecutor;
+ private final AccessibilityManager mAccessibilityManager;
+
+ private final NormalizedIconLoader mIconLoader;
+
+ private final TaskKeyLruCache<Drawable> mIconCache;
+ private final TaskKeyLruCache<String> mContentDescriptionCache;
+ private final LruCache<ComponentName, ActivityInfo> mActivityInfoCache;
+
+ private TaskKeyLruCache.EvictionCallback mClearActivityInfoOnEviction =
+ new TaskKeyLruCache.EvictionCallback() {
+ @Override
+ public void onEntryEvicted(Task.TaskKey key) {
+ if (key != null) {
+ mActivityInfoCache.remove(key.getComponent());
+ }
+ }
+ };
+
+ public TaskIconCache(Context context, Looper backgroundLooper) {
+ mBackgroundHandler = new Handler(backgroundLooper);
+ mMainThreadExecutor = new MainThreadExecutor();
+ mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+
+ Resources res = context.getResources();
+ int cacheSize = res.getInteger(R.integer.recentsIconCacheSize);
+ mIconCache = new TaskKeyLruCache<>(cacheSize, mClearActivityInfoOnEviction);
+ mContentDescriptionCache = new TaskKeyLruCache<>(cacheSize, mClearActivityInfoOnEviction);
+ mActivityInfoCache = new LruCache<>(cacheSize);
+ mIconLoader = new NormalizedIconLoader(context, mIconCache, mActivityInfoCache,
+ true /* disableColorExtraction */);
+ }
+
+ /**
+ * Asynchronously fetches the icon and other task data.
+ *
+ * @param task The task to fetch the data for
+ * @param callback The callback to receive the task after its data has been populated.
+ * @return A cancelable handle to the request
+ */
+ public IconLoadRequest updateIconInBackground(Task task, Consumer<Task> callback) {
+ Preconditions.assertUIThread();
+ if (task.icon != null) {
+ // Nothing to load, the icon is already loaded
+ callback.accept(task);
+ return null;
+ }
+
+ IconLoadRequest request = new IconLoadRequest(mBackgroundHandler) {
+ @Override
+ public void run() {
+ Drawable icon = mIconLoader.getIcon(task);
+ String contentDescription = loadContentDescriptionInBackground(task);
+ if (isCanceled()) {
+ // We don't call back to the provided callback in this case
+ return;
+ }
+ mMainThreadExecutor.execute(() -> {
+ task.icon = icon;
+ task.titleDescription = contentDescription;
+ callback.accept(task);
+ onEnd();
+ });
+ }
+ };
+ Utilities.postAsyncCallback(mBackgroundHandler, request);
+ return request;
+ }
+
+ public void clear() {
+ mIconCache.evictAll();
+ mContentDescriptionCache.evictAll();
+ }
+
+ /**
+ * Loads the content description for the given {@param task}.
+ */
+ private String loadContentDescriptionInBackground(Task task) {
+ // Return the cached content description if it exists
+ String label = mContentDescriptionCache.getAndInvalidateIfModified(task.key);
+ if (label != null) {
+ return label;
+ }
+
+ // Skip loading content descriptions if accessibility is not enabled
+ if (!mAccessibilityManager.isEnabled()) {
+ return "";
+ }
+
+ // Skip loading the content description if the activity no longer exists
+ ActivityInfo activityInfo = mIconLoader.getAndUpdateActivityInfo(task.key);
+ if (activityInfo == null) {
+ return "";
+ }
+
+ // Load the label otherwise
+ label = ActivityManagerWrapper.getInstance().getBadgedContentDescription(activityInfo,
+ task.key.userId, task.taskDescription);
+ mContentDescriptionCache.put(task.key, label);
+ return label;
+ }
+
+ public static abstract class IconLoadRequest extends HandlerRunnable {
+ IconLoadRequest(Handler handler) {
+ super(handler, null);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 9d3ac6a..59a937f 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -18,26 +18,40 @@
import android.content.Context;
import android.graphics.Matrix;
-import android.support.annotation.AnyThread;
import android.view.View;
+import androidx.annotation.AnyThread;
+
+import com.android.launcher3.BaseActivity;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Factory class to create and add an overlays on the TaskView
*/
-public class TaskOverlayFactory {
-
+public class TaskOverlayFactory implements ResourceBasedOverride {
private static TaskOverlayFactory sInstance;
+ /** Note that these will be shown in order from top to bottom, if available for the task. */
+ private static final TaskSystemShortcut[] MENU_OPTIONS = new TaskSystemShortcut[]{
+ new TaskSystemShortcut.AppInfo(),
+ new TaskSystemShortcut.SplitScreen(),
+ new TaskSystemShortcut.Pin(),
+ new TaskSystemShortcut.Install(),
+ };
+
public static TaskOverlayFactory get(Context context) {
Preconditions.assertUIThread();
if (sInstance == null) {
- sInstance = Utilities.getOverrideObject(TaskOverlayFactory.class,
+ sInstance = Overrides.getObject(TaskOverlayFactory.class,
context.getApplicationContext(), R.string.task_overlay_factory_class);
}
return sInstance;
@@ -54,9 +68,23 @@
public static class TaskOverlay {
- public void setTaskInfo(Task task, ThumbnailData thumbnail, Matrix matrix) { }
+ public void setTaskInfo(Task task, ThumbnailData thumbnail, Matrix matrix) {
+ }
- public void reset() { }
+ public void reset() {
+ }
+ public List<TaskSystemShortcut> getEnabledShortcuts(TaskView taskView) {
+ final ArrayList<TaskSystemShortcut> shortcuts = new ArrayList<>();
+ final BaseDraggingActivity activity = BaseActivity.fromContext(taskView.getContext());
+ for (TaskSystemShortcut menuOption : MENU_OPTIONS) {
+ View.OnClickListener onClickListener =
+ menuOption.getOnClickListener(activity, taskView);
+ if (onClickListener != null) {
+ shortcuts.add(menuOption);
+ }
+ }
+ return shortcuts;
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
index e5a2b5e..a8eb321 100644
--- a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
+++ b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
@@ -63,8 +63,8 @@
protected T mSystemShortcut;
- protected TaskSystemShortcut(T systemShortcut) {
- super(systemShortcut.iconResId, systemShortcut.labelResId);
+ public TaskSystemShortcut(T systemShortcut) {
+ super(systemShortcut);
mSystemShortcut = systemShortcut;
}
@@ -132,7 +132,7 @@
public void onLayoutChange(View v, int l, int t, int r, int b,
int oldL, int oldT, int oldR, int oldB) {
taskView.getRootView().removeOnLayoutChangeListener(this);
- recentsView.removeIgnoreResetTask(taskView);
+ recentsView.clearIgnoreResetTask(taskId);
// Start animating in the side pages once launcher has been resized
recentsView.dismissTask(taskView, false, false);
@@ -160,7 +160,7 @@
boolean dockTopOrLeft = navBarPosition != WindowManagerWrapper.NAV_BAR_POS_LEFT;
if (ActivityManagerWrapper.getInstance().startActivityFromRecents(taskId,
ActivityOptionsCompat.makeSplitScreenOptions(dockTopOrLeft))) {
- ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
+ ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(activity).getSystemUiProxy();
try {
sysUiProxy.onSplitScreenInvoked();
} catch (RemoteException e) {
@@ -177,7 +177,7 @@
// Hide the task view and wait for the window to be resized
// TODO: Consider animating in launcher and do an in-place start activity
// afterwards
- recentsView.addIgnoreResetTask(taskView);
+ recentsView.setIgnoreResetTask(taskId);
taskView.setAlpha(0f);
};
@@ -225,7 +225,7 @@
@Override
public View.OnClickListener getOnClickListener(
BaseDraggingActivity activity, TaskView taskView) {
- ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
+ ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(activity).getSystemUiProxy();
if (sysUiProxy == null) {
return null;
}
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
new file mode 100644
index 0000000..7a216ed
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
@@ -0,0 +1,199 @@
+/*
+ * 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.quickstep;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Looper;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.icons.cache.HandlerRunnable;
+import com.android.launcher3.util.Preconditions;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskKeyLruCache;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+public class TaskThumbnailCache {
+
+ private final Handler mBackgroundHandler;
+ private final MainThreadExecutor mMainThreadExecutor;
+
+ private final int mCacheSize;
+ private final TaskKeyLruCache<ThumbnailData> mCache;
+ private final HighResLoadingState mHighResLoadingState;
+
+ public static class HighResLoadingState {
+ private boolean mIsLowRamDevice;
+ private boolean mVisible;
+ private boolean mFlingingFast;
+ private boolean mHighResLoadingEnabled;
+ private ArrayList<HighResLoadingStateChangedCallback> mCallbacks = new ArrayList<>();
+
+ public interface HighResLoadingStateChangedCallback {
+ void onHighResLoadingStateChanged(boolean enabled);
+ }
+
+ private HighResLoadingState(Context context) {
+ ActivityManager activityManager =
+ (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ mIsLowRamDevice = activityManager.isLowRamDevice();
+ }
+
+ public void addCallback(HighResLoadingStateChangedCallback callback) {
+ mCallbacks.add(callback);
+ }
+
+ public void removeCallback(HighResLoadingStateChangedCallback callback) {
+ mCallbacks.remove(callback);
+ }
+
+ public void setVisible(boolean visible) {
+ mVisible = visible;
+ updateState();
+ }
+
+ public void setFlingingFast(boolean flingingFast) {
+ mFlingingFast = flingingFast;
+ updateState();
+ }
+
+ public boolean isEnabled() {
+ return mHighResLoadingEnabled;
+ }
+
+ private void updateState() {
+ boolean prevState = mHighResLoadingEnabled;
+ mHighResLoadingEnabled = !mIsLowRamDevice && mVisible && !mFlingingFast;
+ if (prevState != mHighResLoadingEnabled) {
+ for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+ mCallbacks.get(i).onHighResLoadingStateChanged(mHighResLoadingEnabled);
+ }
+ }
+ }
+ }
+
+ public TaskThumbnailCache(Context context, Looper backgroundLooper) {
+ mBackgroundHandler = new Handler(backgroundLooper);
+ mMainThreadExecutor = new MainThreadExecutor();
+ mHighResLoadingState = new HighResLoadingState(context);
+
+ Resources res = context.getResources();
+ mCacheSize = res.getInteger(R.integer.recentsThumbnailCacheSize);
+ mCache = new TaskKeyLruCache<>(mCacheSize);
+ }
+
+ /**
+ * Synchronously fetches the thumbnail for the given {@param task} and puts it in the cache.
+ */
+ public void updateThumbnailInCache(Task task) {
+ Preconditions.assertUIThread();
+
+ // Fetch the thumbnail for this task and put it in the cache
+ updateThumbnailInBackground(task, true /* reducedResolution */, (t) -> {
+ mCache.put(task.key, t.thumbnail);
+ });
+ }
+
+
+ /**
+ * Asynchronously fetches the icon and other task data for the given {@param task}.
+ *
+ * @param callback The callback to receive the task after its data has been populated.
+ * @return A cancelable handle to the request
+ */
+ public ThumbnailLoadRequest updateThumbnailInBackground(Task task, boolean reducedResolution,
+ Consumer<Task> callback) {
+ Preconditions.assertUIThread();
+
+ if (task.thumbnail != null && (!task.thumbnail.reducedResolution || reducedResolution)) {
+ // Nothing to load, the thumbnail is already high-resolution or matches what the
+ // request, so just callback
+ callback.accept(task);
+ return null;
+ }
+
+ ThumbnailData cachedThumbnail = mCache.getAndInvalidateIfModified(task.key);
+ if (cachedThumbnail != null && (!cachedThumbnail.reducedResolution || reducedResolution)) {
+ // Already cached, lets use that thumbnail
+ task.thumbnail = cachedThumbnail;
+ callback.accept(task);
+ return null;
+ }
+
+ ThumbnailLoadRequest request = new ThumbnailLoadRequest(mBackgroundHandler,
+ reducedResolution) {
+ @Override
+ public void run() {
+ ThumbnailData thumbnail = ActivityManagerWrapper.getInstance().getTaskThumbnail(
+ task.key.id, reducedResolution);
+ if (isCanceled()) {
+ // We don't call back to the provided callback in this case
+ return;
+ }
+ mMainThreadExecutor.execute(() -> {
+ task.thumbnail = thumbnail;
+ callback.accept(task);
+ onEnd();
+ });
+ }
+ };
+ Utilities.postAsyncCallback(mBackgroundHandler, request);
+ return request;
+ }
+
+ /**
+ * Clears the cache.
+ */
+ public void clear() {
+ mCache.evictAll();
+ }
+
+ /**
+ * @return The cache size.
+ */
+ public int getCacheSize() {
+ return mCacheSize;
+ }
+
+ /**
+ * @return The mutable high-res loading state.
+ */
+ public HighResLoadingState getHighResLoadingState() {
+ return mHighResLoadingState;
+ }
+
+ /**
+ * @return Whether to enable background preloading of task thumbnails.
+ */
+ public boolean isPreloadingEnabled() {
+ return !mHighResLoadingState.mIsLowRamDevice && mHighResLoadingState.mVisible;
+ }
+
+ public static abstract class ThumbnailLoadRequest extends HandlerRunnable {
+ public final boolean reducedResolution;
+
+ ThumbnailLoadRequest(Handler handler, boolean reducedResolution) {
+ super(handler, null);
+ this.reducedResolution = reducedResolution;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index f9b5e30..4b86a7f 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -18,8 +18,6 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
-import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber;
-import static com.android.systemui.shared.recents.utilities.Utilities.getSurface;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
import android.animation.ValueAnimator;
@@ -30,7 +28,6 @@
import android.graphics.RectF;
import android.os.UserHandle;
import android.util.Log;
-import android.view.Surface;
import android.view.View;
import com.android.launcher3.BaseDraggingActivity;
@@ -62,7 +59,6 @@
*/
public static CharSequence getTitle(Context context, Task task) {
LauncherAppsCompat launcherAppsCompat = LauncherAppsCompat.getInstance(context);
- UserManagerCompat userManagerCompat = UserManagerCompat.getInstance(context);
PackageManager packageManager = context.getPackageManager();
UserHandle user = UserHandle.of(task.key.userId);
ApplicationInfo applicationInfo = launcherAppsCompat.getApplicationInfo(
@@ -71,7 +67,7 @@
Log.e(TAG, "Failed to get title for task " + task);
return "";
}
- return userManagerCompat.getBadgedLabelForUser(
+ return packageManager.getUserBadgedLabel(
applicationInfo.loadLabel(packageManager), user);
}
@@ -92,10 +88,11 @@
*/
public static TaskView findTaskViewToLaunch(
BaseDraggingActivity activity, View v, RemoteAnimationTargetCompat[] targets) {
- if (v instanceof TaskView) {
- return (TaskView) v;
- }
RecentsView recentsView = activity.getOverviewPanel();
+ if (v instanceof TaskView) {
+ TaskView taskView = (TaskView) v;
+ return recentsView.isTaskViewVisible(taskView) ? taskView : null;
+ }
// It's possible that the launched view can still be resolved to a visible task view, check
// the task id of the opening task and see if we can find a match.
diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java
index 4cecffa..225d29b 100644
--- a/quickstep/src/com/android/quickstep/TouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/TouchConsumer.java
@@ -17,7 +17,6 @@
import android.annotation.TargetApi;
import android.os.Build;
-import android.support.annotation.IntDef;
import android.view.Choreographer;
import android.view.MotionEvent;
@@ -25,10 +24,14 @@
import java.lang.annotation.RetentionPolicy;
import java.util.function.Consumer;
+import androidx.annotation.IntDef;
+
@TargetApi(Build.VERSION_CODES.O)
@FunctionalInterface
public interface TouchConsumer extends Consumer<MotionEvent> {
+ TouchConsumer NO_OP = (ev) -> {};
+
@IntDef(flag = true, value = {
INTERACTION_NORMAL,
INTERACTION_QUICK_SCRUB
@@ -40,7 +43,7 @@
default void reset() { }
- default void updateTouchTracking(@InteractionType int interactionType) { }
+ default void onQuickScrubStart() { }
default void onQuickScrubEnd() { }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionLog.java b/quickstep/src/com/android/quickstep/TouchInteractionLog.java
new file mode 100644
index 0000000..053efbb
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/TouchInteractionLog.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 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.view.MotionEvent;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.LinkedList;
+
+/**
+ * Keeps track of debugging logs for a particular quickstep/scrub gesture.
+ */
+public class TouchInteractionLog {
+
+ // The number of gestures to log
+ private static final int MAX_NUM_LOG_GESTURES = 5;
+
+ private final Calendar mCalendar = Calendar.getInstance();
+ private final SimpleDateFormat mDateFormat = new SimpleDateFormat("MMM dd - kk:mm:ss:SSS");
+ private final LinkedList<ArrayList<String>> mGestureLogs = new LinkedList<>();
+
+ public void prepareForNewGesture() {
+ mGestureLogs.add(new ArrayList<>());
+ while (mGestureLogs.size() > MAX_NUM_LOG_GESTURES) {
+ mGestureLogs.pop();
+ }
+ getCurrentLog().add("[" + mDateFormat.format(mCalendar.getTime()) + "]");
+ }
+
+ public void setTouchConsumer(TouchConsumer consumer) {
+ getCurrentLog().add("tc=" + consumer.getClass().getSimpleName());
+ }
+
+ public void addMotionEvent(MotionEvent event) {
+ getCurrentLog().add("ev=" + event.getActionMasked());
+ }
+
+ public void startQuickStep() {
+ getCurrentLog().add("qstStart");
+ }
+
+ public void startQuickScrub() {
+ getCurrentLog().add("qsStart");
+ }
+
+ public void setQuickScrubProgress(float progress) {
+ getCurrentLog().add("qsP=" + progress);
+ }
+
+ public void endQuickScrub(String reason) {
+ getCurrentLog().add("qsEnd=" + reason);
+ }
+
+ public void startRecentsAnimation() {
+ getCurrentLog().add("raStart");
+ }
+
+ public void startRecentsAnimationCallback(int numTargets) {
+ getCurrentLog().add("raStartCb=" + numTargets);
+ }
+
+ public void cancelRecentsAnimation() {
+ getCurrentLog().add("raCancel");
+ }
+
+ public void finishRecentsAnimation(boolean toHome) {
+ getCurrentLog().add("raFinish=" + toHome);
+ }
+
+ public void launchTaskStart() {
+ getCurrentLog().add("launchStart");
+ }
+
+ public void launchTaskEnd(boolean result) {
+ getCurrentLog().add("launchEnd=" + result);
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.println("TouchInteractionLog {");
+ for (ArrayList<String> gesture : mGestureLogs) {
+ pw.print(" ");
+ for (String log : gesture) {
+ pw.print(log + " ");
+ }
+ pw.println();
+ }
+ pw.println("}");
+ }
+
+ private ArrayList<String> getCurrentLog() {
+ return mGestureLogs.getLast();
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 6c54262..b1a214d 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -19,9 +19,11 @@
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_POINTER_INDEX_SHIFT;
import static android.view.MotionEvent.ACTION_UP;
-import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+
+import static com.android.systemui.shared.system.ActivityManagerWrapper
+ .CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
import android.annotation.TargetApi;
@@ -33,7 +35,6 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;
import android.view.Choreographer;
@@ -50,8 +51,12 @@
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ChoreographerCompat;
+import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* Service connected by system-UI for handling touch interaction.
*/
@@ -79,7 +84,9 @@
private final IBinder mMyBinder = new IOverviewProxy.Stub() {
@Override
- public void onPreMotionEvent(@HitTarget int downHitTarget) throws RemoteException {
+ public void onPreMotionEvent(@HitTarget int downHitTarget) {
+ mTouchInteractionLog.prepareForNewGesture();
+
TraceHelper.beginSection("SysUiBinder");
setupTouchConsumer(downHitTarget);
TraceHelper.partitionSection("SysUiBinder", "Down target " + downHitTarget);
@@ -89,7 +96,14 @@
public void onMotionEvent(MotionEvent ev) {
mEventQueue.queue(ev);
- String name = sMotionEventNames.get(ev.getActionMasked());
+ int action = ev.getActionMasked();
+ if (action == ACTION_DOWN) {
+ mOverviewInteractionState.setSwipeGestureInitializing(true);
+ } else if (action == ACTION_UP || action == ACTION_CANCEL) {
+ mOverviewInteractionState.setSwipeGestureInitializing(false);
+ }
+
+ String name = sMotionEventNames.get(action);
if (name != null){
TraceHelper.partitionSection("SysUiBinder", name);
}
@@ -105,6 +119,7 @@
@Override
public void onQuickScrubStart() {
mEventQueue.onQuickScrubStart();
+ mOverviewInteractionState.setSwipeGestureInitializing(false);
TraceHelper.partitionSection("SysUiBinder", "onQuickScrubStart");
}
@@ -145,8 +160,8 @@
@Override
public void onQuickStep(MotionEvent motionEvent) {
mEventQueue.onQuickStep(motionEvent);
+ mOverviewInteractionState.setSwipeGestureInitializing(false);
TraceHelper.endSection("SysUiBinder", "onQuickStep");
-
}
@Override
@@ -155,8 +170,6 @@
}
};
- private final TouchConsumer mNoOpTouchConsumer = (ev) -> {};
-
private static boolean sConnected = false;
public static boolean isConnected() {
@@ -172,6 +185,8 @@
private OverviewInteractionState mOverviewInteractionState;
private OverviewCallbacks mOverviewCallbacks;
private TaskOverlayFactory mTaskOverlayFactory;
+ private TouchInteractionLog mTouchInteractionLog;
+ private InputConsumerController mInputConsumer;
private Choreographer mMainThreadChoreographer;
private Choreographer mBackgroundThreadChoreographer;
@@ -180,15 +195,17 @@
public void onCreate() {
super.onCreate();
mAM = ActivityManagerWrapper.getInstance();
- mRecentsModel = RecentsModel.getInstance(this);
- mRecentsModel.setPreloadTasksInBackground(true);
+ mRecentsModel = RecentsModel.INSTANCE.get(this);
mMainThreadExecutor = new MainThreadExecutor();
mOverviewCommandHelper = new OverviewCommandHelper(this);
mMainThreadChoreographer = Choreographer.getInstance();
- mEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer);
- mOverviewInteractionState = OverviewInteractionState.getInstance(this);
+ mEventQueue = new MotionEventQueue(mMainThreadChoreographer, TouchConsumer.NO_OP);
+ mOverviewInteractionState = OverviewInteractionState.INSTANCE.get(this);
mOverviewCallbacks = OverviewCallbacks.get(this);
mTaskOverlayFactory = TaskOverlayFactory.get(this);
+ mTouchInteractionLog = new TouchInteractionLog();
+ mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
+ mInputConsumer.registerInputConsumer();
sConnected = true;
@@ -199,6 +216,7 @@
@Override
public void onDestroy() {
+ mInputConsumer.unregisterInputConsumer();
mOverviewCommandHelper.onDestroy();
sConnected = false;
super.onDestroy();
@@ -229,10 +247,11 @@
RunningTaskInfo runningTaskInfo = mAM.getRunningTask(0);
if (runningTaskInfo == null && !forceToLauncher) {
- return mNoOpTouchConsumer;
+ return TouchConsumer.NO_OP;
} else if (forceToLauncher ||
runningTaskInfo.topActivity.equals(mOverviewCommandHelper.overviewComponent)) {
- return getOverviewConsumer();
+ return OverviewTouchConsumer.newInstance(
+ mOverviewCommandHelper.getActivityControlHelper(), false, mTouchInteractionLog);
} else {
if (tracker == null) {
tracker = VelocityTracker.obtain();
@@ -241,20 +260,25 @@
mOverviewCommandHelper.overviewIntent,
mOverviewCommandHelper.getActivityControlHelper(), mMainThreadExecutor,
mBackgroundThreadChoreographer, downHitTarget, mOverviewCallbacks,
- mTaskOverlayFactory, tracker);
+ mTaskOverlayFactory, mInputConsumer, tracker, mTouchInteractionLog);
}
}
- private TouchConsumer getOverviewConsumer() {
- ActivityControlHelper activityHelper = mOverviewCommandHelper.getActivityControlHelper();
- BaseDraggingActivity activity = activityHelper.getCreatedActivity();
- if (activity == null) {
- return mNoOpTouchConsumer;
+ private void initBackgroundChoreographer() {
+ if (sRemoteUiThread == null) {
+ sRemoteUiThread = new HandlerThread("remote-ui");
+ sRemoteUiThread.start();
}
- return new OverviewTouchConsumer(activityHelper, activity);
+ new Handler(sRemoteUiThread.getLooper()).post(() ->
+ mBackgroundThreadChoreographer = ChoreographerCompat.getSfInstance());
}
- private static class OverviewTouchConsumer<T extends BaseDraggingActivity>
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mTouchInteractionLog.dump(pw);
+ }
+
+ public static class OverviewTouchConsumer<T extends BaseDraggingActivity>
implements TouchConsumer {
private final ActivityControlHelper<T> mActivityHelper;
@@ -264,6 +288,9 @@
private final PointF mDownPos = new PointF();
private final int mTouchSlop;
private final QuickScrubController mQuickScrubController;
+ private final TouchInteractionLog mTouchInteractionLog;
+
+ private final boolean mStartingInActivityBounds;
private boolean mTrackingStarted = false;
private boolean mInvalidated = false;
@@ -272,14 +299,18 @@
private boolean mStartPending = false;
private boolean mEndPending = false;
- OverviewTouchConsumer(ActivityControlHelper<T> activityHelper, T activity) {
+ OverviewTouchConsumer(ActivityControlHelper<T> activityHelper, T activity,
+ boolean startingInActivityBounds, TouchInteractionLog touchInteractionLog) {
mActivityHelper = activityHelper;
mActivity = activity;
mTarget = activity.getDragLayer();
- mTouchSlop = ViewConfiguration.get(mTarget.getContext()).getScaledTouchSlop();
+ mTouchSlop = ViewConfiguration.get(mActivity).getScaledTouchSlop();
+ mStartingInActivityBounds = startingInActivityBounds;
mQuickScrubController = mActivity.<RecentsView>getOverviewPanel()
.getQuickScrubController();
+ mTouchInteractionLog = touchInteractionLog;
+ mTouchInteractionLog.setTouchConsumer(this);
}
@Override
@@ -287,29 +318,26 @@
if (mInvalidated) {
return;
}
+ mTouchInteractionLog.addMotionEvent(ev);
int action = ev.getActionMasked();
if (action == ACTION_DOWN) {
+ if (mStartingInActivityBounds) {
+ startTouchTracking(ev, false /* updateLocationOffset */);
+ return;
+ }
mTrackingStarted = false;
mDownPos.set(ev.getX(), ev.getY());
} else if (!mTrackingStarted) {
switch (action) {
- case ACTION_POINTER_UP:
- case ACTION_POINTER_DOWN:
- if (!mTrackingStarted) {
- mInvalidated = true;
- }
+ case ACTION_CANCEL:
+ case ACTION_UP:
+ startTouchTracking(ev, true /* updateLocationOffset */);
break;
case ACTION_MOVE: {
float displacement = ev.getY() - mDownPos.y;
if (Math.abs(displacement) >= mTouchSlop) {
- mTarget.getLocationOnScreen(mLocationOnScreen);
-
- // Send a down event only when mTouchSlop is crossed.
- MotionEvent down = MotionEvent.obtain(ev);
- down.setAction(ACTION_DOWN);
- sendEvent(down);
- down.recycle();
- mTrackingStarted = true;
+ // Start tracking only when mTouchSlop is crossed.
+ startTouchTracking(ev, true /* updateLocationOffset */);
}
}
}
@@ -324,9 +352,34 @@
}
}
+ private void startTouchTracking(MotionEvent ev, boolean updateLocationOffset) {
+ if (updateLocationOffset) {
+ mTarget.getLocationOnScreen(mLocationOnScreen);
+ }
+
+ // Send down touch event
+ MotionEvent down = MotionEvent.obtainNoHistory(ev);
+ down.setAction(ACTION_DOWN);
+ sendEvent(down);
+
+ mTrackingStarted = true;
+ // Send pointer down for remaining pointers.
+ int pointerCount = ev.getPointerCount();
+ for (int i = 1; i < pointerCount; i++) {
+ down.setAction(ACTION_POINTER_DOWN | (i << ACTION_POINTER_INDEX_SHIFT));
+ sendEvent(down);
+ }
+
+ down.recycle();
+ }
+
private void sendEvent(MotionEvent ev) {
+ if (!mTarget.verifyTouchDispatch(this, ev)) {
+ mInvalidated = true;
+ return;
+ }
int flags = ev.getEdgeFlags();
- ev.setEdgeFlags(flags | EDGE_NAV_BAR);
+ ev.setEdgeFlags(flags | TouchInteractionService.EDGE_NAV_BAR);
ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
if (!mTrackingStarted) {
mTarget.onInterceptTouchEvent(ev);
@@ -344,44 +397,48 @@
OverviewCallbacks.get(mActivity).closeAllWindows();
ActivityManagerWrapper.getInstance()
.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+ mTouchInteractionLog.startQuickStep();
}
@Override
- public void updateTouchTracking(int interactionType) {
+ public void onQuickScrubStart() {
if (mInvalidated) {
return;
}
- if (interactionType == INTERACTION_QUICK_SCRUB) {
+ mTouchInteractionLog.startQuickScrub();
+ if (!mQuickScrubController.prepareQuickScrub(TAG)) {
+ mInvalidated = true;
+ mTouchInteractionLog.endQuickScrub("onQuickScrubStart");
+ return;
+ }
+ OverviewCallbacks.get(mActivity).closeAllWindows();
+ ActivityManagerWrapper.getInstance()
+ .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+
+ mStartPending = true;
+ Runnable action = () -> {
if (!mQuickScrubController.prepareQuickScrub(TAG)) {
mInvalidated = true;
+ mTouchInteractionLog.endQuickScrub("onQuickScrubStart");
return;
}
- OverviewCallbacks.get(mActivity).closeAllWindows();
- ActivityManagerWrapper.getInstance()
- .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+ mActivityHelper.onQuickInteractionStart(mActivity, null, true,
+ mTouchInteractionLog);
+ mQuickScrubController.onQuickScrubProgress(mLastProgress);
+ mStartPending = false;
- mStartPending = true;
- Runnable action = () -> {
- if (!mQuickScrubController.prepareQuickScrub(TAG)) {
- mInvalidated = true;
- return;
- }
- mActivityHelper.onQuickInteractionStart(mActivity, null, true);
- mQuickScrubController.onQuickScrubProgress(mLastProgress);
- mStartPending = false;
+ if (mEndPending) {
+ mQuickScrubController.onQuickScrubEnd();
+ mEndPending = false;
+ }
+ };
- if (mEndPending) {
- mQuickScrubController.onQuickScrubEnd();
- mEndPending = false;
- }
- };
-
- mActivityHelper.executeOnWindowAvailable(mActivity, action);
- }
+ mActivityHelper.executeOnWindowAvailable(mActivity, action);
}
@Override
public void onQuickScrubEnd() {
+ mTouchInteractionLog.endQuickScrub("onQuickScrubEnd");
if (mInvalidated) {
return;
}
@@ -394,6 +451,7 @@
@Override
public void onQuickScrubProgress(float progress) {
+ mTouchInteractionLog.setQuickScrubProgress(progress);
mLastProgress = progress;
if (mInvalidated || mStartPending) {
return;
@@ -401,14 +459,14 @@
mQuickScrubController.onQuickScrubProgress(progress);
}
- }
-
- private void initBackgroundChoreographer() {
- if (sRemoteUiThread == null) {
- sRemoteUiThread = new HandlerThread("remote-ui");
- sRemoteUiThread.start();
+ public static TouchConsumer newInstance(ActivityControlHelper activityHelper,
+ boolean startingInActivityBounds, TouchInteractionLog touchInteractionLog) {
+ BaseDraggingActivity activity = activityHelper.getCreatedActivity();
+ if (activity == null) {
+ return TouchConsumer.NO_OP;
+ }
+ return new OverviewTouchConsumer(activityHelper, activity, startingInActivityBounds,
+ touchInteractionLog);
}
- new Handler(sRemoteUiThread.getLooper()).post(() ->
- mBackgroundThreadChoreographer = ChoreographerCompat.getSfInstance());
}
}
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 1f0a057..b0d7ff3 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -23,10 +23,10 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_FROM_APP_START_DURATION;
+import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_FROM_APP_START_DURATION;
import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -43,26 +43,25 @@
import android.os.Looper;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.support.annotation.AnyThread;
-import android.support.annotation.UiThread;
-import android.support.annotation.WorkerThread;
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.View;
import android.view.ViewTreeObserver.OnDrawListener;
import android.view.WindowManager;
import android.view.animation.Interpolator;
-
+import androidx.annotation.AnyThread;
+import androidx.annotation.UiThread;
+import androidx.annotation.WorkerThread;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -74,6 +73,7 @@
import com.android.quickstep.ActivityControlHelper.AnimationFactory;
import com.android.quickstep.ActivityControlHelper.LayoutListener;
import com.android.quickstep.TouchConsumer.InteractionType;
+import com.android.quickstep.TouchInteractionService.OverviewTouchConsumer;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.quickstep.util.TransformedRect;
@@ -87,7 +87,6 @@
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
import com.android.systemui.shared.system.WindowCallbacksCompat;
-import com.android.systemui.shared.system.WindowManagerWrapper;
import java.util.StringJoiner;
import java.util.function.BiFunction;
@@ -123,9 +122,11 @@
private static final int STATE_CAPTURE_SCREENSHOT = 1 << 15;
private static final int STATE_SCREENSHOT_CAPTURED = 1 << 16;
+ private static final int STATE_SCREENSHOT_VIEW_SHOWN = 1 << 17;
- private static final int STATE_RESUME_LAST_TASK = 1 << 17;
- private static final int STATE_ASSIST_DATA_RECEIVED = 1 << 18;
+ private static final int STATE_RESUME_LAST_TASK = 1 << 18;
+ private static final int STATE_ASSIST_DATA_RECEIVED = 1 << 19;
+
private static final int LAUNCHER_UI_STATES =
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_ACTIVITY_MULTIPLIER_COMPLETE
@@ -139,6 +140,9 @@
STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_STARTED
| STATE_APP_CONTROLLER_RECEIVED | STATE_SCREENSHOT_CAPTURED;
+ private static final int QUICK_SCRUB_START_UI_STATE = STATE_LAUNCHER_STARTED
+ | STATE_QUICK_SCRUB_START | STATE_APP_CONTROLLER_RECEIVED;
+
// For debugging, keep in sync with above states
private static final String[] STATES = new String[] {
"STATE_LAUNCHER_PRESENT",
@@ -158,6 +162,7 @@
"STATE_QUICK_SCRUB_END",
"STATE_CAPTURE_SCREENSHOT",
"STATE_SCREENSHOT_CAPTURED",
+ "STATE_SCREENSHOT_VIEW_SHOWN",
"STATE_RESUME_LAST_TASK",
"STATE_ASSIST_DATA_RECEIVED",
};
@@ -182,6 +187,8 @@
// 1 => preview snapShot is completely aligned with the recents view and hotseat is completely
// visible.
private final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
+ // To avoid UI jump when gesture is started, we offset the animation by the threshold.
+ private float mShiftAtGestureStart = 0;
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
@@ -194,6 +201,7 @@
private final Context mContext;
private final ActivityControlHelper<T> mActivityControlHelper;
private final ActivityInitListener mActivityInitListener;
+ private final TouchInteractionLog mTouchInteractionLog;
private final int mRunningTaskId;
private final RunningTaskInfo mRunningTaskInfo;
@@ -221,10 +229,7 @@
private @InteractionType int mInteractionType = INTERACTION_NORMAL;
- private InputConsumerController mInputConsumer =
- InputConsumerController.getRecentsAnimationInputConsumer();
-
- private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper();
+ private final RecentsAnimationWrapper mRecentsAnimationWrapper;
private final long mTouchTimeMs;
private long mLauncherFrameDrawnTime;
@@ -237,7 +242,8 @@
private Bundle mAssistData;
WindowTransformSwipeHandler(int id, RunningTaskInfo runningTaskInfo, Context context,
- long touchTimeMs, ActivityControlHelper<T> controller) {
+ long touchTimeMs, ActivityControlHelper<T> controller,
+ InputConsumerController inputConsumer, TouchInteractionLog touchInteractionLog) {
this.id = id;
mContext = context;
mRunningTaskInfo = runningTaskInfo;
@@ -246,11 +252,11 @@
mActivityControlHelper = controller;
mActivityInitListener = mActivityControlHelper
.createActivityInitListener(this::onActivityInit);
+ mTouchInteractionLog = touchInteractionLog;
+ mRecentsAnimationWrapper = new RecentsAnimationWrapper(inputConsumer,
+ this::createNewTouchProxyHandler);
initStateCallbacks();
- // Register the input consumer on the UI thread, to ensure that it runs after any pending
- // unregister calls
- executeOnUiThread(mInputConsumer::registerInputConsumer);
}
private void initStateCallbacks() {
@@ -262,6 +268,11 @@
}
};
+ // Re-setup the recents UI when gesture starts, as the state could have been changed during
+ // that time by a previous window transition.
+ mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_GESTURE_STARTED_QUICKSTEP,
+ this::setupRecentsViewUi);
+
mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED_QUICKSCRUB,
this::initializeLauncherAnimationController);
mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED_QUICKSTEP,
@@ -314,8 +325,7 @@
| STATE_SCALED_CONTROLLER_APP,
this::notifyTransitionCancelled);
- mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_QUICK_SCRUB_START
- | STATE_APP_CONTROLLER_RECEIVED, this::onQuickScrubStart);
+ mStateCallback.addCallback(QUICK_SCRUB_START_UI_STATE, this::onQuickScrubStartUi);
mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_QUICK_SCRUB_START
| STATE_SCALED_CONTROLLER_RECENTS, this::onFinishedTransitionToQuickScrub);
mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_CURRENT_TASK_FINISHED
@@ -323,6 +333,10 @@
mStateCallback.addCallback(LONG_SWIPE_ENTER_STATE, this::checkLongSwipeCanEnter);
mStateCallback.addCallback(LONG_SWIPE_START_STATE, this::checkLongSwipeCanStart);
+
+ mStateCallback.addChangeHandler(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
+ | STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT,
+ (b) -> mRecentsView.setRunningTaskHidden(!b));
}
private void executeOnUiThread(Runnable action) {
@@ -345,8 +359,8 @@
mDp = dp;
TransformedRect tempRect = new TransformedRect();
- mTransitionDragLength = mActivityControlHelper
- .getSwipeUpDestinationAndLength(dp, mContext, mInteractionType, tempRect);
+ mTransitionDragLength = mActivityControlHelper.getSwipeUpDestinationAndLength(
+ dp, mContext, mInteractionType, tempRect);
mClipAnimationHelper.updateTargetRect(tempRect);
}
@@ -410,7 +424,7 @@
}
mAnimationFactory = mActivityControlHelper.prepareRecentsUI(mActivity,
- mWasLauncherAlreadyVisible, this::onAnimatorPlaybackControllerCreated);
+ mWasLauncherAlreadyVisible, true, this::onAnimatorPlaybackControllerCreated);
AbstractFloatingView.closeAllOpenViews(activity, mWasLauncherAlreadyVisible);
if (mWasLauncherAlreadyVisible) {
@@ -435,13 +449,17 @@
});
}
- mRecentsView.showTask(mRunningTaskId);
- mRecentsView.setRunningTaskHidden(true);
- mRecentsView.setRunningTaskIconScaledDown(true /* isScaledDown */, false /* animate */);
+ setupRecentsViewUi();
mLayoutListener.open();
mStateCallback.setState(STATE_LAUNCHER_STARTED);
}
+ private void setupRecentsViewUi() {
+ mRecentsView.showTask(mRunningTaskId);
+ mRecentsView.setRunningTaskHidden(true);
+ mRecentsView.setRunningTaskIconScaledDown(true);
+ }
+
public void setLauncherOnDrawCallback(Runnable callback) {
mLauncherDrawnCallback = callback;
}
@@ -487,27 +505,8 @@
// This method is only called when STATE_GESTURE_STARTED_QUICKSTEP/
// STATE_GESTURE_STARTED_QUICKSCRUB is set, so we can enable the high-res thumbnail loader
// here once we are sure that we will end up in an overview state
- RecentsModel.getInstance(mContext).getRecentsTaskLoader()
- .getHighResThumbnailLoader().setVisible(true);
- }
-
- public void updateInteractionType(@InteractionType int interactionType) {
- if (mInteractionType != INTERACTION_NORMAL) {
- throw new IllegalArgumentException(
- "Can't change interaction type from " + mInteractionType);
- }
- if (interactionType != INTERACTION_QUICK_SCRUB) {
- throw new IllegalArgumentException(
- "Can't change interaction type to " + interactionType);
- }
- mInteractionType = interactionType;
- mRecentsAnimationWrapper.runOnInit(this::shiftAnimationDestinationForQuickscrub);
-
- setStateOnUiThread(STATE_QUICK_SCRUB_START | STATE_GESTURE_COMPLETED);
-
- // Start the window animation without waiting for launcher.
- animateToProgress(mCurrentShift.value, 1f, QUICK_SCRUB_FROM_APP_START_DURATION, LINEAR,
- true /* goingToHome */);
+ RecentsModel.INSTANCE.get(mContext).getThumbnailCache()
+ .getHighResLoadingState().setVisible(true);
}
private void shiftAnimationDestinationForQuickscrub() {
@@ -542,7 +541,7 @@
public void updateDisplacement(float displacement) {
// We are moving in the negative x/y direction
displacement = -displacement;
- if (displacement > mTransitionDragLength) {
+ if (displacement > mTransitionDragLength && mTransitionDragLength > 0) {
mCurrentShift.updateValue(1);
if (!mBgLongSwipeMode) {
@@ -573,7 +572,7 @@
private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) {
mLauncherTransitionController = anim;
mLauncherTransitionController.dispatchOnStart();
- mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
+ updateLauncherTransitionProgress();
}
@WorkerThread
@@ -599,6 +598,11 @@
}
private void updateFinalShiftUi() {
+ if (mRecentsAnimationWrapper.getController() != null && mLayoutListener != null) {
+ mLayoutListener.update(mCurrentShift.value > 1, mUiLongSwipeMode,
+ mClipAnimationHelper.getCurrentRectWithInsets());
+ }
+
final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW;
if (passed != mPassedOverviewThreshold) {
mPassedOverviewThreshold = passed;
@@ -612,15 +616,19 @@
.getAnimationPlayer().isStarted()) {
return;
}
- mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
+ updateLauncherTransitionProgress();
+ }
+
+ private void updateLauncherTransitionProgress() {
+ float progress = mCurrentShift.value;
+ mLauncherTransitionController.setPlayFraction(
+ progress <= mShiftAtGestureStart || mShiftAtGestureStart >= 1
+ ? 0 : (progress - mShiftAtGestureStart) / (1 - mShiftAtGestureStart));
}
public void onRecentsAnimationStart(RecentsAnimationControllerCompat controller,
RemoteAnimationTargetSet targets, Rect homeContentInsets, Rect minimizedHomeBounds) {
- LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
- InvariantDeviceProfile idp = appState == null ?
- new InvariantDeviceProfile(mContext) : appState.getInvariantDeviceProfile();
- DeviceProfile dp = idp.getDeviceProfile(mContext);
+ DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
final Rect overviewStackBounds;
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mRunningTaskId);
@@ -641,10 +649,8 @@
overviewStackBounds = new Rect(0, 0, dp.widthPx, dp.heightPx);
}
// If we are not in multi-window mode, home insets should be same as system insets.
- Rect insets = new Rect();
- WindowManagerWrapper.getInstance().getStableInsets(insets);
dp = dp.copy(mContext);
- dp.updateInsets(insets);
+ dp.updateInsets(homeContentInsets);
}
dp.updateIsSeascape(mContext.getSystemService(WindowManager.class));
@@ -655,6 +661,7 @@
initTransitionEndpoints(dp);
mRecentsAnimationWrapper.setController(controller, targets);
+ mTouchInteractionLog.startRecentsAnimationCallback(targets.apps.length);
setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
mPassedOverviewThreshold = false;
@@ -664,10 +671,12 @@
mRecentsAnimationWrapper.setController(null, null);
mActivityInitListener.unregister();
setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
+ mTouchInteractionLog.cancelRecentsAnimation();
}
public void onGestureStarted() {
notifyGestureStartedAsync();
+ mShiftAtGestureStart = mCurrentShift.value;
setStateOnUiThread(mInteractionType == INTERACTION_NORMAL
? STATE_GESTURE_STARTED_QUICKSTEP : STATE_GESTURE_STARTED_QUICKSCRUB);
mGestureStarted = true;
@@ -705,6 +714,19 @@
}
}
+ @UiThread
+ private TouchConsumer createNewTouchProxyHandler() {
+ mCurrentShift.finishAnimation();
+ if (mLauncherTransitionController != null) {
+ mLauncherTransitionController.getAnimationPlayer().end();
+ }
+ // Hide the task view, if not already hidden
+ setTargetAlphaProvider(WindowTransformSwipeHandler::getHiddenTargetAlpha);
+
+ return OverviewTouchConsumer.newInstance(mActivityControlHelper, true,
+ mTouchInteractionLog);
+ }
+
private void handleNormalGestureEnd(float endVelocity, boolean isFling) {
float velocityPxPerMs = endVelocity / 1000;
long duration = MAX_SWIPE_DURATION;
@@ -747,6 +769,10 @@
}
}
}
+ if (goingToHome) {
+ mRecentsAnimationWrapper.enableTouchProxy();
+ }
+
animateToProgress(startShift, endShift, duration, interpolator, goingToHome);
}
@@ -764,7 +790,7 @@
}
int dstContainerType = toLauncher ? ContainerType.TASKSWITCHER : ContainerType.APP;
- UserEventDispatcher.newInstance(mContext, dp).logStateChangeAction(
+ UserEventDispatcher.newInstance(mContext).logStateChangeAction(
mLogAction, direction,
ContainerType.NAVBAR, ContainerType.APP,
dstContainerType,
@@ -787,16 +813,20 @@
@Override
public void onAnimationSuccess(Animator animator) {
setStateOnUiThread(mIsGoingToHome
- ? (STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT)
- : STATE_SCALED_CONTROLLER_APP);
+ ? (STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT
+ | STATE_SCREENSHOT_VIEW_SHOWN) : STATE_SCALED_CONTROLLER_APP);
}
});
anim.start();
long startMillis = SystemClock.uptimeMillis();
executeOnUiThread(() -> {
// Animate the launcher components at the same time as the window, always on UI thread.
- if (mLauncherTransitionController != null && !mWasLauncherAlreadyVisible
- && start != end && duration > 0) {
+ if (mLauncherTransitionController == null) {
+ return;
+ }
+ if (start == end || duration <= 0) {
+ mLauncherTransitionController.getAnimationPlayer().end();
+ } else {
// Adjust start progress and duration in case we are on a different thread.
long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
elapsedMillis = Utilities.boundToRange(elapsedMillis, 0, duration);
@@ -823,6 +853,7 @@
@UiThread
private void resumeLastTask() {
mRecentsAnimationWrapper.finish(false /* toHome */, null);
+ mTouchInteractionLog.finishRecentsAnimation(false);
}
public void reset() {
@@ -841,7 +872,6 @@
}
mActivityInitListener.unregister();
- mInputConsumer.unregisterInputConsumer();
mTaskSnapshot = null;
}
@@ -850,8 +880,7 @@
mLayoutListener.finish();
mActivityControlHelper.getAlphaProperty(mActivity).setValue(1);
- mRecentsView.setRunningTaskHidden(false);
- mRecentsView.setRunningTaskIconScaledDown(false /* isScaledDown */, false /* animate */);
+ mRecentsView.setRunningTaskIconScaledDown(false);
mQuickScrubController.cancelActiveQuickscrub();
}
@@ -871,6 +900,7 @@
if (mWasLauncherAlreadyVisible && mLauncherTransitionController != null) {
mLauncherTransitionController.setPlayFraction(1);
}
+ mRecentsView.setRunningTaskHidden(false);
}
private void switchToScreenshot() {
@@ -882,7 +912,6 @@
mTaskSnapshot = controller.screenshotTask(mRunningTaskId);
}
TaskView taskView = mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot);
- mRecentsView.setRunningTaskHidden(false);
if (taskView != null) {
// Defer finishing the animation until the next launcher frame with the
// new thumbnail
@@ -920,6 +949,7 @@
mRecentsAnimationWrapper.finish(true /* toHome */,
() -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
}
+ mTouchInteractionLog.finishRecentsAnimation(true);
}
private void setupLauncherUiAfterSwipeUpAnimation() {
@@ -930,17 +960,34 @@
mActivityControlHelper.onSwipeUpComplete(mActivity);
// Animate the first icon.
- mRecentsView.setRunningTaskIconScaledDown(false /* isScaledDown */, true /* animate */);
+ mRecentsView.animateUpRunningTaskIconScale();
mRecentsView.setSwipeDownShouldLaunchApp(true);
- RecentsModel.getInstance(mContext).onOverviewShown(false, TAG);
+ RecentsModel.INSTANCE.get(mContext).onOverviewShown(false, TAG);
doLogGesture(true /* toLauncher */);
reset();
}
- private void onQuickScrubStart() {
- if (!mQuickScrubController.prepareQuickScrub(TAG)) {
+ public void onQuickScrubStart() {
+ if (mInteractionType != INTERACTION_NORMAL) {
+ throw new IllegalArgumentException(
+ "Can't change interaction type from " + mInteractionType);
+ }
+ mInteractionType = INTERACTION_QUICK_SCRUB;
+ mRecentsAnimationWrapper.runOnInit(this::shiftAnimationDestinationForQuickscrub);
+
+ setStateOnUiThread(STATE_QUICK_SCRUB_START | STATE_GESTURE_COMPLETED);
+
+ // Start the window animation without waiting for launcher.
+ long duration = FeatureFlags.QUICK_SWITCH.get()
+ ? QUICK_SWITCH_FROM_APP_START_DURATION
+ : QUICK_SCRUB_FROM_APP_START_DURATION;
+ animateToProgress(mCurrentShift.value, 1f, duration, LINEAR, true /* goingToHome */);
+ }
+
+ private void onQuickScrubStartUi() {
+ if (!mQuickScrubController.prepareQuickScrub(TAG, FeatureFlags.QUICK_SWITCH.get())) {
mQuickScrubBlocked = true;
setStateOnUiThread(STATE_RESUME_LAST_TASK | STATE_HANDLER_INVALIDATED);
return;
@@ -949,8 +996,10 @@
mLauncherTransitionController.getAnimationPlayer().end();
mLauncherTransitionController = null;
}
+ mLayoutListener.finish();
- mActivityControlHelper.onQuickInteractionStart(mActivity, mRunningTaskInfo, false);
+ mActivityControlHelper.onQuickInteractionStart(mActivity, mRunningTaskInfo, false,
+ mTouchInteractionLog);
// Inform the last progress in case we skipped before.
mQuickScrubController.onQuickScrubProgress(mCurrentQuickScrubProgress);
@@ -962,14 +1011,21 @@
}
mQuickScrubController.onFinishedTransitionToQuickScrub();
- mRecentsView.setRunningTaskIconScaledDown(false /* isScaledDown */, true /* animate */);
- RecentsModel.getInstance(mContext).onOverviewShown(false, TAG);
+ mRecentsView.animateUpRunningTaskIconScale();
+ if (mQuickScrubController.isQuickSwitch()) {
+ TaskView runningTask = mRecentsView.getRunningTaskView();
+ if (runningTask != null) {
+ runningTask.setTranslationY(-mActivity.getResources().getDimension(
+ R.dimen.task_thumbnail_half_top_margin) * 1f / mRecentsView.getScaleX());
+ }
+ }
+ RecentsModel.INSTANCE.get(mContext).onOverviewShown(false, TAG);
}
public void onQuickScrubProgress(float progress) {
mCurrentQuickScrubProgress = progress;
if (Looper.myLooper() != Looper.getMainLooper() || mQuickScrubController == null
- || mQuickScrubBlocked) {
+ || mQuickScrubBlocked || !mStateCallback.hasStates(QUICK_SCRUB_START_UI_STATE)) {
return;
}
mQuickScrubController.onQuickScrubProgress(progress);
@@ -1024,6 +1080,7 @@
private void onLongSwipeDisabledUi() {
mUiLongSwipeMode = false;
+ mStateCallback.clearState(STATE_SCREENSHOT_VIEW_SHOWN);
if (mLongSwipeController != null) {
mLongSwipeController.destroy();
@@ -1049,7 +1106,7 @@
}
// We are entering long swipe mode, make sure the screen shot is captured.
- mStateCallback.setState(STATE_CAPTURE_SCREENSHOT);
+ mStateCallback.setState(STATE_CAPTURE_SCREENSHOT | STATE_SCREENSHOT_VIEW_SHOWN);
}
@@ -1067,9 +1124,9 @@
}
mLongSwipeController = mActivityControlHelper.getLongSwipeController(
- mActivity, mRecentsAnimationWrapper.targetSet);
+ mActivity, mRunningTaskId);
onLongSwipeDisplacementUpdated();
- setTargetAlphaProvider(mLongSwipeController::getTargetAlpha);
+ setTargetAlphaProvider(WindowTransformSwipeHandler::getHiddenTargetAlpha);
}
private void onLongSwipeGestureFinishUi(float velocity, boolean isFling) {
@@ -1097,6 +1154,14 @@
}
private void preloadAssistData() {
- RecentsModel.getInstance(mContext).preloadAssistData(mRunningTaskId, mAssistData);
+ RecentsModel.INSTANCE.get(mContext).preloadAssistData(mRunningTaskId, mAssistData);
+ }
+
+ public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, Float expectedAlpha) {
+ if (!(app.isNotInRecents
+ || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME)) {
+ return 0;
+ }
+ return expectedAlpha;
}
}
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
new file mode 100644
index 0000000..2f411ef
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -0,0 +1,105 @@
+/*
+ * 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.quickstep.logging;
+
+import android.content.Context;
+import android.content.Intent;
+import android.stats.launcher.nano.LauncherExtension;
+import android.stats.launcher.nano.LauncherTarget;
+
+import static android.stats.launcher.nano.Launcher.ALLAPPS;
+import static android.stats.launcher.nano.Launcher.HOME;
+import static android.stats.launcher.nano.Launcher.LAUNCH_APP;
+import static android.stats.launcher.nano.Launcher.LAUNCH_TASK;
+import static android.stats.launcher.nano.Launcher.BACKGROUND;
+import static android.stats.launcher.nano.Launcher.OVERVIEW;
+
+import android.view.View;
+
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.logging.StatsLogUtils;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+import com.android.launcher3.util.ComponentKey;
+import com.android.systemui.shared.system.StatsLogCompat;
+import com.google.protobuf.nano.MessageNano;
+
+import androidx.annotation.Nullable;
+
+/**
+ * This method calls the StatsLog hidden method until they are made available public.
+ *
+ * To see if the logs are properly sent to statsd, execute following command.
+ * $ adb root && adb shell statsd
+ * $ adb shell cmd stats print-logs
+ * $ adb logcat | grep statsd OR $ adb logcat -b stats
+ */
+public class StatsLogCompatManager extends StatsLogManager {
+
+ private static final int SUPPORTED_TARGET_DEPTH = 2;
+
+ public StatsLogCompatManager(Context context) { }
+
+ @Override
+ public void logAppLaunch(View v, Intent intent) {
+ LauncherExtension ext = new LauncherExtension();
+ ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH];
+ int srcState = mStateProvider.getCurrentState();
+ fillInLauncherExtension(v, ext);
+ StatsLogCompat.write(LAUNCH_APP, srcState, BACKGROUND /* dstState */,
+ MessageNano.toByteArray(ext), true);
+ }
+
+ @Override
+ public void logTaskLaunch(View v, ComponentKey componentKey) {
+ LauncherExtension ext = new LauncherExtension();
+ ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH];
+ int srcState = OVERVIEW;
+ fillInLauncherExtension(v, ext);
+ StatsLogCompat.write(LAUNCH_TASK, srcState, BACKGROUND /* dstState */,
+ MessageNano.toByteArray(ext), true);
+ }
+
+ public static boolean fillInLauncherExtension(View v, LauncherExtension extension) {
+ StatsLogUtils.LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(v);
+ if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) {
+ return false;
+ }
+ ItemInfo itemInfo = (ItemInfo) v.getTag();
+ Target child = new Target();
+ Target parent = new Target();
+ provider.fillInLogContainerData(v, itemInfo, child, parent);
+ copy(child, extension.srcTarget[0]);
+ copy(parent, extension.srcTarget[1]);
+ return true;
+ }
+
+ private static void copy(Target src, LauncherTarget dst) {
+ // fill in
+ }
+
+ @Override
+ public void verify() {
+ if(!(StatsLogUtils.LAUNCHER_STATE_ALLAPPS == ALLAPPS &&
+ StatsLogUtils.LAUNCHER_STATE_BACKGROUND == BACKGROUND &&
+ StatsLogUtils.LAUNCHER_STATE_OVERVIEW == OVERVIEW &&
+ StatsLogUtils.LAUNCHER_STATE_HOME == HOME)) {
+ throw new IllegalStateException(
+ "StatsLogUtil constants doesn't match enums in launcher.proto");
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java b/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java
index 6dff187..4392851 100644
--- a/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java
+++ b/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java
@@ -34,6 +34,7 @@
* quickstep interactions.
*/
@SuppressWarnings("unused")
+@Deprecated
public class UserEventDispatcherExtension extends UserEventDispatcher {
private static final String TAG = "UserEventDispatcher";
diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
index df70a8a..57a0e8f 100644
--- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
+++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -29,8 +29,6 @@
import android.graphics.RectF;
import android.os.Build;
import android.os.RemoteException;
-import android.support.annotation.Nullable;
-import android.view.Surface;
import android.view.animation.Interpolator;
import com.android.launcher3.BaseDraggingActivity;
@@ -50,9 +48,10 @@
import com.android.systemui.shared.system.TransactionCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import java.util.function.BiConsumer;
import java.util.function.BiFunction;
+import androidx.annotation.Nullable;
+
/**
* Utility class to handle window clip animation
*/
@@ -78,10 +77,11 @@
public final Rect mHomeStackBounds = new Rect();
// The clip rect in source app window coordinates
- private final Rect mClipRect = new Rect();
+ private final RectF mClipRectF = new RectF();
private final RectFEvaluator mRectFEvaluator = new RectFEvaluator();
private final Matrix mTmpMatrix = new Matrix();
private final RectF mTmpRectF = new RectF();
+ private final RectF mCurrentRectWithInsets = new RectF();
private float mTargetScale = 1f;
private float mOffsetScale = 1f;
@@ -91,8 +91,6 @@
// Whether to boost the opening animation target layers, or the closing
private int mBoostModeTargetLayers = -1;
- // Wether or not applyTransform has been called yet since prepareAnimation()
- private boolean mIsFirstFrame = true;
private BiFunction<RemoteAnimationTargetCompat, Float, Float> mTaskAlphaCallback =
(t, a1) -> a1;
@@ -156,12 +154,12 @@
mTargetOffset.y * offsetYProgress);
}
- mClipRect.left = (int) (mSourceWindowClipInsets.left * progress);
- mClipRect.top = (int) (mSourceWindowClipInsets.top * progress);
- mClipRect.right = (int)
- (mSourceStackBounds.width() - (mSourceWindowClipInsets.right * progress));
- mClipRect.bottom = (int)
- (mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress));
+ mClipRectF.left = mSourceWindowClipInsets.left * progress;
+ mClipRectF.top = mSourceWindowClipInsets.top * progress;
+ mClipRectF.right =
+ mSourceStackBounds.width() - (mSourceWindowClipInsets.right * progress);
+ mClipRectF.bottom =
+ mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress);
SurfaceParams[] params = new SurfaceParams[targetSet.unfilteredApps.length];
for (int i = 0; i < targetSet.unfilteredApps.length; i++) {
@@ -169,11 +167,12 @@
mTmpMatrix.setTranslate(app.position.x, app.position.y);
Rect crop = app.sourceContainerBounds;
float alpha = 1f;
+ int layer;
if (app.mode == targetSet.targetMode) {
if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL);
mTmpMatrix.postTranslate(app.position.x, app.position.y);
- crop = mClipRect;
+ mClipRectF.roundOut(crop);
}
if (app.isNotInRecents
@@ -182,15 +181,22 @@
}
alpha = mTaskAlphaCallback.apply(app, alpha);
+ layer = RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers);
+ } else {
+ crop = null;
+ layer = Integer.MAX_VALUE;
}
-
- params[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop,
- RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers));
+ params[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop, layer);
}
applyParams(syncTransactionApplier, params);
return currentRect;
}
+ public RectF getCurrentRectWithInsets() {
+ mTmpMatrix.mapRect(mCurrentRectWithInsets, mClipRectF);
+ return mCurrentRectWithInsets;
+ }
+
private void applyParams(@Nullable SyncRtSurfaceTransactionApplier syncTransactionApplier,
SurfaceParams[] params) {
if (syncTransactionApplier != null) {
@@ -240,7 +246,7 @@
updateStackBoundsToMultiWindowTaskSize(activity);
} else {
mSourceStackBounds.set(mHomeStackBounds);
- mSourceInsets.set(activity.getDeviceProfile().getInsets());
+ mSourceInsets.set(ttv.getInsets());
}
TransformedRect targetRect = new TransformedRect();
@@ -260,7 +266,7 @@
}
private void updateStackBoundsToMultiWindowTaskSize(BaseDraggingActivity activity) {
- ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
+ ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(activity).getSystemUiProxy();
if (sysUiProxy != null) {
try {
mSourceStackBounds.set(sysUiProxy.getNonMinimizedSplitScreenSecondaryBounds());
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index ec9c7ea..6ca0dce 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -20,14 +20,15 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
-import android.support.annotation.AnyThread;
-import android.support.annotation.IntDef;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import java.lang.annotation.Retention;
+import androidx.annotation.AnyThread;
+import androidx.annotation.IntDef;
+
public class LayoutUtils {
private static final int MULTI_WINDOW_STRATEGY_HALF_SCREEN = 1;
@@ -110,4 +111,9 @@
outRect.set(Math.round(x), Math.round(y),
Math.round(x + outWidth), Math.round(y + outHeight));
}
+
+ public static int getShelfTrackingDistance(DeviceProfile dp) {
+ // Start from a third of bottom inset to provide some shelf overlap.
+ return dp.hotseatBarSizePx + dp.getInsets().bottom / 3 - dp.edgeMarginPx * 2;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
index c359966..eb8da6e 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -21,14 +21,26 @@
import android.util.AttributeSet;
import android.view.View;
+import com.android.launcher3.FastBitmapDrawable;
+
+import java.util.ArrayList;
+
+import androidx.annotation.NonNull;
+
/**
* A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout
* when the drawable changes.
*/
public class IconView extends View {
+ public interface OnScaleUpdateListener {
+ public void onScaleUpdate(float scale);
+ }
+
private Drawable mDrawable;
+ private ArrayList<OnScaleUpdateListener> mScaleListeners;
+
public IconView(Context context) {
super(context);
}
@@ -53,6 +65,10 @@
invalidate();
}
+ public Drawable getDrawable() {
+ return mDrawable;
+ }
+
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
@@ -78,6 +94,16 @@
}
@Override
+ public void invalidateDrawable(@NonNull Drawable drawable) {
+ super.invalidateDrawable(drawable);
+ if (drawable instanceof FastBitmapDrawable && mScaleListeners != null) {
+ for (OnScaleUpdateListener listener : mScaleListeners) {
+ listener.onScaleUpdate(((FastBitmapDrawable) drawable).getScale());
+ }
+ }
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
if (mDrawable != null) {
mDrawable.draw(canvas);
@@ -88,4 +114,20 @@
public boolean hasOverlappingRendering() {
return false;
}
+
+ public void addUpdateScaleListener(OnScaleUpdateListener listener) {
+ if (mScaleListeners == null) {
+ mScaleListeners = new ArrayList<>();
+ }
+ mScaleListeners.add(listener);
+ if (mDrawable instanceof FastBitmapDrawable) {
+ listener.onScaleUpdate(((FastBitmapDrawable) mDrawable).getScale());
+ }
+ }
+
+ public void removeUpdateScaleListener(OnScaleUpdateListener listener) {
+ if (mScaleListeners != null) {
+ mScaleListeners.remove(listener);
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
index c149de5..c12a579 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
@@ -15,11 +15,17 @@
*/
package com.android.quickstep.views;
-import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.view.MotionEvent;
+import android.widget.FrameLayout;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Insettable;
@@ -34,16 +40,28 @@
implements Insettable, LayoutListener {
private final Launcher mLauncher;
+ private final Paint mPaint = new Paint();
private WindowTransformSwipeHandler mHandler;
+ private RectF mCurrentRect;
public LauncherLayoutListener(Launcher launcher) {
super(launcher, null);
mLauncher = launcher;
- setVisibility(INVISIBLE);
+ mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+ setLayoutParams(new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ }
- // For the duration of the gesture, lock the screen orientation to ensure that we do not
- // rotate mid-quickscrub
- launcher.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK);
+ @Override
+ public void update(boolean shouldFinish, boolean isLongSwipe, RectF currentRect) {
+ if (shouldFinish) {
+ finish();
+ return;
+ }
+
+ mCurrentRect = currentRect;
+
+ setWillNotDraw(mCurrentRect == null || isLongSwipe);
+ invalidate();
}
@Override
@@ -85,11 +103,6 @@
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(1, 1);
- }
-
- @Override
public void logActionCommand(int command) {
// We should probably log the weather
}
@@ -101,8 +114,13 @@
@Override
public void finish() {
- setHandler(null);
close(false);
+ setHandler(null);
mLauncher.getRotationHelper().setStateHandlerRequest(REQUEST_NONE);
}
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ canvas.drawRect(mCurrentRect, mPaint);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 7c5828b..697bb4f 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -124,7 +124,7 @@
ClipAnimationHelper helper) {
AnimatorSet anim = super.createAdjacentPageAnimForTaskLaunch(tv, helper);
- if (!OverviewInteractionState.getInstance(mActivity).isSwipeUpGestureEnabled()) {
+ if (!OverviewInteractionState.INSTANCE.get(mActivity).isSwipeUpGestureEnabled()) {
// Hotseat doesn't move when opening recents with the button,
// so don't animate it here either.
return anim;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index e18708b..854e728 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -24,9 +24,10 @@
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
-
import android.animation.Animator;
import android.animation.AnimatorSet;
+import android.animation.LayoutTransition;
+import android.animation.LayoutTransition.TransitionListener;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
@@ -41,12 +42,9 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
-import android.os.UserHandle;
-import android.support.annotation.Nullable;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
-import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.SparseBooleanArray;
@@ -57,10 +55,11 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewDebug;
+import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ListView;
-
+import androidx.annotation.Nullable;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
@@ -77,13 +76,11 @@
import com.android.quickstep.OverviewCallbacks;
import com.android.quickstep.QuickScrubController;
import com.android.quickstep.RecentsModel;
+import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.TaskViewDrawable;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.shared.recents.model.RecentsTaskLoader;
import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.BackgroundExecutor;
@@ -97,7 +94,8 @@
* A list of recent tasks.
*/
@TargetApi(Build.VERSION_CODES.P)
-public abstract class RecentsView<T extends BaseActivity> extends PagedView implements Insettable {
+public abstract class RecentsView<T extends BaseActivity> extends PagedView implements Insettable,
+ TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback {
private static final String TAG = RecentsView.class.getSimpleName();
@@ -117,6 +115,7 @@
private final Rect mTempRect = new Rect();
private static final int DISMISS_TASK_DURATION = 300;
+ private static final int ADDITION_TASK_DURATION = 200;
// The threshold at which we update the SystemUI flags when animating from the task into the app
public static final float UPDATE_SYSUI_FLAGS_THRESHOLD = 0.85f;
@@ -169,8 +168,9 @@
if (!mHandleTaskStackChanges) {
return;
}
- // TODO: Re-enable layout transitions for addition of the unpinned task
+
reloadIfNeeded();
+ enableLayoutTransitions();
}
@Override
@@ -178,6 +178,10 @@
if (!mHandleTaskStackChanges) {
return;
}
+
+ // Notify the quick scrub controller that a particular task has been removed
+ mQuickScrubController.onTaskRemoved(taskId);
+
BackgroundExecutor.get().submit(() -> {
TaskView taskView = getTaskView(taskId);
if (taskView == null) {
@@ -197,17 +201,13 @@
handler.post(() ->
dismissTask(taskView, true /* animate */, false /* removeTask */));
} else {
- RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(getContext());
- RecentsTaskLoadPlan.PreloadOptions opts =
- new RecentsTaskLoadPlan.PreloadOptions();
- opts.loadTitles = false;
- loadPlan.preloadPlan(opts, mModel.getRecentsTaskLoader(), -1,
- UserHandle.myUserId());
- if (loadPlan.getTaskStack().findTaskWithId(taskId) == null) {
- // The task was removed from the recents list
- handler.post(() ->
- dismissTask(taskView, true /* animate */, false /* removeTask */));
- }
+ mModel.findTaskWithId(taskKey.id, (key) -> {
+ if (key == null) {
+ // The task was removed from the recents list
+ handler.post(() -> dismissTask(taskView, true /* animate */,
+ false /* removeTask */));
+ }
+ });
}
});
}
@@ -220,7 +220,9 @@
}
};
- private int mLoadPlanId = -1;
+ // Used to keep track of the last requested task list id, so that we do not request to load the
+ // tasks again if we have already requested it and the task list has not changed
+ private int mTaskListChangeId = -1;
// Only valid until the launcher state changes to NORMAL
private int mRunningTaskId = -1;
@@ -239,12 +241,13 @@
private int mDownY;
private PendingAnimation mPendingAnimation;
+ private LayoutTransition mLayoutTransition;
@ViewDebug.ExportedProperty(category = "launcher")
private float mContentAlpha = 1;
- // Keeps track of task views whose visual state should not be reset
- private ArraySet<TaskView> mIgnoreResetTaskViews = new ArraySet<>();
+ // Keeps track of task id whose visual state should not be reset
+ private int mIgnoreResetTaskId = -1;
// Variables for empty state
private final Drawable mEmptyIcon;
@@ -266,14 +269,13 @@
public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
- enableFreeScroll(true);
+ setEnableFreeScroll(true);
mFastFlingVelocity = getResources()
.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
mActivity = (T) BaseActivity.fromContext(context);
mQuickScrubController = new QuickScrubController(mActivity, this);
- mModel = RecentsModel.getInstance(context);
-
+ mModel = RecentsModel.INSTANCE.get(context);
mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
.inflate(R.layout.overview_clear_all_button, this, false);
mClearAllButton.setOnClickListener(this::dismissAllTasks);
@@ -304,7 +306,7 @@
public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData) {
TaskView taskView = getTaskView(taskId);
if (taskView != null) {
- taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData);
+ taskView.getThumbnail().setThumbnail(taskView.getTask(), thumbnailData);
}
return taskView;
}
@@ -319,6 +321,7 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
updateTaskStackListenerState();
+ mModel.getThumbnailCache().getHighResLoadingState().addCallback(this);
mActivity.addMultiWindowModeChangedListener(mMultiWindowModeChangedListener);
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
}
@@ -327,6 +330,7 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
updateTaskStackListenerState();
+ mModel.getThumbnailCache().getHighResLoadingState().removeCallback(this);
mActivity.removeMultiWindowModeChangedListener(mMultiWindowModeChangedListener);
ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
}
@@ -337,12 +341,11 @@
// Clear the task data for the removed child if it was visible
if (child != mClearAllButton) {
- Task task = ((TaskView) child).getTask();
+ TaskView taskView = (TaskView) child;
+ Task task = taskView.getTask();
if (mHasVisibleTaskData.get(task.key.id)) {
mHasVisibleTaskData.delete(task.key.id);
- RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
- loader.unloadTaskData(task);
- loader.getHighResThumbnailLoader().onTaskInvisible(task);
+ taskView.onTaskListVisibilityChanged(false /* visible */);
}
}
}
@@ -355,7 +358,7 @@
public TaskView getTaskView(int taskId) {
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView tv = (TaskView) getChildAt(i);
- if (tv.getTask().key.id == taskId) {
+ if (tv.getTask().key != null && tv.getTask().key.id == taskId) {
return tv;
}
}
@@ -390,9 +393,6 @@
final int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
- if (mShowEmptyMessage) {
- onAllTasksRemoved();
- }
if (mTouchDownToStartHome) {
startHome();
}
@@ -403,20 +403,26 @@
break;
case MotionEvent.ACTION_MOVE:
// Passing the touch slop will not allow dismiss to home
- if (mTouchDownToStartHome && Math.hypot(mDownX - x, mDownY - y) > mTouchSlop) {
+ if (mTouchDownToStartHome &&
+ (isHandlingTouch() || Math.hypot(mDownX - x, mDownY - y) > mTouchSlop)) {
mTouchDownToStartHome = false;
}
break;
case MotionEvent.ACTION_DOWN:
// Touch down anywhere but the deadzone around the visible clear all button and
// between the task views will start home on touch up
- if (mTouchState == TOUCH_STATE_REST) {
- updateDeadZoneRects();
- final boolean clearAllButtonDeadZoneConsumed = mClearAllButton.getAlpha() == 1
- && mClearAllButtonDeadZoneRect.contains(x, y);
- if (!clearAllButtonDeadZoneConsumed
- && !mTaskViewDeadZoneRect.contains(x + getScrollX(), y)) {
+ if (!isHandlingTouch()) {
+ if (mShowEmptyMessage) {
mTouchDownToStartHome = true;
+ } else {
+ updateDeadZoneRects();
+ final boolean clearAllButtonDeadZoneConsumed =
+ mClearAllButton.getAlpha() == 1
+ && mClearAllButtonDeadZoneRect.contains(x, y);
+ if (!clearAllButtonDeadZoneConsumed
+ && !mTaskViewDeadZoneRect.contains(x + getScrollX(), y)) {
+ mTouchDownToStartHome = true;
+ }
}
}
mDownX = x;
@@ -429,13 +435,13 @@
return true;
}
- private void applyLoadPlan(RecentsTaskLoadPlan loadPlan) {
+ private void applyLoadPlan(ArrayList<Task> tasks) {
if (mPendingAnimation != null) {
- mPendingAnimation.addEndListener((onEndListener) -> applyLoadPlan(loadPlan));
+ mPendingAnimation.addEndListener((onEndListener) -> applyLoadPlan(tasks));
return;
}
- TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null;
- if (stack == null) {
+
+ if (tasks == null || tasks.isEmpty()) {
removeAllViews();
onTaskStackUpdated();
return;
@@ -446,7 +452,12 @@
// Ensure there are as many views as there are tasks in the stack (adding and trimming as
// necessary)
final LayoutInflater inflater = LayoutInflater.from(getContext());
- final ArrayList<Task> tasks = new ArrayList<>(stack.getTasks());
+
+ // Unload existing visible task data
+ unloadVisibleTaskData();
+
+ TaskView ignoreRestTaskView =
+ mIgnoreResetTaskId == -1 ? null : getTaskView(mIgnoreResetTaskId);
final int requiredTaskCount = tasks.size();
if (getTaskViewCount() != requiredTaskCount) {
@@ -454,21 +465,16 @@
removeView(mClearAllButton);
}
for (int i = getChildCount(); i < requiredTaskCount; i++) {
- final TaskView taskView = (TaskView) inflater.inflate(R.layout.task, this, false);
- addView(taskView);
+ addView(inflater.inflate(R.layout.task, this, false));
}
while (getChildCount() > requiredTaskCount) {
- final TaskView taskView = (TaskView) getChildAt(getChildCount() - 1);
- removeView(taskView);
+ removeView(getChildAt(getChildCount() - 1));
}
if (requiredTaskCount > 0) {
addView(mClearAllButton);
}
}
- // Unload existing visible task data
- unloadVisibleTaskData();
-
// Rebind and reset all task views
for (int i = requiredTaskCount - 1; i >= 0; i--) {
final int pageIndex = requiredTaskCount - i - 1;
@@ -476,6 +482,12 @@
final TaskView taskView = (TaskView) getChildAt(pageIndex);
taskView.bind(task);
}
+ if (mIgnoreResetTaskId != -1 && getTaskView(mIgnoreResetTaskId) != ignoreRestTaskView) {
+ // If the taskView mapping is changing, do not preserve the visuals. Since we are
+ // mostly preserving the first task, and new taskViews are added to the end, it should
+ // generally map to the same task.
+ mIgnoreResetTaskId = -1;
+ }
resetTaskVisuals();
if (oldChildCount != getChildCount()) {
@@ -495,14 +507,18 @@
public void resetTaskVisuals() {
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
TaskView taskView = (TaskView) getChildAt(i);
- if (!mIgnoreResetTaskViews.contains(taskView)) {
+ if (mIgnoreResetTaskId != taskView.getTask().key.id) {
taskView.resetVisualProperties();
}
}
if (mRunningTaskTileHidden) {
setRunningTaskHidden(mRunningTaskTileHidden);
}
- applyIconScale(false /* animate */);
+
+ // Force apply the scale.
+ if (mIgnoreResetTaskId != mRunningTaskId) {
+ applyRunningTaskIconScale();
+ }
updateCurveProperties();
// Update the set of visible task's data
@@ -544,7 +560,7 @@
boolean scrolling = super.computeScrollHelper();
boolean isFlingingFast = false;
updateCurveProperties();
- if (scrolling || (mTouchState == TOUCH_STATE_SCROLLING)) {
+ if (scrolling || isHandlingTouch()) {
if (scrolling) {
// Check if we are flinging quickly to disable high res thumbnail loading
isFlingingFast = mScroller.getCurrVelocity() > mFastFlingVelocity;
@@ -554,9 +570,8 @@
loadVisibleTaskData();
}
- // Update the high res thumbnail loader
- RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
- loader.getHighResThumbnailLoader().setFlingingFast(isFlingingFast);
+ // Update the high res thumbnail loader state
+ mModel.getThumbnailCache().getHighResLoadingState().setFlingingFast(isFlingingFast);
return scrolling;
}
@@ -591,12 +606,12 @@
* and unloads the associated task data for tasks that are no longer visible.
*/
public void loadVisibleTaskData() {
- if (!mOverviewStateEnabled) {
- // Skip loading visible task data if we've already left the overview state
+ if (!mOverviewStateEnabled || mTaskListChangeId == -1) {
+ // Skip loading visible task data if we've already left the overview state, or if the
+ // task list hasn't been loaded yet (the task views will not reflect the task list)
return;
}
- RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
int centerPageIndex = getPageNearestToCenterOfScreen();
int numChildren = getTaskViewCount();
int lower = Math.max(0, centerPageIndex - 2);
@@ -613,14 +628,12 @@
continue;
}
if (!mHasVisibleTaskData.get(task.key.id)) {
- loader.loadTaskData(task);
- loader.getHighResThumbnailLoader().onTaskVisible(task);
+ taskView.onTaskListVisibilityChanged(true /* visible */);
}
mHasVisibleTaskData.put(task.key.id, visible);
} else {
if (mHasVisibleTaskData.get(task.key.id)) {
- loader.unloadTaskData(task);
- loader.getHighResThumbnailLoader().onTaskInvisible(task);
+ taskView.onTaskListVisibilityChanged(false /* visible */);
}
mHasVisibleTaskData.delete(task.key.id);
}
@@ -631,20 +644,31 @@
* Unloads any associated data from the currently visible tasks
*/
private void unloadVisibleTaskData() {
- RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
for (int i = 0; i < mHasVisibleTaskData.size(); i++) {
if (mHasVisibleTaskData.valueAt(i)) {
TaskView taskView = getTaskView(mHasVisibleTaskData.keyAt(i));
- Task task = taskView.getTask();
- loader.unloadTaskData(task);
- loader.getHighResThumbnailLoader().onTaskInvisible(task);
+ if (taskView != null) {
+ taskView.onTaskListVisibilityChanged(false /* visible */);
+ }
}
}
mHasVisibleTaskData.clear();
}
- protected void onAllTasksRemoved() {
- startHome();
+ @Override
+ public void onHighResLoadingStateChanged(boolean enabled) {
+ // Whenever the high res loading state changes, poke each of the visible tasks to see if
+ // they want to updated their thumbnail state
+ for (int i = 0; i < mHasVisibleTaskData.size(); i++) {
+ if (mHasVisibleTaskData.valueAt(i)) {
+ TaskView taskView = getTaskView(mHasVisibleTaskData.keyAt(i));
+ if (taskView != null) {
+ // Poke the view again, which will trigger it to load high res if the state
+ // is enabled
+ taskView.onTaskListVisibilityChanged(true /* visible */);
+ }
+ }
+ }
}
protected abstract void startHome();
@@ -652,6 +676,8 @@
public void reset() {
mRunningTaskId = -1;
mRunningTaskTileHidden = false;
+ mIgnoreResetTaskId = -1;
+ mTaskListChangeId = -1;
unloadVisibleTaskData();
setCurrentPage(0);
@@ -663,8 +689,8 @@
* Reloads the view if anything in recents changed.
*/
public void reloadIfNeeded() {
- if (!mModel.isLoadPlanValid(mLoadPlanId)) {
- mLoadPlanId = mModel.loadTasks(mRunningTaskId, this::applyLoadPlan);
+ if (!mModel.isTaskListValid(mTaskListChangeId)) {
+ mTaskListChangeId = mModel.getTasks(this::applyLoadPlan);
}
}
@@ -695,12 +721,16 @@
setCurrentTask(runningTaskId);
}
+ public TaskView getRunningTaskView() {
+ return getTaskView(mRunningTaskId);
+ }
+
/**
* Hides the tile associated with {@link #mRunningTaskId}
*/
public void setRunningTaskHidden(boolean isHidden) {
mRunningTaskTileHidden = isHidden;
- TaskView runningTask = getTaskView(mRunningTaskId);
+ TaskView runningTask = getRunningTaskView();
if (runningTask != null) {
runningTask.setAlpha(isHidden ? 0 : mContentAlpha);
}
@@ -713,20 +743,20 @@
boolean runningTaskTileHidden = mRunningTaskTileHidden;
boolean runningTaskIconScaledDown = mRunningTaskIconScaledDown;
- setRunningTaskIconScaledDown(false, false);
+ setRunningTaskIconScaledDown(false);
setRunningTaskHidden(false);
mRunningTaskId = runningTaskId;
- setRunningTaskIconScaledDown(runningTaskIconScaledDown, false);
+ setRunningTaskIconScaledDown(runningTaskIconScaledDown);
setRunningTaskHidden(runningTaskTileHidden);
setCurrentPage(0);
// Load the tasks (if the loading is already
- mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan);
+ mTaskListChangeId = mModel.getTasks(this::applyLoadPlan);
}
public void showNextTask() {
- TaskView runningTaskView = getTaskView(mRunningTaskId);
+ TaskView runningTaskView = getRunningTaskView();
if (runningTaskView == null) {
// Launch the first task
if (getTaskViewCount() > 0) {
@@ -746,26 +776,60 @@
return mQuickScrubController;
}
- public void setRunningTaskIconScaledDown(boolean isScaledDown, boolean animate) {
- if (mRunningTaskIconScaledDown == isScaledDown) {
- return;
+ public void setRunningTaskIconScaledDown(boolean isScaledDown) {
+ if (mRunningTaskIconScaledDown != isScaledDown) {
+ mRunningTaskIconScaledDown = isScaledDown;
+ applyRunningTaskIconScale();
}
- mRunningTaskIconScaledDown = isScaledDown;
- applyIconScale(animate);
}
- private void applyIconScale(boolean animate) {
- float scale = mRunningTaskIconScaledDown ? 0 : 1;
- TaskView firstTask = getTaskView(mRunningTaskId);
+ private void applyRunningTaskIconScale() {
+ TaskView firstTask = getRunningTaskView();
if (firstTask != null) {
- if (animate) {
- firstTask.animateIconToScaleAndDim(scale);
- } else {
- firstTask.setIconScaleAndDim(scale);
- }
+ firstTask.setIconScaleAndDim(mRunningTaskIconScaledDown ? 0 : 1);
}
}
+ public void animateUpRunningTaskIconScale() {
+ mRunningTaskIconScaledDown = false;
+ TaskView firstTask = getRunningTaskView();
+ if (firstTask != null) {
+ firstTask.animateIconScaleAndDimIntoView();
+ }
+ }
+
+ private void enableLayoutTransitions() {
+ if (mLayoutTransition == null) {
+ mLayoutTransition = new LayoutTransition();
+ mLayoutTransition.enableTransitionType(LayoutTransition.APPEARING);
+ mLayoutTransition.setDuration(ADDITION_TASK_DURATION);
+ mLayoutTransition.setStartDelay(LayoutTransition.APPEARING, 0);
+
+ mLayoutTransition.addTransitionListener(new TransitionListener() {
+ @Override
+ public void startTransition(LayoutTransition transition, ViewGroup viewGroup,
+ View view, int i) {
+ }
+
+ @Override
+ public void endTransition(LayoutTransition transition, ViewGroup viewGroup,
+ View view, int i) {
+ // When the unpinned task is added, snap to first page and disable transitions
+ if (view instanceof TaskView) {
+ snapToPage(0);
+ disableLayoutTransitions();
+ }
+
+ }
+ });
+ }
+ setLayoutTransition(mLayoutTransition);
+ }
+
+ private void disableLayoutTransitions() {
+ setLayoutTransition(null);
+ }
+
public void setSwipeDownShouldLaunchApp(boolean swipeDownShouldLaunchApp) {
mSwipeDownShouldLaunchApp = swipeDownShouldLaunchApp;
}
@@ -796,12 +860,14 @@
public float scrollFromEdge;
}
- public void addIgnoreResetTask(TaskView taskView) {
- mIgnoreResetTaskViews.add(taskView);
+ public void setIgnoreResetTask(int taskId) {
+ mIgnoreResetTaskId = taskId;
}
- public void removeIgnoreResetTask(TaskView taskView) {
- mIgnoreResetTaskViews.remove(taskView);
+ public void clearIgnoreResetTask(int taskId) {
+ if (mIgnoreResetTaskId == taskId) {
+ mIgnoreResetTaskId = -1;
+ }
}
private void addDismissedTaskAnimations(View taskView, AnimatorSet anim, long duration) {
@@ -824,8 +890,8 @@
public PendingAnimation createTaskDismissAnimation(TaskView taskView, boolean animateTaskView,
boolean shouldRemoveTask, long duration) {
- if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) {
- throw new IllegalStateException("Another pending animation is still running");
+ if (mPendingAnimation != null) {
+ mPendingAnimation.finish(false, Touch.SWIPE);
}
AnimatorSet anim = new AnimatorSet();
PendingAnimation pendingAnimation = new PendingAnimation(anim);
@@ -909,7 +975,7 @@
if (getTaskViewCount() == 0) {
removeView(mClearAllButton);
- onAllTasksRemoved();
+ startHome();
} else {
snapToPageImmediately(pageToSnapTo);
}
@@ -935,12 +1001,10 @@
mPendingAnimation = pendingAnimation;
mPendingAnimation.addEndListener((onEndListener) -> {
if (onEndListener.isSuccess) {
- int taskViewCount = getTaskViewCount();
- for (int i = 0; i < taskViewCount; i++) {
- removeTask(getTaskViewAt(i).getTask(), -1, onEndListener, false);
- }
+ // Remove all the task views now
+ ActivityManagerWrapper.getInstance().removeAllRecentTasks();
removeAllViews();
- onAllTasksRemoved();
+ startHome();
}
mPendingAnimation = null;
});
@@ -1212,11 +1276,10 @@
int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - taskIndex);
if (otherAdjacentTaskIndex >= 0 && otherAdjacentTaskIndex < getPageCount()) {
- anim.play(ObjectAnimator.ofPropertyValuesHolder(getPageAt(otherAdjacentTaskIndex),
- new PropertyListBuilder()
- .translationX(mIsRtl ? -displacementX : displacementX)
- .scale(1)
- .build()));
+ anim.play(new PropertyListBuilder()
+ .translationX(mIsRtl ? -displacementX : displacementX)
+ .scale(1)
+ .build(getPageAt(otherAdjacentTaskIndex)));
}
}
return anim;
@@ -1225,11 +1288,10 @@
private Animator createAnimForChild(TaskView child, float[] toScaleAndTranslation) {
AnimatorSet anim = new AnimatorSet();
anim.play(ObjectAnimator.ofFloat(child, TaskView.ZOOM_SCALE, toScaleAndTranslation[0]));
- anim.play(ObjectAnimator.ofPropertyValuesHolder(child,
- new PropertyListBuilder()
- .translationX(toScaleAndTranslation[1])
- .translationY(toScaleAndTranslation[2])
- .build()));
+ anim.play(new PropertyListBuilder()
+ .translationX(toScaleAndTranslation[1])
+ .translationY(toScaleAndTranslation[2])
+ .build(child));
return anim;
}
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index 8b5e832..d2b3bcc 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -15,10 +15,10 @@
*/
package com.android.quickstep.views;
-import static android.support.v4.graphics.ColorUtils.setAlphaComponent;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import android.content.Context;
import android.graphics.Canvas;
@@ -140,7 +140,7 @@
int alpha = Math.round(Utilities.mapToRange(
mProgress, mMidProgress, 1, mMidAlpha, 0, ACCEL));
- mShelfColor = setAlphaComponent(mEndScrim, alpha);
+ mShelfColor = setColorAlphaBound(mEndScrim, alpha);
} else {
mDragHandleOffset += mShiftRange * (mMidProgress - mProgress);
@@ -148,12 +148,12 @@
int alpha = Math.round(
Utilities.mapToRange(mProgress, (float) 0, mMidProgress, (float) mEndAlpha,
(float) mMidAlpha, Interpolators.clampToProgress(ACCEL, 0.5f, 1f)));
- mShelfColor = setAlphaComponent(mEndScrim, alpha);
+ mShelfColor = setColorAlphaBound(mEndScrim, alpha);
int remainingScrimAlpha = Math.round(
Utilities.mapToRange(mProgress, (float) 0, mMidProgress, mMaxScrimAlpha,
(float) 0, LINEAR));
- mRemainingScreenColor = setAlphaComponent(mScrimColor, remainingScrimAlpha);
+ mRemainingScreenColor = setColorAlphaBound(mScrimColor, remainingScrimAlpha);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 6eb6854..667165b 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -22,7 +22,6 @@
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
@@ -34,15 +33,17 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
-import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.TaskSystemShortcut;
import com.android.quickstep.TaskUtils;
+import com.android.quickstep.views.IconView.OnScaleUpdateListener;
+
+import java.util.List;
/**
* Contains options for a recent task when long-pressing its icon.
@@ -51,22 +52,42 @@
private static final Rect sTempRect = new Rect();
- /** Note that these will be shown in order from top to bottom, if available for the task. */
- public static final TaskSystemShortcut[] MENU_OPTIONS = new TaskSystemShortcut[] {
- new TaskSystemShortcut.AppInfo(),
- new TaskSystemShortcut.SplitScreen(),
- new TaskSystemShortcut.Pin(),
- new TaskSystemShortcut.Install(),
+ private final OnScaleUpdateListener mTaskViewIconScaleListener = new OnScaleUpdateListener() {
+ @Override
+ public void onScaleUpdate(float scale) {
+ final Drawable drawable = mTaskIcon.getDrawable();
+ if (drawable instanceof FastBitmapDrawable) {
+ if (scale != ((FastBitmapDrawable) drawable).getScale()) {
+ mMenuIconDrawable.setScale(scale);
+ }
+ }
+ }
+ };
+
+ private final OnScaleUpdateListener mMenuIconScaleListener = new OnScaleUpdateListener() {
+ @Override
+ public void onScaleUpdate(float scale) {
+ final Drawable taskViewDrawable = mTaskView.getIconView().getDrawable();
+ if (taskViewDrawable instanceof FastBitmapDrawable) {
+ final float currentScale = ((FastBitmapDrawable) taskViewDrawable).getScale();
+ if (currentScale != scale) {
+ ((FastBitmapDrawable) taskViewDrawable).setScale(scale);
+ }
+ }
+ }
};
private static final int REVEAL_OPEN_DURATION = 150;
private static final int REVEAL_CLOSE_DURATION = 100;
+ private final float mThumbnailTopMargin;
private BaseDraggingActivity mActivity;
- private TextView mTaskIconAndName;
+ private TextView mTaskName;
+ private IconView mTaskIcon;
private AnimatorSet mOpenCloseAnimator;
private TaskView mTaskView;
private LinearLayout mOptionLayout;
+ private FastBitmapDrawable mMenuIconDrawable;
public TaskMenuView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -76,12 +97,14 @@
super(context, attrs, defStyleAttr);
mActivity = BaseDraggingActivity.fromContext(context);
+ mThumbnailTopMargin = getResources().getDimension(R.dimen.task_thumbnail_top_margin);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mTaskIconAndName = findViewById(R.id.task_icon_and_name);
+ mTaskName = findViewById(R.id.task_name);
+ mTaskIcon = findViewById(R.id.task_icon);
mOptionLayout = findViewById(R.id.menu_option_layout);
}
@@ -113,15 +136,29 @@
}
@Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ // Remove all scale listeners when menu is removed
+ mTaskView.getIconView().removeUpdateScaleListener(mTaskViewIconScaleListener);
+ mTaskIcon.removeUpdateScaleListener(mMenuIconScaleListener);
+ }
+
+ @Override
protected boolean isOfType(int type) {
return (type & TYPE_TASK_MENU) != 0;
}
- public static boolean showForTask(TaskView taskView) {
+ public void setPosition(float x, float y) {
+ setX(x);
+ setY(y + mThumbnailTopMargin);
+ }
+
+ public static TaskMenuView showForTask(TaskView taskView) {
BaseDraggingActivity activity = BaseDraggingActivity.fromContext(taskView.getContext());
final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate(
R.layout.task_menu, activity.getDragLayer(), false);
- return taskMenuView.populateAndShowForTask(taskView);
+ return taskMenuView.populateAndShowForTask(taskView) ? taskMenuView : null;
}
private boolean populateAndShowForTask(TaskView taskView) {
@@ -138,31 +175,37 @@
private void addMenuOptions(TaskView taskView) {
Drawable icon = taskView.getTask().icon.getConstantState().newDrawable();
- int iconSize = getResources().getDimensionPixelSize(R.dimen.task_thumbnail_icon_size);
- icon.setBounds(0, 0, iconSize, iconSize);
- mTaskIconAndName.setCompoundDrawables(null, icon, null, null);
- mTaskIconAndName.setText(TaskUtils.getTitle(getContext(), taskView.getTask()));
- mTaskIconAndName.setOnClickListener(v -> close(true));
+ mTaskIcon.setDrawable(icon);
+ mTaskIcon.setOnClickListener(v -> close(true));
+ mTaskName.setText(TaskUtils.getTitle(getContext(), taskView.getTask()));
+ mTaskName.setOnClickListener(v -> close(true));
+
+ // Set the icons to match scale by listening to each other's changes
+ mMenuIconDrawable = icon instanceof FastBitmapDrawable ? (FastBitmapDrawable) icon : null;
+ taskView.getIconView().addUpdateScaleListener(mTaskViewIconScaleListener);
+ mTaskIcon.addUpdateScaleListener(mMenuIconScaleListener);
// Move the icon and text up half an icon size to lay over the TaskView
LinearLayout.LayoutParams params =
- (LinearLayout.LayoutParams) mTaskIconAndName.getLayoutParams();
- params.topMargin = (int) -getResources().getDimension(R.dimen.task_thumbnail_top_margin);
- mTaskIconAndName.setLayoutParams(params);
+ (LinearLayout.LayoutParams) mTaskIcon.getLayoutParams();
+ params.topMargin = (int) -mThumbnailTopMargin;
+ mTaskIcon.setLayoutParams(params);
- for (TaskSystemShortcut menuOption : MENU_OPTIONS) {
- OnClickListener onClickListener = menuOption.getOnClickListener(mActivity, taskView);
- if (onClickListener != null) {
- addMenuOption(menuOption, onClickListener);
- }
+ final BaseDraggingActivity activity = BaseDraggingActivity.fromContext(getContext());
+ final List<TaskSystemShortcut> shortcuts =
+ taskView.getTaskOverlay().getEnabledShortcuts(taskView);
+ final int count = shortcuts.size();
+ for (int i = 0; i < count; ++i) {
+ final TaskSystemShortcut menuOption = shortcuts.get(i);
+ addMenuOption(menuOption, menuOption.getOnClickListener(activity, taskView));
}
}
private void addMenuOption(TaskSystemShortcut menuOption, OnClickListener onClickListener) {
ViewGroup menuOptionView = (ViewGroup) mActivity.getLayoutInflater().inflate(
R.layout.task_view_menu_option, this, false);
- menuOptionView.findViewById(R.id.icon).setBackgroundResource(menuOption.iconResId);
- ((TextView) menuOptionView.findViewById(R.id.text)).setText(menuOption.labelResId);
+ menuOption.setIconAndLabelFor(
+ menuOptionView.findViewById(R.id.icon), menuOptionView.findViewById(R.id.text));
menuOptionView.setOnClickListener(onClickListener);
mOptionLayout.addView(menuOptionView);
}
@@ -172,12 +215,12 @@
mActivity.getDragLayer().getDescendantRectRelativeToSelf(taskView, sTempRect);
Rect insets = mActivity.getDragLayer().getInsets();
BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
- params.width = sTempRect.width();
- params.gravity = Gravity.LEFT;
+ params.width = taskView.getMeasuredWidth();
+ params.gravity = Gravity.START;
setLayoutParams(params);
- setX(sTempRect.left - insets.left);
- setY(sTempRect.top + getResources().getDimension(R.dimen.task_thumbnail_top_margin)
- - insets.top);
+ setScaleX(taskView.getScaleX());
+ setScaleY(taskView.getScaleY());
+ setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top);
}
private void animateOpen() {
@@ -191,9 +234,9 @@
private void animateOpenOrClosed(boolean closing) {
if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
- return;
+ mOpenCloseAnimator.end();
}
- mOpenCloseAnimator = LauncherAnimUtils.createAnimatorSet();
+ mOpenCloseAnimator = new AnimatorSet();
final Animator revealAnimator = createOpenCloseOutlineProvider()
.createRevealAnimator(this, closing);
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index fb653cf..c92c8d6 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -17,7 +17,6 @@
package com.android.quickstep.views;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
-
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
@@ -33,7 +32,7 @@
import android.util.FloatProperty;
import android.util.Property;
import android.view.View;
-
+import android.view.ViewGroup;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
@@ -54,19 +53,6 @@
private static final LightingColorFilter[] sDimFilterCache = new LightingColorFilter[256];
private static final LightingColorFilter[] sHighlightFilterCache = new LightingColorFilter[256];
- public static final Property<TaskThumbnailView, Float> DIM_ALPHA_MULTIPLIER =
- new FloatProperty<TaskThumbnailView>("dimAlphaMultiplier") {
- @Override
- public void setValue(TaskThumbnailView thumbnail, float dimAlphaMultiplier) {
- thumbnail.setDimAlphaMultipler(dimAlphaMultiplier);
- }
-
- @Override
- public Float get(TaskThumbnailView thumbnailView) {
- return thumbnailView.mDimAlphaMultiplier;
- }
- };
-
public static final Property<TaskThumbnailView, Float> DIM_ALPHA =
new FloatProperty<TaskThumbnailView>("dimAlpha") {
@Override
@@ -91,6 +77,7 @@
private final Matrix mMatrix = new Matrix();
private float mClipBottom = -1;
+ private Rect mScaledInsets = new Rect();
private Task mTask;
private ThumbnailData mThumbnailData;
@@ -186,9 +173,23 @@
return 0;
}
+ public TaskOverlay getTaskOverlay() {
+ return mOverlay;
+ }
+
@Override
protected void onDraw(Canvas canvas) {
- drawOnCanvas(canvas, 0, 0, getMeasuredWidth(), getMeasuredHeight(), mCornerRadius);
+ if (((TaskView) getParent()).isFullscreen()) {
+ // Draw the insets if we're being drawn fullscreen (we do this for quick switch).
+ drawOnCanvas(canvas,
+ -mScaledInsets.left,
+ -mScaledInsets.top,
+ getMeasuredWidth() + mScaledInsets.right,
+ getMeasuredHeight() + mScaledInsets.bottom,
+ mCornerRadius);
+ } else {
+ drawOnCanvas(canvas, 0, 0, getMeasuredWidth(), getMeasuredHeight(), mCornerRadius);
+ }
}
public float getCornerRadius() {
@@ -262,6 +263,9 @@
: getMeasuredWidth() / thumbnailWidth;
}
+ mScaledInsets.set(thumbnailInsets);
+ Utilities.scaleRect(mScaledInsets, thumbnailScale);
+
if (rotate) {
int rotationDir = profile.isVerticalBarLayout() && !profile.isSeascape() ? -1 : 1;
mMatrix.setRotate(90 * rotationDir);
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 508e5bb..9aaaf9c 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -18,16 +18,21 @@
import static android.widget.Toast.LENGTH_SHORT;
-import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA_MULTIPLIER;
+import static com.android.launcher3.BaseActivity.fromContext;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.app.ActivityOptions;
+import android.content.ActivityNotFoundException;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Outline;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.util.AttributeSet;
@@ -40,26 +45,32 @@
import android.widget.FrameLayout;
import android.widget.Toast;
-import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.Launcher;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.quickstep.RecentsModel;
+import com.android.quickstep.TaskIconCache;
+import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskSystemShortcut;
+import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.views.RecentsView.PageCallbacks;
import com.android.quickstep.views.RecentsView.ScrollState;
import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.Task.TaskCallbacks;
-import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.ActivityOptionsCompat;
+import java.util.List;
import java.util.function.Consumer;
/**
* A task in the Recents view.
*/
-public class TaskView extends FrameLayout implements TaskCallbacks, PageCallbacks {
+public class TaskView extends FrameLayout implements PageCallbacks {
private static final String TAG = TaskView.class.getSimpleName();
@@ -76,7 +87,7 @@
/**
* How much to scale down pages near the edge of the screen.
*/
- private static final float EDGE_SCALE_DOWN_FACTOR = 0.03f;
+ public static final float EDGE_SCALE_DOWN_FACTOR = 0.03f;
public static final long SCALE_ICON_DURATION = 120;
private static final long DIM_ANIM_DURATION = 700;
@@ -94,12 +105,53 @@
}
};
+ private static final FloatProperty<TaskView> FOCUS_TRANSITION =
+ new FloatProperty<TaskView>("focusTransition") {
+ @Override
+ public void setValue(TaskView taskView, float v) {
+ taskView.setIconAndDimTransitionProgress(v);
+ }
+
+ @Override
+ public Float get(TaskView taskView) {
+ return taskView.mFocusTransitionProgress;
+ }
+ };
+
+ static final Intent SEE_TIME_IN_APP_TEMPLATE =
+ new Intent("com.android.settings.action.TIME_SPENT_IN_APP");
+
+ private final OnAttachStateChangeListener mTaskMenuStateListener =
+ new OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View view) {
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View view) {
+ if (mMenuView != null) {
+ mMenuView.removeOnAttachStateChangeListener(this);
+ mMenuView = null;
+ }
+ }
+ };
+
private Task mTask;
private TaskThumbnailView mSnapshotView;
+ private TaskMenuView mMenuView;
private IconView mIconView;
private float mCurveScale;
private float mZoomScale;
- private Animator mDimAlphaAnim;
+ private boolean mIsFullscreen;
+
+ private Animator mIconAndDimAnimator;
+ private float mFocusTransitionProgress = 1;
+
+ // The current background requests to load the task thumbnail and icon
+ private TaskThumbnailCache.ThumbnailLoadRequest mThumbnailLoadRequest;
+ private TaskIconCache.IconLoadRequest mIconLoadRequest;
+
+ private long mAppRemainingTimeMs = -1;
public TaskView(Context context) {
this(context, null);
@@ -116,9 +168,12 @@
return;
}
launchTask(true /* animate */);
- BaseActivity.fromContext(context).getUserEventDispatcher().logTaskLaunchOrDismiss(
+
+ fromContext(context).getUserEventDispatcher().logTaskLaunchOrDismiss(
Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this),
TaskUtils.getLaunchComponentKeyForTask(getTask().key));
+ fromContext(context).getStatsLogManager().logTaskLaunch(getRecentsView(),
+ TaskUtils.getLaunchComponentKeyForTask(getTask().key));
});
setOutlineProvider(new TaskOutlineProvider(getResources()));
}
@@ -134,13 +189,8 @@
* Updates this task view to the given {@param task}.
*/
public void bind(Task task) {
- if (mTask != null) {
- mTask.removeCallback(this);
- }
mTask = task;
mSnapshotView.bind();
- task.addCallback(this);
- setContentDescription(task.titleDescription);
}
public Task getTask() {
@@ -155,6 +205,14 @@
return mIconView;
}
+ public TaskOverlayFactory.TaskOverlay getTaskOverlay() {
+ return mSnapshotView.getTaskOverlay();
+ }
+
+ private boolean hasRemainingTime() {
+ return mAppRemainingTimeMs > 0;
+ }
+
public void launchTask(boolean animate) {
launchTask(animate, (result) -> {
if (!result) {
@@ -168,61 +226,114 @@
if (mTask != null) {
final ActivityOptions opts;
if (animate) {
- opts = BaseDraggingActivity.fromContext(getContext())
+ opts = ((BaseDraggingActivity) fromContext(getContext()))
.getActivityLaunchOptions(this);
+ ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key,
+ opts, resultCallback, resultCallbackHandler);
} else {
- opts = ActivityOptions.makeCustomAnimation(getContext(), 0, 0);
+ opts = ActivityOptionsCompat.makeCustomAnimation(getContext(), 0, 0, () -> {
+ if (resultCallback != null) {
+ // Only post the animation start after the system has indicated that the
+ // transition has started
+ resultCallbackHandler.post(() -> resultCallback.accept(true));
+ }
+ }, resultCallbackHandler);
+ ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key,
+ opts, (success) -> {
+ if (resultCallback != null && !success) {
+ // If the call to start activity failed, then post the result
+ // immediately, otherwise, wait for the animation start callback
+ // from the activity options above
+ resultCallbackHandler.post(() -> resultCallback.accept(false));
+ }
+ }, resultCallbackHandler);
}
- ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key,
- opts, resultCallback, resultCallbackHandler);
}
}
- @Override
- public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) {
- mSnapshotView.setThumbnail(task, thumbnailData);
- mIconView.setDrawable(task.icon);
- mIconView.setOnClickListener(icon -> TaskMenuView.showForTask(this));
- mIconView.setOnLongClickListener(icon -> {
- requestDisallowInterceptTouchEvent(true);
- return TaskMenuView.showForTask(this);
- });
+ public void onTaskListVisibilityChanged(boolean visible) {
+ if (mTask == null) {
+ return;
+ }
+ if (visible) {
+ // These calls are no-ops if the data is already loaded, try and load the high
+ // resolution thumbnail if the state permits
+ RecentsModel model = RecentsModel.INSTANCE.get(getContext());
+ TaskThumbnailCache thumbnailCache = model.getThumbnailCache();
+ TaskIconCache iconCache = model.getIconCache();
+ mThumbnailLoadRequest = thumbnailCache.updateThumbnailInBackground(mTask,
+ !thumbnailCache.getHighResLoadingState().isEnabled() /* reducedResolution */,
+ (task) -> mSnapshotView.setThumbnail(task, task.thumbnail));
+ mIconLoadRequest = iconCache.updateIconInBackground(mTask,
+ (task) -> {
+ setContentDescription(task.titleDescription);
+ setIcon(task.icon);
+ });
+ } else {
+ if (mThumbnailLoadRequest != null) {
+ mThumbnailLoadRequest.cancel();
+ }
+ if (mIconLoadRequest != null) {
+ mIconLoadRequest.cancel();
+ }
+ mSnapshotView.setThumbnail(null, null);
+ setIcon(null);
+ }
}
- @Override
- public void onTaskDataUnloaded() {
- mSnapshotView.setThumbnail(null, null);
- mIconView.setDrawable(null);
- mIconView.setOnLongClickListener(null);
+ private boolean showTaskMenu() {
+ getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
+ mMenuView = TaskMenuView.showForTask(this);
+ if (mMenuView != null) {
+ mMenuView.addOnAttachStateChangeListener(mTaskMenuStateListener);
+ }
+ return mMenuView != null;
}
- @Override
- public void onTaskWindowingModeChanged() {
- // Do nothing
+ private void setIcon(Drawable icon) {
+ if (icon != null) {
+ mIconView.setDrawable(icon);
+ mIconView.setOnClickListener(v -> showTaskMenu());
+ mIconView.setOnLongClickListener(v -> {
+ requestDisallowInterceptTouchEvent(true);
+ return showTaskMenu();
+ });
+ } else {
+ mIconView.setDrawable(null);
+ mIconView.setOnClickListener(null);
+ mIconView.setOnLongClickListener(null);
+ }
}
- public void animateIconToScaleAndDim(float scale) {
- mIconView.animate().scaleX(scale).scaleY(scale).setDuration(SCALE_ICON_DURATION).start();
- mDimAlphaAnim = ObjectAnimator.ofFloat(mSnapshotView, DIM_ALPHA_MULTIPLIER, 1 - scale,
- scale);
- mDimAlphaAnim.setDuration(DIM_ANIM_DURATION);
- mDimAlphaAnim.addListener(new AnimatorListenerAdapter() {
+ private void setIconAndDimTransitionProgress(float progress) {
+ mFocusTransitionProgress = progress;
+ mSnapshotView.setDimAlphaMultipler(progress);
+ float scale = FAST_OUT_SLOW_IN.getInterpolation(Utilities.boundToRange(
+ progress * DIM_ANIM_DURATION / SCALE_ICON_DURATION, 0, 1));
+ mIconView.setScaleX(scale);
+ mIconView.setScaleY(scale);
+ }
+
+ public void animateIconScaleAndDimIntoView() {
+ if (mIconAndDimAnimator != null) {
+ mIconAndDimAnimator.cancel();
+ }
+ mIconAndDimAnimator = ObjectAnimator.ofFloat(this, FOCUS_TRANSITION, 1);
+ mIconAndDimAnimator.setDuration(DIM_ANIM_DURATION).setInterpolator(LINEAR);
+ mIconAndDimAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mDimAlphaAnim = null;
+ mIconAndDimAnimator = null;
}
});
- mDimAlphaAnim.start();
+ mIconAndDimAnimator.start();
}
protected void setIconScaleAndDim(float iconScale) {
- mIconView.animate().cancel();
- mIconView.setScaleX(iconScale);
- mIconView.setScaleY(iconScale);
- if (mDimAlphaAnim != null) {
- mDimAlphaAnim.cancel();
+ if (mIconAndDimAnimator != null) {
+ mIconAndDimAnimator.cancel();
}
- mSnapshotView.setDimAlphaMultipler(iconScale);
+ setIconAndDimTransitionProgress(iconScale);
}
public void resetVisualProperties() {
@@ -241,6 +352,12 @@
mSnapshotView.setDimAlpha(curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
setCurveScale(getCurveScaleForCurveInterpolation(curveInterpolation));
+
+ if (mMenuView != null) {
+ mMenuView.setPosition(getX() - getRecentsView().getScrollX(), getY());
+ mMenuView.setScaleX(getScaleX());
+ mMenuView.setScaleY(getScaleY());
+ }
}
@Override
@@ -311,15 +428,25 @@
getContext().getText(R.string.accessibility_close_task)));
final Context context = getContext();
- final BaseDraggingActivity activity = BaseDraggingActivity.fromContext(context);
- for (TaskSystemShortcut menuOption : TaskMenuView.MENU_OPTIONS) {
+ final BaseDraggingActivity activity = fromContext(context);
+ final List<TaskSystemShortcut> shortcuts =
+ mSnapshotView.getTaskOverlay().getEnabledShortcuts(this);
+ final int count = shortcuts.size();
+ for (int i = 0; i < count; ++i) {
+ final TaskSystemShortcut menuOption = shortcuts.get(i);
OnClickListener onClickListener = menuOption.getOnClickListener(activity, this);
if (onClickListener != null) {
- info.addAction(new AccessibilityNodeInfo.AccessibilityAction(menuOption.labelResId,
- context.getText(menuOption.labelResId)));
+ info.addAction(menuOption.createAccessibilityAction(context));
}
}
+ if (hasRemainingTime()) {
+ info.addAction(
+ new AccessibilityNodeInfo.AccessibilityAction(
+ R.string.accessibility_app_usage_settings,
+ getContext().getText(R.string.accessibility_app_usage_settings)));
+ }
+
final RecentsView recentsView = getRecentsView();
final AccessibilityNodeInfo.CollectionItemInfo itemInfo =
AccessibilityNodeInfo.CollectionItemInfo.obtain(
@@ -336,10 +463,19 @@
return true;
}
- for (TaskSystemShortcut menuOption : TaskMenuView.MENU_OPTIONS) {
- if (action == menuOption.labelResId) {
+ if (action == R.string.accessibility_app_usage_settings) {
+ openAppUsageSettings(this);
+ return true;
+ }
+
+ final List<TaskSystemShortcut> shortcuts =
+ mSnapshotView.getTaskOverlay().getEnabledShortcuts(this);
+ final int count = shortcuts.size();
+ for (int i = 0; i < count; ++i) {
+ final TaskSystemShortcut menuOption = shortcuts.get(i);
+ if (menuOption.hasHandlerForAction(action)) {
OnClickListener onClickListener = menuOption.getOnClickListener(
- BaseDraggingActivity.fromContext(getContext()), this);
+ fromContext(getContext()), this);
if (onClickListener != null) {
onClickListener.onClick(this);
}
@@ -350,6 +486,24 @@
return super.performAccessibilityAction(action, arguments);
}
+ private void openAppUsageSettings(View view) {
+ final Intent intent = new Intent(SEE_TIME_IN_APP_TEMPLATE)
+ .putExtra(Intent.EXTRA_PACKAGE_NAME,
+ mTask.getTopComponent().getPackageName()).addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ try {
+ final Launcher launcher = Launcher.getLauncher(getContext());
+ final ActivityOptions options = ActivityOptions.makeScaleUpAnimation(view, 0, 0,
+ view.getWidth(), view.getHeight());
+ launcher.startActivity(intent, options.toBundle());
+ launcher.getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.Touch.TAP,
+ LauncherLogProto.ControlType.APP_USAGE_SETTINGS, this);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "Failed to open app usage settings for task "
+ + mTask.getTopComponent().getPackageName(), e);
+ }
+ }
+
private RecentsView getRecentsView() {
return (RecentsView) getParent();
}
@@ -362,4 +516,18 @@
Log.w(tag, msg);
Toast.makeText(getContext(), R.string.activity_not_available, LENGTH_SHORT).show();
}
+
+ /**
+ * Hides the icon and shows insets when this TaskView is about to be shown fullscreen.
+ */
+ public void setFullscreen(boolean isFullscreen) {
+ mIsFullscreen = isFullscreen;
+ mIconView.setVisibility(mIsFullscreen ? INVISIBLE : VISIBLE);
+ setClipChildren(!mIsFullscreen);
+ setClipToPadding(!mIsFullscreen);
+ }
+
+ public boolean isFullscreen() {
+ return mIsFullscreen;
+ }
}
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
new file mode 100644
index 0000000..6854aa8
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.quickstep;
+
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+
+/**
+ * Base class for all instrumentation tests that deal with Quickstep.
+ */
+public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest {
+ @Rule
+ public TestRule mQuickstepOnOffExecutor =
+ new QuickStepOnOffRule(mMainThreadExecutor, mLauncher);
+}
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
new file mode 100644
index 0000000..88b50d9
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.quickstep;
+
+import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+
+import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
+import static com.android.launcher3.tapl.TestHelpers.getHomeIntentInPackage;
+import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess;
+import static com.android.launcher3.util.rule.ShellCommandRule.disableHeadsUpNotification;
+import static com.android.launcher3.util.rule.ShellCommandRule.getLauncherCommand;
+import static com.android.quickstep.QuickStepOnOffRule.Mode.OFF;
+
+import static org.junit.Assert.assertTrue;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.testcomponent.TestCommandReceiver;
+import com.android.quickstep.QuickStepOnOffRule.QuickstepOnOff;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.model.Statement;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+/**
+ * TODO: Fix fallback when quickstep is enabled
+ */
+public class FallbackRecentsTest {
+
+ private final UiDevice mDevice;
+ private final LauncherInstrumentation mLauncher;
+ private final ActivityInfo mOtherLauncherActivity;
+
+ @Rule public final TestRule mDisableHeadsUpNotification = disableHeadsUpNotification();
+ @Rule public final TestRule mQuickstepOnOffExecutor;
+
+ @Rule public final TestRule mSetLauncherCommand;
+
+ public FallbackRecentsTest() {
+ Instrumentation instrumentation = getInstrumentation();
+ Context context = instrumentation.getContext();
+ mDevice = UiDevice.getInstance(instrumentation);
+ mLauncher = new LauncherInstrumentation(instrumentation);
+
+ mQuickstepOnOffExecutor = new QuickStepOnOffRule(new MainThreadExecutor(), mLauncher);
+ mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
+ getHomeIntentInPackage(context),
+ MATCH_DISABLED_COMPONENTS).get(0).activityInfo;
+
+ mSetLauncherCommand = (base, desc) -> new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ TestCommandReceiver.callCommand(TestCommandReceiver.ENABLE_TEST_LAUNCHER);
+ UiDevice.getInstance(getInstrumentation()).executeShellCommand(
+ getLauncherCommand(mOtherLauncherActivity));
+ try {
+ base.evaluate();
+ } finally {
+ TestCommandReceiver.callCommand(TestCommandReceiver.DISABLE_TEST_LAUNCHER);
+ UiDevice.getInstance(getInstrumentation()).executeShellCommand(
+ getLauncherCommand(getLauncherInMyProcess()));
+ }
+ }
+ };
+ }
+
+ @QuickstepOnOff(mode = OFF)
+ @Test
+ public void goToOverviewFromHome() {
+ mDevice.pressHome();
+ assertTrue("Fallback Launcher not visible", mDevice.wait(Until.hasObject(By.pkg(
+ mOtherLauncherActivity.packageName)), WAIT_TIME_MS));
+
+ mLauncher.getBackground().switchToOverview();
+ }
+
+ @QuickstepOnOff(mode = OFF)
+ @Test
+ public void goToOverviewFromApp() {
+ startAppFast("com.android.settings");
+
+ mLauncher.getBackground().switchToOverview();
+ }
+
+ private void startAppFast(String packageName) {
+ final Instrumentation instrumentation = getInstrumentation();
+ final Intent intent = instrumentation.getContext().getPackageManager().
+ getLaunchIntentForPackage(packageName);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ instrumentation.getTargetContext().startActivity(intent);
+ assertTrue(packageName + " didn't start",
+ mDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), WAIT_TIME_MS));
+ }
+
+}
diff --git a/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java b/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
new file mode 100644
index 0000000..b801b4f
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
@@ -0,0 +1,104 @@
+/*
+ * 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.quickstep;
+
+import static com.android.quickstep.QuickStepOnOffRule.Mode.BOTH;
+import static com.android.quickstep.QuickStepOnOffRule.Mode.OFF;
+import static com.android.quickstep.QuickStepOnOffRule.Mode.ON;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.tapl.TestHelpers;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.concurrent.Executor;
+
+/**
+ * Test rule that allows executing a test with Quickstep on and then Quickstep off.
+ * The test should be annotated with @QuickstepOnOff.
+ */
+public class QuickStepOnOffRule implements TestRule {
+
+ public enum Mode {
+ ON, OFF, BOTH
+ }
+
+ // Annotation for tests that need to be run with quickstep enabled and disabled.
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ public @interface QuickstepOnOff {
+ Mode mode() default BOTH;
+ }
+
+ private final Executor mMainThreadExecutor;
+ private final LauncherInstrumentation mLauncher;
+
+ public QuickStepOnOffRule(Executor mainThreadExecutor, LauncherInstrumentation launcher) {
+ mLauncher = launcher;
+ this.mMainThreadExecutor = mainThreadExecutor;
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ if (TestHelpers.isInLauncherProcess() &&
+ description.getAnnotation(QuickstepOnOff.class) != null) {
+ Mode mode = description.getAnnotation(QuickstepOnOff.class).mode();
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ if (mode == ON || mode == BOTH) {
+ evaluateWithQuickstepOn();
+ }
+ if (mode == OFF || mode == BOTH) {
+ evaluateWithQuickstepOff();
+ }
+ } finally {
+ overrideSwipeUpEnabled(null);
+ }
+ }
+
+ private void evaluateWithQuickstepOff() throws Throwable {
+ overrideSwipeUpEnabled(false);
+ base.evaluate();
+ }
+
+ private void evaluateWithQuickstepOn() throws Throwable {
+ overrideSwipeUpEnabled(true);
+ base.evaluate();
+ }
+
+ private void overrideSwipeUpEnabled(Boolean swipeUpEnabledOverride) {
+ mLauncher.overrideSwipeUpEnabled(swipeUpEnabledOverride);
+ mMainThreadExecutor.execute(() -> OverviewInteractionState.INSTANCE.get(
+ InstrumentationRegistry.getInstrumentation().getTargetContext()).
+ notifySwipeUpSettingChanged(mLauncher.isSwipeUpEnabled()));
+ }
+ };
+ } else {
+ return base;
+ }
+ }
+}
diff --git a/res/drawable-hdpi/ic_allapps.png b/res/drawable-hdpi/ic_allapps.png
deleted file mode 100644
index 253755f..0000000
--- a/res/drawable-hdpi/ic_allapps.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_allapps_pressed.png b/res/drawable-hdpi/ic_allapps_pressed.png
deleted file mode 100644
index 1e644c5..0000000
--- a/res/drawable-hdpi/ic_allapps_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_allapps.png b/res/drawable-mdpi/ic_allapps.png
deleted file mode 100644
index 6936b20..0000000
--- a/res/drawable-mdpi/ic_allapps.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_allapps_pressed.png b/res/drawable-mdpi/ic_allapps_pressed.png
deleted file mode 100644
index 850ded6..0000000
--- a/res/drawable-mdpi/ic_allapps_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-v26/adaptive_icon_drawable_wrapper.xml b/res/drawable-v26/ic_deepshortcut_placeholder.xml
similarity index 82%
copy from res/drawable-v26/adaptive_icon_drawable_wrapper.xml
copy to res/drawable-v26/ic_deepshortcut_placeholder.xml
index 2d78b69..3fa8506 100644
--- a/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
+++ b/res/drawable-v26/ic_deepshortcut_placeholder.xml
@@ -15,8 +15,6 @@
limitations under the License.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
- <background android:drawable="@color/legacy_icon_background"/>
- <foreground>
- <com.android.launcher3.graphics.FixedScaleDrawable />
- </foreground>
+ <background android:drawable="?attr/popupColorSecondary"/>
+ <foreground android:drawable="?attr/popupColorSecondary"/>
</adaptive-icon>
diff --git a/res/drawable-xhdpi/ic_allapps.png b/res/drawable-xhdpi/ic_allapps.png
deleted file mode 100644
index c11c103..0000000
--- a/res/drawable-xhdpi/ic_allapps.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_allapps_pressed.png b/res/drawable-xhdpi/ic_allapps_pressed.png
deleted file mode 100644
index f319bf1..0000000
--- a/res/drawable-xhdpi/ic_allapps_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_allapps.png b/res/drawable-xxhdpi/ic_allapps.png
deleted file mode 100644
index cf6a2cb..0000000
--- a/res/drawable-xxhdpi/ic_allapps.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_allapps_pressed.png b/res/drawable-xxhdpi/ic_allapps_pressed.png
deleted file mode 100644
index 379389a..0000000
--- a/res/drawable-xxhdpi/ic_allapps_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/all_apps_button_icon.xml b/res/drawable/all_apps_button_icon.xml
deleted file mode 100644
index 7c69cad..0000000
--- a/res/drawable/all_apps_button_icon.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="true" android:drawable="@drawable/ic_allapps_pressed" />
- <item android:state_pressed="true" android:drawable="@drawable/ic_allapps_pressed" />
- <item android:drawable="@drawable/ic_allapps" />
-</selector>
diff --git a/res/layout/all_apps_button.xml b/res/drawable/deep_shortcuts_text_placeholder.xml
similarity index 67%
copy from res/layout/all_apps_button.xml
copy to res/drawable/deep_shortcuts_text_placeholder.xml
index 4bc780a..99da50f 100644
--- a/res/layout/all_apps_button.xml
+++ b/res/drawable/deep_shortcuts_text_placeholder.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,5 +13,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<TextView style="@style/BaseIcon" />
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="?attr/popupColorSecondary" />
+ <corners android:radius="8dp" />
+ <size android:height="16dp" />
+</shape>
diff --git a/res/layout/all_apps_button.xml b/res/drawable/ic_deepshortcut_placeholder.xml
similarity index 67%
copy from res/layout/all_apps_button.xml
copy to res/drawable/ic_deepshortcut_placeholder.xml
index 4bc780a..85a9694 100644
--- a/res/layout/all_apps_button.xml
+++ b/res/drawable/ic_deepshortcut_placeholder.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,5 +13,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<TextView style="@style/BaseIcon" />
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <solid android:color="?attr/popupColorSecondary" />
+ <size
+ android:height="32dp"
+ android:width="32dp" />
+</shape>
diff --git a/res/drawable/qsb_host_view_focus_bg.xml b/res/drawable/qsb_host_view_focus_bg.xml
new file mode 100644
index 0000000..7300b6a
--- /dev/null
+++ b/res/drawable/qsb_host_view_focus_bg.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<!-- Used as the widget host view background when giving focus to a child via keyboard. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_selected="true">
+ <shape android:shape="rectangle">
+ <stroke android:color="#fff" android:width="2dp" />
+ </shape>
+ </item>
+ <item android:state_focused="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/focused_background" />
+ </shape>
+ </item>
+</selector>
\ No newline at end of file
diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml
index 6c316e6..830255b 100644
--- a/res/layout/add_item_confirmation_activity.xml
+++ b/res/layout/add_item_confirmation_activity.xml
@@ -44,7 +44,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/colorPrimaryDark"
- android:theme="@style/WidgetContainerTheme">
+ android:theme="?attr/widgetsTheme">
<com.android.launcher3.dragndrop.LivePreviewWidgetCell
android:id="@+id/widget_cell"
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 02d793e..33ff46b 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -26,9 +26,54 @@
android:focusable="false"
android:saveEnabled="false" >
- <include layout="@layout/all_apps_rv_layout" />
+ <include
+ layout="@layout/all_apps_rv_layout"
+ android:visibility="gone" />
- <include layout="@layout/all_apps_floating_header" />
+ <com.android.launcher3.allapps.FloatingHeaderView
+ android:id="@+id/all_apps_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/search_container_all_apps"
+ android:clipToPadding="false"
+ android:paddingTop="@dimen/all_apps_header_top_padding"
+ android:orientation="vertical" >
+
+ <include layout="@layout/floating_header_content" />
+
+ <com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
+ android:id="@+id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/all_apps_header_tab_height"
+ android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
+ android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/tab_personal"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground"
+ android:fontFamily="sans-serif-medium"
+ android:text="@string/all_apps_personal_tab"
+ android:textAllCaps="true"
+ android:textColor="@color/all_apps_tab_text"
+ android:textSize="14sp" />
+
+ <Button
+ android:id="@+id/tab_work"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground"
+ android:fontFamily="sans-serif-medium"
+ android:text="@string/all_apps_work_tab"
+ android:textAllCaps="true"
+ android:textColor="@color/all_apps_tab_text"
+ android:textSize="14sp" />
+ </com.android.launcher3.allapps.PersonalWorkSlidingTabStrip>
+ </com.android.launcher3.allapps.FloatingHeaderView>
<include
android:id="@id/search_container_all_apps"
diff --git a/res/layout/all_apps_floating_header.xml b/res/layout/all_apps_floating_header.xml
deleted file mode 100644
index c4240f8..0000000
--- a/res/layout/all_apps_floating_header.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<com.android.launcher3.allapps.FloatingHeaderView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/all_apps_header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/search_container_all_apps"
- android:clipToPadding="false"
- android:paddingTop="@dimen/all_apps_header_top_padding"
- android:orientation="vertical" >
-
- <com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
- android:id="@+id/tabs"
- android:layout_width="match_parent"
- android:layout_height="@dimen/all_apps_header_tab_height"
- android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
- android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
- android:orientation="horizontal">
-
- <Button
- android:id="@+id/tab_personal"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:background="?android:attr/selectableItemBackground"
- android:fontFamily="sans-serif-medium"
- android:text="@string/all_apps_personal_tab"
- android:textAllCaps="true"
- android:textColor="@color/all_apps_tab_text"
- android:textSize="14sp" />
-
- <Button
- android:id="@+id/tab_work"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:background="?android:attr/selectableItemBackground"
- android:fontFamily="sans-serif-medium"
- android:text="@string/all_apps_work_tab"
- android:textAllCaps="true"
- android:textColor="@color/all_apps_tab_text"
- android:textSize="14sp" />
- </com.android.launcher3.allapps.PersonalWorkSlidingTabStrip>
-</com.android.launcher3.allapps.FloatingHeaderView>
diff --git a/res/layout/deep_shortcut.xml b/res/layout/deep_shortcut.xml
index 4a2ad42..92f70e6 100644
--- a/res/layout/deep_shortcut.xml
+++ b/res/layout/deep_shortcut.xml
@@ -43,7 +43,8 @@
android:layout_width="@dimen/deep_shortcut_icon_size"
android:layout_height="@dimen/deep_shortcut_icon_size"
android:layout_marginStart="@dimen/popup_padding_start"
- android:layout_gravity="start|center_vertical" />
+ android:layout_gravity="start|center_vertical"
+ android:background="@drawable/ic_deepshortcut_placeholder"/>
<View
android:id="@+id/divider"
diff --git a/res/layout/all_apps_button.xml b/res/layout/floating_header_content.xml
similarity index 86%
rename from res/layout/all_apps_button.xml
rename to res/layout/floating_header_content.xml
index 4bc780a..e4061c2 100644
--- a/res/layout/all_apps_button.xml
+++ b/res/layout/floating_header_content.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- 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.
@@ -13,5 +13,4 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<TextView style="@style/BaseIcon" />
+<merge />
\ No newline at end of file
diff --git a/res/layout/hotseat.xml b/res/layout/hotseat.xml
deleted file mode 100644
index 00f0b5f..0000000
--- a/res/layout/hotseat.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<com.android.launcher3.Hotseat
- android:theme="@style/HomeScreenElementTheme"
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:launcher="http://schemas.android.com/apk/res-auto">
-
- <com.android.launcher3.CellLayout
- android:id="@+id/layout"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- launcher:containerType="hotseat"
- android:importantForAccessibility="no" />
-</com.android.launcher3.Hotseat>
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index 304d012..87078b9 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -56,22 +56,25 @@
android:id="@+id/drop_target_bar"
layout="@layout/drop_target_bar" />
- <include android:id="@+id/scrim_view"
+ <include
+ android:id="@+id/scrim_view"
layout="@layout/scrim_view" />
<include
android:id="@+id/apps_view"
layout="@layout/all_apps"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="invisible" />
+ android:layout_height="match_parent" />
<!-- DO NOT CHANGE THE ID -->
- <include
+ <com.android.launcher3.Hotseat
android:id="@+id/hotseat"
- layout="@layout/hotseat"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ android:theme="@style/HomeScreenElementTheme"
+ android:importantForAccessibility="no"
+ launcher:containerType="hotseat" />
+
</com.android.launcher3.dragndrop.DragLayer>
</com.android.launcher3.LauncherRootView>
diff --git a/res/layout/snackbar.xml b/res/layout/snackbar.xml
new file mode 100644
index 0000000..bca3308
--- /dev/null
+++ b/res/layout/snackbar.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <TextView
+ android:id="@+id/label"
+ android:layout_height="@dimen/snackbar_content_height"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:gravity="center_vertical"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:lines="1"
+ android:ellipsize="end"
+ android:textSize="@dimen/snackbar_max_text_size"
+ android:textColor="?android:attr/textColorPrimary"
+ android:theme="@style/TextTitle"/>
+ <TextView
+ android:id="@+id/action"
+ android:layout_height="@dimen/snackbar_content_height"
+ android:layout_width="wrap_content"
+ android:layout_weight="0"
+ android:gravity="center"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:background="?android:attr/selectableItemBackground"
+ android:textStyle="bold"
+ android:textSize="@dimen/snackbar_max_text_size"
+ android:textColor="?android:attr/colorAccent"
+ android:theme="@style/TextTitle"
+ android:capitalize="sentences"/>
+</merge>
\ No newline at end of file
diff --git a/res/layout/switch_preference_with_settings.xml b/res/layout/switch_preference_with_settings.xml
new file mode 100644
index 0000000..d319561
--- /dev/null
+++ b/res/layout/switch_preference_with_settings.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical">
+
+ <ImageView
+ android:id="@+id/settings"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_setting"
+ android:tint="@android:color/black"
+ android:padding="12dp"
+ android:background="?android:attr/selectableItemBackgroundBorderless" />
+
+ <View
+ android:id="@+id/divider"
+ android:layout_width="1dp"
+ android:layout_height="30dp"
+ android:layout_marginEnd="8dp"
+ android:background="?android:attr/listDivider" />
+
+ <!-- Note: seems we need focusable="false" and clickable="false" when moving to androidx -->
+ <Switch
+ android:id="@android:id/switch_widget"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@null" />
+</LinearLayout>
\ No newline at end of file
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 35539e3..56d198c 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Skuif item hierheen"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Item is by tuisskerm gevoeg"</string>
<string name="item_removed" msgid="851119963877842327">"Item is verwyder"</string>
+ <string name="undo" msgid="4151576204245173321">"Ontdoen"</string>
<string name="action_move" msgid="4339390619886385032">"Skuif item"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Skuif na ry <xliff:g id="NUMBER_0">%1$s</xliff:g> kolom <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Skuif na posisie <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Kennisgewings en programme is af"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Maak toe"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Toe"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Misluk: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 921fbd9..6716d27 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"ንጥልን ወደዚህ ውሰድ"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"ወደ መነሻ ማያ ገጽ ንጥል ታክሏል"</string>
<string name="item_removed" msgid="851119963877842327">"ንጥል ነገር ተንቀሳቅሷል"</string>
+ <string name="undo" msgid="4151576204245173321">"ቀልብስ"</string>
<string name="action_move" msgid="4339390619886385032">"ንጥልን አንቀሳቅስ"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"ወደ ረድፍ <xliff:g id="NUMBER_0">%1$s</xliff:g> ዓምድ <xliff:g id="NUMBER_1">%2$s</xliff:g> አንቀሳቅስ"</string>
<string name="move_to_position" msgid="6750008980455459790">"ወደ አቀማመጥ <xliff:g id="NUMBER">%1$s</xliff:g> አንቀሳቅስ"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"ማሳወቂያዎች እና መተግበሪያዎች ጠፍተዋል"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ዝጋ"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ዝግ"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"አልተሳካም፦ <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index ecf32d4..bebc7b3 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -118,6 +118,7 @@
<string name="action_move_here" msgid="2170188780612570250">"نقل العنصر إلى هنا"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"تمت إضافة العنصر إلى الشاشة الرئيسية"</string>
<string name="item_removed" msgid="851119963877842327">"تم حذف العنصر"</string>
+ <string name="undo" msgid="4151576204245173321">"تراجع"</string>
<string name="action_move" msgid="4339390619886385032">"نقل العنصر"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"نقل إلى الصف <xliff:g id="NUMBER_0">%1$s</xliff:g> العمود <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"نقل إلى الموضع <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -148,4 +149,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"الإشعارات والتطبيقات متوقفة."</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"إغلاق"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"تمّ الإغلاق"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"تعذَّر <xliff:g id="WHAT">%1$s</xliff:g>."</string>
</resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 5c896e4..f39c12e 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -108,14 +108,13 @@
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ডাউনল\'ড কৰি থকা হৈছে, <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পূৰ্ণ হ\'ল"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ইনষ্টল হোৱালৈ অপেক্ষা কৰি থকা হৈছে"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ৱিজেট"</string>
- <!-- no translation found for widgets_list (796804551140113767) -->
- <skip />
- <!-- no translation found for widgets_list_closed (6141506579418771922) -->
- <skip />
+ <string name="widgets_list" msgid="796804551140113767">"ৱিজেটৰ তালিকা"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"ৱিজেটৰ তালিকা বন্ধ কৰা হ\'ল"</string>
<string name="action_add_to_workspace" msgid="8902165848117513641">"গৃহ স্ক্ৰীণত যোগ কৰক"</string>
<string name="action_move_here" msgid="2170188780612570250">"বস্তুটো ইয়ালৈ স্থানান্তৰ কৰক"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"বস্তুটো গৃহ স্ক্ৰীণত যোগ কৰা হ\'ল"</string>
<string name="item_removed" msgid="851119963877842327">"বস্তুটো আঁতৰোৱা হ\'ল"</string>
+ <string name="undo" msgid="4151576204245173321">"আনডু কৰক"</string>
<string name="action_move" msgid="4339390619886385032">"বস্তু স্থানান্তৰ কৰক"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"শাৰী <xliff:g id="NUMBER_0">%1$s</xliff:g> স্তম্ভ <xliff:g id="NUMBER_1">%2$s</xliff:g>লৈ স্থানান্তৰিত কৰক"</string>
<string name="move_to_position" msgid="6750008980455459790">"পছন্দৰ অৱস্থান <xliff:g id="NUMBER">%1$s</xliff:g>লৈ স্থানান্তৰিত কৰক"</string>
@@ -146,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"জাননী আৰু এপসমূহ অফ হৈ আছে"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"বন্ধ কৰক"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"বন্ধ"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"বিফল: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml
deleted file mode 100644
index ed86f91..0000000
--- a/res/values-az-rAZ/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"İş"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Tətbiq quraşdırılmayıb."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Tətbiq əlçatmazdır"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Güvənli rejimdə icazə verilməyən tətbiq endirildi"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Vidcetlər Güvənli rejimdə deaktiv edilib"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Qısayol əlçatan deyil"</string>
- <string name="home_screen" msgid="806512411299847073">"Əsas ekran"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Fərdi əməliyyatlar"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Vidceti götürmək üçün toxunub saxlayın."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Vidceti götürmək üçün & iki dəfə toxunub saxlayın və ya fərdi fəaliyyətləri istifadə edin."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%2$d hündürlük %1$d enində"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Manual olaraq yerləşdirmək üçün toxunaraq basıb saxlayın"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Avtomatik əlavə edin"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tətbiqləri axtarın"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Tətbiqlər yüklənir…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"<xliff:g id="QUERY">%1$s</xliff:g> sorğusuna uyğun tətbiq tapılmadı"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Daha çox tətbiq üçün axtarış edin"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Bildirişlər"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Qısayolu seçmək üçün basıb saxlayın."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Qısayolu seçmək üçün iki dəfə basıb saxlayın və ya fərdi əməliyyatlardan istifadə edin."</string>
- <string name="out_of_space" msgid="4691004494942118364">"Bu Əsas ekranda boş yer yoxdur."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoritlər-də yer yoxdur"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Tətbiq siyahısı"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Şəxsi tətbiqlərin siyahısı"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"İş tətbiqlərinin siyahısı"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Əsas səhifə"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Silin"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Sistemdən sil"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Tətbiq məlumatı"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Quraşdırın"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"qısayolları quraşdır"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Tətbiqə istifadəçi müdaxiləsi olmadan qısayolları əlavə etməyə icazə verir."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"Əsas Səhifə ayarlarını və qısayolları oxuyun"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Tətbiqə Əsas Səhifədə parametrləri və qısayolları oxumağa icazə verir."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"Əsas Səhifə ayarlarını və qısayolları yazın"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Tətbiqə Əsas Səhifədə ayarları və qısayolları dəyişməyə icazə verir."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqinə telefon zəngləri etmək üçün icazə verilmir"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Vidcet yükləmə problemi"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Quraşdırma"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Bu sistem tətbiqi olduğu üçün sistemdən silinə bilməz."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Adsız Qovluq"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> deaktiv edildi"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> tətbiqində <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> bildiriş var</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> tətbiqində <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> bildiriş var</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"Səhifə %1$d of %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"Əsas Səhifə ekranı %1$d of %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Yeni əsas ekran səhifəsi"</string>
- <string name="folder_opened" msgid="94695026776264709">"Qovluq açıldı, <xliff:g id="HEIGHT">%2$d</xliff:g> hündürlük ilə <xliff:g id="WIDTH">%1$d</xliff:g> enində"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Qovluq bağlamaq üçün toxunun"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Ad dəyişikliyini yadda saxlamaq üçün toxunun"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Qovluq bağlıdır"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Qovluq adı <xliff:g id="NAME">%1$s</xliff:g> ilə dəyişdirildi"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Qovluq: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Vidcet"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Divar kağızları"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Home ayarları"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Admininiz tərəfindən deaktiv edilib"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Əsas ekranın firlanmağına icazə verin"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Telefon çevrilən zaman"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Bildiriş nişanı"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aktiv"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Deaktiv"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Bildiriş girişi tələb edilir"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Bildiriş Nöqtələrini göstərmək üçün <xliff:g id="NAME">%1$s</xliff:g> bildirişlərini aktiv edin"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Ayarları dəyişin"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Bildiriş nöqtələrini göstərin"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Əsas ekrana ikona əlavə edin"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Yeni tətbiqlər üçün"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"İkona formasını dəyişin"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"Əsas səhifə ekranında"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Sistem defoltu istifadə edin"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Kənarları dairəvi kvadrat"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Çevrə"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Gözyaşı damlası"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"İkona formasına etdiyiniz dəyişikliklər tətbiq edilir"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Naməlum"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Yığışdır"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Axtarış"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Bu tətbiq quraşdırılmayıb"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Bu ikona üçün tətbiq quraşdırılmayıb. Onu silə bilərsiniz, və ya tətbiqi taparaq manual yol ilə quraşdıra bilərsiniz."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> endirilir, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlandı"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> yüklənmək üçün gözləyir"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> vidcetləri"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Əsas ekrana əlavə edin"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Elementi bura köçürün"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Element əsas ekrana əlavə edildi"</string>
- <string name="item_removed" msgid="851119963877842327">"Element silindi"</string>
- <string name="action_move" msgid="4339390619886385032">"Elementi köçürün"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"Sıra <xliff:g id="NUMBER_0">%1$s</xliff:g> sütun <xliff:g id="NUMBER_1">%2$s</xliff:g> köçürün"</string>
- <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> mövqeyinə köçürün"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"<xliff:g id="NUMBER">%1$s</xliff:g> sevimlilər mövqeyinə köçürün"</string>
- <string name="item_moved" msgid="4606538322571412879">"Elementin yeri dəyişildi"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Qovluğa əlavə edin: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> adlı qovluğa əlavə edin"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Element qovluğa əlavə edildi"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Qovluq yaradın: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"Qovluq yaradıldı"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Əsas ekrana köçürün"</string>
- <string name="action_resize" msgid="1802976324781771067">"Ölçüsünü dəyişin"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Eni artırın"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Hündürlüyü artırın"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Eni azaldın"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Hündürlüyü azaldın"</string>
- <string name="widget_resized" msgid="9130327887929620">"Vidcetin eni <xliff:g id="NUMBER_0">%1$s</xliff:g> hündürlüyü <xliff:g id="NUMBER_1">%2$s</xliff:g> kimi ölçüləndirildi"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Qısa yollar"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> üçün <xliff:g id="APP_NAME">%2$s</xliff:g> qısa yolu"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> üçün <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> qısayol və <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> bildiriş"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Rədd edin"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Bildiriş rədd edildi"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Şəxsi"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"İş"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"İş profili"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Burada iş tətbiqləri axtarın"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Hər bir iş tətbiqində təşkilat tərəfindən qorunduğunu göstərən narıncı nişan var. Tətbiqləri daha asan giriş üçün Əsas Səhifə Ekranına köçürün."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Təşkilatınız tərəfindən idarə olunur"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Bildiriş və tətbiqlər deaktivdir"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Bağlayın"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Bağlıdır"</string>
-</resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 3b36f37..f8aba17 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Elementi bura köçürün"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Element əsas ekrana əlavə edildi"</string>
<string name="item_removed" msgid="851119963877842327">"Element silindi"</string>
+ <string name="undo" msgid="4151576204245173321">"Ləğv edin"</string>
<string name="action_move" msgid="4339390619886385032">"Elementi köçürün"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Sıra <xliff:g id="NUMBER_0">%1$s</xliff:g> sütun <xliff:g id="NUMBER_1">%2$s</xliff:g> köçürün"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> mövqeyinə köçürün"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Bildiriş və tətbiqlər deaktivdir"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Bağlayın"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Bağlıdır"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Alınmadı: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 3fb8bf5..d1a3fcc 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -115,6 +115,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Premesti stavku ovde"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Stavka je dodata na početni ekran"</string>
<string name="item_removed" msgid="851119963877842327">"Stavka je uklonjena"</string>
+ <string name="undo" msgid="4151576204245173321">"Opozovi"</string>
<string name="action_move" msgid="4339390619886385032">"Premesti stavku"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Premesti u red <xliff:g id="NUMBER_0">%1$s</xliff:g> i kolonu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Premesti na <xliff:g id="NUMBER">%1$s</xliff:g>. poziciju"</string>
@@ -145,4 +146,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Obaveštenja i aplikacije su isključeni"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zatvori"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zatvoreno"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Nije uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-be-rBY/strings.xml b/res/values-be-rBY/strings.xml
deleted file mode 100644
index 399ae76..0000000
--- a/res/values-be-rBY/strings.xml
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Працоўная"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Праграма не ўсталявана."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Праграма недаступная"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Спампаваная праграма адключана ў Бяспечным рэжыме"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Віджэты адключаны ў Бяспечным рэжыме"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Ярлык недаступны"</string>
- <string name="home_screen" msgid="806512411299847073">"Галоўны экран"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Спецыяльныя дзеянні"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Дакраніцеся і ўтрымлiвайце віджэт, каб выбр. яго."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Дакраніцеся двойчы і ўтрымлівайце, каб выбраць віджэт або выкарыстоўваць карыстальніцкія дзеянні."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Шырына: %1$d, вышыня: %2$d"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Каб размясціць уручную, дакраніцеся і ўтрымлівайце"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Дадаць аўтаматычна"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Пошук праграм"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Праграмы загружаюцца…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"Праграм, якія адпавядаюць запыту \"<xliff:g id="QUERY">%1$s</xliff:g>\", не знойдзена"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Шукаць іншыя праграмы"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Апавяшчэнні"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Дакраніцеся і ўтрымлiвайце ярлык, каб дадаць яго."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Дакраніцеся двойчы і ўтрымлівайце, каб выбраць ярлык або выкарыстоўваць спецыяльныя дзеянні."</string>
- <string name="out_of_space" msgid="4691004494942118364">"На гэтым Галоўным экране больш няма месца."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"У латку \"Абранае\" больш няма месца"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Спіс праграм"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Спіс персанальных праграм"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Спіс працоўных праграм"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Галоўная"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Выдаліць"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Выдаліць"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Звесткі пра праграмы"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Усталяваць"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"усталёўваць ярлыкі"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Дазваляе праграмам дадаваць ярлыкі без умяшання карыстальніка."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"счытваць налады і ярлыкі на Галоўнай старонцы"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Дазваляе праграме счытваць налады і ярлыкі на Галоўнай старонцы."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"запісваць налады і ярлыкі на галоўнай старонцы"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Дазваляе праграме змяняць налады і ярлыкі на Галоўнай старонцы."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> не мае дазволу на здзяйсненне тэлефонных званкоў"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Праблема загрузкі віджэта"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Наладжванне"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Гэта сістэмная праграма, яе нельга выдаліць."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Папка без назвы"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> адключана"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g>: ёсць <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> апавяшчэнне</item>
- <item quantity="few"><xliff:g id="APP_NAME_2">%1$s</xliff:g>: ёсць <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> апавяшчэнні</item>
- <item quantity="many"><xliff:g id="APP_NAME_2">%1$s</xliff:g>: ёсць <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> апавяшчэнняў</item>
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>: ёсць <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> апавяшчэння</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"Старонка %1$d з %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"Галоўны экран %1$d з %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Новая старонка галоўнага экрана"</string>
- <string name="folder_opened" msgid="94695026776264709">"Папка адкрыта, <xliff:g id="WIDTH">%1$d</xliff:g> на <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Краніце, каб закрыць папку"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Краніце, каб захаваць новую назву"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Папка закрыта"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Папка перайменавана ў <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Папка: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Віджэты"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Шпалеры"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Налады галоўнага экрана"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Адключаная адміністратарам"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Дазволіць паварот галоўнага экрана"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Пры павароце тэлефона"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Значкі апавяшчэнняў"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Уключана"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Выключана"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Патрабуецца доступ да апавяшчэнняў"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Каб паказваліся значкі апавяшчэнняў, уключыце апавяшчэнні праграм для <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Змяніць налады"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Паказаць значкі апавяшчэнняў"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Дадаць значок на Галоўны экран"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Для новых праграм"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Змяніць форму значка"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"на галоўным экране"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Выкарыстоўваць стандартныя формы"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Квадрат"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Прамавугольнік са скругленымі вугламі"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Круг"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Сляза"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Змены формы значка прымяняюцца"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Невядома"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Выдаліць"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Шукаць"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Гэта праграма не ўсталявана"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Праграма для гэтага значка не ўсталявана. Вы можаце выдаліць яе або выканаць пошук і ўсталяваць яе ўручную."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"Ідзе спампоўка <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> завершана"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чакае ўсталёўкі"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Віджэты <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Дадаць на Галоўны экран"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Перамясціць элемент сюды"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Элемент дададзены на галоўны экран"</string>
- <string name="item_removed" msgid="851119963877842327">"Элемент выдалены"</string>
- <string name="action_move" msgid="4339390619886385032">"Перамясціць элемент"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"Перамясціць у радок <xliff:g id="NUMBER_0">%1$s</xliff:g> слупок <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="move_to_position" msgid="6750008980455459790">"Перамясціць у пазіцыю <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Перамясціць у абранае, у пазіцыю <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="item_moved" msgid="4606538322571412879">"Элемент перамешчаны"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Дадаць у папку: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"Дадаць у папку з <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Элемент дададзены ў папку"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Стварыць папку з: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"Папка створана"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Перамясціць на Галоўны экран"</string>
- <string name="action_resize" msgid="1802976324781771067">"Змяніць памер"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Павялічыць шырыню"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Павялічыць вышыню"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Паменшыць шырыню"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Паменшыць вышыню"</string>
- <string name="widget_resized" msgid="9130327887929620">"Памеры віджэта зменены на: шырыня <xliff:g id="NUMBER_0">%1$s</xliff:g>, вышыня <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Ярлыкі"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"Ярлыкі (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) для <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Ярлыкі (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) і апавяшчэнні (<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>) для <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Адхіліць"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Апавяшчэнне адхілена"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Асабістыя"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Праца"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Працоўны профіль"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Знайдзіце працоўныя праграмы тут"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Кожная працоўная праграма мае значок і знаходзіцца пад аховай вашай арганізацыі. Для больш простага доступу перамясціце праграмы на Галоўны экран."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Пад кіраваннем вашай арганізацыі"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Апавяшчэнні і праграмы выключаны"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Закрыць"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Закрытыя"</string>
-</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 59a8f1f..1c1237f 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -116,6 +116,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Перамясціць элемент сюды"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Элемент дададзены на галоўны экран"</string>
<string name="item_removed" msgid="851119963877842327">"Элемент выдалены"</string>
+ <string name="undo" msgid="4151576204245173321">"Адрабіць"</string>
<string name="action_move" msgid="4339390619886385032">"Перамясціць элемент"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Перамясціць у радок <xliff:g id="NUMBER_0">%1$s</xliff:g> слупок <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Перамясціць у пазіцыю <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -146,4 +147,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Апавяшчэнні і праграмы выключаны"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Закрыць"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Закрытыя"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Не ўдалося: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 47825f6..613a8ea 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Преместване на елемента тук"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Елементът е добавен към началния екран"</string>
<string name="item_removed" msgid="851119963877842327">"Елементът е премахнат"</string>
+ <string name="undo" msgid="4151576204245173321">"Отмяна"</string>
<string name="action_move" msgid="4339390619886385032">"Преместване на елемента"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Преместване към ред <xliff:g id="NUMBER_0">%1$s</xliff:g>, колона <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Преместване към позиция <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Известията и приложенията са изключени"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Затваряне"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Затворено"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Неуспешно: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
deleted file mode 100644
index ffeeed7..0000000
--- a/res/values-bn-rBD/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"কাজ"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"অ্যাপ্লিকেশান ইনস্টল করা নেই৷"</string>
- <string name="activity_not_available" msgid="7456344436509528827">"অ্যাপ্লিকেশান অনুপলব্ধ"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"ডাউনলোড করা অ্যাপ্লিকেশান নিরাপদ মোডে অক্ষম রয়েছে"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"সুরক্ষিত মোডে উইজেট নিষ্ক্রিয় থাকে"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"শর্টকাটগুলি অনুপলব্ধ"</string>
- <string name="home_screen" msgid="806512411299847073">"হোম স্ক্রিন"</string>
- <string name="custom_actions" msgid="3747508247759093328">"কাস্টম অ্যাকশন"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"একটি উইজেট তুলতে তা স্পর্শ করে ধরে রাখুন৷"</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"কোনো উইজেট বেছে নিতে দুবার-আলতো চেপে ধরে থাকুন অথবা কাস্টম ক্রিয়াগুলি ব্যবহার করুন৷"</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%2$d উচ্চতা অনুযায়ী %1$d প্রস্থ"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"নিজে যোগ করতে টাচ করে ধরে রাখুন"</string>
- <string name="place_automatically" msgid="8064208734425456485">"স্বয়ংক্রিয়ভাবে যোগ করুন"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"অ্যাপ খুঁজুন"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"অ্যাপ লোড হচ্ছে…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" এর সাথে মেলে এমন কোনো অ্যাপ পাওয়া যায়নি"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"আরও অ্যাপ্লিকেশানের জন্য খুঁজুন"</string>
- <string name="notifications_header" msgid="1404149926117359025">"বিজ্ঞপ্তি"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"কোনও শর্টকাট বেছে নিতে টাচ করে ধরে থাকুন।"</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"কোনও শর্টকাট বেছে নিতে ডবল ট্যাপ করে ধরে থাকুন অথবা কাস্টম অ্যাকশন ব্যবহার করুন।"</string>
- <string name="out_of_space" msgid="4691004494942118364">"এই হোম স্ক্রীনে আর কোনো জায়গা নেই৷"</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"পছন্দসই ট্রে-তে আর কোনো জায়গা নেই"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"অ্যাপ্লিকেশানগুলির তালিকা"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ব্যক্তিগত অ্যাপের তালিকা"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"কাজের অ্যাপের তালিকা"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"হোম"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"সরান"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"আনইনস্টল করুন"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"অ্যাপের তথ্য"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"ইনস্টল করুন"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"শর্টকাটগুলি ইনস্টল করে"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"একটি অ্যাপ্লিকেশানকে ব্যবহারকারীর হস্তক্ষেপ ছাড়াই শর্টকাটগুলি যোগ করার অনুমতি দেয়৷"</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"হোম সেটিংস এবং শর্টকাটগুলি পড়ে"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"হোমে অ্যাপ্লিকেশানটিকে সেটিংস এবং শর্টকাটগুলি পড়তে দেয়৷"</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"হোম সেটিংস এবং শর্টকাটগুলি লেখে"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"হোমে অ্যাপ্লিকেশানটিকে সেটিংস এবং শর্টকাটগুলি পরিবর্তন করতে দেয়৷"</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"ফোন কলগুলি করার জন্য <xliff:g id="APP_NAME">%1$s</xliff:g> এর অনুমতি নেই"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"উইজেট লোড হতে সমস্যা হয়েছে"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"সেটআপ"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"এটি একটি সিস্টেম অ্যাপ্লিকেশান এবং আনইনস্টল করা যাবে না৷"</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"নামবিহীন ফোল্ডার"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> অক্ষম করা হয়েছে"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g> এ <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g>টি বিজ্ঞপ্তি আছে</item>
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> এ <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g>টি বিজ্ঞপ্তি আছে</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"%2$dটির মধ্যে %1$dটি পৃষ্ঠা"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$dটির %1$d নম্বর হোম স্ক্রিন"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"নতুন হোম স্ক্রীনের পৃষ্ঠা"</string>
- <string name="folder_opened" msgid="94695026776264709">"ফোল্ডার খোলা হয়েছে, <xliff:g id="WIDTH">%1$d</xliff:g> বাই <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"ফোল্ডার বন্ধ করতে আলতো চাপ দিন"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"পুনঃনামকরণ সংরক্ষণ করতে আলতো চাপ দিন"</string>
- <string name="folder_closed" msgid="4100806530910930934">"ফোল্ডার বন্ধ করা হয়েছে"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"ফোল্ডারের নাম পাল্টে <xliff:g id="NAME">%1$s</xliff:g> করা হয়েছে"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"ফোল্ডার: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"উইজেট"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"ওয়ালপেপারগুলি"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"হোম সেটিংস"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"আপনার প্রশাসক দ্বারা অক্ষম করা হয়েছে"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"হোমস্ক্রীন ঘোরানোর অনুমতি দিন"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"যখন ফোনটি ঘোরানো হয়"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"বিজ্ঞপ্তি ডট"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"চালু হয়েছে"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"বন্ধ আছে"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"বিজ্ঞপ্তিতে অ্যাক্সেস প্রয়োজন"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"বিজ্ঞপ্তির ডটগুলি দেখানোর জন্য, <xliff:g id="NAME">%1$s</xliff:g> এর অ্যাপ বিজ্ঞপ্তি চালু করুন"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"সেটিংস পরিবর্তন করুন"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"বিজ্ঞপ্তির ডট দেখুন"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"হোম স্ক্রিনে আইকন যোগ করুন"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"নতুন অ্যাপ্লিকেশানগুলির জন্যে"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"আইকনের আকৃতি পরিবর্তন করুন"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"হোম স্ক্রিনে"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"সিস্টেমের ডিফল্ট মান ব্যবহার করুন"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"চৌকো"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"চৌকো-গোলাকার"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"গোলাকার"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"চোখের জল"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"আইকনের আকৃতি পরিবর্তন করা হচ্ছে"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"অজানা"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"সরান"</string>
- <string name="abandoned_search" msgid="891119232568284442">"অনুসন্ধান"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"এই অ্যাপ্লিকেশানটি ইন্সটল করা নাই"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"এই আইকনের অ্যাপ্লিকেশানটি ইন্সটল করা নাই। আপনি এটি সরাতে পারেন বা অ্যাপ্লিকেশানটি অনুসন্ধান করে এটি নিজে ইন্সটল করতে পারেন।"</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ডাউনলোড হচ্ছে <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পন্ন হয়েছে"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ইনস্টলের অপেক্ষায় রয়েছে"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> উইজেট"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"হোম স্ক্রীনে যোগ করুন"</string>
- <string name="action_move_here" msgid="2170188780612570250">"এখানে আইটেম সরান"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"হোম স্ক্রীনে আইটেম যোগ করা হয়েছে"</string>
- <string name="item_removed" msgid="851119963877842327">"আইটেম সরানো হয়েছে"</string>
- <string name="action_move" msgid="4339390619886385032">"আইটেম সরান"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"সারি <xliff:g id="NUMBER_0">%1$s</xliff:g> কলাম <xliff:g id="NUMBER_1">%2$s</xliff:g> এ সরান"</string>
- <string name="move_to_position" msgid="6750008980455459790">"অবস্থানে সরান <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"পছন্দসই অবস্থানে সরান <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="item_moved" msgid="4606538322571412879">"আইটেম সরানো হয়েছে"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"ফোল্ডারে যোগ করুন: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> সহ ফোল্ডারে যোগ করা হয়েছে"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"আইটেম ফোল্ডারে যোগ করা হয়েছে"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"এর সাথে ফোল্ডার তৈরি করুন: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"ফোল্ডার তৈরি করা হয়েছে"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"হোম স্ক্রীনে সরান"</string>
- <string name="action_resize" msgid="1802976324781771067">"আবার আকার দিন"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"প্রস্থ বাড়ান"</string>
- <string name="action_increase_height" msgid="459390020612501122">"উচ্চতা বাড়ান"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"প্রস্থ কমান"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"উচ্চতা কমান"</string>
- <string name="widget_resized" msgid="9130327887929620">"উইজেটের আকার প্রস্থ <xliff:g id="NUMBER_0">%1$s</xliff:g> উচ্চতা <xliff:g id="NUMBER_1">%2$s</xliff:g> তে পরিবর্তন করা হয়েছে"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"শর্টকাট"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> এর <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>টি শর্টকার্ট"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> এর জন্য <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>টি শর্টকাট এবং <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>টি বিজ্ঞপ্তি"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"খারিজ করুন"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"বিজ্ঞপ্তি খারিজ করা হয়েছে"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"ব্যক্তিগত"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"অফিস"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"অফিসের প্রোফাইল"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"এখানে কাজের অ্যাপ্সগুলি খুঁজুন"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"প্রতিটি কাজের অ্যাপে একটি করে ব্যাজ রয়েছে এবং অ্যাপগুলি আপনার প্রতিষ্ঠানের দ্বারা সুরক্ষিত। সহজে অ্যাক্সেস করার জন্য অ্যাপগুলি হোম স্ক্রিনে রাখুন।"</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"আপনার প্রতিষ্ঠানের দ্বারা পরিচালিত"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"বিজ্ঞপ্তি এবং অ্যাপ বন্ধ আছে"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"বন্ধ করুন"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"বন্ধ"</string>
-</resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 651f400..cb675ba 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -102,20 +102,19 @@
<string name="icon_shape_override_progress" msgid="3461735694970239908">"আইকনের আকৃতি পরিবর্তন করা হচ্ছে"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"অজানা"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"সরান"</string>
- <string name="abandoned_search" msgid="891119232568284442">"অনুসন্ধান"</string>
+ <string name="abandoned_search" msgid="891119232568284442">"সার্চ"</string>
<string name="abandoned_promises_title" msgid="7096178467971716750">"এই অ্যাপ্লিকেশানটি ইন্সটল করা নাই"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"এই আইকনের অ্যাপ্লিকেশানটি ইন্সটল করা নাই। আপনি এটি সরাতে পারেন বা অ্যাপ্লিকেশানটি অনুসন্ধান করে এটি নিজে ইন্সটল করতে পারেন।"</string>
+ <string name="abandoned_promise_explanation" msgid="3990027586878167529">"এই আইকনের অ্যাপ্লিকেশানটি ইন্সটল করা নাই। আপনি এটি সরাতে পারেন বা অ্যাপ্লিকেশানটি সার্চ করে এটি নিজে ইন্সটল করতে পারেন।"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ডাউনলোড হচ্ছে <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পন্ন হয়েছে"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ইনস্টলের অপেক্ষায় রয়েছে"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> উইজেট"</string>
- <!-- no translation found for widgets_list (796804551140113767) -->
- <skip />
- <!-- no translation found for widgets_list_closed (6141506579418771922) -->
- <skip />
+ <string name="widgets_list" msgid="796804551140113767">"উইজেটের তালিকা"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"উইজেটের তালিকা বন্ধ করা হয়েছে"</string>
<string name="action_add_to_workspace" msgid="8902165848117513641">"হোম স্ক্রীনে যোগ করুন"</string>
<string name="action_move_here" msgid="2170188780612570250">"এখানে আইটেম সরান"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"হোম স্ক্রীনে আইটেম যোগ করা হয়েছে"</string>
<string name="item_removed" msgid="851119963877842327">"আইটেম সরানো হয়েছে"</string>
+ <string name="undo" msgid="4151576204245173321">"ফিরে যান"</string>
<string name="action_move" msgid="4339390619886385032">"আইটেম সরান"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"সারি <xliff:g id="NUMBER_0">%1$s</xliff:g> কলাম <xliff:g id="NUMBER_1">%2$s</xliff:g> এ সরান"</string>
<string name="move_to_position" msgid="6750008980455459790">"অবস্থানে সরান <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -146,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"বিজ্ঞপ্তি এবং অ্যাপ বন্ধ আছে"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"বন্ধ করুন"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"বন্ধ"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"কাজটি করা যায়নি: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-bs-rBA/strings.xml b/res/values-bs-rBA/strings.xml
deleted file mode 100644
index 40c8866..0000000
--- a/res/values-bs-rBA/strings.xml
+++ /dev/null
@@ -1,147 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Posao"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Aplikacija nije instalirana."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Aplikacija nije dostupna"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Preuzeta aplikacija je onemogućena u sigurnom načinu rada"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Vidžeti su onemogućeni u sigurnom načinu rada."</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Prečica nije dostupna"</string>
- <string name="home_screen" msgid="806512411299847073">"Početni ekran"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Prilagođene akcije"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Dodirnite & i držite da biste uzeli dodatak."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Dodirnite dvaput & i držite da biste uzeli vidžet ili koristite prilagođene radnje."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Širina %1$d, visina %2$d"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Dodirnite i držite da postavite ručno"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Dodaj automatski"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretražite aplikacije"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Aplikacije se učitavaju…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nije pronađena nijedna aplikacija za upit \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Pretraži više aplikacija"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Obavještenja"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Dodirnite i držite da uzmete prečicu."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Dodirnite dvaput i držite da uzmete prečicu ili koristite prilagođene akcije."</string>
- <string name="out_of_space" msgid="4691004494942118364">"Na ovom početnom ekranu nema više prostora."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nema više prostora u ladici Omiljeno"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Spisak aplikacija"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista ličnih aplikacija"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista poslovnih aplikacija"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Početna"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Informacije o aplikaciji"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliraj prečice"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Dopušta aplikaciji dodavanje prečica bez posredovanja korisnika."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"čitaj postavke na početnom ekranu i prečice"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Dopušta aplikaciji čitanje postavki i prečica na početnom ekranu."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"zapisuj postavke na početnom ekranu i prečice"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Dopušta aplikaciji promjenu postavki i prečica na početnom ekranu."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> nema odobrenje da uspostavlja telefonske pozive"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Problem pri učitavanju dodatka"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Postavljanje"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ovo je sistemska aplikacija i ne može se deinstalirati."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Neimenovani folder"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogućena"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g> ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obavještenje</item>
- <item quantity="few"><xliff:g id="APP_NAME_2">%1$s</xliff:g> ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obavještenja</item>
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obavještenja</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"Strana %1$d od %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"Početni ekran %1$d od %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Nova stranica početnog ekrana"</string>
- <string name="folder_opened" msgid="94695026776264709">"Folder je otvoren, (š) <xliff:g id="WIDTH">%1$d</xliff:g> (v) <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Dodirnite da zatvorite folder"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Dodirnite da sačuvate promjenu naziva"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Folder je zatvoren"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Ime foldera je promijenjeno u <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Dodaci"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Pozadinske slike"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Postavke početnog ekrana"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Onemogućio vaš administrator"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Dozvoli rotiranje početnog ekrana"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Kada se telefon zarotira"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Tačke za obavještenja"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Uključeno"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Isključeno"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Potreban je pristup obavještenjima"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Za prikaz tačaka obavještenja, uključite obavještenja za aplikacije za aplikaciju <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Promijeni postavke"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Prikaži tačke za obavještenja"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikonu na početni ekran"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Za nove aplikacije"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Promjena oblika ikona"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"na Početnom ekranu"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Koristite sistemski zadano"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Zaobljeni kvadrat"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Krug"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Suza"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Primjenjivanje promjena oblika ikona"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Nepoznato"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Ukloni"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Pretraži"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Ova aplikacija nije instalirana"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikacija za ovu ikonu nije instalirana. Možete je ukloniti ili potražiti aplikaciju i ručno je instalirati."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se preuzima, završeno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> čeka da se instalira"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Vidžeti za aplikaciju <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Dodaj na početni ekran"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Premjesti stavku ovdje"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Stavka je dodana na Početni ekran."</string>
- <string name="item_removed" msgid="851119963877842327">"Stavka je uklonjena"</string>
- <string name="action_move" msgid="4339390619886385032">"Premjesti stavku"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"Pomjeri stavku u red <xliff:g id="NUMBER_0">%1$s</xliff:g> kolonu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="move_to_position" msgid="6750008980455459790">"Pomjeri stavku na poziciju <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Pomjeri stavku na poziciju <xliff:g id="NUMBER">%1$s</xliff:g> među omiljenim"</string>
- <string name="item_moved" msgid="4606538322571412879">"Stavka je premještena"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Dodaj u folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"Dodaj u folder sa aplikacijom <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Stavka je dodana u folder"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Kreirajte folder sa stavkom: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"Folder je kreiran"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Pomjeri na početni ekran"</string>
- <string name="action_resize" msgid="1802976324781771067">"Promijeni veličinu"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Povećaj širinu"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Povećaj visinu"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Smanji širinu"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Smanji visinu"</string>
- <string name="widget_resized" msgid="9130327887929620">"Veličina vidžeta je promijenjena na širinu <xliff:g id="NUMBER_0">%1$s</xliff:g> visinu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Prečice"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> prečica za aplikaciju <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Za aplikaciju <xliff:g id="APP_NAME">%3$s</xliff:g> broj prečica je <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>, a broj obavještenja je <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Odbaci"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Obavještenje je odbačeno"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Lične"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Poslovne"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Radni profil"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Pronađite poslovne aplikacije ovdje"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Svaka poslovna aplikacija ima značku i osigurava je vaša organizacija. Premjestite aplikacije na Početni ekran, radi lakšeg pristupa."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Upravlja vaša organizacija"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Notifikacije i aplikacije su isključene"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zatvori"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zatvoreno"</string>
-</resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 848176d..1e2b267 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -115,6 +115,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Premjesti stavku ovdje"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Stavka je dodana na Početni ekran."</string>
<string name="item_removed" msgid="851119963877842327">"Stavka je uklonjena"</string>
+ <string name="undo" msgid="4151576204245173321">"Poništi"</string>
<string name="action_move" msgid="4339390619886385032">"Premjesti stavku"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Pomjeri stavku u red <xliff:g id="NUMBER_0">%1$s</xliff:g> kolonu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Pomjeri stavku na poziciju <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -145,4 +146,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifikacije i aplikacije su isključene"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zatvori"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zatvoreno"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 27f9c31..ce037b5 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Mou l\'element aquí"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"S\'ha afegit l\'element a la pantalla d\'inici"</string>
<string name="item_removed" msgid="851119963877842327">"S\'ha suprimit l\'element"</string>
+ <string name="undo" msgid="4151576204245173321">"Desfés"</string>
<string name="action_move" msgid="4339390619886385032">"Desplaça l\'element"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Desplaça l\'element a la fila <xliff:g id="NUMBER_0">%1$s</xliff:g> i la columna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Desplaça l\'element a la posició <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Les notificacions i les aplicacions estan desactivades"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Tanca"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"S\'ha tancat"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 48adf44..f26226c 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -116,6 +116,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Přesunout položku sem"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Položka byla přidána na plochu"</string>
<string name="item_removed" msgid="851119963877842327">"Položka byla odstraněna"</string>
+ <string name="undo" msgid="4151576204245173321">"Zpět"</string>
<string name="action_move" msgid="4339390619886385032">"Přesunout položku"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Přesunout na řádek <xliff:g id="NUMBER_0">%1$s</xliff:g> do sloupce <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Přesunout na pozici <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -146,4 +147,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Oznámení a aplikace jsou vypnuty"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zavřít"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zavřeno"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Selhalo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index d141ad9..94beecf 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Flyt elementet hertil"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Elementet er føjet til startskærmen"</string>
<string name="item_removed" msgid="851119963877842327">"Elementet er fjernet"</string>
+ <string name="undo" msgid="4151576204245173321">"Fortryd"</string>
<string name="action_move" msgid="4339390619886385032">"Flyt element"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Flyt til række <xliff:g id="NUMBER_0">%1$s</xliff:g>, kolonne <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Flyt til position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Underretninger og apps er slået fra"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Luk"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Lukket"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Mislykket: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index c309a55..ac76958 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Element hierhin verschieben"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Element zum Startbildschirm hinzugefügt"</string>
<string name="item_removed" msgid="851119963877842327">"Element entfernt"</string>
+ <string name="undo" msgid="4151576204245173321">"Rückgängig"</string>
<string name="action_move" msgid="4339390619886385032">"Element verschieben"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"In Zeile <xliff:g id="NUMBER_0">%1$s</xliff:g>, Spalte <xliff:g id="NUMBER_1">%2$s</xliff:g> verschoben"</string>
<string name="move_to_position" msgid="6750008980455459790">"Auf Position <xliff:g id="NUMBER">%1$s</xliff:g> verschoben"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Benachrichtigungen und Apps sind deaktiviert"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Schließen"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Geschlossen"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Fehler: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 3208fcb..eef66ff 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Μετακίνηση στοιχείου εδώ"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Το στοιχείο προστέθηκε στην αρχική οθόνη"</string>
<string name="item_removed" msgid="851119963877842327">"Το στοιχείο καταργήθηκε"</string>
+ <string name="undo" msgid="4151576204245173321">"Αναίρεση"</string>
<string name="action_move" msgid="4339390619886385032">"Μετακίνηση στοιχείου"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Μετακίνηση στη σειρά <xliff:g id="NUMBER_0">%1$s</xliff:g>, στήλη <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Μετακίνηση στη θέση <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Οι ειδοποιήσεις και οι εφαρμογές είναι απενεργοποιημένες"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Κλείσιμο"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Κλειστή"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Αποτυχία: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 245ee43..0494eb4 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Move item here"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Item added to home screen"</string>
<string name="item_removed" msgid="851119963877842327">"Item removed"</string>
+ <string name="undo" msgid="4151576204245173321">"Undo"</string>
<string name="action_move" msgid="4339390619886385032">"Move item"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Move to row <xliff:g id="NUMBER_0">%1$s</xliff:g> column <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Move to position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Close"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Closed"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 245ee43..0494eb4 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Move item here"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Item added to home screen"</string>
<string name="item_removed" msgid="851119963877842327">"Item removed"</string>
+ <string name="undo" msgid="4151576204245173321">"Undo"</string>
<string name="action_move" msgid="4339390619886385032">"Move item"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Move to row <xliff:g id="NUMBER_0">%1$s</xliff:g> column <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Move to position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Close"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Closed"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 245ee43..0494eb4 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Move item here"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Item added to home screen"</string>
<string name="item_removed" msgid="851119963877842327">"Item removed"</string>
+ <string name="undo" msgid="4151576204245173321">"Undo"</string>
<string name="action_move" msgid="4339390619886385032">"Move item"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Move to row <xliff:g id="NUMBER_0">%1$s</xliff:g> column <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Move to position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Close"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Closed"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 368e4ba..cdde835 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Mover elemento aquí"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Se agregó el elemento a la pantalla principal."</string>
<string name="item_removed" msgid="851119963877842327">"Se eliminó el elemento."</string>
+ <string name="undo" msgid="4151576204245173321">"Deshacer"</string>
<string name="action_move" msgid="4339390619886385032">"Mover elemento"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Mover a fila <xliff:g id="NUMBER_0">%1$s</xliff:g>, columna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Mover a la posición número <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Las notificaciones y las apps están desactivadas"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Cerrar"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Cerrado"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 0829533..117db45 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -80,7 +80,7 @@
<string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
<string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Ajustes de la pantalla de inicio"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Inhabilitada por el administrador"</string>
+ <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Inhabilitado por el administrador"</string>
<string name="allow_rotation_title" msgid="7728578836261442095">"Permitir rotación de la pantalla de inicio"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Al girar el teléfono"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Burbujas de notificación"</string>
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Mover elemento aquí"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Elemento añadido a la pantalla de inicio"</string>
<string name="item_removed" msgid="851119963877842327">"Elemento eliminado"</string>
+ <string name="undo" msgid="4151576204245173321">"Deshacer"</string>
<string name="action_move" msgid="4339390619886385032">"Mover elemento"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Mover a la fila <xliff:g id="NUMBER_0">%1$s</xliff:g>, columna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Mover a la posición número <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Las notificaciones y las aplicaciones están desactivadas"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Cerrar"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Cerrada"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Se ha producido un error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml
deleted file mode 100644
index 1bde8aa..0000000
--- a/res/values-et-rEE/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Töö"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Rakendus pole installitud."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Rakendus ei ole saadaval"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Allalaetud rakendus on turvarežiimis keelatud"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Turvarežiimis on vidinad keelatud"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Otsetee pole saadaval"</string>
- <string name="home_screen" msgid="806512411299847073">"Avaekraan"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Kohandatud toimingud"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Vidina valimiseks vajutage ja hoidke seda all."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Topeltpuudutage ja hoidke vidina valimiseks või kohandatud toimingute kasutamiseks."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d lai ja %2$d kõrge"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Puudutage pikalt, et käsitsi asetada"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Lisa automaatselt"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Otsige rakendusi"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Rakenduste laadimine …"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"Päringule „<xliff:g id="QUERY">%1$s</xliff:g>” ei vastanud ükski rakendus"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Otsi rohkem rakendusi"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Märguanded"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Otsetee valimiseks puudutage seda pikalt."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Topeltpuudutage ja hoidke otsetee valimiseks või kohandatud toimingute kasutamiseks."</string>
- <string name="out_of_space" msgid="4691004494942118364">"Sellel avaekraanil pole enam ruumi."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Salves Lemmikud pole rohkem ruumi"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Rakenduste loend"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Isiklike rakenduste loend"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Töörakenduste loend"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Avaekraan"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Eemalda"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalli"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Rakenduse teave"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Installimine"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"installi otseteed"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Võimaldab rakendusel lisada otseteid kasutaja sekkumiseta."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"loe avaekraani seadeid ja otseteid"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Võimaldab rakendusel lugeda avaekraanil seadeid ja otseteid."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"kirjuta avaekraani seaded ja otseteed"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Võimaldab rakendusel muuta avaekraanil seadeid ja otseteid."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"Rakendusel <xliff:g id="APP_NAME">%1$s</xliff:g> pole lubatud helistada"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Probleem vidina laadimisel"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Seadistamine"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"See on süsteemirakendus ja seda ei saa desinstallida."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Nimetu kaust"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> on keelatud"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> märguannet</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> – <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> märguanne</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"Leht %1$d/%2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"Avaekraan %1$d/%2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Uus avaekraan"</string>
- <string name="folder_opened" msgid="94695026776264709">"Kaust on avatud, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Puudutage kausta sulgemiseks"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Puudutage ümbernimetamise salvestamiseks"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Kaust on suletud"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Kausta uus nimi: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Kaust: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Vidinad"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Taustapildid"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Avaekraani seaded"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Keelas administraator"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Luba avaekraani pööramine"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Kui telefoni pööratakse"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Märguandetäpid"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Sees"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Väljas"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Vaja on juurdepääsu märguannetele"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Märguandetäppide kuvamiseks lülitage sisse rakenduse <xliff:g id="NAME">%1$s</xliff:g> märguanded"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Seadete muutmine"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Kuva märguandetäpid"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Lisa ikoon avaekraanile"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Uute rakenduste puhul"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Ikooni kuju muutmine"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"avaekraanil"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Kasuta süsteemi vaikeseadet"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Ruut"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Ümarate nurkadega ruut"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Ring"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Tilk"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Ikooni kuju muudatuste rakendamine"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Teadmata"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Eemalda"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Otsing"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"See rakendus ei ole installitud"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Selle ikooni rakendust pole installitud. Saate selle eemaldada või rakendust otsida ja käsitsi installida."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"Rakenduse <xliff:g id="NAME">%1$s</xliff:g> allalaadimine, <xliff:g id="PROGRESS">%2$s</xliff:g> on valmis"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> on installimise ootel"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Teenuse <xliff:g id="NAME">%1$s</xliff:g> vidinad"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Lisa avaekraanile"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Teisalda üksus siia"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Üksus lisati avaekraanile"</string>
- <string name="item_removed" msgid="851119963877842327">"Üksus eemaldati"</string>
- <string name="action_move" msgid="4339390619886385032">"Teisalda üksus"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"Teisaldamine <xliff:g id="NUMBER_0">%1$s</xliff:g>. rea <xliff:g id="NUMBER_1">%2$s</xliff:g>. veergu"</string>
- <string name="move_to_position" msgid="6750008980455459790">"Teisaldamine <xliff:g id="NUMBER">%1$s</xliff:g>. positsioonile"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Teisaldamine lemmikute <xliff:g id="NUMBER">%1$s</xliff:g>. positsioonile"</string>
- <string name="item_moved" msgid="4606538322571412879">"Üksus teisaldati"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Lisamine kausta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"Lisamine kausta nimega <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Üksus lisati kausta"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Kausta loomine nimega <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"Kaust on loodud"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Teisalda avaekraanile"</string>
- <string name="action_resize" msgid="1802976324781771067">"Muuda suurust"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Suurenda laiust"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Suurenda kõrgust"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Vähenda laiust"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Vähenda kõrgust"</string>
- <string name="widget_resized" msgid="9130327887929620">"Vidina suurust muudeti. Laius: <xliff:g id="NUMBER_0">%1$s</xliff:g>. Kõrgus: <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Otseteed"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> otseteed rakenduse <xliff:g id="APP_NAME">%2$s</xliff:g> jaoks"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> otseteed ja <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> märguannet rakendusele <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Loobu"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Märguandest loobuti"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Isiklik"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Töö"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Tööprofiil"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Töörakendused leiate siit"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Igal töörakendusel on märk ja teie organisatsioon tagab selle turvalisuse. Teisaldage rakendused avaekraanile, et neile oleks lihtsam juurde pääseda."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Haldab teie organisatsioon"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Märguanded ja rakendused on välja lülitatud"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Sule"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Suletud"</string>
-</resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 1e5caa6..d0f8cd8 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Teisalda üksus siia"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Üksus lisati avaekraanile"</string>
<string name="item_removed" msgid="851119963877842327">"Üksus eemaldati"</string>
+ <string name="undo" msgid="4151576204245173321">"Võta tagasi"</string>
<string name="action_move" msgid="4339390619886385032">"Teisalda üksus"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Teisaldamine <xliff:g id="NUMBER_0">%1$s</xliff:g>. rea <xliff:g id="NUMBER_1">%2$s</xliff:g>. veergu"</string>
<string name="move_to_position" msgid="6750008980455459790">"Teisaldamine <xliff:g id="NUMBER">%1$s</xliff:g>. positsioonile"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Märguanded ja rakendused on välja lülitatud"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Sule"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Suletud"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Nurjus: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
deleted file mode 100644
index 128c6f4..0000000
--- a/res/values-eu-rES/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Lana"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Aplikazioa instalatu gabe dago."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Ez dago erabilgarri aplikazioa"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Deskargatutako aplikazioa modu seguruan desgaitu da"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Widgetak desgaitu egin dira modu seguruan"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Lasterbideak ez daude erabilgarri"</string>
- <string name="home_screen" msgid="806512411299847073">"Hasierako pantaila"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Ekintza pertsonalizatuak"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Eduki sakatuta widgeta aukeratzeko."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Sakatu birritan eta eduki sakatuta widgeta aukeratzeko edo ekintza pertsonalizatuak erabiltzeko."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d zabal eta %2$d luze"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Eduki sakatuta eskuz gehitzeko"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Gehitu automatikoki"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Bilatu aplikazioetan"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Aplikazioak kargatzen…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"Ez da aurkitu \"<xliff:g id="QUERY">%1$s</xliff:g>\" bilaketaren emaitzarik"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Bilatu aplikazio gehiago"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Jakinarazpenak"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Eduki sakatuta lasterbide bat aukeratzeko."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Sakatu birritan eta eduki sakatuta lasterbide bat aukeratzeko edo ekintza pertsonalizatuak erabiltzeko."</string>
- <string name="out_of_space" msgid="4691004494942118364">"Hasierako pantaila honetan ez dago toki gehiago."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ez dago toki gehiago Gogokoak erretiluan"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Aplikazioen zerrenda"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Aplikazio pertsonalen zerrenda"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Laneko aplikazioen zerrenda"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Hasiera"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Kendu"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalatu"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Aplikazioaren datuak"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Instalatu"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"Instalatu lasterbideak"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Erabiltzaileak ezer egin gabe lasterbideak gehitzea baimentzen die aplikazioei."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"Irakurri hasierako ezarpenak eta lasterbideak"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Hasierako pantailako ezarpenak eta lasterbideak irakurtzea baimentzen die aplikazioei."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"Idatzi hasierako ezarpenak eta lasterbideak"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Hasierako pantailako ezarpenak eta lasterbideak aldatzea baimentzen die aplikazioei."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez du telefono-deiak egiteko baimenik"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Arazo bat izan da widgeta kargatzean"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Konfigurazioa"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Sistema-aplikazioa da hau eta ezin da desinstalatu."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Izenik gabeko karpeta"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> desgaituta dago"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> jakinarazpen dauzka <xliff:g id="APP_NAME_2">%1$s</xliff:g> aplikazioak</item>
- <item quantity="one"><xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> jakinarazpen dauka <xliff:g id="APP_NAME_0">%1$s</xliff:g> aplikazioak</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"%1$d/%2$d orria"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d/%2$d hasierako pantaila"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Hasierako pantailaren orri berria"</string>
- <string name="folder_opened" msgid="94695026776264709">"Karpeta ireki da: <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Karpeta ixteko, sakatu hau"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Izen berria gordetzeko, sakatu hau"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Karpeta itxi da"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Karpetari <xliff:g id="NAME">%1$s</xliff:g> izena eman zaio"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Karpeta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Widgetak"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Horma-paperak"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Hasierako pantailaren ezarpenak"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administratzaileak desgaitu du"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Baimendu hasierako pantaila biratzea"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Telefonoa biratzen denean"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Jakinarazpen-biribiltxoak"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aktibatuta"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desaktibatuta"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Jakinarazpenetarako sarbidea behar da"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Jakinarazpen-biribiltxoak ikusteko, aktibatu <xliff:g id="NAME">%1$s</xliff:g> aplikazioaren jakinarazpenak"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Aldatu ezarpenak"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Erakutsi jakinarazpen-biribiltxoak"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Gehitu ikonoa hasierako pantailan"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Aplikazio berrietan"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Aldatu ikonoaren forma"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"Hasierako pantailan"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Erabili sistemaren balio lehenetsiak"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Karratua"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Ertz biribilduko karratua"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Zirkulua"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Malkoa"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Ikonoaren forman egindako aldaketak aplikatzen"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Ezezaguna"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Kendu"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Bilatu"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Aplikazio hau ez dago instalatuta"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Ikono honen aplikazioa ez dago instalatuta. Ikonoa ken dezakezu, edo aplikazioa bilatu eta eskuz instalatu."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> deskargatzen, <xliff:g id="PROGRESS">%2$s</xliff:g> osatuta"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> instalatzeko zain"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> widgetak"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Gehitu hasierako pantailan"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Ekarri elementua hona"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Gehitu da elementua hasierako pantailan"</string>
- <string name="item_removed" msgid="851119963877842327">"Kendu da elementua"</string>
- <string name="action_move" msgid="4339390619886385032">"Mugitu elementua"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"Eraman <xliff:g id="NUMBER_0">%1$s</xliff:g>. errenkadara, <xliff:g id="NUMBER_1">%2$s</xliff:g>. zutabera"</string>
- <string name="move_to_position" msgid="6750008980455459790">"Eraman <xliff:g id="NUMBER">%1$s</xliff:g>. postura"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Eraman gogokoen <xliff:g id="NUMBER">%1$s</xliff:g>. postura"</string>
- <string name="item_moved" msgid="4606538322571412879">"Elementua mugitu da"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Gehitu <xliff:g id="NAME">%1$s</xliff:g> karpetan"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"Gehitu <xliff:g id="NAME">%1$s</xliff:g> duen karpetan"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Elementua karpetan gehitu da"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Sortu karpeta <xliff:g id="NAME">%1$s</xliff:g> elementuarekin"</string>
- <string name="folder_created" msgid="6409794597405184510">"Karpeta sortu da"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Eraman hasierako pantailara"</string>
- <string name="action_resize" msgid="1802976324781771067">"Aldatu tamaina"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Handitu zabalera"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Handitu altuera"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Txikitu zabalera"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Txikitu altuera"</string>
- <string name="widget_resized" msgid="9130327887929620">"Aldatu da widgetaren tamaina. Zabalera: <xliff:g id="NUMBER_0">%1$s</xliff:g>. Altuera: <xliff:g id="NUMBER_1">%2$s</xliff:g>."</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Lasterbideak"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioaren <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> lasterbide"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> aplikazioaren <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> lasterbide eta <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> jakinarazpen"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Baztertu"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Baztertu egin da jakinarazpena"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Pertsonalak"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Lanekoak"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Laneko profila"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Hemen dituzu laneko aplikazioak"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Laneko aplikazio bakoitzak bereizgarri bat dauka eta erakundeak babesten du. Aplikazioak errazago atzitzeko, eraman itzazu hasierako pantailara."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Erakundeak kudeatzen du"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Jakinarazpenak eta aplikazioak desaktibatuta daude"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Itxi"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Itxita"</string>
-</resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index b69228a..29d96f8 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Ekarri elementua hona"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Gehitu da elementua hasierako pantailan"</string>
<string name="item_removed" msgid="851119963877842327">"Kendu da elementua"</string>
+ <string name="undo" msgid="4151576204245173321">"Desegin"</string>
<string name="action_move" msgid="4339390619886385032">"Mugitu elementua"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Eraman <xliff:g id="NUMBER_0">%1$s</xliff:g>. errenkadara, <xliff:g id="NUMBER_1">%2$s</xliff:g>. zutabera"</string>
<string name="move_to_position" msgid="6750008980455459790">"Eraman <xliff:g id="NUMBER">%1$s</xliff:g>. postura"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Jakinarazpenak eta aplikazioak desaktibatuta daude"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Itxi"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Itxita"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Huts egin du: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index aa06188..e78af15 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"انتقال مورد به اینجا"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"مورد به صفحه اصلی اضافه شد"</string>
<string name="item_removed" msgid="851119963877842327">"مورد حذف شد"</string>
+ <string name="undo" msgid="4151576204245173321">"واگرد"</string>
<string name="action_move" msgid="4339390619886385032">"انتقال مورد"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"انتقال به سطر <xliff:g id="NUMBER_0">%1$s</xliff:g> ستون <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"انتقال به موقعیت <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"اعلانها و برنامهها خاموش هستند"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"بستن"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"بستهشده"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"ناموفق بود: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 4b361ac..eb0e8bf 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Siirrä kohde tänne"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Kohde lisättiin aloitusnäytölle."</string>
<string name="item_removed" msgid="851119963877842327">"Kohde poistettiin."</string>
+ <string name="undo" msgid="4151576204245173321">"Kumoa"</string>
<string name="action_move" msgid="4339390619886385032">"Siirrä kohde"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Siirrä rivin <xliff:g id="NUMBER_0">%1$s</xliff:g> sarakkeeseen <xliff:g id="NUMBER_1">%2$s</xliff:g>."</string>
<string name="move_to_position" msgid="6750008980455459790">"Siirrä kohtaan <xliff:g id="NUMBER">%1$s</xliff:g>."</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Ilmoitukset ja sovellukset ovat poissa käytöstä"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Sulje"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Suljettu"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Epäonnistui: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 29b003e..92d5b0b 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Déplacer l\'élément ici"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Élément ajouté à l\'écran d\'accueil"</string>
<string name="item_removed" msgid="851119963877842327">"Élément supprimé"</string>
+ <string name="undo" msgid="4151576204245173321">"Annuler"</string>
<string name="action_move" msgid="4339390619886385032">"Déplacer l\'élément"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Déplacer vers rangée <xliff:g id="NUMBER_0">%1$s</xliff:g> colonne <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Déplacer vers la position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Les notifications et les applications sont désactivées"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Fermer"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Fermé"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index d47ab42..55c7b6b 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Déplacer l\'élément ici"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"L\'élément a bien été ajouté à l\'écran d\'accueil."</string>
<string name="item_removed" msgid="851119963877842327">"L\'élément a bien été supprimé."</string>
+ <string name="undo" msgid="4151576204245173321">"Annuler"</string>
<string name="action_move" msgid="4339390619886385032">"Déplacer l\'élément"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Déplacer vers la ligne <xliff:g id="NUMBER_0">%1$s</xliff:g>, colonne <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Déplacer vers la position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Les notifications et les applications sont désactivées"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Fermer"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Fermé"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
deleted file mode 100644
index 1efa5ce..0000000
--- a/res/values-gl-rES/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Traballo"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"A aplicación non está instalada"</string>
- <string name="activity_not_available" msgid="7456344436509528827">"A aplicación non está dispoñible"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"A aplicación que descargaches está desactivada no modo seguro"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Os widgets están desactivados no modo seguro"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"O atallo non está dispoñible"</string>
- <string name="home_screen" msgid="806512411299847073">"Pantalla de inicio"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Accións personalizadas"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Mantén premido un widget para seleccionalo."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Toca dúas veces e mantén premido para seleccionar un widget ou utiliza accións personalizadas."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largo por %2$d de alto"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Mantén premido o elemento para colocalo manualmente"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Engadir automaticamente"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar aplicacións"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Cargando aplicacións…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"Non se atoparon aplicacións que coincidan con \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Buscar máis aplicacións"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Notificacións"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Mantén premido un atallo para seleccionalo."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Toca dúas veces e mantén premido para seleccionar un atallo ou utiliza accións personalizadas."</string>
- <string name="out_of_space" msgid="4691004494942118364">"Non hai máis espazo nesta pantalla de inicio."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Non hai máis espazo na bandexa de favoritos"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Lista de aplicacións"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista de aplicacións persoais"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista de aplicacións de traballo"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Inicio"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Eliminar"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Info. da aplicación"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atallos"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a unha aplicación engadir atallos sen intervención do usuario."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"ler a configuración e os atallos da pantalla de inicio"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Permite a unha aplicación ler a configuración e os atallos da páxina de inicio."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"modificar a configuración e os atallos da pantalla de inicio"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Permite a unha aplicación cambiar a configuración e os atallos da pantalla de inicio."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> non ten permiso para facer chamadas telefónicas"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Produciuse un problema ao cargar o widget"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Configuración"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Esta aplicación é do sistema e non se pode desinstalar."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Cartafol sen nome"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"Desactivouse <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ten <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notificacións</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, ten <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notificación</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"Páxina %1$d de %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla de inicio %1$d de %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Nova páxina da pantalla de inicio"</string>
- <string name="folder_opened" msgid="94695026776264709">"Abriuse o cartafol, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Toca fóra para pechar o cartafol"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Toca fóra para cambiar o nome do cartafol"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Pechouse o cartafol"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"O cartafol cambiou o nome a <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Cartafol: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Configuración da pantalla de Inicio"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Función desactivada polo administrador"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Permitir xirar a pantalla de inicio"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Ao xirar o teléfono"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Puntos de notificacións"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activado"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivado"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Necesítase acceso ás notificacións"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Para que se mostren os puntos de notificacións, activa as notificacións da aplicación <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Cambiar configuración"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Mostrar puntos de notificación"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Engadir icona á pantalla de inicio"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para novas aplicacións"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Cambiar forma das iconas"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"na pantalla de inicio"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Usar valores predeterminados do sistema"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Cadrado"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Cadrado de bordos redondeados"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Círculo"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Bágoa"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Aplicando cambios na forma das iconas"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Descoñecido"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminar"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Buscar"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Esta aplicación non está instalada"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"A aplicación para esta icona non está instalada. Podes eliminala ou buscar a aplicación e instalala manualmente."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"Descargando <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="PROGRESS">%2$s</xliff:g> completado)"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"Esperando para instalar <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgets de: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Engadir á pantalla de inicio"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Mover elemento aquí"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Engadiuse o elemento á pantalla de inicio"</string>
- <string name="item_removed" msgid="851119963877842327">"Eliminouse o elemento"</string>
- <string name="action_move" msgid="4339390619886385032">"Mover elemento"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"Mover á fila <xliff:g id="NUMBER_0">%1$s</xliff:g> columna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="move_to_position" msgid="6750008980455459790">"Mover á posición <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Mover á posición dos favoritos <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="item_moved" msgid="4606538322571412879">"Moveuse o elemento"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Engadir ao cartafol: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"Engadir ao cartafol con <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Engadiuse o elemento ao cartafol"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Crear cartafol con: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"Creouse o cartafol"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Mover á pantalla de inicio"</string>
- <string name="action_resize" msgid="1802976324781771067">"Cambiar tamaño"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Aumentar ancho"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Aumentar altura"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Reducir ancho"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Reducir altura"</string>
- <string name="widget_resized" msgid="9130327887929620">"Cambiouse o tamaño do widget polo ancho <xliff:g id="NUMBER_0">%1$s</xliff:g> e a altura <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Atallos"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> atallos para <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> atallos e <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notificacións para a aplicación <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignorar"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Ignorouse a notificación"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Persoal"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Traballo"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de traballo"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Buscar aplicacións do traballo aquí"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"As aplicacións do traballo teñen unha insignia e están protexidas pola túa organización. Traslada as aplicacións á pantalla de inicio para acceder a elas de forma máis fácil."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Perfil xestionado pola túa organización"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"As notificacións e as aplicacións están desactivadas"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Pechar"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Pechada"</string>
-</resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index b94d693..9a5772f 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Mover elemento aquí"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Engadiuse o elemento á pantalla de inicio"</string>
<string name="item_removed" msgid="851119963877842327">"Eliminouse o elemento"</string>
+ <string name="undo" msgid="4151576204245173321">"Desfacer"</string>
<string name="action_move" msgid="4339390619886385032">"Mover elemento"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Mover á fila <xliff:g id="NUMBER_0">%1$s</xliff:g> columna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Mover á posición <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"As notificacións e as aplicacións están desactivadas"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Pechar"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Pechada"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Erro: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml
deleted file mode 100644
index 234fada..0000000
--- a/res/values-gu-rIN/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"કાર્યાલય"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"ઍપ્લિકેશન ઇન્સ્ટોલ થઈ નથી."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"ઍપ્લિકેશન ઉપલબ્ધ નથી"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"સુરક્ષિત મોડમાં ડાઉનલોડ કરેલ ઍપ્લિકેશન અક્ષમ કરી"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"સુરક્ષિત મોડમાં વિજેટ્સ અક્ષમ કર્યા"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"શૉર્ટકટ ઉપલબ્ધ નથી"</string>
- <string name="home_screen" msgid="806512411299847073">"હોમ સ્ક્રીન"</string>
- <string name="custom_actions" msgid="3747508247759093328">"કસ્ટમ ક્રિયાઓ"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"વિજેટ ચૂંટવા માટે સ્પર્શ કરો અને પકડી રાખો."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"વિજેટ ચૂંટવા અથવા કસ્ટમ ક્રિયાઓનો ઉપયોગ કરવા માટે બે વાર ટેપ કરો અને પકડી રાખો."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d પહોળાઈ X %2$d ઊંચાઈ"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"મેન્યુઅલી મૂકવા માટે ટચ કરી દબાવી રાખો"</string>
- <string name="place_automatically" msgid="8064208734425456485">"આપમેળે ઉમેરો"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"શોધ ઍપ્લિકેશનો"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"ઍપ્લિકેશનો લોડ કરી રહ્યું છે…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"થી મેળ ખાતી કોઈ ઍપ્લિકેશનો મળી નથી"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"વધુ ઍપ્લિકેશનો શોધો"</string>
- <string name="notifications_header" msgid="1404149926117359025">"નોટિફિકેશનો"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"એક શૉર્ટકટ ચૂંટવા માટે સ્પર્શ કરી રાખો."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"એક શૉર્ટકટ ચૂંટવા અથવા કોઈ કસ્ટમ ક્રિયાઓનો ઉપયોગ કરવા માટે બે વાર ટૅપ કરીને દબાવી રાખો."</string>
- <string name="out_of_space" msgid="4691004494942118364">"આ હોમ સ્ક્રીન પર વધુ જગ્યા નથી."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"મનપસંદ ટ્રે પર વધુ જગ્યા નથી"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"ઍપ્લિકેશનોની સૂચિ"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"વ્યક્તિગત ઍપની સૂચિ"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"કાર્યસ્થળની ઍપની સૂચિ"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"હોમ"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"દૂર કરો"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"અનઇન્સ્ટોલ કરો"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"ઍપ્લિકેશન માહિતી"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"ઇન્સ્ટૉલ કરો"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"શોર્ટકટ્સ ઇન્સ્ટોલ કરો"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"એપ્લિકેશનને વપરાશકર્તા હસ્તક્ષેપ વગર શોર્ટકટ્સ ઉમેરવાની મંજૂરી આપે છે."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"હોમ સેટિંગ્સ અને શોર્ટકટ્સ વાંચો"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"એપ્લિકેશનને હોમમાં સેટિંગ્સ અને શોર્ટકટ્સ વાંચવાની મંજૂરી આપે છે."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"હોમ સેટિંગ્સ અને શોર્ટકટ્સ લખો"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"એપ્લિકેશનને હોમમાં સેટિંગ્સ અને શોર્ટકટ્સ બદલવાની મંજૂરી આપે છે."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> ને ફોન કૉલ્સ કરવાની મંજૂરી નથી"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"વિજેટ લોડ કરવામાં સમસ્યા"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"સેટઅપ"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"આ એક સિસ્ટમ ઍપ્લિકેશન છે અને અનઇન્સ્ટોલ કરી શકાતી નથી."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"અનામી ફોલ્ડર"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> અક્ષમ કરી"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g>ના <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> નોટિફિકેશન છે</item>
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>ના <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> નોટિફિકેશન છે</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"%2$d માંથી %1$d પૃષ્ઠ"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d માંથી %1$d હોમ સ્ક્રીન"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"નવું હોમ સ્ક્રીન પૃષ્ઠ"</string>
- <string name="folder_opened" msgid="94695026776264709">"<xliff:g id="WIDTH">%1$d</xliff:g> બાય <xliff:g id="HEIGHT">%2$d</xliff:g> નું ફોલ્ડર ખોલ્યું"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"ફોલ્ડર બંધ કરવા માટે ટૅપ કરો"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"નામ બદલવાનું સાચવવા માટે ટૅપ કરો"</string>
- <string name="folder_closed" msgid="4100806530910930934">"ફોલ્ડર બંધ કર્યું"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"ફોલ્ડરનું નામ બદલીને <xliff:g id="NAME">%1$s</xliff:g> કર્યું"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"ફોલ્ડર: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"વિજેટ્સ"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"વૉલપેપર્સ"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"હોમ સેટિંગ્સ"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"તમારા વ્યવસ્થાપક દ્વારા અક્ષમ કરેલ"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"હોમ સ્ક્રીનને ફેરવવાની મંજૂરી આપો"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"જ્યારે ફોન ફેરવવામાં આવે ત્યારે"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"સૂચના બિંદુઓ"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"ચાલુ"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"બંધ"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"નોટિફિકેશનનો ઍક્સેસની જરૂરી છે"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"નોટિફિકેશન માટેનું ચિહ્ન બતાવવા હેતુ, <xliff:g id="NAME">%1$s</xliff:g> માટેની ઍપ્લિકેશન નોટિફિકેશન ચાલુ કરો"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"સેટિંગ્સ બદલો"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"નોટિફિકેશન માટેનું ચિહ્ન બતાવો"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"હોમ સ્ક્રીન પર આઇકન ઉમેરો"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"નવી ઍપ્લિકેશનો માટે"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"આઇકનનો આકાર બદલો"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"હોમ સ્ક્રીન પર"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"સિસ્ટમ ડિફૉલ્ટનો ઉપયોગ કરો"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"ચોરસ"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"ચોરસ જેવું ગોળ"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"વર્તુળ"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"ટિઅરડ્રોપ"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"આઇકનના આકારમાં કરેલ ફેરફારો લાગુ કરી રહ્યા છીએ"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"અજાણ્યો"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"દૂર કરો"</string>
- <string name="abandoned_search" msgid="891119232568284442">"શોધો"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"આ ઍપ્લિકેશન ઇન્સ્ટોલ થયેલ નથી"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"આ આયકન માટેની ઍપ્લિકેશન ઇન્સ્ટોલ થયેલ નથી. તમે તેને દૂર કરી શકો છો અથવા ઍપ્લિકેશન માટે શોધ કરી અને તેને મેન્યુઅલી ઇન્સ્ટોલ કરી શકો છો."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ડાઉનલોડ કરી રહ્યાં છે, <xliff:g id="PROGRESS">%2$s</xliff:g> પૂર્ણ"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>, ઇન્સ્ટૉલ થવાની રાહ જોઈ રહ્યું છે"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> વિજેટ"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"હોમ સ્ક્રીન પર ઉમેરો"</string>
- <string name="action_move_here" msgid="2170188780612570250">"આઇટમ અહીં ખસેડો"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"હોમ સ્ક્રીનમાં આઇટમ ઉમેરી"</string>
- <string name="item_removed" msgid="851119963877842327">"આઇટમ દૂર કરી"</string>
- <string name="action_move" msgid="4339390619886385032">"આઇટમ ખસેડો"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> પંક્તિ <xliff:g id="NUMBER_1">%2$s</xliff:g> કૉલમ પર ખસેડો"</string>
- <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> સ્થિતિ પર ખસેડો"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"મનપસંદ સ્થિતિ <xliff:g id="NUMBER">%1$s</xliff:g> પર ખસેડો"</string>
- <string name="item_moved" msgid="4606538322571412879">"આઇટમ ખસેડી"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"ફોલ્ડરમાં ઉમેરો: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> સાથે ફોલ્ડરમાં ઉમેરો"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"ફોલ્ડરમાં આઇટમ ઉમેરી"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"આની સાથે ફોલ્ડર બનાવો: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"ફોલ્ડર બનાવ્યું"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"હોમ સ્ક્રીન પર ખસેડો"</string>
- <string name="action_resize" msgid="1802976324781771067">"આકાર બદલો"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"પહોળાઈ વધારો"</string>
- <string name="action_increase_height" msgid="459390020612501122">"ઊંચાઈ વધારો"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"પહોળાઈ ઘટાડો"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"ઊંચાઈ ઘટાડો"</string>
- <string name="widget_resized" msgid="9130327887929620">"વિજેટનો આકાર બદલીને <xliff:g id="NUMBER_0">%1$s</xliff:g> પહોળાઈ <xliff:g id="NUMBER_1">%2$s</xliff:g> ઊંચાઈ કર્યો"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"શૉર્ટકટ્સ"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> માટે <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> શૉર્ટકટ"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> માટે <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> શૉર્ટકટ અને <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> સૂચનાઓ"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"છોડી દો"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"સૂચના છોડી દીધી"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"મનગમતી ઍપ"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"કાર્યાલયની ઍપ"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"કાર્યાલયની પ્રોફાઇલ"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"કાર્ય ઍપને અહીંથી મેળવો"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"દરેક કાર્ય ઍપ પાસે એક બૅજ હોય છે અને તમારી સંસ્થા દ્વારા તેને સુરક્ષિત રાખવામાં આવે છે. વધુ સરળ ઍક્સેસ માટે ઍપને તમારી હોમ સ્ક્રીન પર ખસેડો."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"તમારી સંસ્થા દ્વારા મેનેજ કરેલ"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"નોટિફિકેશન અને ઍપ બંધ છે"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"બંધ કરો"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"બંધ"</string>
-</resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 6468d8b..0678cba 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -108,14 +108,13 @@
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ડાઉનલોડ કરી રહ્યાં છે, <xliff:g id="PROGRESS">%2$s</xliff:g> પૂર્ણ"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>, ઇન્સ્ટૉલ થવાની રાહ જોઈ રહ્યું છે"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> વિજેટ"</string>
- <!-- no translation found for widgets_list (796804551140113767) -->
- <skip />
- <!-- no translation found for widgets_list_closed (6141506579418771922) -->
- <skip />
+ <string name="widgets_list" msgid="796804551140113767">"વિજેટની સૂચિ"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"વિજેટની સૂચિ બંધ કરવામાં આવી છે"</string>
<string name="action_add_to_workspace" msgid="8902165848117513641">"હોમ સ્ક્રીન પર ઉમેરો"</string>
<string name="action_move_here" msgid="2170188780612570250">"આઇટમ અહીં ખસેડો"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"હોમ સ્ક્રીનમાં આઇટમ ઉમેરી"</string>
<string name="item_removed" msgid="851119963877842327">"આઇટમ દૂર કરી"</string>
+ <string name="undo" msgid="4151576204245173321">"રદ કરો"</string>
<string name="action_move" msgid="4339390619886385032">"આઇટમ ખસેડો"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> પંક્તિ <xliff:g id="NUMBER_1">%2$s</xliff:g> કૉલમ પર ખસેડો"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> સ્થિતિ પર ખસેડો"</string>
@@ -146,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"નોટિફિકેશન અને ઍપ બંધ છે"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"બંધ કરો"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"બંધ"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"નિષ્ફળ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 1b5ce26..bd51f80 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -89,7 +89,7 @@
<string name="title_missing_notification_access" msgid="7503287056163941064">"सूचना के एक्सेस की ज़रूरत है"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"सूचना बिंदु दिखाने के लिए, <xliff:g id="NAME">%1$s</xliff:g> के ऐप्लिकेशन सूचना चालू करें"</string>
<string name="title_change_settings" msgid="1376365968844349552">"सेटिंग बदलें"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"नए नोटिफ़िकेशन बताने वाला गोल निशान दिखाएं"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"नई सूचनाएं बताने वाला गोल निशान दिखाएं"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"होम स्क्रीन में आइकॉन जोड़ें"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"नए ऐप्लिकेशन के लिए"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"आइकॉन का आकार बदलें"</string>
@@ -108,14 +108,13 @@
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड हो रहा है, <xliff:g id="PROGRESS">%2$s</xliff:g> पूर्ण"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> के इंस्टॉल होने की प्रतीक्षा की जा रही है"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> विजेट"</string>
- <!-- no translation found for widgets_list (796804551140113767) -->
- <skip />
- <!-- no translation found for widgets_list_closed (6141506579418771922) -->
- <skip />
+ <string name="widgets_list" msgid="796804551140113767">"विजेट की सूची"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"विजेट की सूची बंद हो गई है"</string>
<string name="action_add_to_workspace" msgid="8902165848117513641">"होम स्क्रीन में जोड़ें"</string>
<string name="action_move_here" msgid="2170188780612570250">"आइटम यहां ले जाएं"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"होम स्क्रीन में आइटम जोड़ा गया"</string>
<string name="item_removed" msgid="851119963877842327">"आइटम निकाला गया"</string>
+ <string name="undo" msgid="4151576204245173321">"पहले जैसा करें"</string>
<string name="action_move" msgid="4339390619886385032">"आइटम ले जाएं"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"पंक्ति <xliff:g id="NUMBER_0">%1$s</xliff:g> स्तंभ <xliff:g id="NUMBER_1">%2$s</xliff:g> पर ले जाएं"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> स्थिति पर ले जाएं"</string>
@@ -146,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"सूचनाएं और ऐप्लिकेशन बंद हैं"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"बंद करें"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"बंद कर दिया गया"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"पूरा नहीं हुआ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index ea340d6..a4b4028 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -115,6 +115,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Premjesti stavku ovdje"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Stavka je dodana na početni zaslon"</string>
<string name="item_removed" msgid="851119963877842327">"Stavka je uklonjena"</string>
+ <string name="undo" msgid="4151576204245173321">"Poništi"</string>
<string name="action_move" msgid="4339390619886385032">"Premještanje stavke"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Premještanje u redak <xliff:g id="NUMBER_0">%1$s</xliff:g>, stupac <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Premještanje na položaj <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -145,4 +146,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Obavijesti i aplikacije isključeni su"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zatvori"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zatvoreno"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 7b87381..d8c433d 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Elem áthelyezése ide"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Elem hozzáadva a kezdőképernyőhöz"</string>
<string name="item_removed" msgid="851119963877842327">"Elem eltávolítva"</string>
+ <string name="undo" msgid="4151576204245173321">"Mégse"</string>
<string name="action_move" msgid="4339390619886385032">"Elem mozgatása"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Áthelyezés ide: <xliff:g id="NUMBER_0">%1$s</xliff:g>. sor, <xliff:g id="NUMBER_1">%2$s</xliff:g>. oszlop"</string>
<string name="move_to_position" msgid="6750008980455459790">"Áthelyezés a(z) <xliff:g id="NUMBER">%1$s</xliff:g>. pozícióba"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Az értesítések és az alkalmazások ki vannak kapcsolva"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Bezárás"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Bezárva"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Sikertelen: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
deleted file mode 100644
index 6844a27..0000000
--- a/res/values-hy-rAM/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Աշխատանքային"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Ծրագիրը տեղադրված չէ:"</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Հավելվածը հասանելի չէ"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Ներբեռնված ծրագիրն անջատված է Անվտանգ ռեժիմում"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Վիջեթներն անջատված են անվտանգ ռեժիմում"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Դյուրանցումն անհասանելի է"</string>
- <string name="home_screen" msgid="806512411299847073">"Հիմնական էկրան"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Հատուկ գործողություններ"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Հպեք և պահեք՝ վիջեթն ընտրելու համար:"</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Կրկնակի հպեք և պահեք՝ վիջեթ ավելացնելու համար կամ օգտվեք հարմարեցրած գործողություններից:"</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Լայնությունը՝ %1$d, բարձրությունը՝ %2$d"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Հպեք և պահեք՝ ձեռքով տեղադրելու համար"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Ավելացնել ավտոմատ կերպով"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Որոնել հավելվածներ"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Հավելվածների բեռնում…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"«<xliff:g id="QUERY">%1$s</xliff:g>» հարցմանը համապատասխանող հավելվածներ չեն գտնվել"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Որոնել այլ հավելվածներ"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Ծանուցումներ"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար։"</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար կամ օգտվեք հարմարեցրած գործողություններից:"</string>
- <string name="out_of_space" msgid="4691004494942118364">"Այլևս տեղ չկա այս հիմնական էկրանին:"</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ընտրյալների ցուցակում այլևս ազատ տեղ չկա"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Հավելվածների ցանկ"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Անձնական հավելվածների ցանկ"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Աշխատանքային հավելվածների ցանկ"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Հիմնական"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Հեռացնել"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Հեռացնել"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Հավելվածի տվյալներ"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Տեղադրել"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"տեղադրել դյուրանցումներ"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ծրագրին թույլ է տալիս ավելացնել դյուրանցումներ՝ առանց օգտագործողի միջամտության:"</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"կարդալ հիմնաէջի կարգավորումներն ու դյուրանցումները"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Ծրագրին թույլ է տալիս կարդալ հիմնաէջի կարգավորումներն ու դյուրանցումները:"</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"ստեղծել հիմնաէջի կարգավորումներ ու դյուրանցումներ"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Ծրագրին թույլ է տալիս փոփոխել հիմնաէջի կարգավորումներն ու դյուրանցումները:"</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածին չի թույլատրվում հեռախոսազանգեր կատարել"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Վիջեթի բեռնման խնդիր կա"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Կարգավորում"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Սա համակարգային ծրագիր է և չի կարող ապատեղադրվել:"</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Անանուն պանակ"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածն անջատված է"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ունի <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> ծանուցում</item>
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ունի <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> ծանուցում</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"Էջ %1$d՝ %2$d-ից"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"Հիմնական էկրան %1$d` %2$d-ից"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Հիմնական էկրանի նոր էջ"</string>
- <string name="folder_opened" msgid="94695026776264709">"Պանակը բաց է, <xliff:g id="WIDTH">%1$d</xliff:g>-ից <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Հպեք՝ պանակը փակելու համար"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Հպեք՝ նոր անվանումը պահելու համար"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Պանակը փակ է"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Պանակը վերանվանվեց <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Պանակ՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Վիջեթներ"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Պաստառներ"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Գլխավոր էջի կարգավորումներ"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Անջատվել է ձեր ադմինիստրատորի կողմից"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Թույլ տալ հիմնական էկրանի պտտումը"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Հեռախոսը պտտելու դեպքում"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Ծանուցումների կետիկներ"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Միացված է"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Անջատված է"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Անհրաժեշտ է ծանուցման թույլտվություն"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Ծանուցումների կետիկները ցուցադրելու համար միացրեք ծանուցումները <xliff:g id="NAME">%1$s</xliff:g>-ի համար"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Փոխել կարգավորումները"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Ցուցադրել ծանուցումների կետիկները"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ավելացնել պատկերակը Հիմնական էկրանին"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Նոր հավելվածների համար"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Փոխել պատկերակների տեսքը"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"հիմնական էկրանին"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Օգտագործել համակարգի կանխադրված կարգավորումը"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Քառակուսի"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Քառանկյուն"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Օղակ"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Արցունքաձև"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Պատկերակների տեսքի փոփոխությունները կիրառվում են"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Անհայտ է"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Հեռացնել"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Գտնել"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Այս ծրագիրը տեղադրված չէ:"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Այս պատկերակի ծրագիրը տեղադրված չէ: Դուք կարող եք հեռացնել այն կամ գտնել ծրագիրը և տեղադրել այն ձեռքով:"</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>–ի ներբեռնում (<xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>-ի տեղադրման սպասում"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> վիջեթներ"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Ավելացնել Հիմնական էկրանին"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Տեղափոխել տարրն այստեղ"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Տարրն ավելացվեց հիմնական էկրանին"</string>
- <string name="item_removed" msgid="851119963877842327">"Տարրը հեռացվեց"</string>
- <string name="action_move" msgid="4339390619886385032">"Տեղափոխել տարրը"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"Տեղափոխել տող <xliff:g id="NUMBER_0">%1$s</xliff:g> սյունակ <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="move_to_position" msgid="6750008980455459790">"Տեղափոխել դիրք <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Տեղափոխել նախընտրած դիրք՝ <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="item_moved" msgid="4606538322571412879">"Տարրը տեղափոխվեց"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Ավելացնել թղթապանակում՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"Ավելացնել «<xliff:g id="NAME">%1$s</xliff:g>» պանակին"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Տարրն ավելացվեց թղթապանակում"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Ստեղծել թղթապանակ, օգտագործելով՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"Պանակը ստեղծվեց"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Տեղափոխել Հիմնական էկրան"</string>
- <string name="action_resize" msgid="1802976324781771067">"Չափափոխել"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Ավելացնել լայնությունը"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Ավելացնել բարձրությունը"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Նվազեցնել լայնությունը"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Նվազեցնել բարձրությունը"</string>
- <string name="widget_resized" msgid="9130327887929620">"Վիջեթի լայնությունը փոխվել է <xliff:g id="NUMBER_0">%1$s</xliff:g>-ի, իսկ բարձրությունը՝ <xliff:g id="NUMBER_1">%2$s</xliff:g>-ի"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Դյուրանցումներ"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> դյուրանցումներ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածի համար"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> դյուրացում և <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ծանուցում <xliff:g id="APP_NAME">%3$s</xliff:g>-ի համար"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Անտեսել"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Ծանուցումը մերժված է"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Անձնական"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Աշխատանքային"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Աշխատանքային պրոֆիլ"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Գտեք աշխատանքային հավելվածներ այստեղ"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Աշխատանքային հավելվածները նշված են հատուկ նշանով: Նման հավելվածների անվտանգությունը ապահովում է ձեր կազմակերպությունը։ Հարմարության համար աշխատանքային հավելվածները կարող եք տեղափոխել հիմնական էկրան։"</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Կառավարվում է ձեր կազմակերպության կողմից"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Ծանուցումներն ու հավելվածներն անջատված են"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Փակել"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Փակվեց"</string>
-</resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 2b4a38b..13bf0c6 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Տեղափոխել տարրն այստեղ"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Տարրն ավելացվեց հիմնական էկրանին"</string>
<string name="item_removed" msgid="851119963877842327">"Տարրը հեռացվեց"</string>
+ <string name="undo" msgid="4151576204245173321">"Հետարկել"</string>
<string name="action_move" msgid="4339390619886385032">"Տեղափոխել տարրը"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Տեղափոխել տող <xliff:g id="NUMBER_0">%1$s</xliff:g> սյունակ <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Տեղափոխել դիրք <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Ծանուցումներն ու հավելվածներն անջատված են"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Փակել"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Փակվեց"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Չհաջողվեց կատարել գործողությունը (<xliff:g id="WHAT">%1$s</xliff:g>)"</string>
</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 78ffc96..a4c6a54 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Pindahkan item ke sini"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Item ditambahkan ke layar utama"</string>
<string name="item_removed" msgid="851119963877842327">"Item dihapus"</string>
+ <string name="undo" msgid="4151576204245173321">"Urungkan"</string>
<string name="action_move" msgid="4339390619886385032">"Pindahkan item"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Pindahkan ke baris <xliff:g id="NUMBER_0">%1$s</xliff:g> kolom <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"PIndahkan ke posisi <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifikasi dan aplikasi nonaktif"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Tutup"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Ditutup"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml
deleted file mode 100644
index 3b5daba..0000000
--- a/res/values-is-rIS/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Vinna"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Forritið er ekki uppsett."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Forritið er ekki í boði"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Sótt forrit er óvirkt í öryggisstillingu"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Græjur eru óvirkar í öruggri stillingu"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Flýtileið er ekki tiltæk"</string>
- <string name="home_screen" msgid="806512411299847073">"Heimaskjár"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Sérsniðnar aðgerðir"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Haltu fingri á græju til að grípa hana."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Ýttu tvisvar og haltu fingri á græju til að grípa hana eða notaðu sérsniðnar aðgerðir."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d á breidd og %2$d á hæð"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Haltu inni til að staðsetja handvirkt"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Bæta sjálfkrafa við"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Leita í forritum"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Hleður forrit…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"Ekki fundust forrit sem samsvara „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Leita að fleiri forritum"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Tilkynningar"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Haltu fingri á flýtileið til að grípa hana."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Ýttu tvisvar og haltu fingri á flýtileið til að grípa hana eða notaðu sérsniðnar aðgerðir."</string>
- <string name="out_of_space" msgid="4691004494942118364">"Ekki meira pláss á þessum heimaskjá."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ekki meira pláss í bakka fyrir uppáhald"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Forritalisti"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Listi yfir eigin forrit"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Listi yfir vinnuforrit"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Heim"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Fjarlægja"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Fjarlægja"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Forritsupplýsingar"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Setja upp"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"setja upp flýtileiðir"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Leyfir forriti að bæta við flýtileiðum án íhlutunar notanda."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"lesa stillingar og flýtileiðir heimaskjás"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Leyfir forriti að lesa stillingar og flýtileiðir heimaskjás."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"skrifa stillingar og flýtileiðir heimaskjás"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Leyfir forriti að breyta stillingum og flýtileiðum heimaskjás."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> hefur ekki leyfi til að hringja símtöl"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Vandamál við að hlaða græju"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Uppsetning"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Þetta er kerfisforrit sem ekki er hægt að fjarlægja."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Ónefnd mappa"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"Óvirkt <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, er með <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> tilkynningu</item>
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, er með <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> tilkynningar</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"Síða %1$d af %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"Heimaskjár %1$d af %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Ný síða á heimaskjá"</string>
- <string name="folder_opened" msgid="94695026776264709">"Mappa opnuð, <xliff:g id="WIDTH">%1$d</xliff:g> sinnum <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Ýttu til að loka möppunni"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Ýttu til að vista breytt heiti"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Möppu lokað"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Heiti möppu breytt í <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Mappa: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Græjur"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Veggfóður"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Heimastillingar"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Gert óvirkt af kerfisstjóra"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Leyfa snúning fyrir heimaskjá"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Þegar símanum er snúið"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Tilkynningapunktar"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Kveikt"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Slökkt"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Aðgangs að tilkynningum er krafist"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Til að sýna tilkynningarpunkta skaltu kveikja á forritstilkynningum fyrir <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Breyta stillingum"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Sýna tilkynningapunkta"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Bæta tákni á heimaskjáinn"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Fyrir ný forrit"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Breyta formi tákns"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"á heimaskjá"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Nota sjálfgildi kerfis"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Ferningur"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Ferhringur"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Hringur"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Dropi"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Breytir formi tákns"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Óþekkt"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Fjarlægja"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Leita"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Þetta forrit er ekki uppsett"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Forritið fyrir þetta tákn er ekki uppsett. Þú getur fjarlægt það eða leitað að forritinu og sett það upp handvirkt."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> í niðurhali, <xliff:g id="PROGRESS">%2$s</xliff:g> lokið"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> bíður uppsetningar"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>-græjur"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Bæta á heimaskjá"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Færa atriði hingað"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Atriði bætt á heimaskjáinn"</string>
- <string name="item_removed" msgid="851119963877842327">"Atriði fjarlægt"</string>
- <string name="action_move" msgid="4339390619886385032">"Færa atriði"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"Færa í línu <xliff:g id="NUMBER_0">%1$s</xliff:g>, dálk <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="move_to_position" msgid="6750008980455459790">"Færa í stöðu <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Færa í stöðu <xliff:g id="NUMBER">%1$s</xliff:g> á festisvæði"</string>
- <string name="item_moved" msgid="4606538322571412879">"Atriði fært"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Setja í möppu: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"Setja í möppu með <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Atriði sett í möppu"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Búa til möppu með: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"Mappa búin til"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Færa á heimaskjá"</string>
- <string name="action_resize" msgid="1802976324781771067">"Breyta stærð"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Auka breidd"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Auka hæð"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Minnka breidd"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Minnka hæð"</string>
- <string name="widget_resized" msgid="9130327887929620">"Stærð græju breytt í <xliff:g id="NUMBER_0">%1$s</xliff:g> á breidd og <xliff:g id="NUMBER_1">%2$s</xliff:g> á hæð"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Flýtileiðir"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> flýtileiðir fyrir <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> flýtileiðir og <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> tilkynningar fyrir <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Hunsa"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Tilkynningu lokað"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Persónulegt"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Vinna"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Vinnusnið"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Hér finnurðu vinnuforrit"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Öll vinnuforrit eru með merki og fyrirtækið þitt tryggir öryggi þeirra. Færðu forrit yfir á heimaskjáinn til að fá auðveldari aðgang að þeim."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Stjórnað af fyrirtækinu þínu"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Slökkt er á tilkynningum og forritum"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Loka"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Lokað"</string>
-</resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 04842e4..733d0b7 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Færa atriði hingað"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Atriði bætt á heimaskjáinn"</string>
<string name="item_removed" msgid="851119963877842327">"Atriði fjarlægt"</string>
+ <string name="undo" msgid="4151576204245173321">"Afturkalla"</string>
<string name="action_move" msgid="4339390619886385032">"Færa atriði"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Færa í línu <xliff:g id="NUMBER_0">%1$s</xliff:g>, dálk <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Færa í stöðu <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Slökkt er á tilkynningum og forritum"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Loka"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Lokað"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Mistókst: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 28a8f93..1c53c75 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Sposta elemento qui"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Elemento aggiunto alla schermata Home"</string>
<string name="item_removed" msgid="851119963877842327">"Elemento rimosso"</string>
+ <string name="undo" msgid="4151576204245173321">"Annulla"</string>
<string name="action_move" msgid="4339390619886385032">"Sposta elemento"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Sposta a riga <xliff:g id="NUMBER_0">%1$s</xliff:g>, colonna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Sposta nella posizione <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Le notifiche e le app non sono attive"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Chiudi"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Chiusa"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Operazione non riuscita: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index d4302c6..6ad2a00 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -39,7 +39,7 @@
<string name="all_apps_loading_message" msgid="5813968043155271636">"טוען אפליקציות…"</string>
<string name="all_apps_no_search_results" msgid="3200346862396363786">"לא נמצאו אפליקציות התואמות ל-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"חפש אפליקציות נוספות"</string>
- <string name="notifications_header" msgid="1404149926117359025">"הודעות"</string>
+ <string name="notifications_header" msgid="1404149926117359025">"התראות"</string>
<string name="long_press_shortcut_to_add" msgid="4524750017792716791">"כדי להוסיף קיצור דרך, יש לגעת בו ולהחזיק אותו."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"כדי להוסיף קיצור דרך או להשתמש בפעולות מותאמות אישית, יש להקיש על קיצור הדרך פעמיים ולהחזיק אותו."</string>
<string name="out_of_space" msgid="4691004494942118364">"אין עוד מקום במסך דף הבית הזה."</string>
@@ -65,10 +65,10 @@
<string name="folder_hint_text" msgid="6617836969016293992">"תיקיה ללא שם"</string>
<string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> מושבתת"</string>
<plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="two">לאפליקציה <xliff:g id="APP_NAME_2">%1$s</xliff:g> יש <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> הודעות</item>
- <item quantity="many">לאפליקציה <xliff:g id="APP_NAME_2">%1$s</xliff:g> יש <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> הודעות</item>
- <item quantity="other">לאפליקציה <xliff:g id="APP_NAME_2">%1$s</xliff:g> יש <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> הודעות</item>
- <item quantity="one">לאפליקציה <xliff:g id="APP_NAME_0">%1$s</xliff:g> יש הודעה אחת (<xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g>)</item>
+ <item quantity="two">לאפליקציה <xliff:g id="APP_NAME_2">%1$s</xliff:g> יש <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> התראות</item>
+ <item quantity="many">לאפליקציה <xliff:g id="APP_NAME_2">%1$s</xliff:g> יש <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> התראות</item>
+ <item quantity="other">לאפליקציה <xliff:g id="APP_NAME_2">%1$s</xliff:g> יש <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> התראות</item>
+ <item quantity="one">לאפליקציה <xliff:g id="APP_NAME_0">%1$s</xliff:g> יש התראה אחת (<xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g>)</item>
</plurals>
<string name="default_scroll_format" msgid="7475544710230993317">"דף %1$d מתוך %2$d"</string>
<string name="workspace_scroll_format" msgid="8458889198184077399">"מסך דף הבית %1$d מתוך %2$d"</string>
@@ -85,13 +85,13 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"הושבת על ידי מנהל המערכת שלך"</string>
<string name="allow_rotation_title" msgid="7728578836261442095">"אפשרות סיבוב של מסך דף הבית"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"כאשר הטלפון מסובב"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"סימני הודעות"</string>
+ <string name="icon_badging_title" msgid="874121399231955394">"סימני ההתראות"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"מופעלת"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"כבויה"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"נדרשת גישה להודעות"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"כדי להציג את סימני ההודעות, יש להפעיל הודעות מהאפליקציה <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"נדרשת גישה להתראות"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"כדי להציג את סימני ההתראות,יש להפעיל התראות מהאפליקציה <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"שנה את ההגדרות"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"הצגה של סימן ההודעות"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"הצגה של סימן ההתראות"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"הוספת סמל במסך דף הבית"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"לאפליקציות חדשות"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"שינוי הצורה של הסמלים"</string>
@@ -116,6 +116,7 @@
<string name="action_move_here" msgid="2170188780612570250">"העבר את הפריט לכאן"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"הפריט הועבר אל מסך דף הבית"</string>
<string name="item_removed" msgid="851119963877842327">"הפריט הוסר"</string>
+ <string name="undo" msgid="4151576204245173321">"ביטול"</string>
<string name="action_move" msgid="4339390619886385032">"העבר את הפריט"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"העבר אל שורה <xliff:g id="NUMBER_0">%1$s</xliff:g> עמודה <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"העבר אל מיקום <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -134,16 +135,17 @@
<string name="action_decrease_height" msgid="282377193880900022">"הקטן גובה"</string>
<string name="widget_resized" msgid="9130327887929620">"גודל הווידג\'ט שונה - רוחב <xliff:g id="NUMBER_0">%1$s</xliff:g> גובה <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="action_deep_shortcut" msgid="2864038805849372848">"קיצורי דרך"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"קיצורי דרך והודעות"</string>
+ <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"קיצורי דרך והתראות"</string>
<string name="action_dismiss_notification" msgid="5909461085055959187">"סגור"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"ההודעה נסגרה"</string>
+ <string name="notification_dismissed" msgid="6002233469409822874">"ההתראה נסגרה"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"אישיות"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"עבודה"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"פרופיל עבודה"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ניתן למצוא כאן את אפליקציות העבודה"</string>
<string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"לכל אפליקציית עבודה יש תג ואבטחתה מטופלת בידי הארגון. אפשר להעביר אפליקציות אל מסך דף הבית כדי להקל את הגישה אליהן."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"מנוהל בידי הארגון"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"הודעות ואפליקציות כבויות"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"התראות ואפליקציות כבויות"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"סגירה"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"סגור"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"הפעולה נכשלה: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 2598d18..4210600 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"アイテムをここに移動"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"アイテムをホーム画面に追加しました"</string>
<string name="item_removed" msgid="851119963877842327">"アイテムを削除しました"</string>
+ <string name="undo" msgid="4151576204245173321">"元に戻す"</string>
<string name="action_move" msgid="4339390619886385032">"アイテムを移動"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"行<xliff:g id="NUMBER_0">%1$s</xliff:g>、列<xliff:g id="NUMBER_1">%2$s</xliff:g>に移動"</string>
<string name="move_to_position" msgid="6750008980455459790">"位置<xliff:g id="NUMBER">%1$s</xliff:g>に移動"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"通知とアプリは OFF です"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"閉じる"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"終了"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"失敗: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
deleted file mode 100644
index 521ec80..0000000
--- a/res/values-ka-rGE/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"სამუშაო"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"აპი არ არის დაყენებული."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"აპი მიუწვდომელია"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"უსაფრთხო რეჟიმში ჩამოტვირთული აპი გაუქმებულია"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"უსაფრთხო რეჟიმში ვიჯეტი გამორთულია"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"მალსახმობი მიუწვდომელია"</string>
- <string name="home_screen" msgid="806512411299847073">"მთავარი ეკრანი"</string>
- <string name="custom_actions" msgid="3747508247759093328">"მორგებული ქმედებები"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"შეეხეთ და დააყოვნეთ ვიჯეტის ასარჩევად."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ორმაგად შეეხეთ და გეჭიროთ ვიჯეტის ასარჩევად ან მორგებული მოქმედებების გამოსაყენებლად."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"სიგრძე: %1$d, სიგანე: %2$d"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"ხანგრძლივად შეეხეთ ხელით განსათავსებლად"</string>
- <string name="place_automatically" msgid="8064208734425456485">"ავტომატურად დამატება"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"აპების ძიება"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"აპები იტვირთება…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"„<xliff:g id="QUERY">%1$s</xliff:g>“-ის თანხვედრი აპები არ მოიძებნა"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"მეტი აპის პოვნა"</string>
- <string name="notifications_header" msgid="1404149926117359025">"შეტყობინებები"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"შეეხეთ და დააყოვნეთ მალსახმობის ასარჩევად."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ორმაგად შეეხეთ და გეჭიროთ მალსახმობის ასარჩევად ან მორგებული მოქმედებების გამოსაყენებლად."</string>
- <string name="out_of_space" msgid="4691004494942118364">"ამ მთავარ ეკრანზე ადგილი აღარ არის."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"რჩეულების თაროზე ადგილი არ არის"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"აპების სია"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"პერსონალური აპების სია"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"სამსახურის აპების სია"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"მთავარი"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"ამოშლა"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"დეინსტალაცია"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"აპის შესახებ"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"ინსტალაცია"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"მალსახმობების დაყენება"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"აპისთვის მალსახმობების დამოუკიდებლად დამატების უფლების მიცემა."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"მთავარი ეკრანის პარამეტრებისა და მალსახმობების წაკითხვა"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"აპისთვის მთავარი ეკრანის პარამეტრებისა და მალსახმობების წაკითხვის უფლების მიცემა."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"მთავარი ეკრანის პარამეტრებისა და მალსახმობების ჩაწერა"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"აპისთვის მთავარი ეკრანის პარამეტრებისა და მალსახმობების შეცვლის უფლების მიცემა."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ს არ აქვს სატელეფონო ზარების განხორციელების უფლება"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"პრობლემა ვიჯეტის ჩატვირთვისას"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"დაყენება"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"ეს სისტემური აპია და მისი წაშლა შეუძლებელია."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"უსახელო საქაღალდე"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> გაითიშა"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>-ში <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> შეტყობინებაა</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>-ში <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> შეტყობინებაა</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"გვერდი %1$d %2$d-დან"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"მთავარი ეკრანი %1$d, %2$d-დან"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"მთავარი ეკრანის ახალი გვერდი"</string>
- <string name="folder_opened" msgid="94695026776264709">"საქაღალდე გახსნილია, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"შეეხეთ საქაღალდის დასახურად"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"შეეხეთ გადარქმეული სახელის შესანახად"</string>
- <string name="folder_closed" msgid="4100806530910930934">"საქაღალდე დაიხურა"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"საქაღალდეს შეეცვალა სახელი „<xliff:g id="NAME">%1$s</xliff:g>“-ად"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"საქაღალდე: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"ვიჯეტები"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"ფონები"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"მთავარი გვერდის პარამეტრები"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"გათიშულია თქვენი ადმინისტრატორის მიერ"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"მთავარი ეკრანის შეტრიალების დაშვება"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"ტელეფონის შეტრიალებისას"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"შეტყობინების ნიშნულები"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"ჩართული"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"გამორთული"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"საჭიროა შეტყობინებებზე წვდომა"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"შეტყობინებათა ნიშნულების საჩვენებლად, ჩართეთ აპის შეტყობინებები <xliff:g id="NAME">%1$s</xliff:g>-ისთვის"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"პარამეტრების შეცვლა"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"შეტყობინების ნიშნულების ჩვენება"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ხატულას მთავარ ეკრანზე დამატება"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ახალი აპებისთვის"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"ხატულას ფორმის შეცვლა"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"მთავარ ეკრანზე"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"ნაგულისხმევი სისტემური პარამეტრების გამოყენება"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"კვადრატი"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"წრეკუთხედი"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"წრე"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"წვეთი"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"მიმდინარეობს ხატულას ფორმის ცვლილებების მიყენება"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"უცნობი"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"ამოშლა"</string>
- <string name="abandoned_search" msgid="891119232568284442">"ძიება"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"ეს აპი დაყენებული არ არის"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ამ ხატულის აპი დაყენებული არ არის. შეგიძლიათ ამოშალოთ, ან მოიძიოთ აპი და ხელით მოახდინოთ მისი ინსტალაცია."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"მიმდინარეობს <xliff:g id="NAME">%1$s</xliff:g>-ის ჩამოტვირთვა, <xliff:g id="PROGRESS">%2$s</xliff:g> დასრულდა"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ელოდება ინსტალაციას"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>-ის ვიჯეტები"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"მთავარ ეკრანზე დამატება"</string>
- <string name="action_move_here" msgid="2170188780612570250">"ერთეულის გადაადგილება აქ"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"ერთეული დაემატა მთავარ ეკრანს"</string>
- <string name="item_removed" msgid="851119963877842327">"ერთეული წაიშალა"</string>
- <string name="action_move" msgid="4339390619886385032">"ერთეულის გადაადგილება"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"გადატანა რიგში <xliff:g id="NUMBER_0">%1$s</xliff:g> სვეტში <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="move_to_position" msgid="6750008980455459790">"გადატანა <xliff:g id="NUMBER">%1$s</xliff:g> პოზიციაზე"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"გადატანა რჩეულთა პოზიციაზე <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="item_moved" msgid="4606538322571412879">"ერთეული გადაადგილდა"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"საქაღალდეში დამატება: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"საქაღალდეში დამატება <xliff:g id="NAME">%1$s</xliff:g>-ით"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"ერთეული დაემატა საქაღალდეს"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"საქაღალდის შექმნა ერთეულით: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"საქაღალდე შექმნილია"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"მთავარ ეკრანზე გადატანა"</string>
- <string name="action_resize" msgid="1802976324781771067">"ზომის შეცვლა"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"სიგანის გაზრდა"</string>
- <string name="action_increase_height" msgid="459390020612501122">"სიმაღლის გაზრდა"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"სიგანის შემცირება"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"სიმაღლის შემცირება"</string>
- <string name="widget_resized" msgid="9130327887929620">"ვიჯეტის ზომები შეიცვალა: სიგანე <xliff:g id="NUMBER_0">%1$s</xliff:g> სიმაღლე <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"მალსახმობები"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g>-ს აქვს <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> მალსახმობი"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g>-ის <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> მალსახმობი და <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> შეტყობინება"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"დახურვა"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"შეტყობინება დაიხურა"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"პირადი"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"სამსახური"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"სამსახურის პროფილი"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"აქ თავმოყრილია სამსახურის აპები"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"სამსახურის თითოეულ აპს აქვს ბეჯი, რაც ნიშნავს, რომ მათ უსაფრთხოებას თქვენი ორგანიზაცია უზრუნველყოფს. მარტივი წვდომისთვის, შეგიძლიათ სამსახურის აპები მთავარი ეკრანზე გადაიტანოთ."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"იმართება თქვენი ორგანიზაციის მიერ"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"შეტყობინებები და აპები გამორთულია"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"დახურვა"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"დახურული"</string>
-</resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 3bdbab7..8b4503e 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"ერთეულის გადაადგილება აქ"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"ერთეული დაემატა მთავარ ეკრანს"</string>
<string name="item_removed" msgid="851119963877842327">"ერთეული წაიშალა"</string>
+ <string name="undo" msgid="4151576204245173321">"მოქმედების გაუქმება"</string>
<string name="action_move" msgid="4339390619886385032">"ერთეულის გადაადგილება"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"გადატანა რიგში <xliff:g id="NUMBER_0">%1$s</xliff:g> სვეტში <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"გადატანა <xliff:g id="NUMBER">%1$s</xliff:g> პოზიციაზე"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"შეტყობინებები და აპები გამორთულია"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"დახურვა"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"დახურული"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"ვერ მოხერხდა: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml
deleted file mode 100644
index 7ab73d9..0000000
--- a/res/values-kk-rKZ/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Жұмыс"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Қолданба орнатылмаған."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Қолданба қол жетімді емес"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Жүктелген қолданба қауіпсіз режимде өшірілген"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Қауіпсіз режимде виджеттер өшіріледі"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Таңбаша қолжетімді емес"</string>
- <string name="home_screen" msgid="806512411299847073">"Негізгі экран"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Арнаулы әрекеттер"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Виджетті таңдау үшін түртіп, мықтап ұстаңыз."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Виджетті таңдау немесе арнаулы әрекеттерді таңдау үшін екі рет түртіп, ұстап тұрыңыз."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Ені: %1$d, биіктігі: %2$d"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Қолмен қою үшін басып тұрыңыз"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Автоматты енгізу"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Қолданбаларды іздеу"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Қолданбалар жүктелуде…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" сұрауына сәйкес келетін қолданбалар жоқ"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Қосымша қолданбалар іздеу"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Хабарландырулар"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Таңбашаны таңдау үшін оны басып, ұстап тұрыңыз."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Екі рет басып, ұстап тұрып, таңбашаны таңдаңыз немесе арнаулы әрекеттерді пайдаланыңыз."</string>
- <string name="out_of_space" msgid="4691004494942118364">"Бұл Негізгі экранда орын қалмады."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Қалаулылар науасында орын қалмады"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Қолданбалар тізімі"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Жеке қолданбалар тізімі"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Жұмыс қолданбаларының тізімі"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Негізгі"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Жою"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Жою"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Қолданба ақпараты"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Орнату"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"төте пернелерді орнату"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Қолданбаға пайдаланушының қатысуынсыз төте пернелерді қосу мүмкіндігін береді."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"Негізгі экрандағы параметрлер мен төте пернелерді оқу"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Қолданбаға Негізгі экрандағы параметрлер мен төте пернелерді оқу мүмкіндігін береді."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"Негізгі экран параметрлері мен төте пернелерін жазу"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Қолданбаға Негізгі экрандағы параметрлер мен төте пернелерді өзгерту мүмкіндігін береді."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> арқылы телефон қоңырауларын соғуға рұқсат етілмеген"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Виджетті жүктеу барысында мәселе орын алды"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Орнату"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Бұл жүйе қолданбасы, сондықтан оны алу мүмкін емес."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Атауы жоқ қалта"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> өшірілді"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> қолданбасында <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> хабарландыру бар</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> қолданбасында <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> хабарландыру бар</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"%1$d бет, барлығы %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d негізгі экран, барлығы %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Жаңа негізгі экран беті"</string>
- <string name="folder_opened" msgid="94695026776264709">"Қалта ашылды, <xliff:g id="WIDTH">%1$d</xliff:g> және <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Қалтаны жабу үшін түртіңіз"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Қайта атауды сақтау үшін түртіңіз"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Қалта жабылды"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Қалта атауы <xliff:g id="NAME">%1$s</xliff:g> болып өзгертілді"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Қалта: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Виджеттер"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Тұсқағаздар"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Негізгі экран параметрлері"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Әкімші өшірді"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Негізгі экранның бұрылуына рұқсат ету"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Телефон бұрылғанда"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Хабарландыру белгілері"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Қосулы"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Өшірулі"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Хабарландыруға кіру рұқсаты қажет"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Хабарландыру белгілерін көрсету үшін <xliff:g id="NAME">%1$s</xliff:g> қолданбасының қолданба хабарландыруларын қосыңыз"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Параметрлерді өзгерту"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Хабарландыру белгілерін көрсету"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Негізгі экранға белгіше енгізу"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Жаңа қолданбаларға арналған"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Белгіше пішінін өзгерту"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"Негізгі экранда"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Жүйенің әдепкі параметрін пайдалану"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Шаршы"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Жұмыр төртбұрыш"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Шеңбер"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Тамшы"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Белгіше пішіні өзгерістері күшіне енуде"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Белгісіз"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Алып тастау"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Іздеу"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Бұл қолданба орнатылмаған"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Осы белгіше үшін қолданба орнатылмаған. Оны жоюға болады немесе қолданбаны іздеп, қолмен орнатуға болады."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> жүктелуде, <xliff:g id="PROGRESS">%2$s</xliff:g> аяқталды"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> орнату күтілуде"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> виджеті"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Негізгі экранға қосу"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Элементті мұнда жылжыту"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Элемент негізгі экранға қосылды"</string>
- <string name="item_removed" msgid="851119963877842327">"Элемент жойылды"</string>
- <string name="action_move" msgid="4339390619886385032">"Элементті жылжыту"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g>-жол, <xliff:g id="NUMBER_1">%2$s</xliff:g>-бағанға жылжыту"</string>
- <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>-орынға жылжыту"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"<xliff:g id="NUMBER">%1$s</xliff:g> нөмірлі таңдаулы орынға жылжыту"</string>
- <string name="item_moved" msgid="4606538322571412879">"Элемент жылжытылды"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Қалтаға қосу: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> бар қалтаға қосу"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Элемент қалтаға қосылды"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Мына бар қалтаны жасау: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"Қалта жасалды"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Негізгі экранға жылжыту"</string>
- <string name="action_resize" msgid="1802976324781771067">"Өлшемін өзгерту"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Енін арттыру"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Биіктігін арттыру"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Енін азайту"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Биіктігін азайту"</string>
- <string name="widget_resized" msgid="9130327887929620">"Виджет өлшемінің ені <xliff:g id="NUMBER_0">%1$s</xliff:g>, биіктігі <xliff:g id="NUMBER_1">%2$s</xliff:g> болып өзгертілді"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Таңбашалар"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасына арналған <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> таңбаша"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> қолданбасының <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> таңбашасы мен <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> хабарландыруы"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Бас тарту"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Хабарландырудан бас тартылды"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Жеке"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Жұмыс"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Жұмыс профилі"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Жұмыс қолданбалары осы жерде берілген"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Әрбір жұмыс қолданбасында танымбелгі бар. Ол оның қауіпсіздігі ұйым арқылы қамтамасыз етілетінін білдіреді. Жұмыс қолданбаларына оңай кіру үшін, оларды Негізгі экранға жылжытуға болады."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Ұйым арқылы басқарылады"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Хабарландырулар мен қолданбалар өшірулі"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Жабу"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Жабық"</string>
-</resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 98afccc..bdcb8b0 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Элементті мұнда жылжыту"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Элемент негізгі экранға қосылды"</string>
<string name="item_removed" msgid="851119963877842327">"Элемент жойылды"</string>
+ <string name="undo" msgid="4151576204245173321">"Қайтару"</string>
<string name="action_move" msgid="4339390619886385032">"Элементті жылжыту"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g>-жол, <xliff:g id="NUMBER_1">%2$s</xliff:g>-бағанға жылжыту"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>-орынға жылжыту"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Хабарландырулар мен қолданбалар өшірулі"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Жабу"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Жабық"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Қате шықты: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml
deleted file mode 100644
index 582bb33..0000000
--- a/res/values-km-rKH/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"ការងារ"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"មិនបានដំឡើងកម្មវិធី។"</string>
- <string name="activity_not_available" msgid="7456344436509528827">"មិនមានកម្មវិធី"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"បានបិទកម្មវិធីដែលបានទាញយកក្នុងរបៀបសុវត្ថិភាព"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"បានបិទធាតុក្រាហ្វិកក្នុងរបៀបសុវត្ថិភាព"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"ផ្លូវកាត់មិនអាចប្រើបានទេ"</string>
- <string name="home_screen" msgid="806512411299847073">"អេក្រង់ដើម"</string>
- <string name="custom_actions" msgid="3747508247759093328">"សកម្មភាពផ្ទាល់ខ្លួន"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"ប៉ះ & សង្កត់ ដើម្បីជ្រើសធាតុក្រាហ្វិក។"</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ប៉ះពីរដង ហើយចុចឲ្យជាប់ដើម្បីជ្រើសយកធាតុក្រាហ្វិក ឬប្រើសកម្មភាពផ្ទាល់ខ្លួន។"</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"ទទឺង %1$d គុណនឹងកម្ពស់ %2$d"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"ចុចឲ្យជាប់ដើម្បីបញ្ចូលវាដោយផ្ទាល់"</string>
- <string name="place_automatically" msgid="8064208734425456485">"បញ្ចូលដោយស្វ័យប្រវត្តិ"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ស្វែងរកកម្មវិធី"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"កំពុងផ្ទុកកម្មវិធី…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"រកមិនឃើញកម្មវិធីដែលត្រូវគ្នាជាមួយ \"<xliff:g id="QUERY">%1$s</xliff:g>\" ទេ"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"ស្វែងរកកម្មវិធីច្រើនទៀត"</string>
- <string name="notifications_header" msgid="1404149926117359025">"ការជូនដំណឹង"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ចុចឱ្យជាប់ដើម្បីជ្រើសរើសផ្លូវកាត់មួយ។"</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ចុចពីរដង ហើយចុចឱ្យជាប់ដើម្បីជ្រើសរើសផ្លូវកាត់មួយ ឬប្រើសកម្មភាពផ្ទាល់ខ្លួន។"</string>
- <string name="out_of_space" msgid="4691004494942118364">"គ្មានបន្ទប់នៅលើអេក្រង់ដើមនេះទៀតទេ។"</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"គ្មានបន្ទប់ក្នុងថាសនិយមប្រើ"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"បញ្ជីកម្មវិធី"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"បញ្ជីកម្មវិធីផ្ទាល់ខ្លួន"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"បញ្ជីកម្មវិធីការងារ"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"ដើម"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"យកចេញ"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"លុបការដំឡើង"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"ព័ត៌មានកម្មវិធី"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"ដំឡើង"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"ដំឡើងផ្លូវកាត់"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"អនុញ្ញាតឲ្យកម្មវិធីបន្ថែមផ្លូវកាត់ ដោយមិនចាំបាច់អំពើពីអ្នកប្រើ។"</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"អានការកំណត់ និងផ្លូវកាត់អេក្រង់ដើម"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"អនុញ្ញាតឲ្យកម្មវិធីអានការកំណត់ និងផ្លូវកាត់ក្នុងអេក្រង់ដើម។"</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"សរសេរការកំណត់ និងផ្លូវកាត់លើអេក្រង់ដើម"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"អនុញ្ញាតឲ្យកម្មវិធីប្ដូរការកំណត់ និងផ្លូវកាត់ក្នុងអេក្រង់ដើម។"</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនត្រូវបានអនុញ្ញាតឲ្យធ្វើការហៅទូរស័ព្ទទេ"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"បញ្ហាក្នុងការផ្ទុកធាតុក្រាហ្វិក"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"រៀបចំ"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"នេះជាកម្មវិធីប្រព័ន្ធ មិនអាចលុបបានទេ។"</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"ថតគ្មានឈ្មោះ"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"បានបិទដំណើរការ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> មានការជូនដំណឹង <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g></item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> មានការជូនដំណឹង <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g></item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"ទំព័រ %1$d នៃ %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"អេក្រង់ដើម %1$d នៃ %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"ទំព័រអេក្រង់ដើមថ្មី"</string>
- <string name="folder_opened" msgid="94695026776264709">"បានបើកថត <xliff:g id="WIDTH">%1$d</xliff:g> ដោយ <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"ប៉ះ ដើម្បីបិទថត"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"ប៉ះដើម្បីរក្សាទុកឈ្មោះដែលបានប្តូរ"</string>
- <string name="folder_closed" msgid="4100806530910930934">"បានបិទថត"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"បានប្ដូរឈ្មោះថតជា <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"ថត៖ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"ធាតុក្រាហ្វិក"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"ផ្ទាំងរូបភាព"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"ការកំណត់ទំព័រដើម"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"បានបិទដំណើរការដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"អនុញ្ញាតការបងិ្វលអេក្រង់ដើម"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"នៅពេលដែលបង្វិលទូរស័ព្ទរបស់អ្នក"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"ស្លាកជូនដំណឹង"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"បើក"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"បិទ"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"តម្រូវឲ្យមានសិទ្ធិចូលប្រើប្រាស់ការជូនដំណឹង"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"ដើម្បីបង្ហាញស្លាកជូនដំណឹង សូមបើកការជូនដំណឹងកម្មវិធីសម្រាប់ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"ប្ដូរការកំណត់"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"បង្ហាញស្លាកជូនដំណឹង"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"បញ្ចូលរូបតំណាងទៅអេក្រង់ដើម"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"សម្រាប់កម្មវិធីថ្មី"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"ប្តូររូបរាងរូបតំណាង"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"នៅលើអេក្រង់ដើម"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"ប្រើលំនាំដើមរបស់ប្រព័ន្ធ"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"ការ៉េ"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"ការ៉េជ្រុងកោង"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"រង្វង់"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"តំណក់ទឹកភ្នែក"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"កំពុងអនុវត្តការប្តូររូបរាងរូបតំណាង"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"មិនស្គាល់"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"លុបចេញ"</string>
- <string name="abandoned_search" msgid="891119232568284442">"ស្វែងរក"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"មិនបានដំឡើងកម្មវិធីនេះ"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"មិនបានដំឡើងកម្មវិធីសម្រាប់រូបតំណាងនេះ។ អ្នកអាចលុបវា ឬស្វែងរកកម្មវិធី និងដំឡើងវាដោយដៃ។"</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"កំពុងដោនឡូត <xliff:g id="NAME">%1$s</xliff:g> បានបញ្ចប់ <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> កំពុងរង់ចាំការដំឡើង"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"ធាតុក្រាហ្វិក <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"បន្ថែមទៅអេក្រង់ដើម"</string>
- <string name="action_move_here" msgid="2170188780612570250">"ផ្លាស់ធាតុមកទីនេះ"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"ធាតុដែលត្រូវបានបន្ថែមទៅអេក្រង់ដើម"</string>
- <string name="item_removed" msgid="851119963877842327">"ធាតុដែលបានដកចេញ"</string>
- <string name="action_move" msgid="4339390619886385032">"ផ្លាស់ទីធាតុ"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"ផ្លាស់ទីទៅជួរដេកទី <xliff:g id="NUMBER_0">%1$s</xliff:g> ជួរឈរទី <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="move_to_position" msgid="6750008980455459790">"ផ្លាស់ទីទៅទីតាំង <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"ផ្លាស់ទីទៅការចូលចិត្តទីតាំងទី <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="item_moved" msgid="4606538322571412879">"បានផ្លាស់ទីធាតុ"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"បន្ថែមទៅថតឯកសារ៖ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"បន្ថែមទៅថតឯកសារដែលមានឈ្មោះ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"បានបន្ថែមធាតុទៅថតឯកសារ"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"បង្កើតថតឯកសារជាមួយ៖ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"បានបង្កើតថតឯកសារ"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"ផ្លាស់ទៅអេក្រង់ដើម"</string>
- <string name="action_resize" msgid="1802976324781771067">"ប្ដូរទំហំ"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"បង្កើនទទឹង"</string>
- <string name="action_increase_height" msgid="459390020612501122">"បង្កើនកម្ពស់"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"បន្ថយទទឹង"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"បន្ថយកម្ពស់"</string>
- <string name="widget_resized" msgid="9130327887929620">"ធាតុក្រាហ្វិកដែលបានប្តូរទំហំទៅទទឹងប្រវែង <xliff:g id="NUMBER_0">%1$s</xliff:g> កម្ពស់ប្រវែង <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"ផ្លូវកាត់"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ផ្លូវកាត់សម្រាប់ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"ផ្លូវកាត់ចំនួន <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> និងការជូនដំណឹងចំនួន <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> សម្រាប់ <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"បដិសេធ"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"បានបដិសេធការជូនដំណឹង"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"ផ្ទាល់ខ្លួន"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"ការងារ"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"កម្រងព័ត៌មានការងារ"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ស្វែងរកកម្មវិធីការងារនៅទីនេះ"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"កម្មវិធីការងារនីមួយៗមានស្លាកមួយ និងត្រូវបានរក្សាទុកយ៉ាងមានសុវត្ថិភាពដោយស្ថាប័នរបស់អ្នក។ សូមផ្លាស់ទីកម្មវិធីទៅកាន់អេក្រង់ដើមរបស់អ្នក ដើម្បីងាយស្រួលចូលប្រើជាងមុន។"</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"គ្រប់គ្រងដោយស្ថាប័នរបស់អ្នក"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"ការជូនដំណឹង និងកម្មវិធីត្រូវបានបិទ"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"បិទ"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"បានបិទ"</string>
-</resources>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index ba8d775..db67e31 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"ផ្លាស់ធាតុមកទីនេះ"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"ធាតុដែលត្រូវបានបន្ថែមទៅអេក្រង់ដើម"</string>
<string name="item_removed" msgid="851119963877842327">"ធាតុដែលបានដកចេញ"</string>
+ <string name="undo" msgid="4151576204245173321">"ត្រឡប់វិញ"</string>
<string name="action_move" msgid="4339390619886385032">"ផ្លាស់ទីធាតុ"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"ផ្លាស់ទីទៅជួរដេកទី <xliff:g id="NUMBER_0">%1$s</xliff:g> ជួរឈរទី <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"ផ្លាស់ទីទៅទីតាំង <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"ការជូនដំណឹង និងកម្មវិធីត្រូវបានបិទ"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"បិទ"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"បានបិទ"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"បានបរាជ័យ៖ <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
deleted file mode 100644
index 56ebe0a..0000000
--- a/res/values-kn-rIN/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"ಕೆಲಸ"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ"</string>
- <string name="activity_not_available" msgid="7456344436509528827">"ಅಪ್ಲಿಕೇಶನ್ ಲಭ್ಯವಿಲ್ಲ"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"ಡೌನ್ಲೋಡ್ ಮಾಡಲಾದ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಸುರಕ್ಷಿತ ಮೋಡ್ನಲ್ಲಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"ಸುರಕ್ಷಿತ ಮೋಡ್ನಲ್ಲಿ ವಿಜೆಟ್ಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"ಶಾರ್ಟ್ಕಟ್ ಲಭ್ಯವಿಲ್ಲ"</string>
- <string name="home_screen" msgid="806512411299847073">"ಮುಖಪುಟದ ಪರದೆ"</string>
- <string name="custom_actions" msgid="3747508247759093328">"ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳು"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"ವಿಜೆಟ್ ಅನ್ನು ಆರಿಸಿಕೊಳ್ಳಲು ಸ್ಪರ್ಶಿಸಿ & ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ವಿಜೆಟ್ ಆರಿಸಿಕೊಳ್ಳಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಿ"</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ಅಗಲ ಮತ್ತು %2$d ಎತ್ತರ"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"ಹಸ್ತಚಾಲಿತವಾಗಿ ಸೇರಿಸಲು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ"</string>
- <string name="place_automatically" msgid="8064208734425456485">"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸೇರಿಸಿ"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಹುಡುಕಿ"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ಹೊಂದಿಕೆಯ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"ಮತ್ತಷ್ಟು ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಹುಡುಕಿ"</string>
- <string name="notifications_header" msgid="1404149926117359025">"ಅಧಿಸೂಚನೆಗಳು"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ ಆರಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ ಆರಿಸಿಕೊಳ್ಳಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಿ."</string>
- <string name="out_of_space" msgid="4691004494942118364">"ಈ ಮುಖಪುಟದ ಪರದೆಯಲ್ಲಿ ಹೆಚ್ಚು ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"ಮೆಚ್ಚಿನವುಗಳ ಟ್ರೇನಲ್ಲಿ ಹೆಚ್ಚಿನ ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"ಅಪ್ಲಿಕೇಶನ್ಗಳ ಪಟ್ಟಿ"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ವೈಯಕ್ತಿಕ ಅಪ್ಲಿಕೇಶನ್ಗಳ ಪಟ್ಟಿ"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್ಗಳ ಪಟ್ಟಿ"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"ಮುಖಪುಟ"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"ತೆಗೆದುಹಾಕಿ"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ಅನ್ಇನ್ಸ್ಟಾಲ್"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"ಸ್ಥಾಪಿಸಿ"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಸ್ಥಾಪಿಸಿ"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"ಬಳಕೆದಾರರ ಹಸ್ತಕ್ಷೇಪವಿಲ್ಲದೆ ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಸೇರಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"ಮುಖಪುಟದ ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಓದಿ"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"ಮುಖಪುಟದಲ್ಲಿ ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಓದಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"ಮುಖಪುಟದ ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಬರೆಯಿರಿ"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"ಮುಖಪುಟದಲ್ಲಿ ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"ಫೋನ್ ಕರೆಗಳನ್ನು ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"ವಿಜೆಟ್ ಲೋಡ್ ಮಾಡುವಲ್ಲಿ ಸಮಸ್ಯೆ"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"ಸೆಟಪ್"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"ಇದೊಂದು ಅಪ್ಲಿಕೇಶನ್ ಆಗಿದೆ ಮತ್ತು ಅಸ್ಥಾಪಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"ಹೆಸರಿಲ್ಲದ ಫೋಲ್ಡರ್"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> ಅಧಿಸೂಚನೆಗಳನ್ನು ಹೊಂದಿದೆ</item>
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> ಅಧಿಸೂಚನೆಗಳನ್ನು ಹೊಂದಿದೆ</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"%2$d ರಲ್ಲಿ %1$d ಪುಟ"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d ರಲ್ಲಿ %1$d ಮುಖಪುಟದ ಪರದೆ"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"ಹೊಸ ಮುಖಪುಟ ಪರದೆ"</string>
- <string name="folder_opened" msgid="94695026776264709">"ಫೋಲ್ಡರ್ ತೆರೆಯಲಾಗಿದೆ, <xliff:g id="WIDTH">%1$d</xliff:g> ಬೈ <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"ಫೋಲ್ಡರ್ ಮುಚ್ಚಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"ಮರುಹೆಸರನ್ನು ಉಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="folder_closed" msgid="4100806530910930934">"ಫೋಲ್ಡರ್ ಮುಚ್ಚಿದೆ"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"ಫೋಲ್ಡರ್ ಅನ್ನು <xliff:g id="NAME">%1$s</xliff:g> ಗೆ ಮರುಹೆಸರಿಸಲಾಗಿದೆ"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"ಫೋಲ್ಡರ್: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"ವಿಜೆಟ್ಗಳು"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"ವಾಲ್ಪೇಪರ್ಗಳು"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"ಮುಖಪುಟ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"ಮುಖಪುಟ ತಿರುಗುವಿಕೆಯನ್ನು ಅನುಮತಿಸಿ"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"ಫೋನ್ ತಿರುಗಿಸಿದಾಗ"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"ಅಧಿಸೂಚನೆ ಡಾಟ್ಗಳು"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"ಆನ್"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"ಆಫ್"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"ಅಧಿಸೂಚನೆ ಪ್ರವೇಶ ಅಗತ್ಯವಿದೆ"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"ಅಧಿಸೂಚನೆ ಚುಕ್ಕೆಗಳನ್ನು ತೋರಿಸಲು, <xliff:g id="NAME">%1$s</xliff:g> ಗೆ ಅಪ್ಲಿಕೇಶನ್ ಅಧಿಸೂಚನೆಗಳನ್ನು ಆನ್ ಮಾಡಿ"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬದಲಾಯಿಸಿ"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"ಅಧಿಸೂಚನೆ ಡಾಟ್ಗಳನ್ನು ತೋರಿಸಿ"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ಮುಖಪುಟದ ಪರದೆಗೆ ಐಕಾನ್ ಸೇರಿಸಿ"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ಹೊಸ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗೆ"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"ಐಕಾನ್ ಆಕಾರವನ್ನು ಬದಲಿಸಿ"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"ಮುಖಪುಟ ಪರದೆಯಲ್ಲಿ"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"ಸಿಸ್ಟಂ ಡಿಫಾಲ್ಟ್ ಬಳಸಿ"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"ಚೌಕ"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"ಚೌಕವೃತ್ತ"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"ವೃತ್ತ"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"ಕಂಬನಿ"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"ಐಕಾನ್ ಆಕಾರ ಬದಲಾವಣೆಯನ್ನು ಅನ್ವಯಿಸಲಾಗುತ್ತಿದೆ"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"ಅಪರಿಚಿತ"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"ತೆಗೆದುಹಾಕಿ"</string>
- <string name="abandoned_search" msgid="891119232568284442">"ಹುಡುಕಿ"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಸ್ಥಾಪನೆಗೊಂಡಿಲ್ಲ"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ಈ ಐಕಾನ್ ಅಪ್ಲಿಕೇಶನ್ ಸ್ಥಾಪನೆಗೊಂಡಿಲ್ಲ. ನೀವು ಅದನ್ನು ತೆಗೆದುಹಾಕಬಹುದು ಅಥವಾ ಅಪ್ಲಿಕೇಶನ್ ಹುಡುಕಬಹುದು ಮತ್ತು ಹಸ್ತಚಾಲಿತವಾಗಿ ಅದನ್ನು ಸ್ಥಾಪಿಸಬಹುದು."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ಡೌನ್ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ, <xliff:g id="PROGRESS">%2$s</xliff:g> ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ಸ್ಥಾಪಿಸಲು ಕಾಯಲಾಗುತ್ತಿದೆ"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ವಿಜೆಟ್ಗಳು"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"ಮುಖಪುಟಕ್ಕೆ ಸೇರಿಸು"</string>
- <string name="action_move_here" msgid="2170188780612570250">"ಐಟಂ ಇಲ್ಲಿಗೆ ಸರಿಸಿ"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"ಮುಖಪುಟ ಪರದೆಗೆ ಐಟಂ ಸೇರಿಸಲಾಗಿದೆ"</string>
- <string name="item_removed" msgid="851119963877842327">"ಐಟಂ ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
- <string name="action_move" msgid="4339390619886385032">"ಐಟಂ ಸರಿಸಿ"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> ಸಾಲು <xliff:g id="NUMBER_1">%2$s</xliff:g> ಕಾಲಮ್ಗೆ ಸರಿಸಿ"</string>
- <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> ಸ್ಥಾನಕ್ಕೆ ಸರಿಸಿ"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"ಮೆಚ್ಚಿನ <xliff:g id="NUMBER">%1$s</xliff:g> ಸ್ಥಾನಕ್ಕೆ ಸರಿಸಿ"</string>
- <string name="item_moved" msgid="4606538322571412879">"ಐಟಂ ಸರಿಸಲಾಗಿದೆ"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"ಫೋಲ್ಡರ್ಗೆ ಸೇರಿಸಿ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> ಮೂಲಕ ಫೋಲ್ಡರ್ಗೆ ಸೇರಿಸಿ"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"ಐಟಂ ಅನ್ನು ಫೋಲ್ಡರ್ಗೆ ಸೇರಿಸಲಾಗಿದೆ"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"ಇದನ್ನು ಬಳಸಿಕೊಂಡು ಫೋಲ್ಡರ್ ರಚಿಸಿ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"ಫೋಲ್ಡರ್ ರಚಿಸಲಾಗಿದೆ"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"ಮುಖಪುಟಕ್ಕೆ ಸರಿಸಿ"</string>
- <string name="action_resize" msgid="1802976324781771067">"ಮರುಗಾತ್ರ"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"ಅಗಲವನ್ನು ಹೆಚ್ಚು ಮಾಡಿ"</string>
- <string name="action_increase_height" msgid="459390020612501122">"ಎತ್ತರವನ್ನು ಹೆಚ್ಚು ಮಾಡಿ"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"ಅಗಲವನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"ಎತ್ತರವನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
- <string name="widget_resized" msgid="9130327887929620">"ವಿಜೆಟ್ ಅನ್ನು <xliff:g id="NUMBER_0">%1$s</xliff:g> ಅಗಲ <xliff:g id="NUMBER_1">%2$s</xliff:g> ಎತ್ತರಕ್ಕೆ ಮರುಗಾತ್ರಗೊಳಿಸಲಾಗಿದೆ"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"ಶಾರ್ಟ್ಕಟ್ಗಳು"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> ಗೆ <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ಶಾರ್ಟ್ಕಟ್ಗಳು"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> ಗಾಗಿ <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ಶಾರ್ಟ್ಕಟ್ಗಳು ಮತ್ತು <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ಅಧಿಸೂಚನೆಗಳು"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"ವಜಾಗೊಳಿಸಿ"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"ಅಧಿಸೂಚನೆಯನ್ನು ವಜಾಗೊಳಿಸಲಾಗಿದೆ"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"ವೈಯಕ್ತಿಕ"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"ಕೆಲಸ"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಇಲ್ಲಿ ಹುಡುಕಿ"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"ಕೆಲಸದ ಪ್ರತಿ ಅಪ್ಲಿಕೇಶನ್ ಬ್ಯಾಡ್ಜ್ ಹೊಂದಿದೆ ಮತ್ತು ನಿಮ್ಮ ಸಂಸ್ಥೆಯಿಂದ ಸುರಕ್ಷಿತವಾಗಿ ಇರಿಸಲಾಗುತ್ತದೆ. ಸುಲಭ ಪ್ರವೇಶಕ್ಕಾಗಿ ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಸರಿಸಿ."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗಿದೆ"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"ಅಧಿಸೂಚನೆಗಳು ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್ಗಳು ಆಫ್ ಆಗಿವೆ"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ಮುಚ್ಚಿ"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ಮುಚ್ಚಲಾಗಿದೆ"</string>
-</resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index e73ff39..91b08dc9 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -108,14 +108,13 @@
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ಡೌನ್ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ, <xliff:g id="PROGRESS">%2$s</xliff:g> ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ಸ್ಥಾಪಿಸಲು ಕಾಯಲಾಗುತ್ತಿದೆ"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ವಿಜೆಟ್ಗಳು"</string>
- <!-- no translation found for widgets_list (796804551140113767) -->
- <skip />
- <!-- no translation found for widgets_list_closed (6141506579418771922) -->
- <skip />
+ <string name="widgets_list" msgid="796804551140113767">"ವಿಜೆಟ್ ಪಟ್ಟಿ"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"ವಿಜೆಟ್ ಪಟ್ಟಿಯನ್ನು ಮುಚ್ಚಲಾಗಿದೆ"</string>
<string name="action_add_to_workspace" msgid="8902165848117513641">"ಮುಖಪುಟಕ್ಕೆ ಸೇರಿಸು"</string>
<string name="action_move_here" msgid="2170188780612570250">"ಐಟಂ ಇಲ್ಲಿಗೆ ಸರಿಸಿ"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"ಮುಖಪುಟ ಪರದೆಗೆ ಐಟಂ ಸೇರಿಸಲಾಗಿದೆ"</string>
<string name="item_removed" msgid="851119963877842327">"ಐಟಂ ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
+ <string name="undo" msgid="4151576204245173321">"ರದ್ದುಮಾಡಿ"</string>
<string name="action_move" msgid="4339390619886385032">"ಐಟಂ ಸರಿಸಿ"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> ಸಾಲು <xliff:g id="NUMBER_1">%2$s</xliff:g> ಕಾಲಮ್ಗೆ ಸರಿಸಿ"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> ಸ್ಥಾನಕ್ಕೆ ಸರಿಸಿ"</string>
@@ -146,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"ಅಧಿಸೂಚನೆಗಳು ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್ಗಳು ಆಫ್ ಆಗಿವೆ"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ಮುಚ್ಚಿ"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ಮುಚ್ಚಲಾಗಿದೆ"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"ವಿಫಲವಾಗಿದೆ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 5e68b17..7130f71 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"여기에 항목을 이동"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"홈 화면에 항목 추가됨"</string>
<string name="item_removed" msgid="851119963877842327">"항목 삭제됨"</string>
+ <string name="undo" msgid="4151576204245173321">"실행취소"</string>
<string name="action_move" msgid="4339390619886385032">"항목 이동"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g>행 <xliff:g id="NUMBER_1">%2$s</xliff:g>열로 이동"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>번 위치로 이동"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"알림 및 앱 사용 중지됨"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"닫기"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"종료됨"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"실패: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml
deleted file mode 100644
index 502a08a..0000000
--- a/res/values-ky-rKG/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Жумуш"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Колдонмо орнотулган эмес."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Колдонмо жеткиликтүү эмес"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Жүктөп алынган колдонмо Коопсуз режиминде иштен чыгарылды"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Виджеттер Коопсуз режимде өчүрүлгөн"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Кыска жол жок"</string>
- <string name="home_screen" msgid="806512411299847073">"Башкы экран"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Ыңгайлаштырылган аракеттер"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Виджетти тандаш үчүн, басып туруңуз"</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Виджет тандоо үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Туурасы: %1$d, бийиктиги: %2$d"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Кол менен жайгаштыруу үчүн басып туруп, таштаңыз"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Автоматтык түрдө кошуу"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Колдонмолорду издөө"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Колдонмолор жүктөлүүдө…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" сурамына дал келген колдонмолор табылган жок"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Көбүрөөк колдонмолорду издөө"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Билдирмелер"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Кыска жолду тандоо үчүн басып туруңуз."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Кыска жолду тандоо үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."</string>
- <string name="out_of_space" msgid="4691004494942118364">"Бул Үй экранында бош орун жок."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Тандамалдар тайпасында орун калган жок"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Колдонмолор тизмеси"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Жеке колдономолордун тизмеси"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Жумуш колдонмолорунун тизмеси"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Үйгө"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Алып салуу"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Чыгарып салуу"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Колдонмо тууралуу"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Орнотуу"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"тез чакырмаларды орнотуу"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Колдонмого колдонуучуга кайрылбастан тез чакырма кошууга уруксат берет."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"Үйдүн тууралоолорун жана тез чакырмаларын окуу"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Колдонмого Үйдүн тууралоолорун жана тез чакырмаларын окууга уруксат берет."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"Үйдүн тууралоолорун жана тез чакырмаларын жазуу"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Колдонмого Үйдүн тууралоолорун жана тез чакырмаларын өзгөртүүгө уруксат берет."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> телефон чалууларды аткарууга уруксаты жок"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Виджетти жүктөөдө маселе бар"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Орнотуу"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Бул системдик колдонмо жана аны чечкенге болбойт."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Аты жок фолдер"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> өчүрүлгөн"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> эскертме бар</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> эскертме бар</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"%2$d ичинен %1$d барак"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"Үй экраны %2$d ичинен %1$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Жаңы башкы экран барагы"</string>
- <string name="folder_opened" msgid="94695026776264709">"Фолдер ачылды, туурасы <xliff:g id="WIDTH">%1$d</xliff:g>, бийиктиги <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Куржунду жабуу үчүн таптаңыз"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Өзгөртүлгөн аталышын сактоо үчүн таптаңыз"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Фолдер жабык"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Фолдердин аты <xliff:g id="NAME">%1$s</xliff:g> деп өзгөртүлдү"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Фолдер: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Виджеттер"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Тушкагаздар"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Башкы беттин жөндөөлөрү"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Администраторуңуз өчүрүп койгон"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Башкы экранды айлантууга уруксат берүү"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Телефон айланганда"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Билдирмелер белгилери"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Күйүк"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Өчүк"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Эскертмелерге уруксат берилиши керек"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Эскертме белгилерин көрсөтүү максатында, <xliff:g id="NAME">%1$s</xliff:g> үчүн колдонмонун эскертмелерин күйгүзүү керек"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Жөндөөлөрдү өзгөртүү"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Эскертме белгилерин көрсөтүү"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Башкы экранга сүрөтчө кошуу"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Жаңы колдонмолор үчүн"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Сүрөтчөнүн формасын өзгөртүү"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"Башкы экранда"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Демейки тутум жөндөөлөрү колдонулат"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Чарчы"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Бурчтары жумуру төрт бурчтук"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Тегерек"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Тамчы"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Өзгөртүлгөн сүрөтчөнүн формасы колдонулууда"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Белгисиз"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Алып салуу"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Издөө"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Бул колдонмо орнотулган эмес"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Бул сүрөтчөнүн колдонмосу орнотулган эмес. Аны алып салсаңыз же колдонмону издеп, кол менен орнотсоңуз болот."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> жүктөлүп алынууда, <xliff:g id="PROGRESS">%2$s</xliff:g> аяктады"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> орнотулушу күтүлүүдө"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> виджеттери"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Башкы экранга кошуу"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Бул нерсени бул жерге жылдыруу"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Башкы экранга кошулду"</string>
- <string name="item_removed" msgid="851119963877842327">"Жоюлду"</string>
- <string name="action_move" msgid="4339390619886385032">"Муну жылдыруу"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> катарга <xliff:g id="NUMBER_1">%2$s</xliff:g> тилкеге жылдыруу"</string>
- <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> орунга жылдыруу"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Сүйүктүүлөргө <xliff:g id="NUMBER">%1$s</xliff:g> жылдыруу"</string>
- <string name="item_moved" msgid="4606538322571412879">"Нерсе жылдырылды"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Куржунга кошуу: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> куржунуна кошуу"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Нерсе куржунга кошулду"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Төмөнкү менен куржун түзүү: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"Куржун түзүлдү"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Башкы экранга жылдыруу"</string>
- <string name="action_resize" msgid="1802976324781771067">"Өлчөмүн өзгөртүү"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Кеңейтүү"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Бийиктетүү"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Ичкертүү"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Жапыздатуу"</string>
- <string name="widget_resized" msgid="9130327887929620">"Виджеттин кеңдиги <xliff:g id="NUMBER_0">%1$s</xliff:g> бийиктиги <xliff:g id="NUMBER_1">%2$s</xliff:g> болду"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Кыска жолдор"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> колдонмосуна <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> кыска жол бар"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> колдонмосу үчүн <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> кыска жол жана <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> эскертме бар"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Этибарга албоо"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Эскертме көз жаздымда калтырылды"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Жеке колдонмолор"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Жумуш колдонмолору"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Жумуш профили"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Жумуш колдонмолорун бул жерден таап алыңыз"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Ар бир жумуш колдонмосунун бейджиги бар жана ал уюмуңуз тарабынан коопсуз сакталат. Колдонмолорго тез өтүү үчүн аларды Башкы экранга кошуп алыңыз."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Уюмуңуз тарабынан башкарылат"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Билдирүүлөр жана колдонмолор өчүрүлгөн"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Жабуу"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Жабык"</string>
-</resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index da7813e..efa3d87 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Бул нерсени бул жерге жылдыруу"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Башкы экранга кошулду"</string>
<string name="item_removed" msgid="851119963877842327">"Жоюлду"</string>
+ <string name="undo" msgid="4151576204245173321">"Кайтаруу"</string>
<string name="action_move" msgid="4339390619886385032">"Муну жылдыруу"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> катарга <xliff:g id="NUMBER_1">%2$s</xliff:g> тилкеге жылдыруу"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> орунга жылдыруу"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Билдирүүлөр жана колдонмолор өчүрүлгөн"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Жабуу"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Жабык"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Аткарылган жок: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml
deleted file mode 100644
index cd2c933..0000000
--- a/res/values-lo-rLA/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"ວຽກ"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"ແອັບຯບໍ່ໄດ້ຖືກຕິດຕັ້ງ."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"ແອັບຯໃຊ້ບໍ່ໄດ້"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"ແອັບຯທີ່ດາວໂຫລດແລ້ວຖືກປິດການນຳໃຊ້ໃນ Safe mode"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"ວິດເຈັດຖືກປິດໃນ Safe mode"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"ບໍ່ສາມາດໃຊ້ທາງລັດໄດ້"</string>
- <string name="home_screen" msgid="806512411299847073">"ໜ້າຈໍຫຼັກ"</string>
- <string name="custom_actions" msgid="3747508247759093328">"ຄຳສັ່ງແບບກຳນົດເອງ"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"ສຳພັດຄ້າງໄວ້ ເພື່ອຈັບວິດເຈັດ."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ແຕະຄ້າງໄວ້ ເພື່ອເລືອກວິດເຈັດ ຫຼື ໃຊ້ການດຳເນີນການກຳນົດເອງ."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"ກວ້າງ %1$d ຄູນສູງ %2$d"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"ແຕະຄ້າງໄວ້ເພື່ອວາງດ້ວຍຕົນເອງ"</string>
- <string name="place_automatically" msgid="8064208734425456485">"ເພີ່ມໂດຍອັດຕະໂນມັດ"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ຊອກຫາແອັບ"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"ກໍາລັງໂຫຼດແອັບ…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"ບໍ່ພົບແອັບທີ່ກົງກັບ \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"ຊອກຫາແອັບເພີ່ມເຕີມ"</string>
- <string name="notifications_header" msgid="1404149926117359025">"ການແຈ້ງເຕືອນ"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ແຕະຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ ຫຼື ໃຊ້ຄຳສັ່ງແບບກຳນົດເອງ."</string>
- <string name="out_of_space" msgid="4691004494942118364">"ບໍ່ມີຫ້ອງເຫຼືອໃນໜ້າຈໍຫຼັກນີ້."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"ບໍ່ມີບ່ອນຫວ່າງໃນຖາດສຳລັບເກັບສິ່ງທີ່ໃຊ້ເປັນປະຈຳ"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"ລາຍຊື່ແອັບ"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ລາຍຊື່ແອັບສ່ວນຕົວ"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"ລາຍຊື່ແອັບເຮັດວຽກ"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"ໜ້າຫຼັກ"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"ເອົາອອກ"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ຖອນການຕິດຕັ້ງ"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"ຂໍ້ມູນແອັບ"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"ຕິດຕັ້ງ"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"ຕິດຕັ້ງທາງລັດ"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"ອະນຸຍາດໃຫ້ແອັບຯ ເພີ່ມທາງລັດໂດຍບໍ່ຕ້ອງຮັບການຢືນຢັນຈາກຜູ່ໃຊ້."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"ອ່ານການຕັ້ງຄ່າໜ້າຫຼັກ ແລະທາງລັດ"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"ອະນຸຍາດໃຫ້ແອັບຯດັ່ງກ່າວອ່ານການຕັ້ງຄ່າ ແລະທາງລັດໃນໜ້າຫຼັກ."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"ຂຽນການຕັ້ງຄ່າໜ້າຫຼັກ ແລະທາງລັດ"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"ອະນຸຍາດໃຫ້ແອັບຯດັ່ງກ່າວ ປ່ຽນການຕັ້ງຄ່າ ແລະທາງລັດໃນໜ້າຫຼັກ."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ໄດ້ຮັບອະນຸຍາດໃຫ້ໂທ"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"ມີບັນຫາໃນການໂຫລດວິດເຈັດ"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"ຕິດຕັ້ງ"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"ນີ້ແມ່ນແອັບຯຂອງລະບົບ ແລະບໍ່ສາມາດຖອນການຕິດຕັ້ງອອກໄດ້."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"ໂຟນເດີຍັງບໍ່ຖືກຕັ້ງຊື່"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"ປິດການນຳໃຊ້ <xliff:g id="APP_NAME">%1$s</xliff:g> ແລ້ວ"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ມີ <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> ການແຈ້ງເຕືອນ</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, ມີ <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> ການແຈ້ງເຕືອນ</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"ໜ້າ %1$d ຈາກ %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"ໜ້າຈໍຫຼັກ %1$d ໃນ %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"ໜ້າຂອງໜ້າຈໍຫຼັກໃໝ່"</string>
- <string name="folder_opened" msgid="94695026776264709">"ເປີດໂຟນເດີແລ້ວ, <xliff:g id="WIDTH">%1$d</xliff:g> ຄູນ <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"ແຕະເພື່ອປິດໂຟນເດີ"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"ແຕະເພື່ອບັນທຶກການປ່ຽນຊື່"</string>
- <string name="folder_closed" msgid="4100806530910930934">"ປິດໂຟນເດີແລ້ວ"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"ປ່ຽນຊື່ໂຟນເດີເປັນ <xliff:g id="NAME">%1$s</xliff:g> ແລ້ວ"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"ໂຟນເດີ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"ວິດເຈັດ"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"ພາບພື້ນຫຼັງ"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"ການຕັ້ງຄ່າ Home"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"ຖືກປິດການນຳໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"ອະນຸຍາດໃຫ້ໝຸນໜ້າຈໍທຳອິດໄດ້"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"ເມື່ອໝຸນໂທລະສັບ"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"ຈຸດການແຈ້ງເຕືອນ"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"ເປີດ"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"ປິດ"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"ຕ້ອງໃຊ້ການເຂົ້າເຖິງການແຈ້ງເຕືອນ"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"ເພື່ອສະແດງຈຸດການແຈ້ງເຕືອນ, ໃຫ້ເປີດການແຈ້ງເຕືອນສຳລັບ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"ບັນທຶກການຕັ້ງຄ່າ"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"ສະແດງຈຸດການແຈ້ງເຕືອນ"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ເພີ່ມໄອຄອນໃສ່ໜ້າຈໍຫຼັກ"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ສຳລັບແອັບໃໝ່"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"ປ່ຽນຮູບຮ່າງໄອຄອນ"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"ຢູ່ໜ້າຈໍຫຼັກ"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"ໃຊ້ຄ່າເລີ່ມຕົ້ນລະບົບ"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"ສີ່ຫຼ່ຽມຈັດຕຸລັດ"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"ສີ່ຫຼ່ຽມຂອບມົນ"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"ວົງມົນ"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"ນ້ຳຢອດ"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"ນຳໃຊ້ການປ່ຽນແປງຮູບຮ່າງໄອຄອນ"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"ບໍ່ຮູ້ຈັກ"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"ລຶບ"</string>
- <string name="abandoned_search" msgid="891119232568284442">"ຊອກຫາ"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"ແອັບຯນີ້ຍັງບໍ່ໄດ້ຕິດຕັ້ງເທື່ອ"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ແອັບຯສຳລັບໄອຄອນນີ້ຍັງບໍ່ໄດ້ຕິດຕັ້ງເທື່ອ. ທ່ານສາມາດລຶບມັນອອກ ຫຼືຊອກຫາແອັບຯ ແລ້ວຕິດຕັ້ງມັນໄດ້ດ້ວຍຕົນເອງ."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ກຳລັງດາວໂຫຼດ, <xliff:g id="PROGRESS">%2$s</xliff:g> ສຳເລັດ"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ກຳລັງລໍຖ້າຕິດຕັ້ງ"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"ວິດເຈັດ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"ເພີ່ມໃສ່ໜ້າຈໍຫຼັກ"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Move item here"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"ເພີ່ມລາຍການໃສ່ໜ້າຈໍຫຼັກແລ້ວ"</string>
- <string name="item_removed" msgid="851119963877842327">"ເອົາລາຍການອອກໄປແລ້ວ"</string>
- <string name="action_move" msgid="4339390619886385032">"ຍ້າຍລາຍການ"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"ຍ້າຍໄປໃສ່ແຖວ <xliff:g id="NUMBER_0">%1$s</xliff:g> ຖັນ <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="move_to_position" msgid="6750008980455459790">"ຍ້າຍໄປໃສ່ຕຳແໜ່ງ <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"ຍ້າຍໄປໃສ່ຕຳແໜ່ງທີ່ມັກ <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="item_moved" msgid="4606538322571412879">"ຍ້າຍລາຍການແລ້ວ"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"ເພີ່ມໃສ່ໂຟລເດີ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"ເພີ່ມໃສ່ໂຟລເດີດ້ວຍ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"ເພີ່ມລາຍການໃສ່ໂຟລເດີແລ້ວ"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"ສ້າງໂຟລເດີກັບ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"ສ້າງໂຟລເດີແລ້ວ"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"ຍ້າຍໄປໃສ່ໜ້າຈໍຫຼັກ"</string>
- <string name="action_resize" msgid="1802976324781771067">"ປັບຂະໜາດ"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"ເພີ່ມລວງກ້ວາງຂຶ້ນ"</string>
- <string name="action_increase_height" msgid="459390020612501122">"ເພີ່ມລວງສູງຂຶ້ນ"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"ຫຼຸດລວງກ້ວາງລົງ"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"ຫຼຸດລວງສູງລົງ"</string>
- <string name="widget_resized" msgid="9130327887929620">"ປ່ຽນຂະໜາດວິດເຈັດເປັນລວງກ້ວາງ <xliff:g id="NUMBER_0">%1$s</xliff:g> ລວງສູງ <xliff:g id="NUMBER_1">%2$s</xliff:g> ແລ້ວ"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"ທາງລັດ"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ທາງລັດສຳລັບ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ທາງລັດ ແລະ <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ການແຈ້ງເຕືອນສຳລັບ <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"ປິດໄວ້"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"ປິດການແຈ້ງເຕືອນແລ້ວ"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"ສ່ວນຕົວ"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"ວຽກ"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ຊອກຫາແອັບວຽກຢູ່ບ່ອນນີ້"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"ແຕ່ລະແອັບວຽກຈະມີປ້າຍ ແລະ ຖືກຈັດເກັບໄວ້ຢ່າງປອດໄພໂດຍອົງກອນຂອງທ່ານ. ທ່ານສາມາດຍ້າຍແອັບໄປໃສ່ໜ້າຈໍຫຼັກເພື່ອໃຫ້ເຂົ້າໃຊ້ງ່າຍຂຶ້ນໄດ້."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"ຈັດການໂດຍອົງກອນຂອງທ່ານ"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"ການແຈ້ງເຕືອນ ແລະ ແອັບຖືກປິດໄວ້"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ປິດ"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ປິດແລ້ວ"</string>
-</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index d0d127f..95b36d3 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Move item here"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"ເພີ່ມລາຍການໃສ່ໜ້າຈໍຫຼັກແລ້ວ"</string>
<string name="item_removed" msgid="851119963877842327">"ເອົາລາຍການອອກໄປແລ້ວ"</string>
+ <string name="undo" msgid="4151576204245173321">"ຍົກເລີກ"</string>
<string name="action_move" msgid="4339390619886385032">"ຍ້າຍລາຍການ"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"ຍ້າຍໄປໃສ່ແຖວ <xliff:g id="NUMBER_0">%1$s</xliff:g> ຖັນ <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"ຍ້າຍໄປໃສ່ຕຳແໜ່ງ <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"ການແຈ້ງເຕືອນ ແລະ ແອັບຖືກປິດໄວ້"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ປິດ"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ປິດແລ້ວ"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"ບໍ່ສຳເລັດ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index c323fd8..d0917e0 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -116,6 +116,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Perkelti elementą čia"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Elementas pridėtas prie pagrindinio ekrano"</string>
<string name="item_removed" msgid="851119963877842327">"Elementas perkeltas"</string>
+ <string name="undo" msgid="4151576204245173321">"Anuliuoti"</string>
<string name="action_move" msgid="4339390619886385032">"Perkelti elementą"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Perkelti į <xliff:g id="NUMBER_0">%1$s</xliff:g> eilutę, <xliff:g id="NUMBER_1">%2$s</xliff:g> stulpelį"</string>
<string name="move_to_position" msgid="6750008980455459790">"Perkelti į <xliff:g id="NUMBER">%1$s</xliff:g> poziciją"</string>
@@ -146,4 +147,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Programos ir pranešimai išjungti"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Uždaryti"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Uždaryta"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Nepavyko: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index be03811..b627f1c 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -115,6 +115,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Pārvietot vienumu šeit"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Vienums pievienots sākuma ekrānam"</string>
<string name="item_removed" msgid="851119963877842327">"Vienums noņemts"</string>
+ <string name="undo" msgid="4151576204245173321">"Atsaukt"</string>
<string name="action_move" msgid="4339390619886385032">"Pārvietot vienumu"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Pārvietot uz <xliff:g id="NUMBER_0">%1$s</xliff:g>. rindu, <xliff:g id="NUMBER_1">%2$s</xliff:g>. kolonnu"</string>
<string name="move_to_position" msgid="6750008980455459790">"Pārvietot uz <xliff:g id="NUMBER">%1$s</xliff:g>. pozīciju"</string>
@@ -145,4 +146,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Paziņojumi un lietotnes ir izslēgtas"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Aizvērt"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Aizvērta"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Neizdevās: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml
deleted file mode 100644
index 54d9c80..0000000
--- a/res/values-mk-rMK/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Стартер3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Работа"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Апликацијата не е инсталирана."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Апликацијата не е достапна"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Преземената апликација е оневозможена во безбеден режим"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Додатоците се оневозможени во безбеден режим"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Кратенката не е достапна"</string>
- <string name="home_screen" msgid="806512411299847073">"Почетен екран"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Приспособени дејства"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Допри и задржи за да се избере виџетот."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Допрете двапати и задржете за да изберете додаток или да користите приспособени дејства."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d широк на %2$d висок"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Допрете и задржете за рачно поставување"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Додај автоматски"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Пребарувајте апликации"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Се вчитуваат апликации…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"Не се најдени апликации што одговараат на „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Пребарај други апликации"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Известувања"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Допрете двапати и задржете за избор на кратенка."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Допрете двапати и задржете за избор на кратенка или користете приспособени дејства."</string>
- <string name="out_of_space" msgid="4691004494942118364">"Нема повеќе простор на овој екран на почетната страница."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Нема повеќе простор на лентата „Омилени“"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Список со апликации"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Список со лични апликации"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Список со апликации за работа"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Почетна страница"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Отстрани"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталирај"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Инф. за апликација"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирај кратенки"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Овозможува апликацијата да додава кратенки без интервенција на корисникот."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"чита поставки и кратенки на почетна страница"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Овозможува апликацијата да ги менува подесувањата и кратенките на почетната страница."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"пишува поставки и кратенки на почетна страница"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Овозможува апликацијата да ги менува подесувањата и кратенките на почетната страница."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> нема дозвола за телефонски повици"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Проблем при вчитувањето на виџетот"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Поставување"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ова е системска апликација и не може да се деинсталира."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Неименувана папка"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> е оневозможена"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g> има <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> известување</item>
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> има <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> известувања</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"Страница %1$d од %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"Екран на почетна страница %1$d од %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Нова страница на почетен екран"</string>
- <string name="folder_opened" msgid="94695026776264709">"Отворена е папка, <xliff:g id="WIDTH">%1$d</xliff:g> на <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Допрете за да ја затворите папката"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Допрете за да го зачувате преименувањето"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Папката е затворена"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Папката е преименувана во <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Папка: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Виџети"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Тапети"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Поставки за Home"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Оневозможено од администраторот"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Дозволете ротација на Почетниот екран"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Кога телефонот се ротира"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Точки за известување"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Вклучено"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Исклучено"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Потребен е пристап до известувањата"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"За да се прикажуваат „Точки за известување“, вклучете ги известувањата за апликацијата <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Промени ги поставките"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Прикажи точки за известување"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Додај икона на почетниот екран"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"За нови апликации"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Променете ја формата на иконата"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"на „Почетен екран“"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Користи ја стандардната поставка на системот"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Квадрат"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Заоблен квадрат"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Круг"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Солза"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Се применуваат промените на формата на иконата"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Непознато"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Отстрани"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Барај"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Апликацијата не е инсталирана"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Апликацијата за оваа икона не е инсталирана. Може да ја отстраните или да се обидете да ја најдете апликацијата и да ја инсталирате рачно."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"Се презема <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> завршено"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чека да се инсталира"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Виџети за <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Додај на Почетен екран"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Премести ја ставката овде"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Ставката е додадена на почетниот екран"</string>
- <string name="item_removed" msgid="851119963877842327">"Ставката е отстранета"</string>
- <string name="action_move" msgid="4339390619886385032">"Премести ја ставката"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"Премести во ред <xliff:g id="NUMBER_0">%1$s</xliff:g> колона <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="move_to_position" msgid="6750008980455459790">"Премести на место <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Премести на место <xliff:g id="NUMBER">%1$s</xliff:g> во омилени"</string>
- <string name="item_moved" msgid="4606538322571412879">"Ставката е преместена"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Додај во папката: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"Додај во папка со <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Ставката е додадена во папката"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Создај папка со: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"Папката е создадена"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Премести на Почетен екран"</string>
- <string name="action_resize" msgid="1802976324781771067">"Промени големина"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Зголеми ширина"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Зголеми висина"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Намали ширина"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Намали висина"</string>
- <string name="widget_resized" msgid="9130327887929620">"Големината на виџетот е променета на ширина <xliff:g id="NUMBER_0">%1$s</xliff:g> висина <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Кратенки"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> кратенки за <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> кратенки и <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> известувања за <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Отфрли"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Известувањето е отфрлено"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Лично"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"За работа"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Работен профил"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Најдете апликации за работа тука"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Секоја апликација за работа има значка, а организацијата се грижи за нејзината безбедност. За полесен пристап, преместете ги апликациите на почетниот екран."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Управувано од вашата организација"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Известувањата и апликациите се исклучени"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Затвори"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Затворено"</string>
-</resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index e5dd027..40ea52a 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Премести ја ставката овде"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Ставката е додадена на почетниот екран"</string>
<string name="item_removed" msgid="851119963877842327">"Ставката е отстранета"</string>
+ <string name="undo" msgid="4151576204245173321">"Врати"</string>
<string name="action_move" msgid="4339390619886385032">"Премести ја ставката"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Премести во ред <xliff:g id="NUMBER_0">%1$s</xliff:g> колона <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Премести на место <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Известувањата и апликациите се исклучени"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Затвори"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Затворено"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Не успеа: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
deleted file mode 100644
index a060933..0000000
--- a/res/values-ml-rIN/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"ലോഞ്ചർ3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"ഔദ്യോഗികം"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"അപ്ലിക്കേഷൻ ഇൻസ്റ്റാളുചെയ്തിട്ടില്ല."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"അപ്ലിക്കേഷൻ ലഭ്യമല്ല"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"ഡൗൺലോഡുചെയ്ത അപ്ലിക്കേഷൻ സുരക്ഷാ മോഡിൽ പ്രവർത്തനരഹിതമാക്കി"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"സുരക്ഷിത മോഡിൽ വിജറ്റുകൾ പ്രവർത്തനരഹിതമാക്കി"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"കുറുക്കുവഴി ലഭ്യമല്ല"</string>
- <string name="home_screen" msgid="806512411299847073">"ഹോം സ്ക്രീൻ"</string>
- <string name="custom_actions" msgid="3747508247759093328">"ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"ഒരു വിജറ്റ് ചേർക്കുന്നതിന് അത് സ്പർശിച്ച് പിടിക്കുക."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"വിജറ്റ് തിരഞ്ഞെടുക്കാനോ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ രണ്ടുതവണ ടാപ്പുചെയ്ത് പിടിക്കുക."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d വീതിയും %2$d ഉയരവും"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"സ്വമേധയാ സ്ഥാപിക്കുന്നതിന് സ്പർശിച്ചുപിടിക്കുക"</string>
- <string name="place_automatically" msgid="8064208734425456485">"സ്വയമേവ ചേർക്കുക"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ആപ്പുകൾ തിരയുക"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"ആപ്പുകൾ ലോഡുചെയ്യുന്നു..."</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" എന്നതുമായി പൊരുത്തപ്പെടുന്ന ആപ്പുകളൊന്നും കണ്ടെത്തിയില്ല"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"കൂടുതൽ ആപ്പുകൾക്ക് തിരയുക"</string>
- <string name="notifications_header" msgid="1404149926117359025">"അറിയിപ്പുകൾ"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"തിരഞ്ഞെടുക്കുന്നതിന് കുറുക്കുവഴി സ്പർശിച്ച് പിടിക്കുക."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"കുറുക്കുവഴി തിരഞ്ഞെടുക്കാനോ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ 2 തവണ ടാപ്പ് ചെയ്ത് പിടിക്കുക."</string>
- <string name="out_of_space" msgid="4691004494942118364">"ഈ ഹോം സ്ക്രീനിൽ ഒഴിവൊന്നുമില്ല."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"പ്രിയപ്പെട്ടവയുടെ ട്രേയിൽ ഒഴിവൊന്നുമില്ല"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"അപ്ലിക്കേഷനുകളുടെ ലിസ്റ്റ്"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"വ്യക്തിഗത ആപ്പുകളുടെ ലിസ്റ്റ്"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"ഔദ്യോഗിക ആപ്പുകളുടെ ലിസ്റ്റ്"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"ഹോം"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"നീക്കംചെയ്യുക"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"അൺഇൻസ്റ്റാളുചെയ്യുക"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"ആപ്പ് വിവരം"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"കുറുക്കുവഴികൾ ഇൻസ്റ്റാളുചെയ്യുക"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"ഉപയോക്തൃ ഇടപെടൽ ഇല്ലാതെ കുറുക്കുവഴികൾ ചേർക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"ഹോം ക്രമീകരണങ്ങളും കുറുക്കുവഴികളും റീഡുചെയ്യുക"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"ഹോമിലെ ക്രമീകരണങ്ങളും കുറുക്കുവഴികളും റീഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"ഹോം ക്രമീകരണങ്ങളും കുറുക്കുവഴികളും റൈറ്റുചെയ്യുക"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"ഹോമിലെ ക്രമീകരണങ്ങളും കുറുക്കുവഴികളും മാറ്റാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"ഫോൺ കോൾ ചെയ്യാൻ <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിച്ചിട്ടില്ല"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"വിജറ്റ് ലോഡുചെയ്യുന്നതിൽ പ്രശ്നമുണ്ട്"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"സജ്ജീകരിക്കുക"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"ഇതൊരു സിസ്റ്റം അപ്ലിക്കേഷനായതിനാൽ അൺഇൻസ്റ്റാളുചെയ്യാനാവില്ല."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"പേരുനൽകാത്ത ഫോൾഡർ"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> പ്രവർത്തനരഹിതമാക്കി"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>-ന്, <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> അറിയിപ്പുകൾ ഉണ്ട്</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>-ന്, <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> അറിയിപ്പ് ഉണ്ട്</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"പേജ് %1$d / %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"ഹോം സ്ക്രീൻ %1$d / %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"പുതിയ ഹോം സ്ക്രീൻ പേജ്"</string>
- <string name="folder_opened" msgid="94695026776264709">"ഫോൾഡർ തുറന്നു, <xliff:g id="WIDTH">%1$d</xliff:g> / <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"ഫോൾഡർ അടയ്ക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"പേരുമാറ്റം സംരക്ഷിക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
- <string name="folder_closed" msgid="4100806530910930934">"ഫോൾഡർ അടച്ചു"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"ഫോൾഡറിന്റെ പേര് <xliff:g id="NAME">%1$s</xliff:g> എന്നായി മാറ്റി"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"ഫോൾഡർ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"വിജറ്റുകൾ"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"വാൾപേപ്പർ"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"ഹോം ക്രമീകരണം"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"അഡ്മിൻ പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"ഹോം സ്ക്രീൻ തിരിക്കൽ അനുവദിക്കുക"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"ഫോൺ തിരിച്ച നിലയിലായിരിക്കുമ്പോൾ"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"അറിയിപ്പ് ഡോട്ടുകൾ"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"ഓൺ"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"ഓഫ്"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"അറിയിപ്പിനായുള്ള ആക്സസ് ആവശ്യമാണ്"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"അറിയിപ്പ് ഡോട്ടുകൾ കാണിക്കുന്നതിന്, <xliff:g id="NAME">%1$s</xliff:g> എന്നയാളിനായുള്ള ആപ്പ് അറിയിപ്പുകൾ ഓണാക്കുക"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"ക്രമീകരണം മാറ്റുക"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"അറിയിപ്പ് ഡോട്ടുകൾ കാണിക്കുക"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ഹോം സ്ക്രീനിലേക്ക് ഐക്കൺ ചേർക്കുക"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"പുതിയ ആപ്പുകൾക്ക്"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"ഐക്കണിന്റെ ആകാരം മാറ്റുക"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"ഹോം സ്ക്രീനിൽ"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"സിസ്റ്റം ഡിഫോൾട്ട് ഉപയോഗിക്കുക"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"ചതുരം"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"ചതുരവൃത്തം"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"വൃത്തം"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"കണ്ണുനീര് തുള്ളി"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"ഐക്കൺ ആകാര മാറ്റങ്ങൾ പ്രയോഗിക്കുന്നു"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"അജ്ഞാതം"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"നീക്കംചെയ്യുക"</string>
- <string name="abandoned_search" msgid="891119232568284442">"തിരയുക"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"ഈ അപ്ലിക്കേഷൻ ഇൻസ്റ്റാളുചെയ്തിട്ടില്ല"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ഈ ഐക്കണുവേണ്ടി അപ്ലിക്കേഷൻ ഇൻസ്റ്റാളുചെയ്തിട്ടില്ല. നിങ്ങൾക്കത് നീക്കംചെയ്യാനാകും അല്ലെങ്കിൽ അപ്ലിക്കേഷനുവേണ്ടി തിരഞ്ഞുകൊണ്ട് അത് സ്വമേധയാ ഇൻസ്റ്റാളുചെയ്യുക."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ഡൗൺലോഡ് ചെയ്യുന്നു, <xliff:g id="PROGRESS">%2$s</xliff:g> പൂർത്തിയായി"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"ഇൻസ്റ്റാൾ ചെയ്യാൻ <xliff:g id="NAME">%1$s</xliff:g> കാക്കുന്നു"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> വിജറ്റുകൾ"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"ഹോം സ്ക്രീനിൽ ചേർക്കുക"</string>
- <string name="action_move_here" msgid="2170188780612570250">"ഇനം ഇവിടേക്ക് നീക്കുക"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"ഹോം സ്ക്രീനിൽ ഇനം ചേർത്തു"</string>
- <string name="item_removed" msgid="851119963877842327">"ഇനം നീക്കംചെയ്തു"</string>
- <string name="action_move" msgid="4339390619886385032">"ഇനം നീക്കുക"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"വരി <xliff:g id="NUMBER_0">%1$s</xliff:g> നിര <xliff:g id="NUMBER_1">%2$s</xliff:g>-ലേക്ക് നീക്കുക"</string>
- <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>-ലേക്ക് നീക്കുക"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"ഇഷ്ടമുള്ള <xliff:g id="NUMBER">%1$s</xliff:g> സ്ഥാനത്തേക്ക് നീക്കുക"</string>
- <string name="item_moved" msgid="4606538322571412879">"ഇനം നീക്കി"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"ഫോൾഡറിൽ ചേർക്കുക: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> ഉള്ള ഫോൾഡറിൽ ചേർക്കുക"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"ഫോൾഡറിൽ ഇനം ചേർത്തു"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"ഇതുപയോഗിച്ച് ഫോൾഡർ സൃഷ്ടിക്കുക: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"ഫോൾഡർ സൃഷ്ടിച്ചു"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"ഹോം സ്ക്രീനിലേക്ക് നീക്കുക"</string>
- <string name="action_resize" msgid="1802976324781771067">"വലുപ്പംമാറ്റുക"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"വീതി കൂട്ടുക"</string>
- <string name="action_increase_height" msgid="459390020612501122">"ഉയരം കൂട്ടുക"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"വീതി കുറയ്ക്കുക"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"ഉയരം കുറയ്ക്കുക"</string>
- <string name="widget_resized" msgid="9130327887929620">"വീതി <xliff:g id="NUMBER_0">%1$s</xliff:g> ഉയരം <xliff:g id="NUMBER_1">%2$s</xliff:g>-ലേക്ക് വിഡ്ജെറ്റിന്റെ വലുപ്പം മാറ്റി"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"കുറുക്കുവഴികൾ"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> ആപ്പിനുള്ള <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> കുറുക്കുവഴികൾ"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> ആപ്പിനായുള്ള <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> കുറുക്കുവഴികളും <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> അറിയിപ്പുകളും"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"നിരസിക്കുക"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"അറിയിപ്പ് നിരസിച്ചു"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"വ്യക്തിപരം"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"ജോലി"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ഔദ്യോഗിക ആപ്പുകൾ ഇവിടെ കണ്ടെത്തുക"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"എല്ലാ ഔദ്യോഗിക ആപ്പിനും ഒരു ബാഡ്ജ് ഉണ്ട്, നിങ്ങളുടെ സ്ഥാപനം അത് സുരക്ഷിതമായി സൂക്ഷിക്കുന്നു. എളുപ്പത്തിൽ ആക്സസ് ചെയ്യാൻ ആപ്പുകളെ ഹോം സ്ക്രീനിലേക്ക് നീക്കുക."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"നിങ്ങളുടെ സ്ഥാപനം നിയന്ത്രിക്കുന്നത്"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"അറിയിപ്പുകളും ആപ്പുകളും ഓഫാണ്"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"അടയ്ക്കുക"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"അടച്ചു"</string>
-</resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index d6a2fd1..e6973de 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -108,14 +108,13 @@
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ഡൗൺലോഡ് ചെയ്യുന്നു, <xliff:g id="PROGRESS">%2$s</xliff:g> പൂർത്തിയായി"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"ഇൻസ്റ്റാൾ ചെയ്യാൻ <xliff:g id="NAME">%1$s</xliff:g> കാക്കുന്നു"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> വിജറ്റുകൾ"</string>
- <!-- no translation found for widgets_list (796804551140113767) -->
- <skip />
- <!-- no translation found for widgets_list_closed (6141506579418771922) -->
- <skip />
+ <string name="widgets_list" msgid="796804551140113767">"വിജറ്റുകളുടെ ലിസ്റ്റ്"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"വിജറ്റുകളുടെ ലിസ്റ്റ് അവസാനിപ്പിച്ചു"</string>
<string name="action_add_to_workspace" msgid="8902165848117513641">"ഹോം സ്ക്രീനിൽ ചേർക്കുക"</string>
<string name="action_move_here" msgid="2170188780612570250">"ഇനം ഇവിടേക്ക് നീക്കുക"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"ഹോം സ്ക്രീനിൽ ഇനം ചേർത്തു"</string>
<string name="item_removed" msgid="851119963877842327">"ഇനം നീക്കംചെയ്തു"</string>
+ <string name="undo" msgid="4151576204245173321">"പഴയപടിയാക്കുക"</string>
<string name="action_move" msgid="4339390619886385032">"ഇനം നീക്കുക"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"വരി <xliff:g id="NUMBER_0">%1$s</xliff:g> നിര <xliff:g id="NUMBER_1">%2$s</xliff:g>-ലേക്ക് നീക്കുക"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>-ലേക്ക് നീക്കുക"</string>
@@ -146,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"അറിയിപ്പുകളും ആപ്പുകളും ഓഫാണ്"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"അടയ്ക്കുക"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"അടച്ചു"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"പരാജയപ്പെട്ടു: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml
deleted file mode 100644
index a3507c5..0000000
--- a/res/values-mn-rMN/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Ажил"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Апп суугаагүй байна."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Апп-г ашиглах боломжгүй"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Татаж авсан апп-г Аюулгүй горим дотроос идэвхгүйжүүлсэн"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Safe горимд виджетүүдийг идэвхгүйжүүлсэн"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Товчлол алга"</string>
- <string name="home_screen" msgid="806512411299847073">"Үндсэн нүүр"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Захиалгат үйлдэл"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Виджетийг авах бол хүрээд барина уу."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Жижиг хэрэгсэл авах болон тохируулсан үйлдлийг ашиглахын тулд 2 удаа товшоод барина уу."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d өргөн %2$d өндөр"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Гараар байршуулахын тулд дараад хүлээнэ үү"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Автоматаар нэмэх"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Апп хайх"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Аппыг ачааллаж байна..."</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"-д тохирох апп олдсонгүй"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Бусад апп-г хайх"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Мэдэгдэл"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Товчлол авах бол удаан дарна уу."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Товчлол авах эсвэл тохируулсан үйлдлийг ашиглахын тулд давхар товшоод хүлээнэ үү."</string>
- <string name="out_of_space" msgid="4691004494942118364">"Энэ Нүүр дэлгэц зайгүй."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"\"Дуртай\" трей дээр өөр зай байхгүй байна"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Апп-н жагсаалт"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Хувийн аппын жагсаалт"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Ажлын аппын жагсаалт"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Нүүр"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Арилгах"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Устгах"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Апп-н мэдээлэл"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Суулгах"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"товчлол суулгах"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Апп нь хэрэглэгчийн оролцоогүйгээр товчлолыг нэмэж чадна"</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"Нүүрний тохиргоо болон товчлолыг унших"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Апп нь Нүүрэндэх товчлол болон тохиргоог уншиж чадна."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"Нүүрний тохиргоо болон товчлолыг бичих"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Апп нь Нүүрэндэх товчлол болон тохиргоог өөрчилж чадна."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> утасны дуудлага хийх боломжгүй"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Виджет ачаалахад асуудал гарав"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Тохируулга"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Энэ апп нь системийн апп ба устгах боломжгүй."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Нэргүй фолдер"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г идэвхгүй болгосон"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> мэдэгдэл байна</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> мэдэгдэл байна</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"%2$d-н %1$d хуудас"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d-н Нүүр дэлгэц %1$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Шинэ үндсэн нүүр хуудас"</string>
- <string name="folder_opened" msgid="94695026776264709">"<xliff:g id="WIDTH">%1$d</xliff:g> <xliff:g id="HEIGHT">%2$d</xliff:g> фолдер нээгдэв"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Фолдерийг хаахын тулд дарна уу"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Шинэ нэрийг хадгалахын тулд дарна уу."</string>
- <string name="folder_closed" msgid="4100806530910930934">"Фолдер хаагдав"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Фолдерын нэр <xliff:g id="NAME">%1$s</xliff:g> болов"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Фолдер: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Виджет"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Ханын зураг"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Нүүр хуудасны тохиргоо"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Таны админ идэвхгүй болгосон"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Нүүр дэлгэцийг эргүүлэхийг зөвшөөрөх"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Утсыг эргүүлсэн үед"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Мэдэгдлийн цэг"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Асаалттай"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Унтраалттай"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Мэдэгдлийн хандалт шаардлагатай"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Мэдэгдлийн цэгийг харуулахын тулд <xliff:g id="NAME">%1$s</xliff:g>-д аппын мэдэгдлийг асаана уу"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Тохиргоог өөрчлөх"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Мэдэгдлийн цэгийг харуулах"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Нүүр хуудаст дүрс тэмдэг нэмэх"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Шинэ аппад зориулсан"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Дүрс тэмдгийн хэлбэрийг өөрчлөх"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"Үндсэн нүүр хэсэгт"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Системийн өгөгдмөл тохиргоог ашиглах"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Дөрвөлжин"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Мохоо өнцөгтэй дөрвөлжин"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Дугуй"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Дусал"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Дүрс тэмдгийн хэлбэрийг өөрчилж байна"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Тодорхойгүй"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Устгах"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Хайх"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Энэ апп-г суулгаагүй байна"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Энэ дүрсний апп-г суулгаагүй байна. Та үүнийг устгах буюу апп-г хайж суулгах боломжтой."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>-г татаж байна, <xliff:g id="PROGRESS">%2$s</xliff:g> татсан"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> нь суулгахыг хүлээж байна"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> жижиг хэрэгсэл"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Нүүр дэлгэц нэмэх"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Энд байршуулах"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Нүүр дэлгэцэнд нэмсэн зүйл"</string>
- <string name="item_removed" msgid="851119963877842327">"Арилгасан зүйл"</string>
- <string name="action_move" msgid="4339390619886385032">"Зөөх"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> мөр <xliff:g id="NUMBER_1">%2$s</xliff:g> баганад зөөх"</string>
- <string name="move_to_position" msgid="6750008980455459790">"Байршил <xliff:g id="NUMBER">%1$s</xliff:g>-д зөөх"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Дуртай байршил болох <xliff:g id="NUMBER">%1$s</xliff:g>-д зөөх"</string>
- <string name="item_moved" msgid="4606538322571412879">"Зөөвөрлөсөн зүйл"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Хавтас: <xliff:g id="NAME">%1$s</xliff:g> руу нэм"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g>-тай хавтас нэмэх"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Хавтсанд нэмэгдсэн зүйл"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Хавтсыг: <xliff:g id="NAME">%1$s</xliff:g> нэрээр үүсгэ"</string>
- <string name="folder_created" msgid="6409794597405184510">"Үүсгэсэн хавтас"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Нүүр дэлгэц рүү зөөх"</string>
- <string name="action_resize" msgid="1802976324781771067">"Хэмжээг өөрчлөх"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Өргөсгөх"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Өндөрсгөх"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Нарийсгах"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Намсгах"</string>
- <string name="widget_resized" msgid="9130327887929620">"Виджэтийн өргөн <xliff:g id="NUMBER_0">%1$s</xliff:g>, өндөр <xliff:g id="NUMBER_1">%2$s</xliff:g> болсон"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Товчлол"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g>-н <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> товчлол"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> товчлол болон <xliff:g id="APP_NAME">%3$s</xliff:g>-н <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> мэдэгдэл"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Хаах"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Мэдэгдлийг хаасан"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Хувийн"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Ажил"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Ажлын профайл"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Ажлын аппыг эндээс олно уу"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Ажлын апп тус бүр тэмдэгтэй ба эдгээрийг танай байгууллагаас аюулгүй байлгадаг. Аппуудад хялбар хандахын тулд тэдгээрийг Үндсэн нүүр хэсэгт зөөнө үү."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Танай байгууллагаас удирддаг"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Мэдэгдэл, апп унтраалттай байна"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Хаах"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Хаасан"</string>
-</resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 9fbb1e5..d28c401 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Энд байршуулах"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Нүүр дэлгэцэнд нэмсэн зүйл"</string>
<string name="item_removed" msgid="851119963877842327">"Арилгасан зүйл"</string>
+ <string name="undo" msgid="4151576204245173321">"Болих"</string>
<string name="action_move" msgid="4339390619886385032">"Зөөх"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> мөр <xliff:g id="NUMBER_1">%2$s</xliff:g> баганад зөөх"</string>
<string name="move_to_position" msgid="6750008980455459790">"Байршил <xliff:g id="NUMBER">%1$s</xliff:g>-д зөөх"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Мэдэгдэл, апп унтраалттай байна"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Хаах"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Хаасан"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Амжилтгүй болсон: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
deleted file mode 100644
index bf1e188..0000000
--- a/res/values-mr-rIN/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"कार्य"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"अॅप इंस्टॉल केलेला नाही."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"अॅप उपलब्ध नाही"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"डाउनलोड केलेला अॅप सुरक्षित मोड मध्ये अक्षम केला"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"विजेट सुरक्षित मोडमध्ये अक्षम झाले"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"शॉर्टकट उपलब्ध नाही"</string>
- <string name="home_screen" msgid="806512411299847073">"होम स्क्रीन"</string>
- <string name="custom_actions" msgid="3747508247759093328">"कस्टम क्रिया"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"विजेट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"एक विजेट निवडण्यासाठी दोनदा टॅप करा आणि धरून ठेवा किंवा कस्टम क्रिया वापरा."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d रूंद बाय %2$d उंच"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"स्वतः ठेवण्यासाठी स्पर्श करा आणि धरून ठेवा"</string>
- <string name="place_automatically" msgid="8064208734425456485">"अापोआप जोडा"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"अॅप्स शोधा"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"अॅप्स लोड करत आहे…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"अधिक अॅप्स शोधा"</string>
- <string name="notifications_header" msgid="1404149926117359025">"सूचना"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"शॉर्टकट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"शॉर्टकट निवडण्यासाठी किंवा कस्टम क्रिया वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."</string>
- <string name="out_of_space" msgid="4691004494942118364">"या मुख्य स्क्रीनवर आणखी जागा नाही."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"आवडीच्या ट्रे मध्ये आणखी जागा नाही"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"अॅप्स सूची"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"वैयक्तिक अॅप्स सूची"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"कामाच्या ठिकाणी वापरली जाणाऱ्या अॅप्सची सूची"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"होम"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"काढा"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"अनइंस्टॉल करा"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"अॅप माहिती"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"इंस्टॉल करा"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"शॉर्टकट स्थापित करा"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"वापरकर्ता हस्तक्षेपाशिवाय शॉर्टकट जोडण्यास अॅप ला अनुमती देते."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"होम सेटिंग्ज आणि शॉर्टकट वाचा"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"मुख्यपृष्ठातील सेटिंग्ज आणि शॉर्टकट वाचण्यास अॅप ला अनुमती देते."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"होम सेटिंग्ज आणि शॉर्टकट लिहा"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"मुख्यपृष्ठातील सेटिंग्ज आणि शॉर्टकट बदलण्यास अॅप ला अनुमती देते."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला फोन कॉल करण्याची अनुमती नाही"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"विजेट लोड करण्यात समस्या"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"सेटअप"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"हा सिस्टम अॅप आहे आणि अनइंस्टॉल केला जाऊ शकत नाही."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"अनामित फोल्डर"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> अक्षम केला आहे"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, कडे <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> सूचना आहे</item>
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, कडे <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> सूचना आहेत</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"%2$d पैकी %1$d पृष्ठ"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d पैकी %1$d मुख्य स्क्रीन"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"नवीन मुख्य स्क्रीन पृष्ठ"</string>
- <string name="folder_opened" msgid="94695026776264709">"फोल्डर उघडले, <xliff:g id="WIDTH">%1$d</xliff:g> बाय <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"फोल्डर बंद करण्यासाठी टॅप करा"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"पुनर्नामित करणे सेव्ह करण्यासाठी टॅप करा"</string>
- <string name="folder_closed" msgid="4100806530910930934">"फोल्डर बंद"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"फोल्डरचे नाव बदलून <xliff:g id="NAME">%1$s</xliff:g> असे ठेवले"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"फोल्डर: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"विजेट"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"वॉलपेपर"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"होम सेटिंग्ज"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"आपल्या प्रशासकाने अक्षम केले"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"मुख्यस्क्रीन फिरविण्यास अनुमती द्या"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"फोन फिरविला जातो तेव्हा"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"सूचना बिंदू"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"चालू"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"बंद"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"सूचनांच्या अॅक्सेसची आवश्यकता आहे"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"सूचना बिंदू दाखवण्यासाठी, <xliff:g id="NAME">%1$s</xliff:g> साठी अॅप सूचना चालू करा"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"सेटिंग्ज बदला"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"सूचना बिंदू दाखवा"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"होम स्क्रीनवर आयकन जोडा"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"नवीन अॅप्ससाठी"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"चिन्हाचा आकार बदला"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"होम स्क्रीनवर"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"सिस्टमचे डीफॉल्ट वापरा"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"चौरस"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"गोलाकार चौरस"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"वर्तुळ"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"अश्रू"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"चिन्हाचा आकार बदल लागू करत आहे"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"अज्ञात"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"काढा"</string>
- <string name="abandoned_search" msgid="891119232568284442">"शोधा"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"हा अॅप इंस्टॉल केलेला नाही"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"या चिन्हासाठी अॅप इंस्टॉल केलेला नाही. तुम्ही ते काढू शकता किंवा अॅपचा शोध घेऊ शकता आणि त्यास व्यक्तिचलितपणे इंस्टॉल करू शकता."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड होत आहे , <xliff:g id="PROGRESS">%2$s</xliff:g> पूर्ण झाले"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> इंस्टॉल करण्याची प्रतिक्षा करत आहे"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> विजेट"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"होम स्क्रीनवर जोडा"</string>
- <string name="action_move_here" msgid="2170188780612570250">"आयटम येथे हलवा"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"आयटम मुख्य स्क्रीनवर जोडला"</string>
- <string name="item_removed" msgid="851119963877842327">"आयटम काढला"</string>
- <string name="action_move" msgid="4339390619886385032">"आयटम हलवा"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"पंक्ति <xliff:g id="NUMBER_0">%1$s</xliff:g> स्तंभ <xliff:g id="NUMBER_1">%2$s</xliff:g> मध्ये हलवा"</string>
- <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> स्थानावर हलवा"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"आवडत्या <xliff:g id="NUMBER">%1$s</xliff:g> स्थानावर हलवा"</string>
- <string name="item_moved" msgid="4606538322571412879">"आयटम हलविला"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"फोल्डरवर जोडा: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> सह फोल्डरमध्ये जोडा"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"फोल्डरमध्ये आयटम जोडले"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"यासह फोल्डर तयार करा: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"फोल्डर तयार केले"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"मुख्य स्क्रीनवर हलवा"</string>
- <string name="action_resize" msgid="1802976324781771067">"आकार बदला"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"रूंदी वाढवा"</string>
- <string name="action_increase_height" msgid="459390020612501122">"उंची वाढवा"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"रुंदी कमी करा"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"उंची कमी करा"</string>
- <string name="widget_resized" msgid="9130327887929620">"विजेटचा आकार रुंदी <xliff:g id="NUMBER_0">%1$s</xliff:g> उंची <xliff:g id="NUMBER_1">%2$s</xliff:g> मध्ये बदलला"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"शॉर्टकट"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> साठी <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> शॉर्टकट"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g>साठी <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> शॉर्टकट आणि <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> सूचना"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"डिसमिस करा"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"सूचना डिसमिस केली"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"वैयक्तिक"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"कार्यालय"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफाइल"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"कामाची अॅप्स येथे मिळवा"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"प्रत्येक कार्य अॅपला एक बॅज असतो आणि तो तुमच्या संस्थेकडून सुरक्षित ठेवला जातो. अधिक सहज अॅक्सेससाठी अॅप्स तुमच्या होम स्क्रीनवर हलवा."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"तुमच्या संस्थेकडून व्यवस्थापित"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"सूचना आणि अॅप्स बंद आहेत"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"बंद करा"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"बंद केले"</string>
-</resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index a297e06..ec7ddb1 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"आयटम येथे हलवा"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"आयटम मुख्य स्क्रीनवर जोडला"</string>
<string name="item_removed" msgid="851119963877842327">"आयटम काढला"</string>
+ <string name="undo" msgid="4151576204245173321">"पूर्ववत करा"</string>
<string name="action_move" msgid="4339390619886385032">"आयटम हलवा"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"पंक्ति <xliff:g id="NUMBER_0">%1$s</xliff:g> स्तंभ <xliff:g id="NUMBER_1">%2$s</xliff:g> मध्ये हलवा"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> स्थानावर हलवा"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"सूचना आणि अॅप्स बंद आहेत"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"बंद करा"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"बंद केले"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"हे करता आले नाही: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
deleted file mode 100644
index 3c223b6..0000000
--- a/res/values-ms-rMY/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Kerja"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Apl tidak dipasang."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Apl tidak tersedia"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Apl yang dimuat turun dilumpuhkan dalam mod Selamat"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Widget dilumpuhkan dalam mod Selamat"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Pintasan tidak tersedia"</string>
- <string name="home_screen" msgid="806512411299847073">"Skrin utama"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Tindakan tersuai"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Sentuh & tahan untuk mengambil widget."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Ketik dua kali & tahan untuk mengambil widget atau menggunakan tindakan tersuai"</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Lebar %1$d kali tinggi %2$d"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Sentuh & tahan untuk meletakkan widget/ikon secara manual"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Tambahkan secara automatik"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cari apl"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Memuatkan apl…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"Tiada apl yang ditemui sepadan dengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Cari lagi apl"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Pemberitahuan"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Sentuh & tahan untuk mengambil pintasan."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Ketik dua kali & tahan untuk mengambil pintasan atau menggunakan tindakan tersuai."</string>
- <string name="out_of_space" msgid="4691004494942118364">"Tiada lagi ruang pada skrin Laman Utama ini."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Tiada ruang dalam dulang Kegemaran lagi"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Senarai apl"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Senarai apl peribadi"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Senarai apl kerja"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Laman Utama"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Alih keluar"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Nyahpasang"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Maklumat apl"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Pasang"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"pasang pintasan"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Membenarkan apl menambah pintasan tanpa campur tangan pengguna."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"baca tetapan dan pintasan Laman Utama"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Membenarkan apl membaca tetapan dan pintasan di Laman Utama."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"tulis tetapan dan pintasan Laman Utama"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Membenarkan apl menukar tetapan dan pintasan di Laman Utama."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak dibenarkan membuat panggilan telefon"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Masalah memuatkan widget"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Persediaan"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ini ialah apl sistem dan tidak boleh dinyahpasang."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Folder Tanpa Nama"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> dilumpuhkan"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, mempunyai <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> pemberitahuan</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, mempunyai <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> pemberitahuan</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"Halaman %1$d daripada %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"Skrin Laman Utama %1$d daripada %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Halaman skrin utama baharu"</string>
- <string name="folder_opened" msgid="94695026776264709">"Folder dibuka, <xliff:g id="WIDTH">%1$d</xliff:g> kali <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Ketik untuk menutup folder"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Ketik untuk menyimpan penamaan semula"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Folder ditutup"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Folder dinamakan semula kepada <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Widget"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Kertas dinding"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Tetapan laman utama"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Dilumpuhkan oleh pentadbir anda"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Benarkan putaran Skrin Utama"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Apabila telefon diputar"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Titik pemberitahuan"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Hidup"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Mati"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Akses pemberitahuan diperlukan"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Untuk menunjukkan Titik Pemberitahuan, hidupkan pemberitahuan apl untuk <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Tukar tetapan"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Tunjukkan titik pemberitahuan"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Tambahkan ikon pada Skrin Utama"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Untuk apl baharu"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Tukar bentuk ikon"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"pada Skrin Utama"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Gunakan lalai sistem"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Segi empat sama"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Segi empat berbucu bulat"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Bulatan"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Titisan air mata"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Menggunakan perubahan bentuk ikon"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Tidak diketahui"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Alih keluar"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Carian"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Apl ini tidak dipasang"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Apl untuk ikon ini tidak dipasang. Anda boleh mengalih keluar atau mencari dan memasang apl itu secara manual."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> memuat turun, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> menunggu untuk dipasang"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widget <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Tambahkan pada Skrin Utama"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Alihkan item ke sini"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Item ditambahkan pada skrin utama"</string>
- <string name="item_removed" msgid="851119963877842327">"Item dialih keluar"</string>
- <string name="action_move" msgid="4339390619886385032">"Alihkan Item"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"Alihkan ke baris <xliff:g id="NUMBER_0">%1$s</xliff:g> lajur <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="move_to_position" msgid="6750008980455459790">"Alihkan ke kedudukan <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Alihkan ke kedudukan kegemaran <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="item_moved" msgid="4606538322571412879">"Item dialihkan"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Tambahkan pada folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"Tambahkan pada folder dengan <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Item ditambahkan pada folder"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Buat folder dengan: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"Folder dibuat"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Alihkan ke Skrin Utama"</string>
- <string name="action_resize" msgid="1802976324781771067">"Ubah saiz"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Tambahkan kelebaran"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Tambahkan ketinggian"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Kurangkan kelebaran"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Kurangkan ketinggian"</string>
- <string name="widget_resized" msgid="9130327887929620">"Saiz widget diubah menjadi <xliff:g id="NUMBER_0">%1$s</xliff:g> lebar <xliff:g id="NUMBER_1">%2$s</xliff:g> tinggi"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Pintasan"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> pintasan untuk <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> pintasan dan <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> pemberitahuan untuk <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Ketepikan"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Pemberitahuan diketepikan"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Peribadi"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Kerja"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil kerja"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Temui apl kerja di sini"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Setiap apl kerja terdapat lencana dan dilindungi oleh organisasi anda. Alihkan apl ke Skrin Utama untuk akses yang lebih mudah."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Diurus oleh organisasi anda"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Pemberitahuan dan apl dimatikan"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Tutup"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Ditutup"</string>
-</resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 71047fb..29fe343 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Alihkan item ke sini"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Item ditambahkan pada skrin utama"</string>
<string name="item_removed" msgid="851119963877842327">"Item dialih keluar"</string>
+ <string name="undo" msgid="4151576204245173321">"Buat asal"</string>
<string name="action_move" msgid="4339390619886385032">"Alihkan Item"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Alihkan ke baris <xliff:g id="NUMBER_0">%1$s</xliff:g> lajur <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Alihkan ke kedudukan <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Pemberitahuan dan apl dimatikan"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Tutup"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Ditutup"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
deleted file mode 100644
index 59ac4ca..0000000
--- a/res/values-my-rMM/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"ဖွင့်တင်စက်၃"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"အလုပ်"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"အက်ပ်မထည့်သွင်းထားပါ"</string>
- <string name="activity_not_available" msgid="7456344436509528827">"အက်ပ်လက်လှမ်း မမှီပါ"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"ဒေါင်းလုဒ် အက်ပ်ကို လုံခြုံရေး မုဒ်ထဲမှာ ပိတ်ထား"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"လုံခြုံရေး မုဒ်ထဲမှာ ဝီဂျက်များကို ပိတ်ထား"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"ဖြတ်လမ်း မရနိုင်ပါ"</string>
- <string name="home_screen" msgid="806512411299847073">"ပင်မစာမျက်နှာ"</string>
- <string name="custom_actions" msgid="3747508247759093328">"စိတ်ကြိုက် လုပ်ဆောင်ချက်များ"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"ဝဒ်ဂျက်တစ်ခုကို ကောက်ယူရန် ဖိနှိပ်ထားပါ"</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ဝစ်ဂျက်တစ်ခုကိုရယူရန် သို့မဟုတ် စိတ်ကြိုက်လုပ်ဆောင်မှုများကို အသုံးပြုရန် နှစ်ချက်တို့ပြီး ကိုင်ထားပါ။"</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"အလျား %1$d နှင့် အမြင့် %2$d"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"ကိုယ်တိုင်ထည့်ရန် ထိထားပါ"</string>
- <string name="place_automatically" msgid="8064208734425456485">"အလိုအလျောက် ထည့်ရန်"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ရှာဖွေမှု အက်ပ်များ"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"အက်ပ်များကို ဖွင့်နေသည်…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" နှင့်ကိုက်ညီသည့် အပ်ပ်များကို မတွေ့ပါ"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"နောက်ထပ် အက်ပ်များကို ရှာပါ"</string>
- <string name="notifications_header" msgid="1404149926117359025">"အကြောင်းကြားချက်များ"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ဖြတ်လမ်းလင့်ခ်တစ်ခုကို ရွေးရန် ထိပြီး ဖိထားပါ။"</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ဖြတ်လမ်းလင့်ခ်ကို ရွေးရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန် နှစ်ချက်တို့ပြီး ဖိထားပါ။"</string>
- <string name="out_of_space" msgid="4691004494942118364">"ဤပင်မမျက်နှာစာတွင် နေရာလွတ် မကျန်တော့ပါ"</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"အနှစ်သက်ဆုံးများ ထားရာတွင် နေရာလွတ် မကျန်တော့ပါ"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"အက်ပ်စာရင်း"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"တစ်ကိုယ်ရေသုံး အက်ပ်စာရင်း"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"အလုပ်သုံး အက်ပ်စာရင်း"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"ပင်မစာမျက်နှာ"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"ဖယ်ရှားမည်"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ဖယ်ထုတ်မည်"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"အက်ပ်အချက်အလက်များ"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"ထည့်သွင်းရန်"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"အတိုကောက်မှတ်သားမှုများအား ထည့်သွင်းခြင်း"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"အသုံးပြုသူ လုပ်ဆောင်မှုမရှိပဲ အပ်ပလီကေးရှင်းကို အတိုကောက်မှတ်သားမှုများ ပြုလုပ်ခွင့် ပေးခြင်း"</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"ပင်မမျက်နှာစာ အပြင်အဆင် နှင့် အတိုကောက်မှတ်သားမှုများအား ဖတ်ခြင်း"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"ပင်မမျက်နှာစာတွင်ရှိသော အပြင်အဆင်နှင့် အတိုကောက်မှတ်သားမှုများကို အပ်ပလီကေးရှင်းအား ဖတ်ခွင့်ပြုခြင်း"</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"ပင်မမျက်နှာစာ အပြင်အဆင် နှင့် အတိုကောက်မှတ်သားမှုများအား ရေးသားခြင်း"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"ပင်မမျက်နှာစာတွင် ရှိသော အပြင်အဆင် နှင့် အတိုကောက်မှတ်သားမှုများ ကို အပ်ပလီကေးရှင်းအား ပြောင်းခွင့်ပြုခြင်း"</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g>သည် ဖုန်းခေါ်ဆိုခွင့် မရှိပါ"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"ဝဒ်ဂျက် တင်ရာတွင် ပြသနာ ရှိပါသည်"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"စဖွင့်သတ်မှတ်ရန်"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"ဤအပ်ပလီကေးရှင်းမှာ စစ်စတန်ပိုင်းဆိုင်ရာ အပ်ပလီကေးရှင်းဖြစ်ပါသည်။ ထုတ်ပစ်၍ မရပါ"</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"အမည်မရှိအကန့်"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို ပိတ်ထားသည်"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> တွင် အကြောင်းကြားချက် <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> ခု ရှိသည်</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> တွင် အကြောင်းကြားချက် <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> ခု ရှိသည်</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"စာမျက်နှာ %1$d မှ %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"ပင်မစာမျက်နှာ %1$d မှ %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"ပင်မမျက်နှာပြင် စာမျက်နှာသစ်"</string>
- <string name="folder_opened" msgid="94695026776264709">"ဖွင့်ထားသောအကန့်, <xliff:g id="WIDTH">%1$d</xliff:g> နှင့် <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"ဖိုင်တွဲကို ပိတ်ရန် တို့ပါ"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"အမည်ပြောင်းခြင်းကို သိမ်းဆည်းရန် တို့ပါ"</string>
- <string name="folder_closed" msgid="4100806530910930934">"ပိတ်ထားသောအကန့်"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"ပြောင်းလဲလိုက်သော အကန့်အမည် <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"အကန့်အမည်: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"ဝိဂျက်များ"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"နောက်ခံများ"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"ပင်မဆက်တင်များ"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"သင့်စီမံခန့်ခွဲသူက ပိတ်လိုက်ပါသည်"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"ပင်မစာမျက်နှာလှည့်ခြင်းကို ခွင့်ပြုပါ"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"ဖုန်းကိုလှည့်ထားစဉ်"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"အကြောင်းကြားချက်အမှတ်အသားများ"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"ဖွင့်ထားသည်"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"ပိတ်ထားသည်"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"အကြောင်းကြားချက် အသုံးပြုခွင့် လိုအပ်သည်"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"အကြောင်းကြားချက် အစက်များကို ပြသရန် <xliff:g id="NAME">%1$s</xliff:g> အတွက် အက်ပ်အကြောင်းကြားချက်များကို ဖွင့်ပါ"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"ဆက်တင်များ ပြောင်းရန်"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"အကြောင်းကြားချက် အမှတ်အသားများကို ပြရန်"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ပင်မစာမျက်နှာသို့ သင်္ကေတပုံ ထည့်ရန်"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"အက်ပ်အသစ်များအတွက်"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"သင်္ကေတပုံစံကို ပြောင်းရန်"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"\'ပင်မမျက်နှာပြင်\' ပေါ်တွင်"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"စနစ်၏ မူရင်းပုံကို အသုံးပြုရန်"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"လေးထောင့်"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"စတုရန်းမကျ စက်ဝိုင်းမကျပုံ"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"စက်ဝိုင်း"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"မျက်ရည်စက်ပုံ"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"သင်္ကေတပုံစံကို ပြောင်းလဲနေသည်"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"မသိရ"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"ဖယ်ရှားရန်"</string>
- <string name="abandoned_search" msgid="891119232568284442">"ရှာဖွေရန်"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"အက်ပ်မတပ်ဆင်ရသေးပါ"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ဤအိုင်ကွန်အတွက် အက်ပ်အားမထည့်သွင်းထားပါ။ You can remove it, or search for the အက်ပ်and install it manually."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ဒေါင်းလုဒ်လုပ်နေသည်၊ <xliff:g id="PROGRESS">%2$s</xliff:g> ပြီးပါပြီ"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ကိုထည့်သွင်းရန်စောင့်နေသည်"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ဝိဂျက်များ"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"ပင်မမျက်နှာစာသို့ ထည့်ပါ"</string>
- <string name="action_move_here" msgid="2170188780612570250">"၎င်းအား ဤသို့ ရွှေ့ပါ"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"ပင်မ ဖန်မျက်နှာပြင်သို့ ထည့်ပြီး၏"</string>
- <string name="item_removed" msgid="851119963877842327">"၎င်းအား ဖယ်ရှားပြီး၏"</string>
- <string name="action_move" msgid="4339390619886385032">"၎င်းအား ရွှေ့ပါ"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"အတန်း <xliff:g id="NUMBER_0">%1$s</xliff:g> အတိုင် <xliff:g id="NUMBER_1">%2$s</xliff:g> သို့ ရွှေ့ပါ"</string>
- <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> သို့ နေရာရွှေ့ပါ"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"စိတ်ကြိုက်နေရာ <xliff:g id="NUMBER">%1$s</xliff:g> သို့ ရွှေ့ပါ"</string>
- <string name="item_moved" msgid="4606538322571412879">"၎င်းအားရွှေ့ပြီး"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"ဖိုလ်ဒါသို့ ထည့်ရန်- <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> အမည်ရှိ ဖိုလ်ဒါသို့ ထည့်ပြီး၏"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"ဖိုလ်ဒါသို့ ထည့်ပြီး"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"ဖိုလ်ဒါ ပြုလုပ်ရန်- <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"ဖိုလ်ဒါ ပြုလုပ်ပြီး"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"ပင်မမျက်နှာပြင်သို့ ရွှေ့ပါ"</string>
- <string name="action_resize" msgid="1802976324781771067">"အရွယ်အစားပြောင်းပါ"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"အကျယ်အား တိုးပါ"</string>
- <string name="action_increase_height" msgid="459390020612501122">"အမြင့်အား တိုးပါ"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"အကျယ်အား လျှော့ပါ"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"အမြင့်အား လျှော့ပါ"</string>
- <string name="widget_resized" msgid="9130327887929620">"Widget အား အကျယ် <xliff:g id="NUMBER_0">%1$s</xliff:g> အမြင့် <xliff:g id="NUMBER_1">%2$s</xliff:g> အရွယ်အစားပြန်လည်ချိန်ညှိပြီး၏"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"ဖြတ်လမ်းများ"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> အတွက် အမြန်နည်း <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ခု"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> အတွက် ဖြတ်လမ်းလင့်ခ် <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> နှင့် အကြောင်းကြားချက် <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ခု"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"ပယ်ရန်"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"အသိပေးချက်ကို ဖယ်ထုတ်ပြီးပါပြီ"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"ကိုယ်ပိုင်"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"အလုပ်"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"အလုပ်ပရိုဖိုင်"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"အလုပ်အက်ပ်များကို ဤနေရာတွင်ရှာဖွေပါ"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"အလုပ်အက်ပ်တိုင်းတွင် တံဆိပ် တစ်ခုစီရှိပြီး သင်၏ အဖွဲ့အစည်းက လုံခြုံအောင် ထားရှိပါသည်။ အသုံးပြုရ ပိုမိုလွယ်ကူစေရန် အက်ပ်များကို သင်၏ ပင်မမျက်နှာပြင်သို့ ရွှေ့ပါ။"</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"သင်၏ အဖွဲ့အစည်းက စီမံခန့်ခွဲထားပါသည်"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"အကြောင်းကြားချက်များနှင့် အက်ပ်များကို ပိတ်ထားသည်"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ပိတ်ရန်"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ပိတ်ထားသည်"</string>
-</resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 6c26185..0b07e30 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -73,7 +73,7 @@
<string name="workspace_new_page" msgid="257366611030256142">"ပင်မမျက်နှာပြင် စာမျက်နှာသစ်"</string>
<string name="folder_opened" msgid="94695026776264709">"ဖွင့်ထားသောအကန့်, <xliff:g id="WIDTH">%1$d</xliff:g> နှင့် <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
<string name="folder_tap_to_close" msgid="4625795376335528256">"ဖိုင်တွဲကို ပိတ်ရန် တို့ပါ"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"အမည်ပြောင်းခြင်းကို သိမ်းဆည်းရန် တို့ပါ"</string>
+ <string name="folder_tap_to_rename" msgid="4017685068016979677">"အမည်ပြောင်းခြင်းကို သိမ်းရန် တို့ပါ"</string>
<string name="folder_closed" msgid="4100806530910930934">"ပိတ်ထားသောအကန့်"</string>
<string name="folder_renamed" msgid="1794088362165669656">"ပြောင်းလဲလိုက်သော အကန့်အမည် <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_name_format" msgid="6629239338071103179">"အကန့်အမည်: <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"၎င်းအား ဤသို့ ရွှေ့ပါ"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"ပင်မ ဖန်မျက်နှာပြင်သို့ ထည့်ပြီး၏"</string>
<string name="item_removed" msgid="851119963877842327">"၎င်းအား ဖယ်ရှားပြီး၏"</string>
+ <string name="undo" msgid="4151576204245173321">"နောက်ပြန်"</string>
<string name="action_move" msgid="4339390619886385032">"၎င်းအား ရွှေ့ပါ"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"အတန်း <xliff:g id="NUMBER_0">%1$s</xliff:g> အတိုင် <xliff:g id="NUMBER_1">%2$s</xliff:g> သို့ ရွှေ့ပါ"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> သို့ နေရာရွှေ့ပါ"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"အကြောင်းကြားချက်များနှင့် အက်ပ်များကို ပိတ်ထားသည်"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ပိတ်ရန်"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ပိတ်ထားသည်"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"မအောင်မြင်ပါ− <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 67a912b..c0049e1 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Flytt elementet hit"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Elementet er lagt til på startskjermen"</string>
<string name="item_removed" msgid="851119963877842327">"Elementet er fjernet"</string>
+ <string name="undo" msgid="4151576204245173321">"Angre"</string>
<string name="action_move" msgid="4339390619886385032">"Flytt elementet"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Flytt til rad <xliff:g id="NUMBER_0">%1$s</xliff:g>, kolonne <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Flytt til posisjon <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Varsler og apper er slått av"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Lukk"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Lukket"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Mislyktes: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
deleted file mode 100644
index a8a64f1..0000000
--- a/res/values-ne-rNP/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"कार्य"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"अनुप्रयोग स्थापित छैन।"</string>
- <string name="activity_not_available" msgid="7456344436509528827">"अनुप्रयोग उपलब्ध छैन"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"सुरक्षित मोडमा डाउनलोड गरेको अनुप्रयोग अक्षम गरिएको छ"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"सुरक्षित मोडमा विगेटहरू अक्षम गरियो"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"सर्टकट उपलब्ध छैन"</string>
- <string name="home_screen" msgid="806512411299847073">"गृह स्क्रिन"</string>
- <string name="custom_actions" msgid="3747508247759093328">"आफू अनुकूलका कारबाहीहरू"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"एउटा विजेटलाई टिप्नको लागि टच गरेर होल्ड गर्नुहोस्।"</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"विजेटलाई छान्न वा आफू अनुकूल कार्यहरू प्रयोग गर्न डबल ट्याप गरी होल्ड गर्नुहोस्।"</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d चौडाइ गुणा %2$d उचाइ"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"म्यानुअल तरिकाले थप्न छुनुहोस् र थिची राख्नुहोस्"</string>
- <string name="place_automatically" msgid="8064208734425456485">"स्वतः थप्नुहोस्"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"खोजसम्बन्धी अनुप्रयोगहरू"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"अनुप्रयोगहरू लोड गर्दै…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" सँग मिल्दो कुनै अनुप्रयोग भेटिएन"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"थप अनुप्रयोगहरू खोज्नुहोस्"</string>
- <string name="notifications_header" msgid="1404149926117359025">"सूचनाहरू"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"कुनै सर्टकट छनौट गर्न छोइराख्नुहोस्।"</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"कुनै सर्टकट छनौट गर्न वा रोजेका कारबाहीहरू प्रयोग गर्न डबल ट्याप गरेर छोइराख्नुहोस्।"</string>
- <string name="out_of_space" msgid="4691004494942118364">"यो गृह स्क्रिनमा कुनै थप ठाउँ छैन।"</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"मनपर्ने ट्रे अब कुनै ठाँउ छैन"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"अनुप्रयोगको सूची"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"व्यक्तिगत अनुप्रयोगहरूको सूची"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"कार्यसम्बन्धी अनुप्रयोगहरूको सूची"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"गृह"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"हटाउनुहोस्"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"विस्थापित गर्नुहोस्"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"अनुप्रयोग जानकारी"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"स्थापना गर्नुहोस्"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"सर्टकट स्थापना गर्नेहोस्"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा अनुप्रयोगलाई सर्टकटमा थप्नको लागि अनुमति दिनुहोस्।"</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"गृह सेटिङहरू र सर्टकटहरू पढ्नुहोस्"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"गृहमा एउटा अनुप्रयोगलाई सेटिङहरू र सर्टकटहरू पढ्न अनुमति दिनुहोस्।"</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"गृह सेटिङहरू र सर्टकटहरू लेख्नुहोस्"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"गृहमा एउटा अनुप्रयोगलाई सेटिङ र सर्टकट बदल्न अनुमति दिनुहोस्।"</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले फोन कलहरू गर्न अनुमति छैन"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"समस्या लोडिङ गर्ने विजेट"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"सेटअप"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"यो प्रणाली अनुप्रयोग हो र यसलाई स्थापना रद्द गर्न सकिँदैन।"</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"बेनाम फोल्डर"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"असक्षम पारिएको <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, यसमा <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> सूचनाहरू छन्</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, यसमा <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> सूचना छ</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"पृष्ठ %2$d को %1$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"गृह स्क्रिन %1$d को %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"नयाँ गृह स्क्रिन पृष्ठ"</string>
- <string name="folder_opened" msgid="94695026776264709">"फोल्डर खुल्यो <xliff:g id="WIDTH">%1$d</xliff:g> बाट <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"फोल्डरलाई बन्द गर्न ट्याप गर्नुहोस्"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"पुनःनामाकरणलाई सुरक्षित गर्न ट्याप गर्नुहोस्"</string>
- <string name="folder_closed" msgid="4100806530910930934">"फोल्डर बन्द भयो"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"फोल्डर <xliff:g id="NAME">%1$s</xliff:g> मा पुनःनामाकरण गरियो।"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"फोल्डर: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"विजेटहरू"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"वालपेपरहरु"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"गृहपृष्ठका सेटिङहरू"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"तपाईँको प्रशासकद्वारा असक्षम गरिएको"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"गृह स्क्रिनलाई घुम्ने अनुमति दिनुहोस्"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"फोनलाई घुमाइँदा"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"सूचनाको प्रतीक जनाउने थोप्लोहरू"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"सक्रिय छ"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"निष्क्रिय छ"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"सूचनासम्बन्धी पहुँच आवश्यक हुन्छ"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"सूचनाको प्रतीक जनाउने थोप्लाहरू देखाउन <xliff:g id="NAME">%1$s</xliff:g> को अनुप्रयोगसम्बन्धी सूचनाहरूलाई सक्रिय गर्नुहोस्"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"सेटिङहरू बदल्नुहोस्"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"सूचनाको प्रतीक जनाउने थोप्लाहरू देखाउनुहोस्"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"गृह स्क्रिनमा आइकन थप्नुहोस्"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"नयाँ अनुप्रयोगका लागि"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"आइकनको आकार परिवर्तन गर्नुहोस्"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"गृह स्क्रिनमा"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"प्रणालीको पूर्वनिर्धारित सेटिङ प्रयोग गर्नुहोस्"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"वर्ग"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"वर्गाकार वृत्त"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"वृत्त"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"आँसुको थोपा"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"आइकनको आकारमा गरिएका परिवर्तनहरू लागू गरिँदैछन्"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"अज्ञात"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"हटाउनुहोस्"</string>
- <string name="abandoned_search" msgid="891119232568284442">"खोजी गर्नुहोस्"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"यो अनुप्रयोग स्थापित छैन"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"यो प्रतिमाका लागि अनुप्रयोगलाई स्थापना गरिएको छैन। तपाईं यसलाई हटाउन, वा अनुप्रयोग खोजी र स्वयं यो स्थापित गर्न सक्नुहुन्छ।"</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड गर्दै, <xliff:g id="PROGRESS">%2$s</xliff:g> सम्पन्न"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> स्थापना गर्न प्रतीक्षा गर्दै"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> विजेटहरू"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"गृह स्क्रिनमा थप्नुहोस्"</string>
- <string name="action_move_here" msgid="2170188780612570250">"वस्तु यहाँ सार्नुहोस्"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"वस्तु गृह स्क्रिनमा थपियो"</string>
- <string name="item_removed" msgid="851119963877842327">"वस्तु हटाइयो"</string>
- <string name="action_move" msgid="4339390619886385032">"वस्तु सार्नुहोस्"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"पङ्क्ति <xliff:g id="NUMBER_0">%1$s</xliff:g> स्तम्भ <xliff:g id="NUMBER_1">%2$s</xliff:g> मा सार्नुहोस्"</string>
- <string name="move_to_position" msgid="6750008980455459790">"स्थिति <xliff:g id="NUMBER">%1$s</xliff:g> मा सार्नुहोस्"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"मनपर्ने स्थिति <xliff:g id="NUMBER">%1$s</xliff:g> मा सार्नुहोस्"</string>
- <string name="item_moved" msgid="4606538322571412879">"वस्तु सारियो"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"फोल्डर: <xliff:g id="NAME">%1$s</xliff:g> मा थप्नुहोस्"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"फोल्डरमा <xliff:g id="NAME">%1$s</xliff:g> सँग थप्नुहोस्"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"वस्तु फोल्डरमा थपियो"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"<xliff:g id="NAME">%1$s</xliff:g>: मार्फत फोल्डर सिर्जना गर्नुहोस्"</string>
- <string name="folder_created" msgid="6409794597405184510">"फोल्डर सिर्जना गरियो"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"गृह स्क्रिनमा सार्नुहोस्"</string>
- <string name="action_resize" msgid="1802976324781771067">"पुनःआकार मिलाउनुहोस्"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"चौडाइ बढाउनुहोस्"</string>
- <string name="action_increase_height" msgid="459390020612501122">"उँचाइ बढाउनुहोस्"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"चौडाइ घटाउनुहोस्"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"उँचाइ घटाउनुहोस्"</string>
- <string name="widget_resized" msgid="9130327887929620">"विजेट चौडाइ <xliff:g id="NUMBER_0">%1$s</xliff:g> उचाइ <xliff:g id="NUMBER_1">%2$s</xliff:g> मा पुनः आकार मिलाइयो"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"सर्टकटहरू"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> का <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> सर्टकटहरू"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> का <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> सर्टकट र <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> सूचनाहरू"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"खारेज गर्नुहोस्"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"सूचना खारेज गरियो"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"व्यक्तिगत"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"कार्यसम्बन्धी"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफाइल"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"कार्यसम्बन्धी अनुप्रयोगहरू यहाँ प्राप्त गर्नुहोस्"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"कार्यसम्बन्धी प्रत्येक अनुप्रयोगमा एउटा ब्याज छ र तपाईंको संगठनले यसलाई सुरक्षित राखेको छ । अझ सजिलो गरी पहुँच राख्नका लागि अनुप्रयोगहरूलाई आफ्नो गृहस्क्रिनमा सार्नुहोस्।"</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"तपाईंको सङ्गठनले व्यवस्थापन गरेको"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"सूचना र अनुप्रयोगहरू निष्क्रिय छन्"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"बन्द गर्नुहोस्"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"बन्द गरियो"</string>
-</resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 50c4279..1133362 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -43,7 +43,7 @@
<string name="long_press_shortcut_to_add" msgid="4524750017792716791">"कुनै सर्टकट छनौट गर्न छोइराख्नुहोस्।"</string>
<string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"कुनै सर्टकट छनौट गर्न वा रोजेका कारबाहीहरू प्रयोग गर्न डबल ट्याप गरेर छोइराख्नुहोस्।"</string>
<string name="out_of_space" msgid="4691004494942118364">"यो गृह स्क्रिनमा कुनै थप ठाउँ छैन।"</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"मनपर्ने ट्रे अब कुनै ठाँउ छैन"</string>
+ <string name="hotseat_out_of_space" msgid="7448809638125333693">"मन पर्ने ट्रे अब कुनै ठाँउ छैन"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"अनुप्रयोगको सूची"</string>
<string name="all_apps_button_personal_label" msgid="1315764287305224468">"व्यक्तिगत अनुप्रयोगहरूको सूची"</string>
<string name="all_apps_button_work_label" msgid="7270707118948892488">"कार्यसम्बन्धी अनुप्रयोगहरूको सूची"</string>
@@ -108,18 +108,17 @@
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड गर्दै, <xliff:g id="PROGRESS">%2$s</xliff:g> सम्पन्न"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> स्थापना गर्न प्रतीक्षा गर्दै"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> विजेटहरू"</string>
- <!-- no translation found for widgets_list (796804551140113767) -->
- <skip />
- <!-- no translation found for widgets_list_closed (6141506579418771922) -->
- <skip />
+ <string name="widgets_list" msgid="796804551140113767">"विजेटहरूको सूची"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"विजेटहरूको सूची बन्द गरियो"</string>
<string name="action_add_to_workspace" msgid="8902165848117513641">"गृह स्क्रिनमा थप्नुहोस्"</string>
<string name="action_move_here" msgid="2170188780612570250">"वस्तु यहाँ सार्नुहोस्"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"वस्तु गृह स्क्रिनमा थपियो"</string>
<string name="item_removed" msgid="851119963877842327">"वस्तु हटाइयो"</string>
+ <string name="undo" msgid="4151576204245173321">"अन्डू गर्नुहोस्"</string>
<string name="action_move" msgid="4339390619886385032">"वस्तु सार्नुहोस्"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"पङ्क्ति <xliff:g id="NUMBER_0">%1$s</xliff:g> स्तम्भ <xliff:g id="NUMBER_1">%2$s</xliff:g> मा सार्नुहोस्"</string>
<string name="move_to_position" msgid="6750008980455459790">"स्थिति <xliff:g id="NUMBER">%1$s</xliff:g> मा सार्नुहोस्"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"मनपर्ने स्थिति <xliff:g id="NUMBER">%1$s</xliff:g> मा सार्नुहोस्"</string>
+ <string name="move_to_hotseat_position" msgid="6295412897075147808">"मन पर्ने स्थिति <xliff:g id="NUMBER">%1$s</xliff:g> मा सार्नुहोस्"</string>
<string name="item_moved" msgid="4606538322571412879">"वस्तु सारियो"</string>
<string name="add_to_folder" msgid="9040534766770853243">"फोल्डर: <xliff:g id="NAME">%1$s</xliff:g> मा थप्नुहोस्"</string>
<string name="add_to_folder_with_app" msgid="4534929978967147231">"फोल्डरमा <xliff:g id="NAME">%1$s</xliff:g> सँग थप्नुहोस्"</string>
@@ -146,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"सूचना र अनुप्रयोगहरू निष्क्रिय छन्"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"बन्द गर्नुहोस्"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"बन्द गरियो"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"कार्य पूरा गर्न सकिएन: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-v19/styles.xml b/res/values-night-v26/styles.xml
similarity index 70%
copy from res/values-v19/styles.xml
copy to res/values-night-v26/styles.xml
index 36c0971..510e1f4 100644
--- a/res/values-v19/styles.xml
+++ b/res/values-night-v26/styles.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
-* Copyright (C) 2016 The Android Open Source Project
+* 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.
@@ -16,11 +16,11 @@
* limitations under the License.
*/
-->
+
<resources>
- <style name="LauncherTheme" parent="@style/BaseLauncherThemeWithCustomAttrs">
- <item name="android:windowTranslucentStatus">true</item>
- <item name="android:windowTranslucentNavigation">true</item>
+ <style name="AppItemActivityTheme" parent="@android:style/Theme.DeviceDefault.Dialog.Alert">
+ <item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
</style>
</resources>
\ No newline at end of file
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 64f4d79..8b4e7b4 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Item hier naartoe verplaatsen"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Item toegevoegd aan startscherm"</string>
<string name="item_removed" msgid="851119963877842327">"Item verwijderd"</string>
+ <string name="undo" msgid="4151576204245173321">"Ongedaan maken"</string>
<string name="action_move" msgid="4339390619886385032">"Item verplaatsen"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Verplaatsen naar rij <xliff:g id="NUMBER_0">%1$s</xliff:g>, kolom <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Verplaatsen naar positie <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Meldingen en apps zijn uitgeschakeld"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Sluiten"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Gesloten"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Mislukt: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 5fa6607..29e35ea 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -108,14 +108,13 @@
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ଡାଉନଲୋଡ୍ ହେଉଛି, <xliff:g id="PROGRESS">%2$s</xliff:g> ସମ୍ପୂର୍ଣ୍ଣ"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ଇନଷ୍ଟଲ୍ ହେବାକୁ ଅପେକ୍ଷା କରିଛି"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ୱିଜେଟ୍"</string>
- <!-- no translation found for widgets_list (796804551140113767) -->
- <skip />
- <!-- no translation found for widgets_list_closed (6141506579418771922) -->
- <skip />
+ <string name="widgets_list" msgid="796804551140113767">"ୱିଜେଟ୍ ତାଲିକା"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"ୱିଜେଟ୍ ତାଲିକା ବନ୍ଦ ହୋଇଛି"</string>
<string name="action_add_to_workspace" msgid="8902165848117513641">"ହୋମ୍ ସ୍କ୍ରୀନରେ ଯୋଡ଼ନ୍ତୁ"</string>
<string name="action_move_here" msgid="2170188780612570250">"ଆଇଟମ୍କୁ ଏଠାକୁ ଘୁଞ୍ଚାନ୍ତୁ"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"ହୋମ୍ ସ୍କ୍ରୀନରେ ଆଇଟମ୍ ଯୋଡ଼ାଗଲା"</string>
<string name="item_removed" msgid="851119963877842327">"ଆଇଟମ୍ ବାହାର କରାଗଲା"</string>
+ <string name="undo" msgid="4151576204245173321">"ପୂର୍ବବତ୍"</string>
<string name="action_move" msgid="4339390619886385032">"ଆଇଟମ୍ ଘୁଞ୍ଚାନ୍ତୁ"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"ଧାଡ଼ି <xliff:g id="NUMBER_0">%1$s</xliff:g> ସ୍ତମ୍ଭ <xliff:g id="NUMBER_1">%2$s</xliff:g>କୁ ନିଅନ୍ତୁ"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> ସ୍ଥିତିକୁ ନିଅନ୍ତୁ"</string>
@@ -146,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"ବିଜ୍ଞପ୍ତି ଓ ଆପ୍ଗୁଡ଼ିକ ବନ୍ଦ ଅଛି"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ବନ୍ଦ ହୋଇଯାଇଛି"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"ବିଫଳ ହୋଇଛି: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa-rIN/strings.xml
deleted file mode 100644
index c077869..0000000
--- a/res/values-pa-rIN/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"ਦਫ਼ਤਰ"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"ਐਪ ਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤਾ ਹੋਇਆ ਹੈ।"</string>
- <string name="activity_not_available" msgid="7456344436509528827">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"ਡਾਊਨਲੋਡ ਕੀਤਾ ਐਪ ਸੁਰੱਖਿਅਤ ਮੋਡ ਵਿੱਚ ਅਸਮਰਥਿਤ"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"ਵਿਜੇਟ ਸੁਰੱਖਿਅਤ ਮੋਡ ਵਿੱਚ ਅਸਮਰਥਿਤ"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"ਸ਼ਾਰਟਕੱਟ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
- <string name="home_screen" msgid="806512411299847073">"ਹੋਮ ਸਕ੍ਰੀਨ"</string>
- <string name="custom_actions" msgid="3747508247759093328">"ਵਿਉਂਂਤੀ ਕਾਰਵਾਈਆਂ"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"ਇੱਕ ਵਿਜੇਟ ਚੁਣਨ ਲਈ ਛੋਹਵੋT & ਹੋਲਡ ਕਰੋ।"</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ਇੱਕ ਵਿਜੇਟ ਚੁਣਨ ਲਈ ਜਾਂ ਵਿਉਂਂਤੀ ਕਾਰਵਾਈਆਂ ਵਰਤਣ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ਚੌੜਾਈ ਅਤੇ %2$d ਲੰਬਾਈ"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"ਹੱਥੀਂ ਰੱਖਣ ਲਈ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾਈ ਰੱਖੋ"</string>
- <string name="place_automatically" msgid="8064208734425456485">"ਸਵੈਚਲਿਤ ਤਰੀਕੇ ਨਾਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ਐਪਾਂ ਖੋਜੋ"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"ਐਪਾਂ ਨੂੰ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ਨਾਲ ਮੇਲ ਖਾਂਦੀਆਂ ਕੋਈ ਐਪਾਂ ਨਹੀਂ ਮਿਲੀਆਂ"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"ਹੋਰ ਐਪਾਂ ਖੋਜੋ"</string>
- <string name="notifications_header" msgid="1404149926117359025">"ਸੂਚਨਾਵਾਂ"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਸਪੱਰਸ਼ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ।"</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਡਬਲ ਟੈਪ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ ਜਾਂ ਵਿਉਂਤੀਆਂ ਕਾਰਵਾਈਆਂ ਵਰਤੋ।"</string>
- <string name="out_of_space" msgid="4691004494942118364">"ਇਸ ਹੋਮ ਸਕ੍ਰੀਨ ਲਈ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ ਹੈ।"</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"ਮਨਪਸੰਦ ਟ੍ਰੇ ਵਿੱਚ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ।"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"ਐਪ ਸੂਚੀ"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ਨਿੱਜੀ ਐਪਾਂ ਦੀ ਸੂਚੀ"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"ਕਾਰਜ-ਸਥਾਨ ਸੰਬੰਧੀ ਐਪਾਂ ਦੀ ਸੂਚੀ"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"ਹੋਮ"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"ਹਟਾਓ"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ਅਣਸਥਾਪਤ ਕਰੋ"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"ਐਪ ਜਾਣਕਾਰੀ"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"ਸਥਾਪਤ ਕਰੋ"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"ਸ਼ਾਰਟਕੱਟ ਸਥਾਪਤ ਕਰੋ"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"ਇੱਕ ਐਪ ਨੂੰ ਵਰਤੋਂਕਾਰ ਦੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਸ਼ਾਰਟਕੱਟ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"ਹੋਮ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਪੜ੍ਹੋ"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"ਐਪ ਨੂੰ ਹੋਮ ਵਿੱਚ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"ਹੋਮ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਲਿਖੋ"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"ਐਪ ਨੂੰ ਹੋਮ ਵਿੱਚ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ਾਰਟਕੱਟ ਬਦਲਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਫ਼ੋਨ ਕਾਲਾਂ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਹੈ"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"ਵਿਜੇਟ ਲੋਡ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"ਸਥਾਪਤ ਕਰੋ"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"ਇਹ ਇੱਕ ਸਿਸਟਮ ਐਪ ਹੈ ਅਤੇ ਇਸਨੂੰ ਅਣਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"ਬਿਨਾਂ ਨਾਮ ਦਿੱਤਾ ਫੋਲਡਰ"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ਦੀ <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> ਸੂਚਨਾ</item>
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ਦੀਆਂ <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> ਸੂਚਨਾਵਾਂ</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"ਸਫ਼ਾ %2$d ਦਾ %1$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"ਹੋਮ ਸਕ੍ਰੀਨ %2$d ਦੀ %1$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"ਨਵਾਂ ਹੋਮ ਸਕ੍ਰੀਨ ਸਫ਼ਾ"</string>
- <string name="folder_opened" msgid="94695026776264709">"ਫੋਲਡਰ ਖੋਲ੍ਹਿਆ, <xliff:g id="WIDTH">%1$d</xliff:g> ਬਾਇ <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"ਫੋਲਡਰ ਬੰਦ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"ਬਦਲੇ ਗਏ ਨਾਮ ਨੂੰ ਰੱਖਿਅਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="folder_closed" msgid="4100806530910930934">"ਫੋਲਡਰ ਬੰਦ ਕੀਤਾ"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"ਫੋਲਡਰ ਨੂੰ <xliff:g id="NAME">%1$s</xliff:g> ਮੁੜ ਨਾਮ ਦਿੱਤਾ ਗਿਆ"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"ਫੋਲਡਰ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"ਵਿਜੇਟ"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"ਵਾਲਪੇਪਰ"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"ਹੋਮ ਸੈਟਿੰਗਾਂ"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਅਯੋਗ ਬਣਾਈ ਗਈ"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"ਹੋਮ ਸਕ੍ਰੀਨ ਨੂੰ ਘੁੰਮਾਉਣ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"ਜਦੋਂ ਫ਼ੋਨ ਘੁੰਮਾਇਆ ਜਾਂਦਾ ਹੈ"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"ਸੂਚਨਾ ਬਿੰਦੂ"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"ਚਾਲੂ"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"ਬੰਦ"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"ਸੂਚਨਾ ਪਹੁੰਚ ਲੋੜੀਂਦੀ ਹੈ"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"ਸੂਚਨਾ ਬਿੰਦੂਆਂ ਦਿਖਾਉਣ ਲਈ, <xliff:g id="NAME">%1$s</xliff:g> ਲਈ ਐਪ ਸੂਚਨਾਵਾਂ ਚਾਲੂ ਕਰੋ"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"ਸੈਟਿੰਗਾਂ ਬਦਲੋ"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"ਸੂਚਨਾ ਬਿੰਦੂ ਦਿਖਾਓ"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰਤੀਕ ਸ਼ਾਮਲ ਕਰੋ"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ਨਵੀਆਂ ਐਪਾਂ ਲਈ"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"ਪ੍ਰਤੀਕ ਦੀ ਆਕ੍ਰਿਤੀ ਬਦਲੋ"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"ਸਿਸਟਮ ਦੀ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੈਟਿੰਗ ਵਰਤੋ"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"ਵਰਗ"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"ਵਰਗਾਕਾਰ-ਚੱਕਰ"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"ਚੱਕਰ"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"ਹੰਝੂ ਦੀ ਬੂੰਦ"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"ਪ੍ਰਤੀਕ ਦੀ ਆਕ੍ਰਿਤੀ ਵਿੱਚ ਤਬਦੀਲੀਆਂ ਨੂੰ ਲਾਗੂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"ਅਗਿਆਤ"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"ਹਟਾਓ"</string>
- <string name="abandoned_search" msgid="891119232568284442">"ਖੋਜੋ"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"ਇਹ ਐਪ ਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤਾ ਹੋਇਆ ਹੈ।"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ਇਸ ਪ੍ਰਤੀਕ ਲਈ ਐਪ ਸਥਾਪਤ ਨਹੀਂ ਕੀਤਾ ਹੋਇਆ ਹੈ। ਤੁਸੀਂ ਇਸਨੂੰ ਹਟਾ ਸਕਦੇ ਹੋ ਜਾਂ ਐਪ ਖੋਜ ਸਕਦੇ ਹੋ ਅਤੇ ਇਸਨੂੰ ਮੈਨੂਅਲੀ ਸਥਾਪਤ ਕਰ ਸਕਦੇ ਹੋ।"</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ਡਾਉਨਲੋਡ ਹੋਰ ਰਿਹਾ ਹੈ, <xliff:g id="PROGRESS">%2$s</xliff:g> ਸੰਪੂਰਣ"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ਸਥਾਪਤ ਕਰਨ ਦੀ ਉਡੀਕ ਕਰ ਰਿਹਾ ਹੈ"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ਵਿਜੇਟ"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
- <string name="action_move_here" msgid="2170188780612570250">"ਆਈਟਮ ਨੂੰ ਇੱਥੇ ਮੂਵ ਕਰੋ"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"ਆਈਟਮ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਜੋੜਿਆ ਗਿਆ"</string>
- <string name="item_removed" msgid="851119963877842327">"ਅਈਟਮ ਹਟਾਈ ਗਈ"</string>
- <string name="action_move" msgid="4339390619886385032">"ਆਈਟਮ ਨੂੰ ਮੂਵ ਕਰੋ"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"ਕਤਾਰ <xliff:g id="NUMBER_0">%1$s</xliff:g> ਕਾਲਮ <xliff:g id="NUMBER_1">%2$s</xliff:g> ਵਿੱਚ ਮੂਵ ਕਰੋ"</string>
- <string name="move_to_position" msgid="6750008980455459790">"ਸਥਿਤੀ <xliff:g id="NUMBER">%1$s</xliff:g> ਵਿੱਚ ਮੂਵ ਕਰੋ"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"ਮਨਪਸੰਦ ਸਥਿਤੀ <xliff:g id="NUMBER">%1$s</xliff:g> ਵਿੱਚ ਮੂਵ ਕਰੋ"</string>
- <string name="item_moved" msgid="4606538322571412879">"ਆਈਟਮ ਮੂਵ ਕੀਤੀ ਗਈ"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"ਇਸ ਫੋਲਡਰ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> ਦੇ ਨਾਲ ਫੋਲਡਰ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"ਆਈਟਮ ਨੂੰ ਫੋਲਡਰ ਵਿੱਚ ਜੋੜਿਆ ਗਿਆ"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"ਇਸਦੇ ਨਾਲ ਫੋਲਡਰ ਬਣਾਓ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"ਫੋਲਡਰ ਬਣਾਇਆ ਗਿਆ"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਮੂਵ ਕਰੋ"</string>
- <string name="action_resize" msgid="1802976324781771067">"ਮੁੜ ਆਕਾਰ ਦਿਓ"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"ਚੌੜਾਈ ਵਧਾਓ"</string>
- <string name="action_increase_height" msgid="459390020612501122">"ਉਂਚਾਈ ਵਧਾਓ"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"ਚੌੜਾਈ ਘਟਾਓ"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"ਉਂਚਾਈ ਘਟਾਓ"</string>
- <string name="widget_resized" msgid="9130327887929620">"ਵਿਜੈਟ ਨੂੰ ਚੌੜਾਈ <xliff:g id="NUMBER_0">%1$s</xliff:g> ਉਂਚਾਈ <xliff:g id="NUMBER_1">%2$s</xliff:g> ਨੂੰ ਮੁੜ ਆਕਾਰ ਦਿੱਤਾ"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"ਸ਼ਾਰਟਕੱਟ"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਲਈ <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ਸ਼ਾਰਟਕੱਟ"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> ਲਈ <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ਸ਼ਾਰਟਕੱਟ ਅਤੇ <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ਸੂਚਨਾਵਾਂ"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"ਖਾਰਜ ਕਰੋ"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"ਸੂਚਨਾ ਖਾਰਜ ਕੀਤੀ ਗਈ"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"ਨਿੱਜੀ"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"ਕਾਰਜ-ਸਥਾਨ"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ਕਾਰਜ-ਸਥਾਨ ਐਪਾਂ ਇੱਥੇ ਲੱਭੋ"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"ਹਰੇਕ ਕਾਰਜ-ਸਥਾਨ ਐਪ ਦਾ ਇੱਕ ਬੈਜ ਹੁੰਦਾ ਹੈ ਅਤੇ ਉਸਨੂੰ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਸੁਰੱਖਿਅਤ ਰੱਖਿਆ ਜਾਂਦਾ ਹੈ। ਵਧੇਰੇ ਆਸਾਨ ਪਹੁੰਚ ਲਈ ਐਪਾਂ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲਿਜਾਓ।"</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"ਸੂਚਨਾਵਾਂ ਅਤੇ ਐਪਾਂ ਬੰਦ ਹਨ"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ਬੰਦ ਕਰੋ"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
-</resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 3400e7b..a791117 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -108,14 +108,13 @@
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ਡਾਉਨਲੋਡ ਹੋਰ ਰਿਹਾ ਹੈ, <xliff:g id="PROGRESS">%2$s</xliff:g> ਸੰਪੂਰਣ"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ਸਥਾਪਤ ਕਰਨ ਦੀ ਉਡੀਕ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ਵਿਜੇਟ"</string>
- <!-- no translation found for widgets_list (796804551140113767) -->
- <skip />
- <!-- no translation found for widgets_list_closed (6141506579418771922) -->
- <skip />
+ <string name="widgets_list" msgid="796804551140113767">"ਵਿਜੇਟਾਂ ਦੀ ਸੂਚੀ"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"ਵਿਜੇਟਾਂ ਦੀ ਸੂਚੀ ਬੰਦ ਕੀਤੀ ਗਈ"</string>
<string name="action_add_to_workspace" msgid="8902165848117513641">"ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="action_move_here" msgid="2170188780612570250">"ਆਈਟਮ ਨੂੰ ਇੱਥੇ ਮੂਵ ਕਰੋ"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"ਆਈਟਮ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਜੋੜਿਆ ਗਿਆ"</string>
<string name="item_removed" msgid="851119963877842327">"ਅਈਟਮ ਹਟਾਈ ਗਈ"</string>
+ <string name="undo" msgid="4151576204245173321">"ਅਣਕੀਤਾ ਕਰੋ"</string>
<string name="action_move" msgid="4339390619886385032">"ਆਈਟਮ ਨੂੰ ਮੂਵ ਕਰੋ"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"ਕਤਾਰ <xliff:g id="NUMBER_0">%1$s</xliff:g> ਕਾਲਮ <xliff:g id="NUMBER_1">%2$s</xliff:g> ਵਿੱਚ ਮੂਵ ਕਰੋ"</string>
<string name="move_to_position" msgid="6750008980455459790">"ਸਥਿਤੀ <xliff:g id="NUMBER">%1$s</xliff:g> ਵਿੱਚ ਮੂਵ ਕਰੋ"</string>
@@ -146,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"ਸੂਚਨਾਵਾਂ ਅਤੇ ਐਪਾਂ ਬੰਦ ਹਨ"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ਬੰਦ ਕਰੋ"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"ਇਹ ਕਾਰਵਾਈ ਅਸਫਲ ਹੋਈ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 776f39d..6b4796d 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -116,6 +116,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Przenieś element tutaj"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Element został dodany do ekranu głównego"</string>
<string name="item_removed" msgid="851119963877842327">"Element został usunięty"</string>
+ <string name="undo" msgid="4151576204245173321">"Cofnij"</string>
<string name="action_move" msgid="4339390619886385032">"Przenieś element"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Przenieś do wiersza <xliff:g id="NUMBER_0">%1$s</xliff:g> w kolumnie <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Przenieś do pozycji <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -146,4 +147,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Powiadomienia i aplikacje są wyłączone"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zamknij"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zamknięto"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Niepowodzenie: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 4010591..a0d311f 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Mover o item para aqui"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Item adicionado ao ecrã principal"</string>
<string name="item_removed" msgid="851119963877842327">"Item removido"</string>
+ <string name="undo" msgid="4151576204245173321">"Anular"</string>
<string name="action_move" msgid="4339390619886385032">"Mover item"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Mover para a linha <xliff:g id="NUMBER_0">%1$s</xliff:g>, coluna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Mover para a posição <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"As notificações e as aplicações estão desativadas."</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Fechar"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Fechado"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Falhou: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 6238e7a..e640339 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Mover item para cá"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Item adicionado à tela inicial"</string>
<string name="item_removed" msgid="851119963877842327">"Item removido"</string>
+ <string name="undo" msgid="4151576204245173321">"Desfazer"</string>
<string name="action_move" msgid="4339390619886385032">"Mover item"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Mover para a linha <xliff:g id="NUMBER_0">%1$s</xliff:g>, coluna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Mover para a posição <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"As notificações e os apps estão desativados"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Fechar"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Fechado"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Falha: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index fb5fb96..5464929 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -115,6 +115,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Mutați elementul aici"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Element adăugat pe ecranul de pornire"</string>
<string name="item_removed" msgid="851119963877842327">"Element eliminat"</string>
+ <string name="undo" msgid="4151576204245173321">"Anulați"</string>
<string name="action_move" msgid="4339390619886385032">"Mutați elementul"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Mutați pe rândul <xliff:g id="NUMBER_0">%1$s</xliff:g>, coloana <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Mutați pe poziția <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -145,4 +146,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Notificările și aplicațiile sunt dezactivate"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Închideți"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Închis"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Eșuare: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index dd70521..7ba4a47 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -116,6 +116,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Переместить элемент сюда"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Элемент добавлен на главный экран"</string>
<string name="item_removed" msgid="851119963877842327">"Элемент удален"</string>
+ <string name="undo" msgid="4151576204245173321">"Отменить"</string>
<string name="action_move" msgid="4339390619886385032">"Переместить элемент"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Переместить в ячейку <xliff:g id="NUMBER_0">%1$s</xliff:g> <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Переместить в позицию <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -146,4 +147,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Уведомления и приложения отключены."</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Закрыть"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Закрыта"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Не удалось выполнить действие (<xliff:g id="WHAT">%1$s</xliff:g>)."</string>
</resources>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
deleted file mode 100644
index 10835dc..0000000
--- a/res/values-si-rLK/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"කාර්යාලය"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"යෙදුම ස්ථාපනය කර නැත."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"යෙදුම නොතිබේ"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"ආරක්ෂිත ආකාරය තුළ බාගන්න ලද යෙදුම් අබල කරන්න"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"සුරක්ෂිත ආකාරය තුළ විජටය අබල කරන ලදි"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"කෙටි මග ලබා ගත නොහැකිය"</string>
- <string name="home_screen" msgid="806512411299847073">"මුල් පිටු තිරය"</string>
- <string name="custom_actions" msgid="3747508247759093328">"අභිරුචි ක්රියා"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"විජට් එක ස්පර්ශ කර අහුලා ගැනීමට අල්ලාගෙන සිටින්න."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"විජට් එකක් අහුලා ගැනීමට හෝ අභිරුචි ක්රියා කිරීමට ඩබල් ටැප් කර අල්ලා ගෙන සිටින්න."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"පළල %1$d උස %2$d"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"අතින් ස්ථානගත කිරීමට ස්පර්ශ කර අල්ලාගෙන සිටින්න"</string>
- <string name="place_automatically" msgid="8064208734425456485">"ස්වයංක්රියව එක් කරන්න"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"යෙදුම් සොයන්න"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"යෙදුම් පූරණය වෙමින්…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" සමග ගැළපෙන යෙදුම් හමු නොවිණි"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"තව යෙදුම් සඳහා සොයන්න"</string>
- <string name="notifications_header" msgid="1404149926117359025">"දැනුම්දීම්"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"කෙටි මගක් තෝරා ගැනීමට ස්පර්ශ කර අල්ලාගෙන සිටින්න."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"විජට් එකක් තෝරා ගැනීමට හෝ අභිරුචි භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."</string>
- <string name="out_of_space" msgid="4691004494942118364">"මෙම මුල් පිටු තිරය මත තවත් අවසර නැත."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"ප්රියතම දෑ ඇති තැටියේ තවත් ඉඩ නොමැත"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"යෙදුම් ලැයිස්තුව"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"පෞද්ගලික යෙදුම් ලැයිස්තුව"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"වැඩ යෙදුම් ලැයිස්තුව"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"මුල් පිටුව"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"ඉවත් කරන්න"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"අස්ථාපනය කරන්න"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"යෙදුම් තොරතුරු"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"ස්ථාපනය කරන්න"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"කෙටිමං ස්ථාපනය කරන්න"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"පරිශීලක මැදිහත්වීමෙන් තොරව කෙටිමං එක් කිරීමට යෙදුමකට අවසර දෙයි."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"මුල් පිටු සැකසීම් සහ කෙටිමං කියවන්න"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"මුල් පිටුවේ ඇති සැකසීම් සහ කෙටිමං කියවීමට යෙදුමකට අවසර දෙයි."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"මුල් පිටු සැකසීම් සහ කෙටිමං ලියන්න"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"මුල් පිටුවේ සැකසීම් සහ කෙටිමං ඉවත් කිරීමට යෙදුමට අවසර දෙයි."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> හට දුරකථන ඇමතුම් සිදු කිරීමට ඉඩ නොදේ"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"ගැටලු පූරණ විජට් එක"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"ස්ථාපනය කරන්න"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"මෙය පද්ධති යෙදුමක් වන අතර අස්ථාපනය කළ නොහැක."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"නම් නොකළ ෆෝල්ඩරය"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> අබල කෙරිණි"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, දැනුම්දීම් <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g>ක් ඇත</item>
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, දැනුම්දීම් <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g>ක් ඇත</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"%2$d හි %1$d පිටුව"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"මුල් පිටු තිරය %2$d හි %1$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"නව මුල් පිටුව"</string>
- <string name="folder_opened" msgid="94695026776264709">"ෆෝල්ඩරය විවෘත විය, <xliff:g id="WIDTH">%1$d</xliff:g> හි <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"ෆෝල්ඩරය වැසීමට තට්ටු කරන්න"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"යළි නම් කිරීම සුරැකීමට තට්ටු කරන්න"</string>
- <string name="folder_closed" msgid="4100806530910930934">"ෆෝල්ඩරය වසා ඇත"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"<xliff:g id="NAME">%1$s</xliff:g> වෙත ෆෝල්ඩරය නැවත නම් කෙරිණි"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"ෆෝල්ඩරය: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"විජට්"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"වෝල්පේපර"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Home සැකසීම්"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"ඔබගේ පරිපාලක විසින් අබල කරන ලදී"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"මුල් පිටු තිරය කරකැවීමට ඉඩ දෙන්න"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"දුරකථනය කරකවන විට"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"දැනුම්දීම් තිත්"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"ක්රියාත්මකයි"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"ක්රියාවිරහිතයි"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"දැනුම්දීම් ප්රවේශය අවශ්යයි"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"දැනුම්දීම් තිත් පෙන්වීමට, <xliff:g id="NAME">%1$s</xliff:g> සඳහා යෙදුම් දැනුම්දීම් සබල කරන්න"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"සැකසීම් වෙනස් කරන්න"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"දැනුම් දීමේ තිත් පෙන්වන්න"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"මුල් පිටු තිරය වෙත අයිකනය එක් කරන්න"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"නව යෙදුම් සඳහා"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"නිරූපක හැඩය වෙනස් කරන්න"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"මුල් පිටු තිරය මත"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"පද්ධති පෙරනිමි භාවිත කරන්න"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"සමචතුරස්රය"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"හතරැස් කවය"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"කවය"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"කඳුළු බිංදුව"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"නිරූපක හැඩය වෙනස් කිරීම් යොදමින්"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"නොදනී"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"ඉවත් කරන්න"</string>
- <string name="abandoned_search" msgid="891119232568284442">"සොයන්න"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"මෙම යෙදුම ස්ථාපනය කර නොමැත"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"මෙම නිරුපකයට යෙදුම ස්ථාපනය කර නොමැත. ඔබට එය ඉවත් කළ හැක, හෝ යෙදුම් සඳහා සොයන්න සහ අතින් ස්ථාපනය කරන්න."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> බාගත කරමින්, <xliff:g id="PROGRESS">%2$s</xliff:g> සම්පූර්ණයි"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ස්ථාපනය කිරීමට බලා සිටිමින්"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> විජට්"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"මුල් තිරය වෙත එක් කරන්න"</string>
- <string name="action_move_here" msgid="2170188780612570250">"මෙතනට අයිතමය ගෙන එන්න"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"අයිතමය මුල් තිරය වෙත එකතු කරන ලදි"</string>
- <string name="item_removed" msgid="851119963877842327">"අයිතමය ඉවත් කරන ලදි"</string>
- <string name="action_move" msgid="4339390619886385032">"අයිතමය ගෙනයන්න"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"පේළිය <xliff:g id="NUMBER_0">%1$s</xliff:g> තීරුව <xliff:g id="NUMBER_1">%2$s</xliff:g> වෙත ගෙන යන්න"</string>
- <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> ස්ථානය වෙත ගෙන යන්න"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"ප්රියතම ස්ථානය <xliff:g id="NUMBER">%1$s</xliff:g> වෙත ගෙන යන්න"</string>
- <string name="item_moved" msgid="4606538322571412879">"අයිතමය ගෙන යන ලදි"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"ෆෝල්ඩරය එක් කරන්න: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> සමඟ ෆෝල්ඩරය වෙත එක් කරන්න"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"අයිතමය ෆෝඩරය වෙතට එක් කරන ලදි"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"මේ සමග ෆෝල්ඩරය සාදන්න: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"ෆෝල්ඩරය සාදන ලදි"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"මුල් තිරය වෙත ගෙන යන්න"</string>
- <string name="action_resize" msgid="1802976324781771067">"නැවත ප්රමාණගත කිරීම"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"පළල වැඩි කරන්න"</string>
- <string name="action_increase_height" msgid="459390020612501122">"උස වැඩි කරන්න"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"පළල අඩු කරන්න"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"උස අඩු කරන්න"</string>
- <string name="widget_resized" msgid="9130327887929620">"විජට් පළල <xliff:g id="NUMBER_0">%1$s</xliff:g> උස <xliff:g id="NUMBER_1">%2$s</xliff:g> වෙත ප්රමාණකරණය කරන ලදි"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"කෙටිමං"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> සඳහා කෙටි මං <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> සඳහා කෙටි මං <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>ක් සහ දැනුම්දීම් <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>ක්"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"ඉවතලන්න"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"දැනුම්දීම ඉවතලන ලදී"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"පුද්ගලික"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"කාර්යාලය"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"කාර්යාල පැතිකඩ"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"මෙහි කාර්යාල යෙදුම් සොයා ගන්න"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"සෑම කාර්යාල යෙදුමකම ලාංඡනයක් ඇත ඇති අතර එය ඔබේ සංවිධානය මගින් සුරක්ෂිතව තබා ගනී. වඩාත් පහසු ප්රවේශයකට යෙදුම් ඔබේ මුල් පිටු තිරය වෙත ගෙන යන්න."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"ඔබේ සංවිධානය විසින් කළමනාකරණය කරනු ලැබේ"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"දැනුම්දීම් සහ යෙදුම් ක්රියාවිරහිතයි"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"වසන්න"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"වසා ඇත"</string>
-</resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index ee61124..83eaff0 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"මෙතනට අයිතමය ගෙන එන්න"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"අයිතමය මුල් තිරය වෙත එකතු කරන ලදි"</string>
<string name="item_removed" msgid="851119963877842327">"අයිතමය ඉවත් කරන ලදි"</string>
+ <string name="undo" msgid="4151576204245173321">"අස් කරන්න"</string>
<string name="action_move" msgid="4339390619886385032">"අයිතමය ගෙනයන්න"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"පේළිය <xliff:g id="NUMBER_0">%1$s</xliff:g> තීරුව <xliff:g id="NUMBER_1">%2$s</xliff:g> වෙත ගෙන යන්න"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> ස්ථානය වෙත ගෙන යන්න"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"දැනුම්දීම් සහ යෙදුම් ක්රියාවිරහිතයි"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"වසන්න"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"වසා ඇත"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"අසාර්ථකයි: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 649aecc8..c983fe1 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -116,6 +116,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Presunúť položku sem"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Položka bola pridaná na plochu"</string>
<string name="item_removed" msgid="851119963877842327">"Položka bola odstránená"</string>
+ <string name="undo" msgid="4151576204245173321">"Späť"</string>
<string name="action_move" msgid="4339390619886385032">"Presunúť položku"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Presunúť do stĺpca <xliff:g id="NUMBER_1">%2$s</xliff:g> v riadku <xliff:g id="NUMBER_0">%1$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Presunúť na <xliff:g id="NUMBER">%1$s</xliff:g>. miesto"</string>
@@ -146,4 +147,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Upozornenia a aplikácie sú vypnuté"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zavrieť"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zavreté"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Zlyhalo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index aa3bc4f..a037c41 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -116,6 +116,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Premik elementa sem"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Element je bil dodan na začetni zaslon"</string>
<string name="item_removed" msgid="851119963877842327">"Element je bil odstranjen"</string>
+ <string name="undo" msgid="4151576204245173321">"Razveljavi"</string>
<string name="action_move" msgid="4339390619886385032">"Premik elementa"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Premik v <xliff:g id="NUMBER_0">%1$s</xliff:g>. vrstico <xliff:g id="NUMBER_1">%2$s</xliff:g>. stolpca"</string>
<string name="move_to_position" msgid="6750008980455459790">"Premk na mesto št. <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -146,4 +147,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Obvestila in aplikacije – izklopljeno"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zapri"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zaprto"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Ni uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-sq-rAL/strings.xml b/res/values-sq-rAL/strings.xml
deleted file mode 100644
index 82cc42a..0000000
--- a/res/values-sq-rAL/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Nisësi3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Puna"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Aplikacioni nuk është i instaluar."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Aplikacioni nuk mundësohet"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplikacioni i shkarkuar është i çaktivizuar në modalitetin e sigurt"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Miniaplikacionet janë të çaktivizuara në modalitetin e sigurt"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Shkurtorja nuk është e disponueshme"</string>
- <string name="home_screen" msgid="806512411299847073">"Ekrani bazë"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Veprimet e personalizuara"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Prek dhe mbaj shtypur për të zgjedhur një miniaplikacion."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Prek dy herë dhe mbaj shtypur për të zgjedhur një miniaplikacion ose për të përdorur veprimet e personalizuara."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d i gjerë me %2$d i lartë"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Prek dhe mbaj të shtypur për të vendosur në mënyrë manuale"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Shto automatikisht"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Kërko për aplikacione"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Po ngarkon aplikacionet..."</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nuk u gjet asnjë aplikacion që përputhet me \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Kërko për më shumë aplikacione"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Njoftimet"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Prek dhe mbaj prekur për të zgjedhur një shkurtore."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Prek dy herë dhe mbaj prekur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara."</string>
- <string name="out_of_space" msgid="4691004494942118364">"Nuk ka më hapësirë në këtë ekran bazë."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nuk ka më hapësirë në tabakanë \"Të preferuarat\""</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Lista e aplikacioneve"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista e aplikacioneve personale"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista e aplikacioneve të punës"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Faqja kryesore"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Hiqe"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Çinstalo"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Informacion mbi aplikacionin"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"Instalo"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalo shkurtore"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Lejon një aplikacion të shtojë shkurtore pa ndërhyrjen e përdoruesit."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"lexo cilësimet dhe shkurtoret e ekranit bazë"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Lejon aplikacionin të lexojë cilësimet dhe shkurtoret në ekranin bazë."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"shkruaj cilësimet dhe shkurtoret e ekranit bazë"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Lejon aplikacionin të ndryshojë cilësimet dhe shkurtoret në ekranin bazë."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk lejohet të kryejë telefonata"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Problem në ngarkimin e miniaplikacionit"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Konfiguro"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ky është aplikacion sistemi dhe nuk mund të çinstalohet."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Dosje e paemërtuar"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> u çaktivizua"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ka <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> njoftime</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, ka <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> njoftime</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"Faqja: %1$d nga gjithsej %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"Ekrani bazë: %1$d nga gjithsej %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Faqja e ekranit të ri kryesor"</string>
- <string name="folder_opened" msgid="94695026776264709">"Dosja u hap, <xliff:g id="WIDTH">%1$d</xliff:g> me <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Trokit për të mbyllur dosjen"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"Trokit për të ruajtur riemërtimin"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Dosja u mbyll"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Dosja u riemërtua në <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Dosja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Miniaplikacionet"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Imazhet e sfondit"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Cilësimet e Home"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Çaktivizuar nga administratori"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Lejo rrotullimin e ekranit kryesor"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Kur telefoni rrotullohet"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Pikat e njoftimeve"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aktiv"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Joaktiv"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Nevojitet qasja në njoftime"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Për të shfaqur \"Pikat e njoftimeve\", aktivizo njoftimet e aplikacionit për <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Ndrysho cilësimet"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Shfaq pikat e njoftimeve"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Shto ikonë në ekranin bazë"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Për aplikacionet e reja"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Ndrysho formën e ikonës"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"në ekranin bazë"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Përdor parazgjedhjen e sistemit"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Katror"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Katror me kënde të rrumbullakëta"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Rreth"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Pikë loti"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Po zbatohen ndryshimet e formës së ikonës"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"I panjohur"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"Hiq"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Kërko"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Aplikacioni nuk është i instaluar"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikacioni për këtë ikonë nuk është i instaluar. Mund ta heqësh ose të kërkosh aplikacionin dhe ta instalosh atë në mënyrë manuale."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> po shkarkohet, <xliff:g id="PROGRESS">%2$s</xliff:g> të përfunduara"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> po pret të instalohet"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Miniaplikacionet e <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Shto në Ekranin bazë"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Zhvendose artikullin këtu"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Artikulli u shtua tek ekrani bazë"</string>
- <string name="item_removed" msgid="851119963877842327">"Artikulli u hoq"</string>
- <string name="action_move" msgid="4339390619886385032">"Zhvendose artikullin"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"Zhvendos te rreshti <xliff:g id="NUMBER_0">%1$s</xliff:g>, kolona <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="move_to_position" msgid="6750008980455459790">"Zhvendos te pozicioni <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Zhvendos te pozicioni <xliff:g id="NUMBER">%1$s</xliff:g> i preferencave"</string>
- <string name="item_moved" msgid="4606538322571412879">"Artikulli u zhvendos"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"Shto te dosja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"Shto te dosja me <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Artikulli u shtua te dosja"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"Krijo një dosje me: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"Dosja u krijua"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Zhvendose në Ekranin bazë"</string>
- <string name="action_resize" msgid="1802976324781771067">"Ndrysho madhësinë"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Rrit gjerësinë"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Rrit lartësinë"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Zvogëlo gjerësinë"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Zvogëlo lartësinë"</string>
- <string name="widget_resized" msgid="9130327887929620">"Madhësia e miniaplikacionit u ndryshua me gjerësinë <xliff:g id="NUMBER_0">%1$s</xliff:g> dhe lartësinë <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Shkurtoret"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> shkurtesa për <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> shkurtore dhe <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> njoftime për <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Hiqe"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Njoftimi u hoq"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personale"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Punë"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profili i punës"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Gjej këtu aplikacionet e punës"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Secili aplikacion pune ka një distinktiv dhe mbahet i sigurt nga organizata jote. Zhvendosi aplikacionet e punës në ekranin tënd kryesor për qasje më të lehtë."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Menaxhohet nga organizata jote"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Njoftimet dhe aplikacionet janë joaktive"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Mbyll"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Mbyllur"</string>
-</resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 8cf0a81..c26b7a5 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Zhvendose artikullin këtu"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Artikulli u shtua tek ekrani bazë"</string>
<string name="item_removed" msgid="851119963877842327">"Artikulli u hoq"</string>
+ <string name="undo" msgid="4151576204245173321">"Zhbëj"</string>
<string name="action_move" msgid="4339390619886385032">"Zhvendose artikullin"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Zhvendos te rreshti <xliff:g id="NUMBER_0">%1$s</xliff:g>, kolona <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Zhvendos te pozicioni <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Njoftimet dhe aplikacionet janë joaktive"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Mbyll"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Mbyllur"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Dështoi: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 42522a5..38f9c9d 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -115,6 +115,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Премести ставку овде"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Ставка је додата на почетни екран"</string>
<string name="item_removed" msgid="851119963877842327">"Ставка је уклоњена"</string>
+ <string name="undo" msgid="4151576204245173321">"Опозови"</string>
<string name="action_move" msgid="4339390619886385032">"Премести ставку"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Премести у ред <xliff:g id="NUMBER_0">%1$s</xliff:g> и колону <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Премести на <xliff:g id="NUMBER">%1$s</xliff:g>. позицију"</string>
@@ -145,4 +146,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Обавештења и апликације су искључени"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Затвори"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Затворено"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Није успело: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 957a4cb..7ef24dc 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Flytta objekt hit"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Objektet har lagts till på startskärmen"</string>
<string name="item_removed" msgid="851119963877842327">"Objektet har tagits bort"</string>
+ <string name="undo" msgid="4151576204245173321">"Ångra"</string>
<string name="action_move" msgid="4339390619886385032">"Flytta objekt"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Flytta till rad <xliff:g id="NUMBER_0">%1$s</xliff:g>, kolumn <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Flytta till plats <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Aviseringar och appar är inaktiverade"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Stäng"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Stängd"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Misslyckades: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index faa40a7..875f9a4 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -116,6 +116,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Hamishia kipengee hapa"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Kipengee kimeongezwa kwenye skrini ya kwanza"</string>
<string name="item_removed" msgid="851119963877842327">"Kipengee kimeondolewa"</string>
+ <string name="undo" msgid="4151576204245173321">"Tendua"</string>
<string name="action_move" msgid="4339390619886385032">"Hamisha kipengee"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Hamishia safu mlalo <xliff:g id="NUMBER_0">%1$s</xliff:g> safu wima <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Hamishia nafasi ya <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -146,4 +147,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Vipenge vya arifa na programu vimezimwa"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Funga"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Imefungwa"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Hitilafu: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index b211207..691219a 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -16,7 +16,6 @@
<resources>
<!-- All Apps -->
- <dimen name="all_apps_button_scale_down">8dp</dimen>
<dimen name="all_apps_empty_search_message_top_offset">64dp</dimen>
<dimen name="all_apps_empty_search_bg_top_offset">180dp</dimen>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
deleted file mode 100644
index a51247c..0000000
--- a/res/values-ta-rIN/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"பணியிடம்"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"பயன்பாடு நிறுவப்படவில்லை."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"பயன்பாடு இல்லை"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"இறக்கிய பயன்பாடு பாதுகாப்பு முறையில் முடக்கப்பட்டது"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"பாதுகாப்புப் பயன்முறையில் விட்ஜெட்கள் முடக்கப்பட்டுள்ளன"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"குறுக்குவழி இல்லை"</string>
- <string name="home_screen" msgid="806512411299847073">"முகப்புத் திரை"</string>
- <string name="custom_actions" msgid="3747508247759093328">"தனிப்பயன் செயல்கள்"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"விட்ஜெட்டைத் தேர்வுசெய்ய தொட்டுப் பிடிக்கவும்."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"விட்ஜெட்டைத் தேர்ந்தெடுக்க இருமுறை தட்டிப் பிடிக்கவும் அல்லது தனிப்பயன் செயல்களைப் பயன்படுத்தவும்."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d அகலத்திற்கு %2$d உயரம்"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"நீங்களே சேர்க்க, தொட்டுப் பிடித்திருக்கவும்"</string>
- <string name="place_automatically" msgid="8064208734425456485">"தானாகவே சேர்"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"பயன்பாடுகளில் தேடுக"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"பயன்பாடுகளை ஏற்றுகிறது…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" உடன் பொருந்தும் பயன்பாடுகள் இல்லை"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"கூடுதல் பயன்பாடுகளைத் தேடு"</string>
- <string name="notifications_header" msgid="1404149926117359025">"அறிவிப்புகள்"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ஷார்ட்கட்டைச் சேர்க்க, தொட்டு பிடித்திருக்கவும்."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ஷார்ட்கட்டைச் சேர்க்க, இருமுறை தட்டிப் பிடித்திருக்கவும் (அ) தனிப்பயன் செயல்களைப் பயன்படுத்தவும்."</string>
- <string name="out_of_space" msgid="4691004494942118364">"முகப்புத் திரையில் இடமில்லை."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"பிடித்தவை ட்ரேயில் இடமில்லை"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"பயன்பாடுகளின் பட்டியல்"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"தனிப்பட்ட ஆப்ஸ் பட்டியல்"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"பணி ஆப்ஸ் பட்டியல்"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"முகப்பு"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"அகற்று"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"நிறுவல் நீக்கு"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"பயன்பாட்டுத் தகவல்"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"நிறுவு"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"குறுக்குவழிகளை நிறுவுதல்"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"பயனரின் அனுமதி இல்லாமல் குறுக்குவழிகளைச் சேர்க்கப் பயன்பாட்டை அனுமதிக்கிறது."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"முகப்பின் அமைப்பு மற்றும் குறுக்குவழிகளைப் படித்தல்"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"முகப்பில் உள்ள அமைப்பு மற்றும் குறுக்குவழிகளைப் படிக்க பயன்பாட்டை அனுமதிக்கிறது."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"முகப்பின் அமைப்பு மற்றும் குறுக்குவழிகளை எழுதுதல்"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"முகப்பில் உள்ள அமைப்பு மற்றும் குறுக்குவழிகளை மாற்ற பயன்பாட்டை அனுமதிக்கிறது."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"ஃபோன் அழைப்புகள் செய்ய, <xliff:g id="APP_NAME">%1$s</xliff:g> அனுமதிக்கப்படவில்லை"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"விட்ஜெட்டை ஏற்றுவதில் சிக்கல்"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"அமைவு"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"இது அமைப்பு பயன்பாடு என்பதால் நிறுவல் நீக்கம் செய்ய முடியாது."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"பெயரிடப்படாத கோப்புறை"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> முடக்கப்பட்டது"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> பயன்பாட்டில், <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> அறிவிப்புகள் வந்துள்ளன</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> பயன்பாட்டில், <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> அறிவிப்பு வந்துள்ளது</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"பக்கம் %1$d / %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"முகப்புத் திரை %1$d of %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"புதிய முகப்புத் திரை பக்கம்"</string>
- <string name="folder_opened" msgid="94695026776264709">"திறக்கப்பட்டக் கோப்புறை, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"கோப்புறையை மூட, தட்டவும்"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"மாற்றிய பெயரைச் சேமிக்க, தட்டவும்"</string>
- <string name="folder_closed" msgid="4100806530910930934">"கோப்புறை மூடப்பட்டது"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"கோப்புறை <xliff:g id="NAME">%1$s</xliff:g> என மறுபெயரிடப்பட்டது"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"கோப்புறை: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"ஷார்ட்கட்ஸ்"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"வால்பேப்பர்கள்"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"முகப்பு அமைப்புகள்"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"உங்கள் நிர்வாகி முடக்கியுள்ளார்"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"முகப்புத் திரை சுழற்சியை அனுமதி"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"மொபைலைச் சுழற்றும் போது"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"அறிவிப்புப் புள்ளிகள்"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"ஆன்"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"முடக்கப்பட்டுள்ளது"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"அறிவிப்பிற்கான அணுகல் தேவை"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"அறிவிப்புப் புள்ளிகளைக் காட்ட, <xliff:g id="NAME">%1$s</xliff:g> இன் பயன்பாட்டு அறிவிப்புகளை இயக்கவும்"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"அமைப்புகளை மாற்று"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"அறிவிப்புப் புள்ளிகளைக் காட்டு"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"முகப்புத் திரையில் ஐகானைச் சேர்"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"புதிய பயன்பாடுகளுக்கு"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"ஐகான் வடிவத்தை மாற்று"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"முகப்புத் திரையில்"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"அமைப்பின் இயல்புநிலையைப் பயன்படுத்து"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"சதுரம்"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"சதுரவட்டம்"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"வட்டம்"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"கண்ணீர்துளி"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"ஐகான் வடிவத்தை மாற்றுகிறது"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"தெரியாதது"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"அகற்று"</string>
- <string name="abandoned_search" msgid="891119232568284442">"தேடு"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"பயன்பாடு நிறுவப்படவில்லை"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ஐகானுக்கான பயன்பாடு நிறுவப்படவில்லை. இதை அகற்றலாம் அல்லது பயன்பாட்டைத் தேடி கைமுறையாக நிறுவலாம்."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>ஐப் பதிவிறக்குகிறது, <xliff:g id="PROGRESS">%2$s</xliff:g> முடிந்தது"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>ஐ நிறுவுவதற்காகக் காத்திருக்கிறது"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> விட்ஜெட்டுகள்"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"முகப்புத் திரையில் சேர்"</string>
- <string name="action_move_here" msgid="2170188780612570250">"இங்கு நகர்த்து"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"முகப்புத் திரையில் சேர்க்கப்பட்டது"</string>
- <string name="item_removed" msgid="851119963877842327">"அகற்றப்பட்டது"</string>
- <string name="action_move" msgid="4339390619886385032">"நகர்த்து"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> வரிசை, <xliff:g id="NUMBER_1">%2$s</xliff:g> நெடுவரிசைக்கு நகர்த்து"</string>
- <string name="move_to_position" msgid="6750008980455459790">"நிலை <xliff:g id="NUMBER">%1$s</xliff:g>க்கு நகர்த்து"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"விரும்பும் நிலை <xliff:g id="NUMBER">%1$s</xliff:g>க்கு நகர்த்து"</string>
- <string name="item_moved" msgid="4606538322571412879">"உருப்படி நகர்த்தப்பட்டது"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"இந்தக் கோப்புறையில் சேர்க்கும்: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> உள்ள கோப்புறையில் சேர்க்கும்"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"கோப்புறையில் உருப்படி சேர்க்கப்பட்டது"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"இதனுடன் கோப்புறையை உருவாக்கும்: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"கோப்புறை உருவாக்கப்பட்டது"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"முகப்புத் திரைக்கு நகர்த்து"</string>
- <string name="action_resize" msgid="1802976324781771067">"அளவு மாற்று"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"அகலத்தை அதிகரி"</string>
- <string name="action_increase_height" msgid="459390020612501122">"உயரத்தை அதிகரி"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"அகலத்தைக் குறை"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"உயரத்தைக் குறை"</string>
- <string name="widget_resized" msgid="9130327887929620">"அகலம் <xliff:g id="NUMBER_0">%1$s</xliff:g> மற்றும் உயரம் <xliff:g id="NUMBER_1">%2$s</xliff:g>க்கு விட்ஜெட் அளவு மாற்றப்பட்டது"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"குறுக்குவழிகள்"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g>க்கான <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> குறுக்குவழிகள்"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> பயன்பாட்டிற்கான <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> குறுக்குவழிகளும் <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> அறிவிப்புகளும் உள்ளன"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"நிராகரி"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"அறிவிப்பு நிராகரிக்கப்பட்டது"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"தனிப்பட்டவை"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"பணி"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"பணி விவரம்"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"பணி ஆப்ஸை இங்கு காணலாம்"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"ஒவ்வொரு பணிப் பயன்பாடும் ஒரு பேட்ஜைக் கொண்டிருக்கும். இவை, ஆப்ஸ் உங்கள் நிறுவனத்தால் பாதுகாப்பாக வைக்கப்பட்டுள்ளன என்பதைக் குறிக்கின்றன. இந்த ஆப்ஸை எளிதாக அணுக, முகப்புத் திரைக்கு நகர்த்திக்கொள்ளவும்."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"உங்கள் நிறுவனம் நிர்வகிக்கிறது"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"ஆப்ஸும் அறிவிப்புகளும் ஆஃப் செய்யப்பட்டுள்ளன"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"மூடுக"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"மூடப்பட்டது"</string>
-</resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 983a0d1..805b254 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -108,14 +108,13 @@
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>ஐப் பதிவிறக்குகிறது, <xliff:g id="PROGRESS">%2$s</xliff:g> முடிந்தது"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>ஐ நிறுவுவதற்காகக் காத்திருக்கிறது"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> விட்ஜெட்டுகள்"</string>
- <!-- no translation found for widgets_list (796804551140113767) -->
- <skip />
- <!-- no translation found for widgets_list_closed (6141506579418771922) -->
- <skip />
+ <string name="widgets_list" msgid="796804551140113767">"விட்ஜெட்கள் பட்டியல்"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"விட்ஜெட்கள் பட்டியல் மூடப்பட்டது"</string>
<string name="action_add_to_workspace" msgid="8902165848117513641">"முகப்புத் திரையில் சேர்"</string>
<string name="action_move_here" msgid="2170188780612570250">"இங்கு நகர்த்து"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"முகப்புத் திரையில் சேர்க்கப்பட்டது"</string>
<string name="item_removed" msgid="851119963877842327">"அகற்றப்பட்டது"</string>
+ <string name="undo" msgid="4151576204245173321">"செயல்தவிர்"</string>
<string name="action_move" msgid="4339390619886385032">"நகர்த்து"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> வரிசை, <xliff:g id="NUMBER_1">%2$s</xliff:g> நெடுவரிசைக்கு நகர்த்து"</string>
<string name="move_to_position" msgid="6750008980455459790">"நிலை <xliff:g id="NUMBER">%1$s</xliff:g>க்கு நகர்த்து"</string>
@@ -146,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"ஆப்ஸும் அறிவிப்புகளும் ஆஃப் செய்யப்பட்டுள்ளன"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"மூடுக"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"மூடப்பட்டது"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"தோல்வி: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
deleted file mode 100644
index bffb1a8..0000000
--- a/res/values-te-rIN/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"కార్యాలయం"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"యాప్ ఇన్స్టాల్ చేయబడలేదు."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"యాప్ అందుబాటులో లేదు"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"డౌన్లోడ్ చేసిన యాప్ సురక్షిత మోడ్లో నిలిపివేయబడింది"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"సురక్షిత మోడ్లో విడ్జెట్లు నిలిపివేయబడ్డాయి"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"షార్ట్కట్ అందుబాటులో లేదు"</string>
- <string name="home_screen" msgid="806512411299847073">"హోమ్ స్క్రీన్"</string>
- <string name="custom_actions" msgid="3747508247759093328">"అనుకూల చర్యలు"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"విడ్జెట్ను ఎంచుకోవడానికి తాకి & నొక్కి పెట్టండి."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"విడ్జెట్ను ఎంచుకోవడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కి, ఉంచండి."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d వెడల్పు X %2$d ఎత్తు"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"మాన్యువల్గా ఉంచడానికి నొక్కి &amp పట్టుకోండి"</string>
- <string name="place_automatically" msgid="8064208734425456485">"స్వయంచాలకంగా జోడించు"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"అప్లికేషన్లను శోధించండి"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"అప్లికేషన్లను లోడ్ చేస్తోంది…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"కి సరిపోలే అప్లికేషన్లేవీ కనుగొనబడలేదు"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"మరిన్ని యాప్ల కోసం వెతుకు"</string>
- <string name="notifications_header" msgid="1404149926117359025">"నోటిఫికేషన్లు"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"షార్ట్కట్ని ఎంచుకోవడం కోసం నొక్కి, పట్టుకోండి."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"రెండుసార్లు నొక్కి, పట్టుకోవడం ద్వారా షార్ట్కట్ని ఎంచుకోండి లేదా అనుకూల చర్యలను ఉపయోగించండి."</string>
- <string name="out_of_space" msgid="4691004494942118364">"ఈ హోమ్ స్క్రీన్లో ఖాళీ లేదు."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"ఇష్టమైనవి ట్రేలో ఖాళీ లేదు"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"అనువర్తనాల జాబితా"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"వ్యక్తిగత యాప్ల జాబితా"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"కార్యాలయ యాప్ల జాబితా"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"హోమ్"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"తీసివేయి"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"అన్ఇన్స్టాల్ చేయి"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"యాప్ సమాచారం"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"ఇన్స్టాల్ చేయండి"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"సత్వరమార్గాలను ఇన్స్టాల్ చేయడం"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"వినియోగదారు ప్రమేయం లేకుండా సత్వరమార్గాలను జోడించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"హోమ్ సెట్టింగ్లు మరియు సత్వరమార్గాలను చదవడం"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"హోమ్లో సెట్టింగ్లు మరియు సత్వరమార్గాలను చదవడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"హోమ్ సెట్టింగ్లు మరియు సత్వరమార్గాలను వ్రాయడం"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"హోమ్లో సెట్టింగ్లు మరియు సత్వరమార్గాలను మార్చడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"ఫోన్ కాల్లను చేసేందుకు <xliff:g id="APP_NAME">%1$s</xliff:g>కి అనుమతి లేదు"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"విడ్జెట్ను లోడ్ చేయడంలో సమస్య"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"సెటప్ చేయి"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"ఇది సిస్టమ్ యాప్ మరియు దీన్ని అన్ఇన్స్టాల్ చేయడం సాధ్యపడదు."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"పేరు లేని ఫోల్డర్"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> నిలిపివేయబడింది"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> నోటిఫికేషన్లను కలిగి ఉన్నారు</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> నోటిఫికేషన్ను కలిగి ఉన్నారు</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"%2$dలో %1$dవ పేజీ"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$dలో %1$dవ హోమ్ స్క్రీన్"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"కొత్త హోమ్ స్క్రీన్ పేజీ"</string>
- <string name="folder_opened" msgid="94695026776264709">"ఫోల్డర్ తెరవబడింది, <xliff:g id="WIDTH">%1$d</xliff:g> X <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"ఫోల్డర్ను మూసివేయడానికి నొక్కండి"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"పేరు మార్పును సేవ్ చేయడానికి నొక్కండి"</string>
- <string name="folder_closed" msgid="4100806530910930934">"ఫోల్డర్ మూసివేయబడింది"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"ఫోల్డర్ పేరు <xliff:g id="NAME">%1$s</xliff:g>గా మార్చబడింది"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"ఫోల్డర్: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"విడ్జెట్లు"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"వాల్పేపర్లు"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"హోమ్ సెట్టింగ్లు"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"మీ నిర్వాహకులు నిలిపివేసారు"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"హోమ్ స్క్రీన్ భ్రమణాన్ని అనుమతించండి"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"ఫోన్ను తిప్పినప్పుడు"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"నోటిఫికేషన్ డాట్లు"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"ఆన్"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"ఆఫ్"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"నోటిఫికేషన్ యాక్సెస్ అవసరం"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"నోటిఫికేషన్ డాట్లను చూపించడానికి <xliff:g id="NAME">%1$s</xliff:g>కు యాప్ నోటిఫికేషన్లను ఆన్ చేయండి"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"సెట్టింగ్లను మార్చు"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"నోటిఫికేషన్ డాట్లను చూపుతుంది"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"హోమ్ స్క్రీన్కి చిహ్నాన్ని జోడించు"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"కొత్త యాప్ల కోసం"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"చిహ్న ఆకారాన్ని మార్చు"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"హోమ్ స్క్రీన్పై"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"సిస్టమ్ డిఫాల్ట్ను ఉపయోగించండి"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"చతురస్రం"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"చతురస్రాకార వృత్తం"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"వృత్తం"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"కన్నీటి చుక్క"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"చిహ్న ఆకార మార్పులను వర్తింపజేస్తోంది"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"తెలియదు"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"తీసివేయి"</string>
- <string name="abandoned_search" msgid="891119232568284442">"వెతుకు"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"ఈ యాప్ ఇన్స్టాల్ చేయబడలేదు"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ఈ చిహ్నం యొక్క యాప్ ఇన్స్టాల్ చేయబడలేదు. మీరు దీన్ని తీసివేయవచ్చు లేదా ఆ యాప్ కోసం శోధించి దాన్ని మాన్యువల్గా ఇన్స్టాల్ చేయవచ్చు."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> డౌన్లోడ్ అవుతోంది, <xliff:g id="PROGRESS">%2$s</xliff:g> పూర్తయింది"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ఇన్స్టాల్ కావడానికి వేచి ఉంది"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> విడ్జెట్లు"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"హోమ్ స్క్రీన్కు జోడించు"</string>
- <string name="action_move_here" msgid="2170188780612570250">"అంశాన్ని ఇక్కడికి తరలించు"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"అంశం హోమ్స్క్రీన్కి జోడించబడింది"</string>
- <string name="item_removed" msgid="851119963877842327">"అంశం తీసివేయబడింది"</string>
- <string name="action_move" msgid="4339390619886385032">"అంశాన్ని తరలించు"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"అడ్డు వరుస <xliff:g id="NUMBER_0">%1$s</xliff:g> నిలువు వరుస <xliff:g id="NUMBER_1">%2$s</xliff:g>కి తరలించు"</string>
- <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>వ స్థానానికి తరలించు"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"ఇష్టమైనవిలో <xliff:g id="NUMBER">%1$s</xliff:g>వ స్థానానికి తరలించు"</string>
- <string name="item_moved" msgid="4606538322571412879">"అంశం తరలించబడింది"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"ఈ ఫోల్డర్కి జోడించండి: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> గల ఫోల్డర్కు జోడించు"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"అంశం ఫోల్డర్కు జోడించబడింది"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"ఈ పేరుతో ఫోల్డర్ను సృష్టించండి: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"ఫోల్డర్ సృష్టించబడింది"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"హోమ్స్క్రీన్కు తరలించు"</string>
- <string name="action_resize" msgid="1802976324781771067">"పరిమాణం మార్చు"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"వెడల్పును పెంచు"</string>
- <string name="action_increase_height" msgid="459390020612501122">"ఎత్తును పెంచు"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"వెడల్పును తగ్గించు"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"ఎత్తును తగ్గించు"</string>
- <string name="widget_resized" msgid="9130327887929620">"విడ్జెట్ పరిమాణం వెడల్పు <xliff:g id="NUMBER_0">%1$s</xliff:g>కి, ఎత్తు <xliff:g id="NUMBER_1">%2$s</xliff:g>కి మార్చబడింది"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"సత్వరమార్గాలు"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> కోసం <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> సత్వరమార్గాలు"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> కోసం <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> సత్వరమార్గాలు మరియు <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> నోటిఫికేషన్లు"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"తీసివేయి"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"నోటిఫికేషన్ తీసివేయబడింది"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"వ్యక్తిగతం"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"కార్యాలయం"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"కార్యాలయ ప్రొఫైల్"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"కార్యాలయ యాప్లను ఇక్కడ కనుగొనండి"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"ప్రతి కార్యాలయ యాప్కు బ్యాడ్జ్ ఉంది మరియు మీ సంస్థ ద్వారా సురక్షితంగా ఉంచబడుతుంది. సులభ యాక్సెస్ కోసం యాప్లను మీ హోమ్ స్క్రీన్కి తరలించండి."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"మీ సంస్థ ద్వారా నిర్వహించబడతాయి"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"నోటిఫికేషన్లు మరియు యాప్లు ఆఫ్ చేయబడ్డాయి"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"మూసివేయి"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"మూసివేయబడింది"</string>
-</resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index a18d649..67c3a7f 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -108,14 +108,13 @@
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> డౌన్లోడ్ అవుతోంది, <xliff:g id="PROGRESS">%2$s</xliff:g> పూర్తయింది"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ఇన్స్టాల్ కావడానికి వేచి ఉంది"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> విడ్జెట్లు"</string>
- <!-- no translation found for widgets_list (796804551140113767) -->
- <skip />
- <!-- no translation found for widgets_list_closed (6141506579418771922) -->
- <skip />
+ <string name="widgets_list" msgid="796804551140113767">"విడ్జెట్ల జాబితా"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"విడ్జెట్ల జాబితా మూసివేయబడింది"</string>
<string name="action_add_to_workspace" msgid="8902165848117513641">"హోమ్ స్క్రీన్కు జోడించు"</string>
<string name="action_move_here" msgid="2170188780612570250">"అంశాన్ని ఇక్కడికి తరలించు"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"అంశం హోమ్స్క్రీన్కి జోడించబడింది"</string>
<string name="item_removed" msgid="851119963877842327">"అంశం తీసివేయబడింది"</string>
+ <string name="undo" msgid="4151576204245173321">"చర్య రద్దు"</string>
<string name="action_move" msgid="4339390619886385032">"అంశాన్ని తరలించు"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"అడ్డు వరుస <xliff:g id="NUMBER_0">%1$s</xliff:g> నిలువు వరుస <xliff:g id="NUMBER_1">%2$s</xliff:g>కి తరలించు"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>వ స్థానానికి తరలించు"</string>
@@ -146,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"నోటిఫికేషన్లు మరియు యాప్లు ఆఫ్ చేయబడ్డాయి"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"మూసివేయి"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"మూసివేయబడింది"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"విఫలమైంది: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 2da32de..cbf22a6 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"ย้ายรายการมาที่นี่"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"เพิ่มรายการไปยังหน้าจอหลักแล้ว"</string>
<string name="item_removed" msgid="851119963877842327">"นำออกรายการออกแล้ว"</string>
+ <string name="undo" msgid="4151576204245173321">"เลิกทำ"</string>
<string name="action_move" msgid="4339390619886385032">"ย้ายรายการ"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"ย้ายไปที่แถว <xliff:g id="NUMBER_0">%1$s</xliff:g> คอลัมน์ <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"ย้ายไปยังตำแหน่ง <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"ปิดการแจ้งเตือนและแอปอยู่"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ปิด"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ปิด"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"ไม่สำเร็จ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 68d5259..8329e33 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Ilipat ang item dito"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Naidagdag sa home screen ang item"</string>
<string name="item_removed" msgid="851119963877842327">"Naalis na ang item"</string>
+ <string name="undo" msgid="4151576204245173321">"I-undo"</string>
<string name="action_move" msgid="4339390619886385032">"Ilipat ang item"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Ilipat sa row <xliff:g id="NUMBER_0">%1$s</xliff:g> column <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Ilipat sa posisyon <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Naka-off ang mga notification at app"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Isara"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Nakasara"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Hindi nagawa: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index af121f2..6e77c48 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Öğeyi buraya taşı"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Öğe ana ekrana eklendi"</string>
<string name="item_removed" msgid="851119963877842327">"Öğe kaldırıldı"</string>
+ <string name="undo" msgid="4151576204245173321">"Geri al"</string>
<string name="action_move" msgid="4339390619886385032">"Öğeyi taşı"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g>. satır <xliff:g id="NUMBER_1">%2$s</xliff:g>. sütuna taşı"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>. sıraya taşı"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Bildirimler ve uygulamalar kapalı"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Kapat"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Kapalı"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Başarısız: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 305c9aa..1d23e4e 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -116,6 +116,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Перемістити елемент сюди"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Елемент додано на головний екран"</string>
<string name="item_removed" msgid="851119963877842327">"Елемент вилучено"</string>
+ <string name="undo" msgid="4151576204245173321">"Відмінити"</string>
<string name="action_move" msgid="4339390619886385032">"Перемістити елемент"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Перемістити в рядок <xliff:g id="NUMBER_0">%1$s</xliff:g>, стовпець <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Перемістити на <xliff:g id="NUMBER">%1$s</xliff:g> місце"</string>
@@ -146,4 +147,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Сповіщення та додатки вимкнено"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Закрити"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Закрито"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Не вдалося <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
deleted file mode 100644
index 77aa0a1..0000000
--- a/res/values-ur-rPK/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"دفتری"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"ایپ انسٹال نہیں ہے۔"</string>
- <string name="activity_not_available" msgid="7456344436509528827">"ایپ دستیاب نہیں ہے"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"ڈاؤن لوڈ کردہ ایپ کو محفوظ وضع میں غیر فعال کر دیا گیا"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"ویجیٹس کو محفوظ وضع میں غیر فعال کر دیا گیا"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"شارٹ کٹ دستیاب نہیں ہے"</string>
- <string name="home_screen" msgid="806512411299847073">"ہوم اسکرین"</string>
- <string name="custom_actions" msgid="3747508247759093328">"حسب ضرورت کارروائیاں"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"کوئی ویجیٹ منتخب کرنے کیلئے ٹچ کریں اور پکڑے رہیں۔"</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"کوئی ویجٹ منتخب کرنے یا حسب ضرورت کاروائیاں استعمال کرنے کیلئے دو بار تھپتھپائیں اور پکڑے رکھیں۔"</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d چوڑا اور %2$d اونچا"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"دستی طور پر رکھنے کیلئے & ٹچ کرکے ہولڈ کریں"</string>
- <string name="place_automatically" msgid="8064208734425456485">"خود کار طور پر شامل کریں"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ایپس تلاش کریں"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"ایپس لوڈ کی جا رہی ہیں…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" سے مماثل کوئی ایپس نہیں ملیں"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"مزید ایپس تلاش کریں"</string>
- <string name="notifications_header" msgid="1404149926117359025">"اطلاعات"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ایک شارٹ کٹ منتخب کرنے کیلئے ٹچ کر کے دبائے رکھیں۔"</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ایک شارٹ کٹ منتخب کرنے یا حسب ضرورت کارروائیاں استعمال کرنے کیلئے دو بار تھپتھپائیں اور دبائے رکھیں۔"</string>
- <string name="out_of_space" msgid="4691004494942118364">"اس ہوم اسکرین پر مزید کوئی گنجائش نہیں ہے۔"</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"پسندیدہ ٹرے میں مزید کوئی گنجائش نہیں ہے"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"ایپس کی فہرست"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ذاتی ایپس کی فہرست"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"دفتری ایپس کی فہرست"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"ہوم"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"ہٹائیں"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"اَن انسٹال کریں"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"ایپ کی معلومات"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"انسٹال کریں"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"شارٹ کٹس انسٹال کریں"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"کسی ایپ کو صارف کی مداخلت کے بغیر شارٹ کٹس شامل کرنے کی اجازت دیتا ہے۔"</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"ہوم ترتیبات اور شارٹ کٹس کو پڑھیں"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"ایپ کو ہوم میں ترتیبات اور شارٹ کٹس کو پڑھنے کی اجازت دیتا ہے۔"</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"ہوم ترتیبات اور شارٹ کٹس کو لکھیں"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"ایپ کو ہوم میں ترتیبات اور شارٹ کٹس کو تبدیل کرنے کی اجازت دیتا ہے۔"</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> کو فون کالیں کرنے کی اجازت نہیں ہے"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"ویجیٹ کو لوڈ کرنے میں مسئلہ"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"ترتیب دیں"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"یہ ایک سسٹم ایپ ہے اور اسے اَن انسٹال نہیں کیا جا سکتا ہے۔"</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"بلا نام فولڈر"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> غیر فعال ہے"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> میں <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> اطلاعات ہیں</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> میں <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> اطلاع ہے</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"صفحہ %1$d از %2$d"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"ہوم اسکرین %1$d از %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"نیا ہوم اسکرین صفحہ"</string>
- <string name="folder_opened" msgid="94695026776264709">"فولڈر کھولا گیا، <xliff:g id="WIDTH">%1$d</xliff:g> × <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"فولڈر کو بند کرنے کیلئے تھپتھپائیں"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"نام کی تبدیلی محفوظ کرنے کیلئے تھپتھپائیں"</string>
- <string name="folder_closed" msgid="4100806530910930934">"فولڈر بند ہو گیا"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"فولڈر کا نام تبدیل کر کے <xliff:g id="NAME">%1$s</xliff:g> کر دیا گیا"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"فولڈر: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"ویجیٹس"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"وال پیپرز"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"ہوم ترتیبات"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"آپ کے منتظم کی طرف سے غیر فعال کر دیا گیا"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"ہوم اسکرین گھمانے کی اجازت دیں"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"جب فون گھمایا جاتا ہے"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"اطلاعاتی ڈاٹس"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"آن"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"آف"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"اطلاعاتی رسائی درکار ہے"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"اطلاعاتی ڈاٹس دکھانے کی خاطر <xliff:g id="NAME">%1$s</xliff:g> کیلئے ایپ کی اطلاعات آن کریں"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"ترتیبات تبدیل کریں"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"اطلاعاتی ڈاٹس دکھائیں"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"آئیکن کو ہوم اسکرین میں شامل کریں"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"نئی ایپس کیلئے"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"آئیکن کی شکل تبدیل کریں"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"ہوم اسکرین پر"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"سسٹم ڈیفالٹ کا استعمال کریں"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"مربع"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"اسکورکل"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"حلقہ"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"آنسو کا قطرہ"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"آئيکن کی شکل کی تبدیلیاں لاگو ہو رہی ہیں"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"نامعلوم"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"ہٹائیں"</string>
- <string name="abandoned_search" msgid="891119232568284442">"تلاش کریں"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"یہ ایپ انسٹال کردہ نہیں ہے"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"اس آئیکن کیلئے ایپ انسٹال کردہ نہیں ہے۔ آپ اسے ہٹا سکتے ہیں یا ایپ کو تلاش کر سکتے اور دستی طور پر اسے انسٹال کر سکتے ہیں۔"</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ڈاؤن لوڈ ہو رہا ہے، <xliff:g id="PROGRESS">%2$s</xliff:g> مکمل ہو گیا"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> انسٹال ہونے کا انتظار کر رہی ہے"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ویجیٹس"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"ہوم اسکرین میں شامل کریں"</string>
- <string name="action_move_here" msgid="2170188780612570250">"آئٹم یہاں منتقل کریں"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"آئٹم کو ہوم اسکرین میں شامل کر دیا گیا"</string>
- <string name="item_removed" msgid="851119963877842327">"آئٹم ہٹا دیا گیا"</string>
- <string name="action_move" msgid="4339390619886385032">"آئٹم منتقل کریں"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"قطار <xliff:g id="NUMBER_0">%1$s</xliff:g> کالم <xliff:g id="NUMBER_1">%2$s</xliff:g> میں منتقل کریں"</string>
- <string name="move_to_position" msgid="6750008980455459790">"پوزیشن <xliff:g id="NUMBER">%1$s</xliff:g> میں منتقل کریں"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"پسندیدہ پوزیشن <xliff:g id="NUMBER">%1$s</xliff:g> میں منتقل کریں"</string>
- <string name="item_moved" msgid="4606538322571412879">"آئٹم منتقل کر دیا گیا"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"فولڈر میں شامل کریں: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> کے فولڈر میں شامل کریں"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"آئٹم فولڈر میں شامل کر دیا گیا"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"اس کے ساتھ فولڈر بنائیں: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="folder_created" msgid="6409794597405184510">"فولڈر بنا دیا گیا"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"ہوم اسکرین میں منتقل کریں"</string>
- <string name="action_resize" msgid="1802976324781771067">"سائز تبدیل کریں"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"چوڑائی بڑھائیں"</string>
- <string name="action_increase_height" msgid="459390020612501122">"اونچائی بڑھائیں"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"چوڑائی کم کریں"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"اونچائی کم کریں"</string>
- <string name="widget_resized" msgid="9130327887929620">"ویجیٹ کے سائز کو چوڑائی <xliff:g id="NUMBER_0">%1$s</xliff:g> اونچائی <xliff:g id="NUMBER_1">%2$s</xliff:g> میں تبدیل کر دیا گیا"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"شارٹ کٹس"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> کیلئے <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> شارٹ کٹس"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> کے <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> شارٹ کٹس اور <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> اطلاعات"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"برخاست کریں"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"اطلاع مسترد ہو گئی"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"ذاتی"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"دفتری"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"دفتری پروفائل"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"یہاں دفتری ایپس تلاش کریں"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"ہر دفتری ایپ میں ایک بَیج ہوتا ہے اور اسے آپ کی تنظیم محفوظ رکھتی ہے۔ زیادہ آسان رسائی کیلئے ایپس کو اپنی ہوم اسکرین پر منتقل کریں۔"</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"آپ کی تنظیم کے زیر انتظام"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"اطلاعات اور ایپس آف ہیں"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"بند کریں"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"بند"</string>
-</resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 7853fd4..d46ac2a 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -108,14 +108,13 @@
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ڈاؤن لوڈ ہو رہا ہے، <xliff:g id="PROGRESS">%2$s</xliff:g> مکمل ہو گیا"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> انسٹال ہونے کا انتظار کر رہی ہے"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ویجیٹس"</string>
- <!-- no translation found for widgets_list (796804551140113767) -->
- <skip />
- <!-- no translation found for widgets_list_closed (6141506579418771922) -->
- <skip />
+ <string name="widgets_list" msgid="796804551140113767">"ویجیٹس کی فہرست"</string>
+ <string name="widgets_list_closed" msgid="6141506579418771922">"ویجیٹس کی فہرست بند کر دی گئی"</string>
<string name="action_add_to_workspace" msgid="8902165848117513641">"ہوم اسکرین میں شامل کریں"</string>
<string name="action_move_here" msgid="2170188780612570250">"آئٹم یہاں منتقل کریں"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"آئٹم کو ہوم اسکرین میں شامل کر دیا گیا"</string>
<string name="item_removed" msgid="851119963877842327">"آئٹم ہٹا دیا گیا"</string>
+ <string name="undo" msgid="4151576204245173321">"کالعدم کریں"</string>
<string name="action_move" msgid="4339390619886385032">"آئٹم منتقل کریں"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"قطار <xliff:g id="NUMBER_0">%1$s</xliff:g> کالم <xliff:g id="NUMBER_1">%2$s</xliff:g> میں منتقل کریں"</string>
<string name="move_to_position" msgid="6750008980455459790">"پوزیشن <xliff:g id="NUMBER">%1$s</xliff:g> میں منتقل کریں"</string>
@@ -146,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"اطلاعات اور ایپس آف ہیں"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"بند کریں"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"بند"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"ناکام ہو گيا: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
deleted file mode 100644
index 0360a71..0000000
--- a/res/values-uz-rUZ/strings.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
- <string name="work_folder_name" msgid="3753320833950115786">"Ishga oid"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"Ilova o‘rnatilmadi."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Ilova mavjud emas"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Yuklab olingan ilova xavfsiz rejimda o‘chirib qo‘yildi"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Xavfsiz rejimda vidjetlar o‘chirib qo‘yilgan"</string>
- <string name="shortcut_not_available" msgid="2536503539825726397">"Tezkor tugmadan foydalanib bo‘lmaydi"</string>
- <string name="home_screen" msgid="806512411299847073">"Bosh ekran"</string>
- <string name="custom_actions" msgid="3747508247759093328">"Maxsus amallar"</string>
- <string name="long_press_widget_to_add" msgid="7699152356777458215">"Vidjetni tanlash uchun bosib turing."</string>
- <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Ikki marta bosib va bosib turgan holatda vidjetni tanlang yoki maxsus amaldan foydalaning."</string>
- <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
- <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Eni %1$d, bo‘yi %2$d"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Qo‘lda joylashtirish uchun bosib turing"</string>
- <string name="place_automatically" msgid="8064208734425456485">"Avtomatik chiqarish"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Ilovalarni qidirish"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Ilovalar yuklanmoqda…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"“<xliff:g id="QUERY">%1$s</xliff:g>” bilan mos hech qanday ilova topilmadi"</string>
- <string name="all_apps_search_market_message" msgid="1366263386197059176">"Boshqa ilovalarni qidirish"</string>
- <string name="notifications_header" msgid="1404149926117359025">"Bildirishnomalar"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Yorliqni tanlab olish uchun bosib turing."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Ikki marta bosib va bosib turgan holatda yorliqni tanlang yoki maxsus amaldan foydalaning."</string>
- <string name="out_of_space" msgid="4691004494942118364">"Uy ekranida bitta ham xona yo‘q."</string>
- <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ajratilganlarda birorta ham xona yo‘q"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Ilovalar ro‘yxati"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Shaxsiy ilovalar ro‘yxati"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Ishchi ilovalar ro‘yxati"</string>
- <string name="all_apps_home_button_label" msgid="252062713717058851">"Bosh sahifa"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Olib tashlash"</string>
- <string name="uninstall_drop_target_label" msgid="4722034217958379417">"O‘chirib tashlash"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Ilova haqida"</string>
- <string name="install_drop_target_label" msgid="2539096853673231757">"O‘rnatish"</string>
- <string name="permlab_install_shortcut" msgid="5632423390354674437">"yorliqlar yaratish"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ilovalarga foydalanuvchidan so‘ramasdan yorliqlar qo‘shishga ruxsat beradi."</string>
- <string name="permlab_read_settings" msgid="1941457408239617576">"Uy sozlamalari va yorliqlarini o‘qish"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Ilovaga \"Uy\" ekranidagi yorliqlar va sozlamalarni o‘qish uchun ruxsat beradi."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"Uy sozlamalari va yorliqlarini yozish"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Ilovaga \"Uy\" ekranidagi yorliqlar va sozlamalrni o‘zgartirish uchun ruxsat beradi."</string>
- <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga qo‘ng‘iroqlarni amalga oshirishga ruxsat berilmagan"</string>
- <string name="gadget_error_text" msgid="6081085226050792095">"Vidjetni yuklashda muammo"</string>
- <string name="gadget_setup_text" msgid="8274003207686040488">"Sozlash"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Bu tizim ilovasi, shuning uchun o‘chirib bo‘lmaydi."</string>
- <string name="folder_hint_text" msgid="6617836969016293992">"Nomsiz jild"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi o‘chirib qo‘yildi"</string>
- <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
- <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> ta bildirishnoma bor</item>
- <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> ta bildirishnoma bor</item>
- </plurals>
- <string name="default_scroll_format" msgid="7475544710230993317">"%2$ddan %1$d ta sahifa"</string>
- <string name="workspace_scroll_format" msgid="8458889198184077399">"Uy ekrani %2$ddan %1$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Yangi bosh ekran sahifasi"</string>
- <string name="folder_opened" msgid="94695026776264709">"Jild ochildi, <xliff:g id="WIDTH">%1$d</xliff:g> ga <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
- <string name="folder_tap_to_close" msgid="4625795376335528256">"Jildni yopish uchun ustiga bosing"</string>
- <string name="folder_tap_to_rename" msgid="4017685068016979677">"O‘zgarishni saqlash uchun ustiga bosing"</string>
- <string name="folder_closed" msgid="4100806530910930934">"Jild yopildi"</string>
- <string name="folder_renamed" msgid="1794088362165669656">"Jild nomi <xliff:g id="NAME">%1$s</xliff:g>ga o‘zgartirildi"</string>
- <string name="folder_name_format" msgid="6629239338071103179">"Jild: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="widget_button_text" msgid="2880537293434387943">"Vidjetlar"</string>
- <string name="wallpaper_button_text" msgid="8404103075899945851">"Fon rasmlari"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Bosh ekran sozlamalari"</string>
- <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administrator tomonidan o‘chirilgan"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Asosiy ekranni aylantirishga ruxsat berish"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Telefon burilganda"</string>
- <string name="icon_badging_title" msgid="874121399231955394">"Bildirishnoma belgilari"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Yoniq"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"O‘chiq"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"Bildirishnomalarga ruxsat berilmagan"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Bildirishnoma belgilarini ko‘rsatish uchun <xliff:g id="NAME">%1$s</xliff:g> ilovasida bildirishnomalarni yoqing"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Sozlamalarni o‘zgartirish"</string>
- <string name="icon_badging_service_title" msgid="2309733118428242174">"Bildirishnoma belgilarini ko‘rsatish"</string>
- <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Bosh ekranga ikonka chiqarish"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Yangi o‘rnatilgan ilovalar ikonkasini bosh ekranga chiqarish"</string>
- <string name="icon_shape_override_label" msgid="2977264953998281004">"Ikonka shaklini o‘zgartirish"</string>
- <string name="icon_shape_override_label_location" msgid="3841607380657692863">"Bosh ekranda"</string>
- <string name="icon_shape_system_default" msgid="1709762974822753030">"Standart tizim parametrlaridan foydalanish"</string>
- <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
- <string name="icon_shape_squircle" msgid="5658049910802669495">"Qirralari aylana kvadrat"</string>
- <string name="icon_shape_circle" msgid="6550072265930144217">"Aylana"</string>
- <string name="icon_shape_teardrop" msgid="4525869388200835463">"Tomchi"</string>
- <string name="icon_shape_override_progress" msgid="3461735694970239908">"Ikonka shakli o‘zgartirilmoqda"</string>
- <string name="package_state_unknown" msgid="7592128424511031410">"Noma’lum"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"O‘chirish"</string>
- <string name="abandoned_search" msgid="891119232568284442">"Qidirish"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Ushbu ilova o‘rnatilmagan"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Ilova o‘rnatilmagan. Belgini o‘chirib tashlashingiz yoki ilovani topib, uni qo‘lda o‘rnatishingiz mumkin."</string>
- <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> yuklab olinmoqda, <xliff:g id="PROGRESS">%2$s</xliff:g> bajarildi"</string>
- <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ilovasi o‘rnatilishi kutilmoqda"</string>
- <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> vidjetlari"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Bosh ekranga qo‘shish"</string>
- <string name="action_move_here" msgid="2170188780612570250">"Obyektni bu yerga ko‘chirish"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"Obyekt bosh ekranga qo‘shildi"</string>
- <string name="item_removed" msgid="851119963877842327">"Obyekt o‘chirib tashlandi"</string>
- <string name="action_move" msgid="4339390619886385032">"Obyektni ko‘chirib o‘tkazish"</string>
- <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> <xliff:g id="NUMBER_1">%2$s</xliff:g> katakka ko‘chirib o‘tkazish"</string>
- <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>-joyga ko‘chirib o‘tkazish"</string>
- <string name="move_to_hotseat_position" msgid="6295412897075147808">"Sevimlilarga (<xliff:g id="NUMBER">%1$s</xliff:g>) ko‘chirib o‘tkazish"</string>
- <string name="item_moved" msgid="4606538322571412879">"Element ko‘chirib o‘tkazildi"</string>
- <string name="add_to_folder" msgid="9040534766770853243">"<xliff:g id="NAME">%1$s</xliff:g> jildiga qo‘shish"</string>
- <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> ilovasi bor jildga qo‘shish"</string>
- <string name="added_to_folder" msgid="4793259502305558003">"Element jildga qo‘shildi"</string>
- <string name="create_folder_with" msgid="4050141361160214248">"<xliff:g id="NAME">%1$s</xliff:g> bilan jild yaratish"</string>
- <string name="folder_created" msgid="6409794597405184510">"Jild yaratildi"</string>
- <string name="action_move_to_workspace" msgid="1603837886334246317">"Bosh ekranga ko‘chirish"</string>
- <string name="action_resize" msgid="1802976324781771067">"O‘lchamini o‘zgartirish"</string>
- <string name="action_increase_width" msgid="8773715375078513326">"Enini uzaytirish"</string>
- <string name="action_increase_height" msgid="459390020612501122">"Bo‘yini uzaytirish"</string>
- <string name="action_decrease_width" msgid="1374549771083094654">"Enini kichraytirish"</string>
- <string name="action_decrease_height" msgid="282377193880900022">"Bo‘yini kichraytirish"</string>
- <string name="widget_resized" msgid="9130327887929620">"Vidjetning eni <xliff:g id="NUMBER_0">%1$s</xliff:g>, bo‘yi <xliff:g id="NUMBER_1">%2$s</xliff:g> qilib o‘zgartirildi"</string>
- <string name="action_deep_shortcut" msgid="2864038805849372848">"Tezkor tugmalar"</string>
- <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> ilovasi uchun <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ta tezkor tugma"</string>
- <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> ilovasi uchun <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ta yorliq va <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ta bildirishnoma"</string>
- <string name="action_dismiss_notification" msgid="5909461085055959187">"Yopish"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Bildirishnoma yopildi"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Shaxsiy"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Ishchi"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Ishchi profil"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Ishga oid ilovalarni shu yerdan topish mumkin"</string>
- <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Nishonga ega har bir ishga oid ilova tashkilotingiz tomonidan himoyalanadi. Ishga oid ilovalarga osonroq kirish uchun ularni bosh ekranga chiqaring."</string>
- <string name="work_mode_on_label" msgid="4781128097185272916">"Tashkilotingiz tomonidan boshqariladi"</string>
- <string name="work_mode_off_label" msgid="3194894777601421047">"Bildirishnomalar va ilovalar faol emas"</string>
- <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Yopish"</string>
- <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Yopiq"</string>
-</resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 287ec09..c3b3dde 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Obyektni bu yerga ko‘chirish"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Obyekt bosh ekranga qo‘shildi"</string>
<string name="item_removed" msgid="851119963877842327">"Obyekt o‘chirib tashlandi"</string>
+ <string name="undo" msgid="4151576204245173321">"Qaytarish"</string>
<string name="action_move" msgid="4339390619886385032">"Obyektni ko‘chirib o‘tkazish"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> <xliff:g id="NUMBER_1">%2$s</xliff:g> katakka ko‘chirib o‘tkazish"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>-joyga ko‘chirib o‘tkazish"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Bildirishnomalar va ilovalar faol emas"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Yopish"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Yopiq"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Xato: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-v21/styles.xml b/res/values-v21/styles.xml
deleted file mode 100644
index 927719c..0000000
--- a/res/values-v21/styles.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2016 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
--->
-<resources>
-
- <style name="LauncherTheme" parent="@style/BaseLauncherThemeWithCustomAttrs">
- <item name="android:windowTranslucentStatus">false</item>
- <item name="android:windowTranslucentNavigation">false</item>
- <item name="android:windowDrawsSystemBarBackgrounds">true</item>
- <item name="android:statusBarColor">#00000000</item>
- <item name="android:navigationBarColor">#00000000</item>
- </style>
-</resources>
diff --git a/res/values-v19/styles.xml b/res/values-v22/styles.xml
similarity index 71%
rename from res/values-v19/styles.xml
rename to res/values-v22/styles.xml
index 36c0971..f86db7a 100644
--- a/res/values-v19/styles.xml
+++ b/res/values-v22/styles.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
-* Copyright (C) 2016 The Android Open Source Project
+* 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.
@@ -16,11 +16,11 @@
* limitations under the License.
*/
-->
+
<resources>
- <style name="LauncherTheme" parent="@style/BaseLauncherThemeWithCustomAttrs">
- <item name="android:windowTranslucentStatus">true</item>
- <item name="android:windowTranslucentNavigation">true</item>
+ <style name="AppItemActivityTheme" parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert">
+ <item name="widgetsTheme">@style/WidgetContainerTheme</item>
</style>
</resources>
\ No newline at end of file
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 06278f5..a27d26c 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Di chuyển mục vào đây"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Đã thêm mục vào màn hình chính"</string>
<string name="item_removed" msgid="851119963877842327">"Đã xóa mục"</string>
+ <string name="undo" msgid="4151576204245173321">"Hoàn tác"</string>
<string name="action_move" msgid="4339390619886385032">"Di chuyển mục"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Di chuyển đến hàng <xliff:g id="NUMBER_0">%1$s</xliff:g> cột <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Di chuyển tới vị trí <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Thông báo và ứng dụng đang tắt"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Đóng"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Đã đóng"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Không thực hiện được thao tác: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 640aa0e..dbe70c9 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"将项目移至此处"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"已将项目添加到主屏幕"</string>
<string name="item_removed" msgid="851119963877842327">"项目已移除"</string>
+ <string name="undo" msgid="4151576204245173321">"撤消"</string>
<string name="action_move" msgid="4339390619886385032">"移动项目"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"移至第 <xliff:g id="NUMBER_0">%1$s</xliff:g> 行第 <xliff:g id="NUMBER_1">%2$s</xliff:g> 列"</string>
<string name="move_to_position" msgid="6750008980455459790">"移至第 <xliff:g id="NUMBER">%1$s</xliff:g> 个位置"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"通知和应用均已关闭"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"关闭"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"已关闭"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"失败:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 5a8c6ca..ff59d02 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -41,7 +41,7 @@
<string name="all_apps_search_market_message" msgid="1366263386197059176">"搜尋更多應用程式"</string>
<string name="notifications_header" msgid="1404149926117359025">"通知"</string>
<string name="long_press_shortcut_to_add" msgid="4524750017792716791">"按住捷徑即可選取。"</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"撳兩下之後撳住,就可以揀選捷徑或者用自訂嘅操作。"</string>
+ <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"連㩒兩下之後繼續㩒住,就可以揀選捷徑或者用自訂嘅操作。"</string>
<string name="out_of_space" msgid="4691004494942118364">"主畫面已無空間。"</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"我的收藏寄存區沒有足夠空間"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"應用程式清單"</string>
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"移動項目至這裡"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"已將項目加入至主畫面"</string>
<string name="item_removed" msgid="851119963877842327">"項目已移除"</string>
+ <string name="undo" msgid="4151576204245173321">"復原"</string>
<string name="action_move" msgid="4339390619886385032">"移動項目"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"移動至第 <xliff:g id="NUMBER_0">%1$s</xliff:g> 行第 <xliff:g id="NUMBER_1">%2$s</xliff:g> 列"</string>
<string name="move_to_position" msgid="6750008980455459790">"移動至位置 <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"通知和應用程式已關閉"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"關閉"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"已關閉"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"操作失敗:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 4d37cdd..246f6eb 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"將項目移至這裡"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"已將項目新增到主畫面"</string>
<string name="item_removed" msgid="851119963877842327">"已移除項目"</string>
+ <string name="undo" msgid="4151576204245173321">"復原"</string>
<string name="action_move" msgid="4339390619886385032">"移動項目"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"移至第 <xliff:g id="NUMBER_0">%1$s</xliff:g> 列第 <xliff:g id="NUMBER_1">%2$s</xliff:g> 欄"</string>
<string name="move_to_position" msgid="6750008980455459790">"移至位置 <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"已關閉通知和應用程式"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"關閉"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"已關閉"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"失敗:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 8e3e5ab..c25319e 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -114,6 +114,7 @@
<string name="action_move_here" msgid="2170188780612570250">"Hambisa into lapha"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Into ingezwe kusikrini sasekhaya"</string>
<string name="item_removed" msgid="851119963877842327">"Into isusiwe"</string>
+ <string name="undo" msgid="4151576204245173321">"Susa"</string>
<string name="action_move" msgid="4339390619886385032">"Hambisa into"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Hambisa kurowu engu-<xliff:g id="NUMBER_0">%1$s</xliff:g> ikholomu engu-<xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Hambisa kusimo esingu-<xliff:g id="NUMBER">%1$s</xliff:g>"</string>
@@ -144,4 +145,5 @@
<string name="work_mode_off_label" msgid="3194894777601421047">"Izaziso nezinhlelo zokusebenza kuvaliwe"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Vala"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Kuvaliwe"</string>
+ <string name="remote_action_failed" msgid="1383965239183576790">"Yehlulekile: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 30091a5..956270c 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -33,6 +33,8 @@
<attr name="workspaceKeyShadowColor" format="color" />
<attr name="workspaceStatusBarScrim" format="reference" />
<attr name="widgetsTheme" format="reference" />
+ <attr name="folderBadgeColor" format="color" />
+ <attr name="loadingIconColor" format="color" />
<!-- BubbleTextView specific attributes. -->
<declare-styleable name="BubbleTextView">
diff --git a/res/values/colors.xml b/res/values/colors.xml
index eb207af..3c8fe1e 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -34,7 +34,6 @@
<color name="notification_icon_default_color">#757575</color> <!-- Gray 600 -->
<color name="icon_background">#E0E0E0</color> <!-- Gray 300 -->
- <color name="legacy_icon_background">#FFFFFF</color>
<color name="all_apps_bg_hand_fill">#E5E5E5</color>
<color name="all_apps_bg_hand_fill_dark">#9AA0A6</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index f2d6c21..b33cfa1 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -18,6 +18,9 @@
<!-- String representing the intent to delete a package.-->
<string name="delete_package_intent" translatable="false">#Intent;action=android.intent.action.DELETE;launchFlags=0x10800000;end</string>
+ <!-- String representing the fragment class for settings activity.-->
+ <string name="settings_fragment_name" translatable="false">com.android.launcher3.settings.SettingsActivity$LauncherSettingsFragment</string>
+
<!-- Values for icon shape overrides. These should correspond to entries defined
in icon_shape_override_paths_names -->
<string-array translatable="false" name="icon_shape_override_paths_values">
@@ -76,30 +79,16 @@
<!-- Hotseat -->
<bool name="hotseat_transpose_layout_with_orientation">true</bool>
- <!-- Name of a subclass of com.android.launcher3.AppFilter used to
- filter the activities shown in the launcher. Can be empty. -->
+ <!-- Various classes overriden by projects/build flavors. -->
<string name="app_filter_class" translatable="false"></string>
-
- <!-- Name of an icon provider class. -->
<string name="icon_provider_class" translatable="false"></string>
-
- <!-- Name of a drawable factory class. -->
<string name="drawable_factory_class" translatable="false"></string>
-
- <!-- Name of a user event dispatcher class. -->
<string name="user_event_dispatcher_class" translatable="false"></string>
-
- <!-- Name of an app transition manager class. -->
+ <string name="stats_log_manager_class" translatable="false"></string>
<string name="app_transition_manager_class" translatable="false"></string>
-
- <!-- Name of a color extraction implementation class. -->
- <string name="color_extraction_impl_class" translatable="false"></string>
-
- <!-- Name of a subclass of com.android.launcher3.util.InstantAppResolver. Can be empty. -->
<string name="instant_app_resolver_class" translatable="false"></string>
-
- <!-- Name of a main process initializer class. -->
<string name="main_process_initializer_class" translatable="false"></string>
+ <string name="system_shortcut_factory_class" translatable="false"></string>
<!-- Package name of the default wallpaper picker. -->
<string name="wallpaper_picker_package" translatable="false"></string>
@@ -113,16 +102,16 @@
<!-- View ID used by cell layout to jail its content -->
<item type="id" name="cell_layout_jail_id" />
- <!-- Tag id used for view scrim -->
- <item type="id" name="view_scrim" />
-
<!-- View IDs to store item highlight information -->
<item type="id" name="view_unhighlight_background" />
<item type="id" name="view_highlighted" />
-<!-- Popup items -->
+ <!-- Menu id for feature flags -->
+ <item type="id" name="menu_apply_flags" />
+
+ <!-- Popup items -->
<integer name="config_popupOpenCloseDuration">150</integer>
- <integer name="config_popupArrowOpenDuration">80</integer>
+ <integer name="config_popupArrowOpenCloseDuration">40</integer>
<integer name="config_removeNotificationViewDuration">300</integer>
<!-- Accessibility actions -->
@@ -138,16 +127,12 @@
<item type="id" name="action_deep_shortcuts" />
<item type="id" name="action_shortcuts_and_notifications"/>
<item type="id" name="action_dismiss_notification" />
+ <item type="id" name="action_remote_action_shortcut" />
<!-- QSB IDs. DO not change -->
<item type="id" name="search_container_workspace" />
- <item type="id" name="search_container_hotseat" />
<item type="id" name="search_container_all_apps" />
<!-- Recents -->
<item type="id" name="overview_panel"/>
- <integer name="config_recentsMaxThumbnailCacheSize">6</integer>
- <integer name="config_recentsMaxIconCacheSize">12</integer>
-
- <item name="workspace_page_container" type="id" />
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 3bb7a79..8adae36 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -76,7 +76,6 @@
<dimen name="fastscroll_end_margin">-26dp</dimen>
<!-- All Apps -->
- <dimen name="all_apps_button_scale_down">0dp</dimen>
<dimen name="all_apps_search_bar_field_height">48dp</dimen>
<dimen name="all_apps_search_bar_bottom_padding">30dp</dimen>
<dimen name="all_apps_empty_search_message_top_offset">40dp</dimen>
@@ -226,4 +225,15 @@
<!-- Overview -->
<dimen name="options_menu_icon_size">24dp</dimen>
<dimen name="options_menu_thumb_size">32dp</dimen>
+
+<!-- Snackbar -->
+ <dimen name="snackbar_height">48dp</dimen>
+ <dimen name="snackbar_content_height">32dp</dimen>
+ <dimen name="snackbar_padding">8dp</dimen>
+ <dimen name="snackbar_min_margin_left_right">6dp</dimen>
+ <dimen name="snackbar_max_margin_left_right">72dp</dimen>
+ <dimen name="snackbar_margin_bottom">30dp</dimen>
+ <dimen name="snackbar_elevation">3dp</dimen>
+ <dimen name="snackbar_min_text_size">12sp</dimen>
+ <dimen name="snackbar_max_text_size">14sp</dimen>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7bc11c3..7e5784d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -259,9 +259,12 @@
<!-- Accessibility confirmation for item added to workspace. -->
<string name="item_added_to_workspace">Item added to home screen</string>
- <!-- Accessibility confirmation for item removed. -->
+ <!-- Accessibility confirmation for item removed. [CHAR_LIMIT=50]-->
<string name="item_removed">Item removed</string>
+ <!-- Action shown in snackbar to undo item removal. [CHAR_LIMIT=20] -->
+ <string name="undo">Undo</string>
+
<!-- Accessibility action to move an item on the workspace. [CHAR_LIMIT=30] -->
<string name="action_move">Move item</string>
@@ -344,4 +347,7 @@
<string name="work_mode_off_label">Notifications and apps are off</string>
<string name="bottom_work_tab_user_education_close_button">Close</string>
<string name="bottom_work_tab_user_education_closed">Closed</string>
+
+ <!-- Failed action error message: e.g. Failed: Pause -->
+ <string name="remote_action_failed">Failed: <xliff:g id="what" example="Pause">%1$s</xliff:g></string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 07bd800..e6791aa 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -27,7 +27,7 @@
<item name="android:colorEdgeEffect">#FF757575</item>
</style>
- <style name="BaseLauncherThemeWithCustomAttrs" parent="@style/BaseLauncherTheme">
+ <style name="LauncherTheme" parent="@style/BaseLauncherTheme">
<item name="allAppsScrimColor">#EAFFFFFF</item>
<item name="allAppsInterimScrimAlpha">46</item>
<item name="allAppsNavBarScrimColor">#66FFFFFF</item>
@@ -42,9 +42,15 @@
<item name="workspaceKeyShadowColor">#44000000</item>
<item name="workspaceStatusBarScrim">@drawable/workspace_bg</item>
<item name="widgetsTheme">@style/WidgetContainerTheme</item>
- </style>
+ <item name="folderBadgeColor">?android:attr/colorPrimary</item>
+ <item name="loadingIconColor">#FFF</item>
- <style name="LauncherTheme" parent="@style/BaseLauncherThemeWithCustomAttrs"></style>
+ <item name="android:windowTranslucentStatus">false</item>
+ <item name="android:windowTranslucentNavigation">false</item>
+ <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+ <item name="android:statusBarColor">#00000000</item>
+ <item name="android:navigationBarColor">#00000000</item>
+ </style>
<style name="LauncherTheme.DarkText" parent="@style/LauncherTheme">
<item name="workspaceTextColor">#FF212121</item>
@@ -70,7 +76,9 @@
<item name="popupColorSecondary">#424242</item> <!-- Gray 800 -->
<item name="popupColorTertiary">#757575</item> <!-- Gray 600 -->
<item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
+ <item name="folderBadgeColor">#FF464646</item>
<item name="isMainColorDark">true</item>
+ <item name="loadingIconColor">#000</item>
</style>
<style name="LauncherTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark">
@@ -90,6 +98,10 @@
<style name="AppTheme.Dark" parent="@style/LauncherTheme.Dark" />
<style name="AppTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark.DarkText" />
+ <style name="AppItemActivityTheme" parent="@android:style/Theme.Material.Light.Dialog.Alert">
+ <item name="widgetsTheme">@style/WidgetContainerTheme</item>
+ </style>
+
<!--
Theme overrides to element on homescreen, i.e., which are drawn on top on wallpaper.
Various foreground colors are overridden to be workspaceTextColor so that they are properly
@@ -132,7 +144,7 @@
<item name="android:layout_gravity">center</item>
<item name="android:focusable">true</item>
<item name="android:gravity">center_horizontal</item>
- <item name="android:singleLine">true</item>
+ <item name="android:lines">1</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:fontFamily">sans-serif-condensed</item>
<item name="android:defaultFocusHighlightEnabled">false</item>
diff --git a/res/xml/dw_phone_hotseat.xml b/res/xml/dw_phone_hotseat.xml
index b58994d..c691ebc 100644
--- a/res/xml/dw_phone_hotseat.xml
+++ b/res/xml/dw_phone_hotseat.xml
@@ -16,7 +16,7 @@
<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
<!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
- <!-- Dialer, Messaging, [All Apps], Browser, Camera -->
+ <!-- Dialer, Messaging, [Maps/Music], Browser, Camera -->
<resolve
launcher:container="-101"
launcher:screen="0"
@@ -39,7 +39,14 @@
<favorite launcher:uri="mmsto:" />
</resolve>
- <!-- All Apps -->
+ <resolve
+ launcher:container="-101"
+ launcher:screen="2"
+ launcher:x="2"
+ launcher:y="0" >
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MAPS;end" />
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MUSIC;end" />
+ </resolve>
<resolve
launcher:container="-101"
diff --git a/res/xml/dw_tablet_hotseat.xml b/res/xml/dw_tablet_hotseat.xml
index 671ccba..6fe7f93 100644
--- a/res/xml/dw_tablet_hotseat.xml
+++ b/res/xml/dw_tablet_hotseat.xml
@@ -16,7 +16,7 @@
<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
<!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
- <!-- Messaging, Email, Browser, [All Apps], Music, Gallery, Camera -->
+ <!-- Messaging, Email, Browser, Maps, Music, Gallery, Camera -->
<resolve
launcher:container="-101"
launcher:screen="0"
@@ -48,7 +48,13 @@
<favorite launcher:uri="http://www.example.com/" />
</resolve>
- <!-- All Apps -->
+ <resolve
+ launcher:container="-101"
+ launcher:screen="3"
+ launcher:x="3"
+ launcher:y="0" >
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MAPS;end" />
+ </resolve>
<favorite
launcher:container="-101"
diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml
index 3bba73a..2c86f8e 100644
--- a/res/xml/launcher_preferences.xml
+++ b/res/xml/launcher_preferences.xml
@@ -14,9 +14,10 @@
limitations under the License.
-->
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+<androidx.preference.PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android">
- <com.android.launcher3.views.ButtonPreference
+ <com.android.launcher3.settings.IconBadgingPreference
android:key="pref_icon_badging"
android:title="@string/icon_badging_title"
android:persistent="false"
@@ -27,7 +28,7 @@
android:name=":settings:fragment_args_key"
android:value="notification_badging" />
</intent>
- </com.android.launcher3.views.ButtonPreference>
+ </com.android.launcher3.settings.IconBadgingPreference>
<SwitchPreference
android:key="pref_add_icon_to_home"
@@ -52,4 +53,10 @@
android:defaultValue=""
android:persistent="false" />
-</PreferenceScreen>
+ <androidx.preference.PreferenceScreen
+ android:key="pref_developer_options"
+ android:persistent="false"
+ android:title="Developer Options"
+ android:fragment="com.android.launcher3.settings.DeveloperOptionsFragment"/>
+
+</androidx.preference.PreferenceScreen>
diff --git a/robolectric_tests/Android.mk b/robolectric_tests/Android.mk
new file mode 100644
index 0000000..a57b97a
--- /dev/null
+++ b/robolectric_tests/Android.mk
@@ -0,0 +1,55 @@
+# 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.
+
+#############################################
+# Launcher Robolectric test target. #
+#############################################
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := LauncherRoboTests
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ androidx.test.runner \
+ androidx.test.rules \
+ mockito-robolectric-prebuilt \
+ truth-prebuilt
+LOCAL_JAVA_LIBRARIES := \
+ platform-robolectric-3.6.1-prebuilt
+
+LOCAL_JAVA_RESOURCE_DIRS := resources config
+
+LOCAL_INSTRUMENTATION_FOR := Launcher3
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+############################################
+# Target to run the previous target. #
+############################################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := RunLauncherRoboTests
+LOCAL_SDK_VERSION := current
+LOCAL_JAVA_LIBRARIES := \
+ LauncherRoboTests
+
+LOCAL_TEST_PACKAGE := Launcher3
+
+LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))../src \
+
+LOCAL_ROBOTEST_TIMEOUT := 36000
+
+include prebuilts/misc/common/robolectric/3.6.1/run_robotests.mk
diff --git a/robolectric_tests/config/robolectric.properties b/robolectric_tests/config/robolectric.properties
new file mode 100644
index 0000000..782b8cb
--- /dev/null
+++ b/robolectric_tests/config/robolectric.properties
@@ -0,0 +1,2 @@
+manifest=packages/apps/Launcher3/AndroidManifest.xml
+sdk=28
\ No newline at end of file
diff --git a/tests/res/raw/cache_data_updated_task_data.txt b/robolectric_tests/resources/cache_data_updated_task_data.txt
similarity index 100%
rename from tests/res/raw/cache_data_updated_task_data.txt
rename to robolectric_tests/resources/cache_data_updated_task_data.txt
diff --git a/tests/res/raw/package_install_state_change_task_data.txt b/robolectric_tests/resources/package_install_state_change_task_data.txt
similarity index 100%
rename from tests/res/raw/package_install_state_change_task_data.txt
rename to robolectric_tests/resources/package_install_state_change_task_data.txt
diff --git a/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java
new file mode 100644
index 0000000..92bcc64
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java
@@ -0,0 +1,116 @@
+package com.android.launcher3.config;
+
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.robolectric.RuntimeEnvironment;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Test rule that makes overriding flags in Robolectric tests easier. This rule clears all flags
+ * before and after your test, avoiding one test method affecting subsequent methods.
+ *
+ * <p>Usage:
+ * <pre>
+ * {@literal @}Rule public final FlagOverrideRule flags = new FlagOverrideRule();
+ *
+ * {@literal @}FlagOverride(flag = "FOO", value=true)
+ * {@literal @}Test public void myTest() {
+ * ...
+ * }
+ * </pre>
+ */
+public final class FlagOverrideRule implements TestRule {
+
+ /**
+ * Container annotation for handling multiple {@link FlagOverride} annotations.
+ * <p>
+ * <p>Don't use this directly, use repeated {@link FlagOverride} annotations instead.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.METHOD})
+ public @interface FlagOverrides {
+ FlagOverride[] value();
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.METHOD})
+ @Repeatable(FlagOverrides.class)
+ public @interface FlagOverride {
+ String key();
+
+ boolean value();
+ }
+
+ private boolean ruleInProgress;
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ FeatureFlags.initialize(RuntimeEnvironment.application.getApplicationContext());
+ ruleInProgress = true;
+ try {
+ clearOverrides();
+ applyAnnotationOverrides(description);
+ base.evaluate();
+ } finally {
+ ruleInProgress = false;
+ clearOverrides();
+ }
+ }
+ };
+ }
+
+ private void override(BaseFlags.TogglableFlag flag, boolean newValue) {
+ if (!ruleInProgress) {
+ throw new IllegalStateException(
+ "Rule isn't in progress. Did you remember to mark it with @Rule?");
+ }
+ flag.setForTests(newValue);
+ }
+
+ private void applyAnnotationOverrides(Description description) {
+ for (Annotation annotation : description.getAnnotations()) {
+ if (annotation.annotationType() == FlagOverride.class) {
+ applyAnnotation((FlagOverride) annotation);
+ } else if (annotation.annotationType() == FlagOverrides.class) {
+ // Note: this branch is hit if the annotation is repeated
+ for (FlagOverride flagOverride : ((FlagOverrides) annotation).value()) {
+ applyAnnotation(flagOverride);
+ }
+ }
+ }
+ }
+
+ private void applyAnnotation(FlagOverride flagOverride) {
+ boolean found = false;
+ for (BaseFlags.TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
+ if (flag.getKey().equals(flagOverride.key())) {
+ override(flag, flagOverride.value());
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ throw new IllegalStateException("Flag " + flagOverride.key() + " not found");
+ }
+ }
+
+ /**
+ * Resets all flags to their default values.
+ */
+ private void clearOverrides() {
+ for (BaseFlags.TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
+ flag.setForTests(flag.getDefaultValue());
+ }
+ }
+}
diff --git a/robolectric_tests/src/com/android/launcher3/config/FlagOverrideSampleTest.java b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideSampleTest.java
new file mode 100644
index 0000000..c5a0820
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideSampleTest.java
@@ -0,0 +1,38 @@
+package com.android.launcher3.config;
+
+import com.android.launcher3.config.FlagOverrideRule.FlagOverride;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Sample Robolectric test that demonstrates flag-overriding.
+ */
+@RunWith(RobolectricTestRunner.class)
+public class FlagOverrideSampleTest {
+
+ // Check out https://junit.org/junit4/javadoc/4.12/org/junit/Rule.html for more information
+ // on @Rules.
+ @Rule
+ public final FlagOverrideRule flags = new FlagOverrideRule();
+
+ @FlagOverride(key = "EXAMPLE_FLAG", value = true)
+ @FlagOverride(key = "QUICK_SWITCH", value = false)
+ @Test
+ public void withFlagOn() {
+ assertTrue(FeatureFlags.EXAMPLE_FLAG.get());
+ assertFalse(FeatureFlags.QUICK_SWITCH.get());
+ }
+
+
+ @FlagOverride(key = "EXAMPLE_FLAG", value = false)
+ @Test
+ public void withFlagOff() {
+ assertFalse(FeatureFlags.EXAMPLE_FLAG.get());
+ }
+}
diff --git a/tests/src/com/android/launcher3/logging/FileLogTest.java b/robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java
similarity index 89%
rename from tests/src/com/android/launcher3/logging/FileLogTest.java
rename to robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java
index 9c7cb8f..096db57 100644
--- a/tests/src/com/android/launcher3/logging/FileLogTest.java
+++ b/robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java
@@ -1,13 +1,11 @@
package com.android.launcher3.logging;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
import java.io.File;
import java.io.PrintWriter;
@@ -20,8 +18,7 @@
/**
* Tests for {@link FileLog}
*/
-@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(RobolectricTestRunner.class)
public class FileLogTest {
private File mTempDir;
@@ -30,9 +27,9 @@
public void setUp() throws Exception {
int count = 0;
do {
- mTempDir = new File(InstrumentationRegistry.getTargetContext().getCacheDir(),
+ mTempDir = new File(RuntimeEnvironment.application.getCacheDir(),
"log-test-" + (count++));
- } while(!mTempDir.mkdir());
+ } while (!mTempDir.mkdir());
FileLog.setDir(mTempDir);
}
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
similarity index 78%
rename from tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
rename to robolectric_tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
index 401711d..fd31033 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
@@ -1,5 +1,11 @@
package com.android.launcher3.model;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.verify;
+
import android.content.ComponentName;
import android.content.ContentProviderOperation;
import android.content.ContentValues;
@@ -7,7 +13,6 @@
import android.content.Intent;
import android.graphics.Rect;
import android.net.Uri;
-import android.support.test.runner.AndroidJUnit4;
import android.util.Pair;
import com.android.launcher3.ItemInfo;
@@ -15,40 +20,36 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.util.GridOccupancy;
-import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSparseArrayMap;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.robolectric.RobolectricTestRunner;
import java.util.ArrayList;
import java.util.List;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.verify;
-
/**
* Tests for {@link AddWorkspaceItemsTask}
*/
-@RunWith(AndroidJUnit4.class)
+@RunWith(RobolectricTestRunner.class)
public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase {
private final ComponentName mComponent1 = new ComponentName("a", "b");
private final ComponentName mComponent2 = new ComponentName("b", "b");
- private ArrayList<Long> existingScreens;
- private ArrayList<Long> newScreens;
- private LongArrayMap<GridOccupancy> screenOccupancy;
+ private IntArray existingScreens;
+ private IntArray newScreens;
+ private IntSparseArrayMap<GridOccupancy> screenOccupancy;
@Before
public void initData() throws Exception {
- existingScreens = new ArrayList<>();
- screenOccupancy = new LongArrayMap<>();
- newScreens = new ArrayList<>();
+ existingScreens = new IntArray();
+ screenOccupancy = new IntSparseArrayMap<>();
+ newScreens = new IntArray();
idp.numColumns = 5;
idp.numRows = 5;
@@ -62,7 +63,7 @@
return new AddWorkspaceItemsTask(list) {
@Override
- protected void updateScreens(Context context, ArrayList<Long> workspaceScreens) { }
+ protected void updateScreens(Context context, IntArray workspaceScreens) { }
};
}
@@ -74,18 +75,18 @@
// Second screen has 2 holes of sizes 3x2 and 2x3
setupWorkspaceWithHoles(nextId, 2, new Rect(2, 0, 5, 2), new Rect(0, 2, 2, 5));
- Pair<Long, int[]> spaceFound = newTask()
+ int[] spaceFound = newTask()
.findSpaceForItem(appState, bgDataModel, existingScreens, newScreens, 1, 1);
- assertEquals(2L, (long) spaceFound.first);
- assertTrue(screenOccupancy.get(spaceFound.first)
- .isRegionVacant(spaceFound.second[0], spaceFound.second[1], 1, 1));
+ assertEquals(2, spaceFound[0]);
+ assertTrue(screenOccupancy.get(spaceFound[0])
+ .isRegionVacant(spaceFound[1], spaceFound[2], 1, 1));
// Find a larger space
spaceFound = newTask()
.findSpaceForItem(appState, bgDataModel, existingScreens, newScreens, 2, 3);
- assertEquals(2L, (long) spaceFound.first);
- assertTrue(screenOccupancy.get(spaceFound.first)
- .isRegionVacant(spaceFound.second[0], spaceFound.second[1], 2, 3));
+ assertEquals(2, spaceFound[0]);
+ assertTrue(screenOccupancy.get(spaceFound[0])
+ .isRegionVacant(spaceFound[1], spaceFound[2], 2, 3));
}
@Test
@@ -94,11 +95,11 @@
setupWorkspaceWithHoles(1, 1, new Rect(2, 0, 5, 2), new Rect(0, 2, 2, 5));
commitScreensToDb();
- ArrayList<Long> oldScreens = new ArrayList<>(existingScreens);
- Pair<Long, int[]> spaceFound = newTask()
+ IntArray oldScreens = existingScreens.clone();
+ int[] spaceFound = newTask()
.findSpaceForItem(appState, bgDataModel, existingScreens, newScreens, 3, 3);
- assertFalse(oldScreens.contains(spaceFound.first));
- assertTrue(newScreens.contains(spaceFound.first));
+ assertFalse(oldScreens.contains(spaceFound[0]));
+ assertTrue(newScreens.contains(spaceFound[0]));
}
@Test
@@ -132,7 +133,7 @@
// only info2 should be added because info was already added to the workspace
// in setupWorkspaceWithHoles()
- verify(callbacks).bindAppsAdded(any(ArrayList.class), notAnimated.capture(),
+ verify(callbacks).bindAppsAdded(any(IntArray.class), notAnimated.capture(),
animated.capture());
assertTrue(notAnimated.getValue().isEmpty());
@@ -140,7 +141,7 @@
assertTrue(animated.getValue().contains(info2));
}
- private int setupWorkspaceWithHoles(int startId, long screenId, Rect... holes) {
+ private int setupWorkspaceWithHoles(int startId, int screenId, Rect... holes) {
GridOccupancy occupancy = new GridOccupancy(idp.numColumns, idp.numRows);
occupancy.markCells(0, 0, idp.numColumns, idp.numRows, true);
for (Rect r : holes) {
@@ -170,7 +171,7 @@
}
private void commitScreensToDb() throws Exception {
- LauncherSettings.Settings.call(mProviderRule.getResolver(),
+ LauncherSettings.Settings.call(targetContext.getContentResolver(),
LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
@@ -180,11 +181,11 @@
int count = existingScreens.size();
for (int i = 0; i < count; i++) {
ContentValues v = new ContentValues();
- long screenId = existingScreens.get(i);
+ int screenId = existingScreens.get(i);
v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());
}
- mProviderRule.getResolver().applyBatch(LauncherProvider.AUTHORITY, ops);
+ targetContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, ops);
}
}
diff --git a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
similarity index 82%
rename from tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
rename to robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
index b217847..92d065e 100644
--- a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
+++ b/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
@@ -7,25 +7,17 @@
import static org.mockito.Mockito.when;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
-import android.content.pm.LauncherActivityInfo;
-import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Color;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.NonNull;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.provider.ProviderTestRule;
import com.android.launcher3.AllAppsList;
import com.android.launcher3.AppFilter;
import com.android.launcher3.AppInfo;
-import com.android.launcher3.IconCache;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
@@ -33,14 +25,19 @@
import com.android.launcher3.LauncherModel.Callbacks;
import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.LauncherProvider;
-import com.android.launcher3.graphics.BitmapInfo;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.icons.cache.CachingLogic;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.Provider;
import com.android.launcher3.util.TestLauncherProvider;
import org.junit.Before;
-import org.junit.Rule;
import org.mockito.ArgumentCaptor;
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowContentResolver;
+import org.robolectric.shadows.ShadowLog;
import java.io.BufferedReader;
import java.io.InputStreamReader;
@@ -49,17 +46,15 @@
import java.util.List;
import java.util.concurrent.Executor;
+import androidx.annotation.NonNull;
+
/**
* Base class for writing tests for Model update tasks.
*/
public class BaseModelUpdateTaskTestCase {
- @Rule
- public ProviderTestRule mProviderRule =
- new ProviderTestRule.Builder(TestLauncherProvider.class, LauncherProvider.AUTHORITY)
- .build();
-
public final HashMap<Class, HashMap<String, Field>> fieldCache = new HashMap<>();
+ private TestLauncherProvider mProvider;
public Context targetContext;
public UserHandle myUser;
@@ -76,6 +71,11 @@
@Before
public void setUp() throws Exception {
+ ShadowLog.stream = System.out;
+
+ mProvider = Robolectric.setupContentProvider(TestLauncherProvider.class);
+ ShadowContentResolver.registerProviderInternal(LauncherProvider.AUTHORITY, mProvider);
+
callbacks = mock(Callbacks.class);
appState = mock(LauncherAppState.class);
model = mock(LauncherModel.class);
@@ -88,12 +88,8 @@
myUser = Process.myUserHandle();
bgDataModel = new BgDataModel();
- targetContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()) {
- @Override
- public ContentResolver getContentResolver() {
- return mProviderRule.getResolver();
- }
- };
+ targetContext = RuntimeEnvironment.application;
+
idp = new InvariantDeviceProfile();
iconCache = new MyIconCache(targetContext, idp);
@@ -102,7 +98,6 @@
when(appState.getIconCache()).thenReturn(iconCache);
when(appState.getInvariantDeviceProfile()).thenReturn(idp);
when(appState.getContext()).thenReturn(targetContext);
-
}
/**
@@ -125,11 +120,8 @@
* Initializes mock data for the test.
*/
public void initializeData(String resourceName) throws Exception {
- Context myContext = InstrumentationRegistry.getContext();
- Resources res = myContext.getResources();
- int id = res.getIdentifier(resourceName, "raw", myContext.getPackageName());
- try (BufferedReader reader =
- new BufferedReader(new InputStreamReader(res.openRawResource(id)))) {
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(
+ this.getClass().getResourceAsStream(resourceName)))) {
String line;
HashMap<String, Class> classMap = new HashMap<>();
while((line = reader.readLine()) != null) {
@@ -202,10 +194,11 @@
}
@Override
- protected CacheEntry cacheLocked(
+ protected <T> CacheEntry cacheLocked(
@NonNull ComponentName componentName,
- @NonNull Provider<LauncherActivityInfo> infoProvider,
- UserHandle user, boolean usePackageIcon, boolean useLowResIcon) {
+ UserHandle user, @NonNull Provider<T> infoProvider,
+ @NonNull CachingLogic<T> cachingLogic,
+ boolean usePackageIcon, boolean useLowResIcon) {
CacheEntry entry = mCache.get(new ComponentKey(componentName, user));
if (entry == null) {
entry = new CacheEntry();
@@ -225,10 +218,5 @@
public Bitmap newIcon() {
return Bitmap.createBitmap(1, 1, Config.ARGB_8888);
}
-
- @Override
- protected BitmapInfo makeDefaultIcon(UserHandle user) {
- return BitmapInfo.fromBitmap(newIcon());
- }
}
}
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
similarity index 89%
rename from tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
rename to robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index ac9d319..f17eac7 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -1,6 +1,10 @@
package com.android.launcher3.model;
-import android.support.test.runner.AndroidJUnit4;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
import com.android.launcher3.AppInfo;
import com.android.launcher3.ItemInfo;
@@ -9,27 +13,22 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
import java.util.Arrays;
import java.util.HashSet;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-
/**
* Tests for {@link CacheDataUpdatedTask}
*/
-@RunWith(AndroidJUnit4.class)
+@RunWith(RobolectricTestRunner.class)
public class CacheDataUpdatedTaskTest extends BaseModelUpdateTaskTestCase {
private static final String NEW_LABEL_PREFIX = "new-label-";
@Before
public void initData() throws Exception {
- initializeData("cache_data_updated_task_data");
+ initializeData("/cache_data_updated_task_data.txt");
// Add dummy entries in the cache to simulate update
for (ItemInfo info : bgDataModel.itemsIdMap) {
iconCache.addCache(info.getTargetComponent(), NEW_LABEL_PREFIX + info.id);
@@ -51,7 +50,7 @@
// Verify that only the app icons of app1 (id 1 & 2) are updated. Custom shortcut (id 7)
// is not updated
- verifyUpdate(1L, 2L);
+ verifyUpdate(1, 2);
// Verify that only app1 var updated in allAppsList
assertFalse(allAppsList.data.isEmpty());
@@ -78,11 +77,11 @@
// app3 has only restored apps (id 5, 6) and shortcuts (id 9). Verify that only apps were
// were updated
- verifyUpdate(5L, 6L);
+ verifyUpdate(5, 6);
}
- private void verifyUpdate(Long... idsUpdated) {
- HashSet<Long> updates = new HashSet<>(Arrays.asList(idsUpdated));
+ private void verifyUpdate(Integer... idsUpdated) {
+ HashSet<Integer> updates = new HashSet<>(Arrays.asList(idsUpdated));
for (ItemInfo info : bgDataModel.itemsIdMap) {
if (updates.contains(info.id)) {
assertEquals(NEW_LABEL_PREFIX + info.id, info.title);
diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
similarity index 77%
rename from tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
rename to robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
index b92f612..67580dd 100644
--- a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
@@ -1,82 +1,73 @@
package com.android.launcher3.model;
-import android.content.ContentResolver;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
import android.content.ContentValues;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Point;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.provider.ProviderTestRule;
-import android.support.test.runner.AndroidJUnit4;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherProvider;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.config.FlagOverrideRule;
+import com.android.launcher3.config.FlagOverrideRule.FlagOverride;
import com.android.launcher3.model.GridSizeMigrationTask.MultiStepMigrationTask;
+import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.TestLauncherProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowContentResolver;
-import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
/**
* Unit tests for {@link GridSizeMigrationTask}
*/
-@MediumTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(RobolectricTestRunner.class)
public class GridSizeMigrationTaskTest {
- @Rule
- public ProviderTestRule mProviderRule =
- new ProviderTestRule.Builder(TestLauncherProvider.class, LauncherProvider.AUTHORITY)
- .build();
-
- private static final long DESKTOP = LauncherSettings.Favorites.CONTAINER_DESKTOP;
- private static final long HOTSEAT = LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+ private static final int DESKTOP = LauncherSettings.Favorites.CONTAINER_DESKTOP;
+ private static final int HOTSEAT = LauncherSettings.Favorites.CONTAINER_HOTSEAT;
private static final int APPLICATION = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
private static final int SHORTCUT = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
private static final String TEST_PACKAGE = "com.android.launcher3.validpackage";
- private static final String VALID_INTENT =
- new Intent(Intent.ACTION_MAIN).setPackage(TEST_PACKAGE).toUri(0);
+
+ @Rule
+ public final FlagOverrideRule flags = new FlagOverrideRule();
private HashSet<String> mValidPackages;
private InvariantDeviceProfile mIdp;
private Context mContext;
+ private TestLauncherProvider mProvider;
@Before
- public void setUp() throws Exception {
+ public void setUp() {
+
mValidPackages = new HashSet<>();
mValidPackages.add(TEST_PACKAGE);
-
mIdp = new InvariantDeviceProfile();
+ mContext = RuntimeEnvironment.application;
- mContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()) {
-
- @Override
- public ContentResolver getContentResolver() {
- return mProviderRule.getResolver();
- }
- };
+ mProvider = Robolectric.setupContentProvider(TestLauncherProvider.class);
+ ShadowContentResolver.registerProviderInternal(LauncherProvider.AUTHORITY, mProvider);
}
@Test
public void testHotseatMigration_apps_dropped() throws Exception {
- long[] hotseatItems = {
+ int[] hotseatItems = {
addItem(APPLICATION, 0, HOTSEAT, 0, 0),
addItem(SHORTCUT, 1, HOTSEAT, 0, 0),
-1,
@@ -87,18 +78,13 @@
mIdp.numHotseatIcons = 3;
new GridSizeMigrationTask(mContext, mIdp, mValidPackages, 5, 3)
.migrateHotseat();
- if (FeatureFlags.NO_ALL_APPS_ICON) {
- // First item is dropped as it has the least weight.
- verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
- } else {
- // First & last items are dropped as they have the least weight.
- verifyHotseat(hotseatItems[1], -1, hotseatItems[3]);
- }
+ // First item is dropped as it has the least weight.
+ verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
}
@Test
public void testHotseatMigration_shortcuts_dropped() throws Exception {
- long[] hotseatItems = {
+ int[] hotseatItems = {
addItem(APPLICATION, 0, HOTSEAT, 0, 0),
addItem(30, 1, HOTSEAT, 0, 0),
-1,
@@ -109,21 +95,16 @@
mIdp.numHotseatIcons = 3;
new GridSizeMigrationTask(mContext, mIdp, mValidPackages, 5, 3)
.migrateHotseat();
- if (FeatureFlags.NO_ALL_APPS_ICON) {
- // First item is dropped as it has the least weight.
- verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
- } else {
- // First & third items are dropped as they have the least weight.
- verifyHotseat(hotseatItems[1], -1, hotseatItems[4]);
- }
+ // First item is dropped as it has the least weight.
+ verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
}
- private void verifyHotseat(long... sortedIds) {
+ private void verifyHotseat(int... sortedIds) {
int screenId = 0;
int total = 0;
- for (long id : sortedIds) {
- Cursor c = mProviderRule.getResolver().query(LauncherSettings.Favorites.CONTENT_URI,
+ for (int id : sortedIds) {
+ Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
new String[]{LauncherSettings.Favorites._ID},
"container=-101 and screen=" + screenId, null, null, null);
@@ -141,7 +122,7 @@
}
// Verify that not other entry exist in the DB.
- Cursor c = mProviderRule.getResolver().query(LauncherSettings.Favorites.CONTENT_URI,
+ Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
new String[]{LauncherSettings.Favorites._ID},
"container=-101", null, null, null);
assertEquals(total, c.getCount());
@@ -150,7 +131,7 @@
@Test
public void testWorkspace_empty_row_column_removed() throws Exception {
- long[][][] ids = createGrid(new int[][][]{{
+ int[][][] ids = createGrid(new int[][][]{{
{ 0, 0, -1, 1},
{ 3, 1, -1, 4},
{ -1, -1, -1, -1},
@@ -161,7 +142,7 @@
new Point(4, 4), new Point(3, 3)).migrateWorkspace();
// Column 2 and row 2 got removed.
- verifyWorkspace(new long[][][] {{
+ verifyWorkspace(new int[][][] {{
{ids[0][0][0], ids[0][0][1], ids[0][0][3]},
{ids[0][1][0], ids[0][1][1], ids[0][1][3]},
{ids[0][3][0], ids[0][3][1], ids[0][3][3]},
@@ -170,7 +151,7 @@
@Test
public void testWorkspace_new_screen_created() throws Exception {
- long[][][] ids = createGrid(new int[][][]{{
+ int[][][] ids = createGrid(new int[][][]{{
{ 0, 0, 0, 1},
{ 3, 1, 0, 4},
{ -1, -1, -1, -1},
@@ -181,7 +162,7 @@
new Point(4, 4), new Point(3, 3)).migrateWorkspace();
// Items in the second column get moved to new screen
- verifyWorkspace(new long[][][] {{
+ verifyWorkspace(new int[][][] {{
{ids[0][0][0], ids[0][0][1], ids[0][0][3]},
{ids[0][1][0], ids[0][1][1], ids[0][1][3]},
{ids[0][3][0], ids[0][3][1], ids[0][3][3]},
@@ -192,7 +173,7 @@
@Test
public void testWorkspace_items_merged_in_next_screen() throws Exception {
- long[][][] ids = createGrid(new int[][][]{{
+ int[][][] ids = createGrid(new int[][][]{{
{ 0, 0, 0, 1},
{ 3, 1, 0, 4},
{ -1, -1, -1, -1},
@@ -207,7 +188,7 @@
// Items in the second column of the first screen should get placed on the 3rd
// row of the second screen
- verifyWorkspace(new long[][][] {{
+ verifyWorkspace(new int[][][] {{
{ids[0][0][0], ids[0][0][1], ids[0][0][3]},
{ids[0][1][0], ids[0][1][1], ids[0][1][3]},
{ids[0][3][0], ids[0][3][1], ids[0][3][3]},
@@ -222,7 +203,7 @@
public void testWorkspace_items_not_merged_in_next_screen() throws Exception {
// First screen has 2 items that need to be moved, but second screen has only one
// empty space after migration (top-left corner)
- long[][][] ids = createGrid(new int[][][]{{
+ int[][][] ids = createGrid(new int[][][]{{
{ 0, 0, 0, 1},
{ 3, 1, 0, 4},
{ -1, -1, -1, -1},
@@ -238,7 +219,7 @@
new Point(4, 4), new Point(3, 3)).migrateWorkspace();
// Items in the second column of the first screen should get placed on a new screen.
- verifyWorkspace(new long[][][] {{
+ verifyWorkspace(new int[][][] {{
{ids[0][0][0], ids[0][0][1], ids[0][0][3]},
{ids[0][1][0], ids[0][1][1], ids[0][1][3]},
{ids[0][3][0], ids[0][3][1], ids[0][3][3]},
@@ -251,11 +232,12 @@
}});
}
+ @FlagOverride(key = "QSB_ON_FIRST_SCREEN", value = true)
@Test
public void testWorkspace_first_row_blocked() throws Exception {
// The first screen has one item on the 4th column which needs moving, as the first row
// will be kept empty.
- long[][][] ids = createGrid(new int[][][]{{
+ int[][][] ids = createGrid(new int[][][]{{
{ -1, -1, -1, -1},
{ 3, 1, 7, 0},
{ 8, 7, 7, -1},
@@ -266,7 +248,7 @@
new Point(4, 4), new Point(3, 4)).migrateWorkspace();
// Items in the second column of the first screen should get placed on a new screen.
- verifyWorkspace(new long[][][] {{
+ verifyWorkspace(new int[][][] {{
{ -1, -1, -1},
{ids[0][1][0], ids[0][1][1], ids[0][1][2]},
{ids[0][2][0], ids[0][2][1], ids[0][2][2]},
@@ -276,10 +258,11 @@
}});
}
+ @FlagOverride(key = "QSB_ON_FIRST_SCREEN", value = true)
@Test
public void testWorkspace_items_moved_to_empty_first_row() throws Exception {
// Items will get moved to the next screen to keep the first screen empty.
- long[][][] ids = createGrid(new int[][][]{{
+ int[][][] ids = createGrid(new int[][][]{{
{ -1, -1, -1, -1},
{ 0, 1, 0, 0},
{ 8, 7, 7, -1},
@@ -290,7 +273,7 @@
new Point(4, 4), new Point(3, 3)).migrateWorkspace();
// Items in the second column of the first screen should get placed on a new screen.
- verifyWorkspace(new long[][][] {{
+ verifyWorkspace(new int[][][] {{
{ -1, -1, -1},
{ids[0][2][0], ids[0][2][1], ids[0][2][2]},
{ids[0][3][0], ids[0][3][1], ids[0][3][2]},
@@ -300,7 +283,7 @@
}});
}
- private long[][][] createGrid(int[][][] typeArray) throws Exception {
+ private int[][][] createGrid(int[][][] typeArray) throws Exception {
return createGrid(typeArray, 1);
}
@@ -311,27 +294,27 @@
* two represent the workspace grid.
* @return the same grid representation where each entry is the corresponding item id.
*/
- private long[][][] createGrid(int[][][] typeArray, long startScreen) throws Exception {
- LauncherSettings.Settings.call(mProviderRule.getResolver(),
+ private int[][][] createGrid(int[][][] typeArray, int startScreen) throws Exception {
+ LauncherSettings.Settings.call(mContext.getContentResolver(),
LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
- long[][][] ids = new long[typeArray.length][][];
+ int[][][] ids = new int[typeArray.length][][];
for (int i = 0; i < typeArray.length; i++) {
// Add screen to DB
- long screenId = startScreen + i;
+ int screenId = startScreen + i;
// Keep the screen id counter up to date
- LauncherSettings.Settings.call(mProviderRule.getResolver(),
+ LauncherSettings.Settings.call(mContext.getContentResolver(),
LauncherSettings.Settings.METHOD_NEW_SCREEN_ID);
ContentValues v = new ContentValues();
v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
- mProviderRule.getResolver().insert(LauncherSettings.WorkspaceScreens.CONTENT_URI, v);
+ mContext.getContentResolver().insert(LauncherSettings.WorkspaceScreens.CONTENT_URI, v);
- ids[i] = new long[typeArray[i].length][];
+ ids[i] = new int[typeArray[i].length][];
for (int y = 0; y < typeArray[i].length; y++) {
- ids[i][y] = new long[typeArray[i][y].length];
+ ids[i][y] = new int[typeArray[i][y].length];
for (int x = 0; x < typeArray[i][y].length; x++) {
if (typeArray[i][y][x] < 0) {
// Empty cell
@@ -342,6 +325,8 @@
}
}
}
+
+ IntArray allScreens = LauncherModel.loadWorkspaceScreensDb(mContext);
return ids;
}
@@ -350,18 +335,18 @@
* @param ids A 3d array where the first dimension represents the screen, and the rest two
* represent the workspace grid.
*/
- private void verifyWorkspace(long[][][] ids) {
- ArrayList<Long> allScreens = LauncherModel.loadWorkspaceScreensDb(mContext);
+ private void verifyWorkspace(int[][][] ids) {
+ IntArray allScreens = LauncherModel.loadWorkspaceScreensDb(mContext);
assertEquals(ids.length, allScreens.size());
int total = 0;
for (int i = 0; i < ids.length; i++) {
- long screenId = allScreens.get(i);
+ int screenId = allScreens.get(i);
for (int y = 0; y < ids[i].length; y++) {
for (int x = 0; x < ids[i][y].length; x++) {
- long id = ids[i][y][x];
+ int id = ids[i][y][x];
- Cursor c = mProviderRule.getResolver().query(
+ Cursor c = mContext.getContentResolver().query(
LauncherSettings.Favorites.CONTENT_URI,
new String[]{LauncherSettings.Favorites._ID},
"container=-100 and screen=" + screenId +
@@ -381,7 +366,7 @@
}
// Verify that not other entry exist in the DB.
- Cursor c = mProviderRule.getResolver().query(LauncherSettings.Favorites.CONTENT_URI,
+ Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
new String[]{LauncherSettings.Favorites._ID},
"container=-100", null, null, null);
assertEquals(total, c.getCount());
@@ -393,10 +378,10 @@
* @param type {@link #APPLICATION} or {@link #SHORTCUT} or >= 2 for
* folder (where the type represents the number of items in the folder).
*/
- private long addItem(int type, long screen, long container, int x, int y) throws Exception {
- long id = LauncherSettings.Settings.call(mProviderRule.getResolver(),
+ private int addItem(int type, int screen, int container, int x, int y) throws Exception {
+ int id = LauncherSettings.Settings.call(mContext.getContentResolver(),
LauncherSettings.Settings.METHOD_NEW_ITEM_ID)
- .getLong(LauncherSettings.Settings.EXTRA_VALUE);
+ .getInt(LauncherSettings.Settings.EXTRA_VALUE);
ContentValues values = new ContentValues();
values.put(LauncherSettings.Favorites._ID, id);
@@ -409,7 +394,8 @@
if (type == APPLICATION || type == SHORTCUT) {
values.put(LauncherSettings.Favorites.ITEM_TYPE, type);
- values.put(LauncherSettings.Favorites.INTENT, VALID_INTENT);
+ values.put(LauncherSettings.Favorites.INTENT,
+ new Intent(Intent.ACTION_MAIN).setPackage(TEST_PACKAGE).toUri(0));
} else {
values.put(LauncherSettings.Favorites.ITEM_TYPE,
LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
@@ -419,7 +405,7 @@
}
}
- mProviderRule.getResolver().insert(LauncherSettings.Favorites.CONTENT_URI, values);
+ mContext.getContentResolver().insert(LauncherSettings.Favorites.CONTENT_URI, values);
return id;
}
diff --git a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
similarity index 82%
rename from tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
rename to robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
index 0a741c4..c7b4613 100644
--- a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
@@ -1,6 +1,6 @@
package com.android.launcher3.model;
-import android.support.test.runner.AndroidJUnit4;
+import static org.junit.Assert.assertEquals;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppWidgetInfo;
@@ -11,21 +11,20 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
import java.util.Arrays;
import java.util.HashSet;
-import static org.junit.Assert.assertEquals;
-
/**
* Tests for {@link PackageInstallStateChangedTask}
*/
-@RunWith(AndroidJUnit4.class)
+@RunWith(RobolectricTestRunner.class)
public class PackageInstallStateChangedTaskTest extends BaseModelUpdateTaskTestCase {
@Before
public void initData() throws Exception {
- initializeData("package_install_state_change_task_data");
+ initializeData("/package_install_state_change_task_data.txt");
}
private PackageInstallStateChangedTask newTask(String pkg, int progress) {
@@ -46,18 +45,18 @@
public void testSessionUpdate_shortcuts_updated() throws Exception {
executeTaskForTest(newTask("app3", 30));
- verifyProgressUpdate(30, 5L, 6L, 7L);
+ verifyProgressUpdate(30, 5, 6, 7);
}
@Test
public void testSessionUpdate_widgets_updated() throws Exception {
executeTaskForTest(newTask("app4", 30));
- verifyProgressUpdate(30, 8L, 9L);
+ verifyProgressUpdate(30, 8, 9);
}
- private void verifyProgressUpdate(int progress, Long... idsUpdated) {
- HashSet<Long> updates = new HashSet<>(Arrays.asList(idsUpdated));
+ private void verifyProgressUpdate(int progress, Integer... idsUpdated) {
+ HashSet<Integer> updates = new HashSet<>(Arrays.asList(idsUpdated));
for (ItemInfo info : bgDataModel.itemsIdMap) {
if (info instanceof ShortcutInfo) {
assertEquals(updates.contains(info.id) ? progress: 0,
diff --git a/tests/src/com/android/launcher3/util/GridOccupancyTest.java b/robolectric_tests/src/com/android/launcher3/util/GridOccupancyTest.java
similarity index 91%
rename from tests/src/com/android/launcher3/util/GridOccupancyTest.java
rename to robolectric_tests/src/com/android/launcher3/util/GridOccupancyTest.java
index fdd8e88..aa51ad2 100644
--- a/tests/src/com/android/launcher3/util/GridOccupancyTest.java
+++ b/robolectric_tests/src/com/android/launcher3/util/GridOccupancyTest.java
@@ -1,10 +1,8 @@
package com.android.launcher3.util;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -13,8 +11,7 @@
/**
* Unit tests for {@link GridOccupancy}
*/
-@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(RobolectricTestRunner.class)
public class GridOccupancyTest {
@Test
@@ -24,7 +21,7 @@
0, 0, 1, 1, 0,
0, 0, 0, 0, 0,
1, 1, 0, 0, 0
- );
+ );
int[] vacant = new int[2];
assertTrue(grid.findVacantCell(vacant, 2, 2));
diff --git a/robolectric_tests/src/com/android/launcher3/util/IntSetTest.java b/robolectric_tests/src/com/android/launcher3/util/IntSetTest.java
new file mode 100644
index 0000000..8513353
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/util/IntSetTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.robolectric.RobolectricTestRunner;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Robolectric unit tests for {@link IntSet}
+ */
+@RunWith(RobolectricTestRunner.class)
+public class IntSetTest {
+
+ @Test
+ public void shouldBeEmptyInitially() {
+ IntSet set = new IntSet();
+ assertThat(set.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void oneElementSet() {
+ IntSet set = new IntSet();
+ set.add(2);
+ assertThat(set.size()).isEqualTo(1);
+ assertTrue(set.contains(2));
+ assertFalse(set.contains(1));
+ }
+
+
+ @Test
+ public void twoElementSet() {
+ IntSet set = new IntSet();
+ set.add(2);
+ set.add(1);
+ assertThat(set.size()).isEqualTo(2);
+ assertTrue(set.contains(2));
+ assertTrue(set.contains(1));
+ }
+
+ @Test
+ public void threeElementSet() {
+ IntSet set = new IntSet();
+ set.add(2);
+ set.add(1);
+ set.add(10);
+ assertThat(set.size()).isEqualTo(3);
+ assertEquals("1, 2, 10", set.mArray.toConcatString());
+ }
+
+
+ @Test
+ public void duplicateEntries() {
+ IntSet set = new IntSet();
+ set.add(2);
+ set.add(2);
+ assertEquals(1, set.size());
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/TestLauncherProvider.java b/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java
similarity index 90%
rename from tests/src/com/android/launcher3/util/TestLauncherProvider.java
rename to robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java
index 1d6c18b..32808f5 100644
--- a/tests/src/com/android/launcher3/util/TestLauncherProvider.java
+++ b/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java
@@ -23,11 +23,6 @@
}
}
- public SQLiteOpenHelper getHelper() {
- createDbIfNotExists();
- return mOpenHelper;
- }
-
@Override
protected void notifyListeners() { }
@@ -48,4 +43,4 @@
@Override
protected void handleOneTimeDataUpgrade(SQLiteDatabase db) { }
}
-}
\ No newline at end of file
+}
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..b52bd4f
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,2 @@
+include ':IconLoader'
+project(':IconLoader').projectDir = new File(rootDir, 'iconloaderlib')
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index daf2032..7cab18d 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -19,13 +19,11 @@
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
-
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import android.annotation.SuppressLint;
import android.content.Context;
-import android.support.annotation.IntDef;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.MotionEvent;
@@ -34,11 +32,14 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import androidx.annotation.IntDef;
+
/**
* Base class for a View which shows a floating UI on top of the launcher UI.
*/
@@ -52,6 +53,7 @@
TYPE_WIDGETS_FULL_SHEET,
TYPE_ON_BOARD_POPUP,
TYPE_DISCOVERY_BOUNCE,
+ TYPE_SNACKBAR,
TYPE_QUICKSTEP_PREVIEW,
TYPE_TASK_MENU,
@@ -66,25 +68,33 @@
public static final int TYPE_WIDGETS_FULL_SHEET = 1 << 4;
public static final int TYPE_ON_BOARD_POPUP = 1 << 5;
public static final int TYPE_DISCOVERY_BOUNCE = 1 << 6;
+ public static final int TYPE_SNACKBAR = 1 << 7;
// Popups related to quickstep UI
- public static final int TYPE_QUICKSTEP_PREVIEW = 1 << 6;
- public static final int TYPE_TASK_MENU = 1 << 7;
- public static final int TYPE_OPTIONS_POPUP = 1 << 8;
+ public static final int TYPE_QUICKSTEP_PREVIEW = 1 << 8;
+ public static final int TYPE_TASK_MENU = 1 << 9;
+ public static final int TYPE_OPTIONS_POPUP = 1 << 10;
public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
| TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU
- | TYPE_OPTIONS_POPUP;
+ | TYPE_OPTIONS_POPUP | TYPE_SNACKBAR;
// Type of popups which should be kept open during launcher rebind
public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
| TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE;
// Usually we show the back button when a floating view is open. Instead, hide for these types.
- public static final int TYPE_HIDE_BACK_BUTTON = TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE;
+ public static final int TYPE_HIDE_BACK_BUTTON = TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
+ | TYPE_SNACKBAR;
- public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE;
+ public static final int TYPE_ACCESSIBLE = TYPE_ALL
+ & ~TYPE_DISCOVERY_BOUNCE & ~TYPE_QUICKSTEP_PREVIEW;
+
+ // These view all have particular operation associated with swipe down interaction.
+ public static final int TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW = TYPE_WIDGETS_BOTTOM_SHEET |
+ TYPE_WIDGETS_FULL_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_ON_BOARD_POPUP |
+ TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU ;
protected boolean mIsOpen;
@@ -151,7 +161,7 @@
if (mIsOpen) {
sendAccessibilityEvent(TYPE_VIEW_FOCUSED);
}
- BaseDraggingActivity.fromContext(getContext()).getDragLayer()
+ ActivityContext.lookupContext(getContext()).getDragLayer()
.sendAccessibilityEvent(TYPE_WINDOW_CONTENT_CHANGED);
}
@@ -160,7 +170,7 @@
}
protected static <T extends AbstractFloatingView> T getOpenView(
- BaseDraggingActivity activity, @FloatingViewType int type) {
+ ActivityContext activity, @FloatingViewType int type) {
BaseDragLayer dragLayer = activity.getDragLayer();
// Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
// and will be one of the last views.
@@ -176,7 +186,7 @@
return null;
}
- public static void closeOpenContainer(BaseDraggingActivity activity,
+ public static void closeOpenContainer(ActivityContext activity,
@FloatingViewType int type) {
AbstractFloatingView view = getOpenView(activity, type);
if (view != null) {
@@ -184,7 +194,7 @@
}
}
- public static void closeOpenViews(BaseDraggingActivity activity, boolean animate,
+ public static void closeOpenViews(ActivityContext activity, boolean animate,
@FloatingViewType int type) {
BaseDragLayer dragLayer = activity.getDragLayer();
// Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
@@ -200,20 +210,31 @@
}
}
- public static void closeAllOpenViews(BaseDraggingActivity activity, boolean animate) {
+ public static void closeAllOpenViews(ActivityContext activity, boolean animate) {
closeOpenViews(activity, animate, TYPE_ALL);
activity.finishAutoCancelActionMode();
}
- public static void closeAllOpenViews(BaseDraggingActivity activity) {
+ public static void closeAllOpenViews(ActivityContext activity) {
closeAllOpenViews(activity, true);
}
- public static AbstractFloatingView getTopOpenView(BaseDraggingActivity activity) {
+ public static void closeAllOpenViewsExcept(ActivityContext activity, boolean animate,
+ @FloatingViewType int type) {
+ closeOpenViews(activity, animate, TYPE_ALL & ~type);
+ activity.finishAutoCancelActionMode();
+ }
+
+ public static void closeAllOpenViewsExcept(ActivityContext activity,
+ @FloatingViewType int type) {
+ closeAllOpenViewsExcept(activity, true, type);
+ }
+
+ public static AbstractFloatingView getTopOpenView(ActivityContext activity) {
return getTopOpenViewWithType(activity, TYPE_ALL);
}
- public static AbstractFloatingView getTopOpenViewWithType(BaseDraggingActivity activity,
+ public static AbstractFloatingView getTopOpenViewWithType(ActivityContext activity,
@FloatingViewType int type) {
return getOpenView(activity, type);
}
diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java
index 5eb6cc7..733f295 100644
--- a/src/com/android/launcher3/AllAppsList.java
+++ b/src/com/android/launcher3/AllAppsList.java
@@ -22,12 +22,11 @@
import android.content.pm.LauncherActivityInfo;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.util.Log;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -35,6 +34,9 @@
import java.util.HashSet;
import java.util.List;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
/**
* Stores the list of all applications for the all apps view.
@@ -91,7 +93,7 @@
// only if not yet installed
if (applicationInfo == null) {
PromiseAppInfo info = new PromiseAppInfo(installInfo);
- mIconCache.getTitleAndIcon(info, info.usingLowResIcon);
+ mIconCache.getTitleAndIcon(info, info.usingLowResIcon());
data.add(info);
added.add(info);
}
@@ -185,7 +187,7 @@
if (user.equals(applicationInfo.user)
&& packageName.equals(applicationInfo.componentName.getPackageName())) {
if (!findActivity(matches, applicationInfo.componentName)) {
- Log.w(TAG, "Shortcut will be removed due to app component name change.");
+ Log.w(TAG, "Changing shortcut target due to app component name change.");
removed.add(applicationInfo);
data.remove(i);
}
diff --git a/src/com/android/launcher3/AppFilter.java b/src/com/android/launcher3/AppFilter.java
index 923835a..9b6166f 100644
--- a/src/com/android/launcher3/AppFilter.java
+++ b/src/com/android/launcher3/AppFilter.java
@@ -3,10 +3,12 @@
import android.content.ComponentName;
import android.content.Context;
-public class AppFilter {
+import com.android.launcher3.util.ResourceBasedOverride;
+
+public class AppFilter implements ResourceBasedOverride {
public static AppFilter newInstance(Context context) {
- return Utilities.getOverrideObject(AppFilter.class, context, R.string.app_filter_class);
+ return Overrides.getObject(AppFilter.class, context, R.string.app_filter_class);
}
public boolean shouldShowApp(ComponentName app) {
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index 4d1bedc..ed79914 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -26,7 +26,6 @@
import android.os.UserHandle;
import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageManagerHelper;
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 7648e30..8e2ffe9 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -1,10 +1,13 @@
package com.android.launcher3;
+import static com.android.launcher3.LauncherAnimUtils.LAYOUT_HEIGHT;
+import static com.android.launcher3.LauncherAnimUtils.LAYOUT_WIDTH;
+import static com.android.launcher3.views.BaseDragLayer.LAYOUT_X;
+import static com.android.launcher3.views.BaseDragLayer.LAYOUT_Y;
+
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
@@ -39,6 +42,7 @@
private final Launcher mLauncher;
private final DragViewStateAnnouncer mStateAnnouncer;
+ private final FirstFrameAnimatorHelper mFirstFrameAnimatorHelper;
private final View[] mDragHandles = new View[HANDLE_COUNT];
@@ -101,6 +105,7 @@
mBackgroundPadding = getResources()
.getDimensionPixelSize(R.dimen.resize_frame_background_padding);
mTouchTargetWidth = 2 * mBackgroundPadding;
+ mFirstFrameAnimatorHelper = new FirstFrameAnimatorHelper(this);
}
@Override
@@ -368,12 +373,7 @@
mDeltaX = 0;
mDeltaY = 0;
- post(new Runnable() {
- @Override
- public void run() {
- snapToWidget(true);
- }
- });
+ post(() -> snapToWidget(true));
}
/**
@@ -433,24 +433,19 @@
}
requestLayout();
} else {
- PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
- PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
- newHeight);
- PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
- PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
- ObjectAnimator oa =
- LauncherAnimUtils.ofPropertyValuesHolder(lp, this, width, height, x, y);
- oa.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- requestLayout();
- }
- });
- AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
+ ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp,
+ PropertyValuesHolder.ofInt(LAYOUT_WIDTH, lp.width, newWidth),
+ PropertyValuesHolder.ofInt(LAYOUT_HEIGHT, lp.height, newHeight),
+ PropertyValuesHolder.ofInt(LAYOUT_X, lp.x, newX),
+ PropertyValuesHolder.ofInt(LAYOUT_Y, lp.y, newY));
+ mFirstFrameAnimatorHelper.addTo(oa).addUpdateListener(a -> requestLayout());
+
+ AnimatorSet set = new AnimatorSet();
set.play(oa);
for (int i = 0; i < HANDLE_COUNT; i++) {
- set.play(LauncherAnimUtils.ofFloat(mDragHandles[i], ALPHA, 1.0f));
+ set.play(mFirstFrameAnimatorHelper.addTo(
+ ObjectAnimator.ofFloat(mDragHandles[i], ALPHA, 1f)));
}
-
set.setDuration(SNAP_DURATION);
set.start();
}
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index b249c95..0250c36 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -9,7 +9,6 @@
import android.content.Intent;
import android.database.Cursor;
import android.os.Handler;
-import android.support.annotation.WorkerThread;
import android.util.Log;
import com.android.launcher3.LauncherSettings.Favorites;
@@ -18,6 +17,8 @@
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.util.ContentWriter;
+import androidx.annotation.WorkerThread;
+
public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
private static final String TAG = "AWRestoredReceiver";
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 469b8bb..e5b1448 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -28,7 +28,6 @@
import android.database.sqlite.SQLiteDatabase;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.Build;
import android.os.Build.VERSION;
import android.os.Bundle;
import android.os.Process;
@@ -37,17 +36,20 @@
import android.util.Log;
import android.util.Pair;
import android.util.Patterns;
+
import com.android.launcher3.LauncherProvider.SqlArguments;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.icons.GraphicsUtils;
+import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.Thunk;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Locale;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.IOException;
+import java.util.Locale;
+
/**
* Layout parsing code for auto installs layout
*/
@@ -162,7 +164,7 @@
private final int mRowCount;
private final int mColumnCount;
- private final long[] mTemp = new long[2];
+ private final int[] mTemp = new int[2];
@Thunk final ContentValues mValues;
protected final String mRootTag;
@@ -190,7 +192,7 @@
/**
* Loads the layout in the db and returns the number of entries added on the desktop.
*/
- public int loadLayout(SQLiteDatabase db, ArrayList<Long> screenIds) {
+ public int loadLayout(SQLiteDatabase db, IntArray screenIds) {
mDb = db;
try {
return parseLayout(mLayoutId, screenIds);
@@ -203,7 +205,7 @@
/**
* Parses the layout and returns the number of elements added on the homescreen.
*/
- protected int parseLayout(int layoutId, ArrayList<Long> screenIds)
+ protected int parseLayout(int layoutId, IntArray screenIds)
throws XmlPullParserException, IOException {
XmlResourceParser parser = mSourceRes.getXml(layoutId);
beginDocument(parser, mRootTag);
@@ -226,16 +228,14 @@
* Parses container and screenId attribute from the current tag, and puts it in the out.
* @param out array of size 2.
*/
- protected void parseContainerAndScreen(XmlResourceParser parser, long[] out) {
+ protected void parseContainerAndScreen(XmlResourceParser parser, int[] out) {
if (HOTSEAT_CONTAINER_NAME.equals(getAttributeValue(parser, ATTR_CONTAINER))) {
out[0] = Favorites.CONTAINER_HOTSEAT;
// Hack: hotseat items are stored using screen ids
- long rank = Long.parseLong(getAttributeValue(parser, ATTR_RANK));
- out[1] = (FeatureFlags.NO_ALL_APPS_ICON || rank < mIdp.getAllAppsButtonRank())
- ? rank : (rank + 1);
+ out[1] = Integer.parseInt(getAttributeValue(parser, ATTR_RANK));
} else {
out[0] = Favorites.CONTAINER_DESKTOP;
- out[1] = Long.parseLong(getAttributeValue(parser, ATTR_SCREEN));
+ out[1] = Integer.parseInt(getAttributeValue(parser, ATTR_SCREEN));
}
}
@@ -243,9 +243,7 @@
* Parses the current node and returns the number of elements added.
*/
protected int parseAndAddNode(
- XmlResourceParser parser,
- ArrayMap<String, TagParser> tagParserMap,
- ArrayList<Long> screenIds)
+ XmlResourceParser parser, ArrayMap<String, TagParser> tagParserMap, IntArray screenIds)
throws XmlPullParserException, IOException {
if (TAG_INCLUDE.equals(parser.getName())) {
@@ -260,8 +258,8 @@
mValues.clear();
parseContainerAndScreen(parser, mTemp);
- final long container = mTemp[0];
- final long screenId = mTemp[1];
+ final int container = mTemp[0];
+ final int screenId = mTemp[1];
mValues.put(Favorites.CONTAINER, container);
mValues.put(Favorites.SCREEN, screenId);
@@ -276,7 +274,7 @@
if (LOGD) Log.d(TAG, "Ignoring unknown element tag: " + parser.getName());
return 0;
}
- long newElementId = tagParser.parseAndAdd(parser);
+ int newElementId = tagParser.parseAndAdd(parser);
if (newElementId >= 0) {
// Keep track of the set of screens which need to be added to the db.
if (!screenIds.contains(screenId) &&
@@ -288,8 +286,8 @@
return 0;
}
- protected long addShortcut(String title, Intent intent, int type) {
- long id = mCallback.generateNewItemId();
+ protected int addShortcut(String title, Intent intent, int type) {
+ int id = mCallback.generateNewItemId();
mValues.put(Favorites.INTENT, intent.toUri(0));
mValues.put(Favorites.TITLE, title);
mValues.put(Favorites.ITEM_TYPE, type);
@@ -326,7 +324,7 @@
* Parses the tag and adds to the db
* @return the id of the row added or -1;
*/
- long parseAndAdd(XmlResourceParser parser)
+ int parseAndAdd(XmlResourceParser parser)
throws XmlPullParserException, IOException;
}
@@ -336,7 +334,7 @@
protected class AppShortcutParser implements TagParser {
@Override
- public long parseAndAdd(XmlResourceParser parser) {
+ public int parseAndAdd(XmlResourceParser parser) {
final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
@@ -373,7 +371,7 @@
/**
* Helper method to allow extending the parser capabilities
*/
- protected long invalidPackageOrClass(XmlResourceParser parser) {
+ protected int invalidPackageOrClass(XmlResourceParser parser) {
Log.w(TAG, "Skipping invalid <favorite> with no component");
return -1;
}
@@ -385,7 +383,7 @@
protected class AutoInstallParser implements TagParser {
@Override
- public long parseAndAdd(XmlResourceParser parser) {
+ public int parseAndAdd(XmlResourceParser parser) {
final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className)) {
@@ -416,7 +414,7 @@
}
@Override
- public long parseAndAdd(XmlResourceParser parser) {
+ public int parseAndAdd(XmlResourceParser parser) {
final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
final int iconId = getAttributeResourceValue(parser, ATTR_ICON, 0);
@@ -438,7 +436,7 @@
// Auto installs should always support the current platform version.
LauncherIcons li = LauncherIcons.obtain(mContext);
- mValues.put(LauncherSettings.Favorites.ICON, Utilities.flattenBitmap(
+ mValues.put(LauncherSettings.Favorites.ICON, GraphicsUtils.flattenBitmap(
li.createBadgedIconBitmap(icon, Process.myUserHandle(), VERSION.SDK_INT).icon));
li.recycle();
@@ -472,7 +470,7 @@
protected class PendingWidgetParser implements TagParser {
@Override
- public long parseAndAdd(XmlResourceParser parser)
+ public int parseAndAdd(XmlResourceParser parser)
throws XmlPullParserException, IOException {
final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
@@ -511,7 +509,7 @@
return verifyAndInsert(new ComponentName(packageName, className), extras);
}
- protected long verifyAndInsert(ComponentName cn, Bundle extras) {
+ protected int verifyAndInsert(ComponentName cn, Bundle extras) {
mValues.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString());
mValues.put(Favorites.RESTORED,
LauncherAppWidgetInfo.FLAG_ID_NOT_VALID |
@@ -522,7 +520,7 @@
mValues.put(Favorites.INTENT, new Intent().putExtras(extras).toUri(0));
}
- long insertedId = mCallback.insertAndCheck(mDb, mValues);
+ int insertedId = mCallback.insertAndCheck(mDb, mValues);
if (insertedId < 0) {
return -1;
} else {
@@ -543,7 +541,7 @@
}
@Override
- public long parseAndAdd(XmlResourceParser parser)
+ public int parseAndAdd(XmlResourceParser parser)
throws XmlPullParserException, IOException {
final String title;
final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
@@ -558,14 +556,14 @@
mValues.put(Favorites.SPANX, 1);
mValues.put(Favorites.SPANY, 1);
mValues.put(Favorites._ID, mCallback.generateNewItemId());
- long folderId = mCallback.insertAndCheck(mDb, mValues);
+ int folderId = mCallback.insertAndCheck(mDb, mValues);
if (folderId < 0) {
if (LOGD) Log.e(TAG, "Unable to add folder");
return -1;
}
final ContentValues myValues = new ContentValues(mValues);
- ArrayList<Long> folderItems = new ArrayList<>();
+ IntArray folderItems = new IntArray();
int type;
int folderDepth = parser.getDepth();
@@ -581,7 +579,7 @@
TagParser tagParser = mFolderElements.get(parser.getName());
if (tagParser != null) {
- final long id = tagParser.parseAndAdd(parser);
+ final int id = tagParser.parseAndAdd(parser);
if (id >= 0) {
folderItems.add(id);
rank++;
@@ -591,7 +589,7 @@
}
}
- long addedId = folderId;
+ int addedId = folderId;
// We can only have folders with >= 2 items, so we need to remove the
// folder and clean up if less than 2 items were included, or some
@@ -676,9 +674,9 @@
}
public interface LayoutParserCallback {
- long generateNewItemId();
+ int generateNewItemId();
- long insertAndCheck(SQLiteDatabase db, ContentValues values);
+ int insertAndCheck(SQLiteDatabase db, ContentValues values);
}
@Thunk static void copyInteger(ContentValues from, ContentValues to, String key) {
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index a4b6f5b..77b6010 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -17,7 +17,6 @@
package com.android.launcher3;
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
-
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.app.Activity;
@@ -25,10 +24,13 @@
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.res.Configuration;
-import android.support.annotation.IntDef;
+import android.view.ContextThemeWrapper;
import android.view.View.AccessibilityDelegate;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
+import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.logging.StatsLogUtils;
+import com.android.launcher3.logging.StatsLogUtils.LogStateProvider;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.logging.UserEventDispatcher.UserEventDelegate;
import com.android.launcher3.uioverrides.UiFactory;
@@ -40,7 +42,9 @@
import java.lang.annotation.Retention;
import java.util.ArrayList;
-public abstract class BaseActivity extends Activity implements UserEventDelegate{
+import androidx.annotation.IntDef;
+
+public abstract class BaseActivity extends Activity implements UserEventDelegate, LogStateProvider{
public static final int INVISIBLE_BY_STATE_HANDLER = 1 << 0;
public static final int INVISIBLE_BY_APP_TRANSITIONS = 1 << 1;
@@ -71,6 +75,7 @@
protected DeviceProfile mDeviceProfile;
protected UserEventDispatcher mUserEventDispatcher;
+ protected StatsLogManager mStatsLogManager;
protected SystemUiController mSystemUiController;
private static final int ACTIVITY_STATE_STARTED = 1 << 0;
@@ -103,11 +108,20 @@
return null;
}
+ public int getCurrentState() { return StatsLogUtils.LAUNCHER_STATE_BACKGROUND; }
+
public void modifyUserEvent(LauncherLogProto.LauncherEvent event) {}
+ public final StatsLogManager getStatsLogManager() {
+ if (mStatsLogManager == null) {
+ mStatsLogManager = StatsLogManager.newInstance(this, this);
+ }
+ return mStatsLogManager;
+ }
+
public final UserEventDispatcher getUserEventDispatcher() {
if (mUserEventDispatcher == null) {
- mUserEventDispatcher = UserEventDispatcher.newInstance(this, mDeviceProfile, this);
+ mUserEventDispatcher = UserEventDispatcher.newInstance(this, this);
}
return mUserEventDispatcher;
}
@@ -116,13 +130,6 @@
return Utilities.ATLEAST_NOUGAT && isInMultiWindowMode();
}
- public static BaseActivity fromContext(Context context) {
- if (context instanceof BaseActivity) {
- return (BaseActivity) context;
- }
- return ((BaseActivity) ((ContextWrapper) context).getBaseContext());
- }
-
public SystemUiController getSystemUiController() {
if (mSystemUiController == null) {
mSystemUiController = new SystemUiController(getWindow());
@@ -259,4 +266,14 @@
writer.println(" mActivityFlags: " + mActivityFlags);
writer.println(" mForceInvisible: " + mForceInvisible);
}
+
+ public static <T extends BaseActivity> T fromContext(Context context) {
+ if (context instanceof BaseActivity) {
+ return (T) context;
+ } else if (context instanceof ContextThemeWrapper) {
+ return fromContext(((ContextWrapper) context).getBaseContext());
+ } else {
+ throw new IllegalArgumentException("Cannot find BaseActivity in parent tree");
+ }
+ }
}
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index eec196e..152dc84 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -18,33 +18,33 @@
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
+import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.Build;
import android.os.Bundle;
import android.os.Process;
import android.os.StrictMode;
import android.os.UserHandle;
import android.util.Log;
import android.view.ActionMode;
-import android.view.Surface;
import android.view.View;
import android.widget.Toast;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.uioverrides.DisplayRotationListener;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.views.ActivityContext;
/**
* Extension of BaseActivity allowing support for drag-n-drop
*/
public abstract class BaseDraggingActivity extends BaseActivity
- implements WallpaperColorInfo.OnChangeListener {
+ implements WallpaperColorInfo.OnChangeListener, ActivityContext {
private static final String TAG = "BaseDraggingActivity";
@@ -83,13 +83,33 @@
@Override
public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) {
+ updateTheme();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ updateTheme();
+ }
+
+ private void updateTheme() {
+ WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);
if (mThemeRes != getThemeRes(wallpaperColorInfo)) {
recreate();
}
}
protected int getThemeRes(WallpaperColorInfo wallpaperColorInfo) {
- if (wallpaperColorInfo.isDark()) {
+ boolean darkTheme;
+ if (Utilities.ATLEAST_Q) {
+ Configuration configuration = getResources().getConfiguration();
+ int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
+ darkTheme = nightMode == Configuration.UI_MODE_NIGHT_YES;
+ } else {
+ darkTheme = wallpaperColorInfo.isDark();
+ }
+
+ if (darkTheme) {
return wallpaperColorInfo.supportsDarkText() ?
R.style.AppTheme_Dark_DarkText : R.style.AppTheme_Dark;
} else {
@@ -110,6 +130,7 @@
mCurrentActionMode = null;
}
+ @Override
public boolean finishAutoCancelActionMode() {
if (mCurrentActionMode != null && AUTO_CANCEL_ACTION_MODE == mCurrentActionMode.getTag()) {
mCurrentActionMode.finish();
@@ -128,13 +149,6 @@
public abstract void invalidateParent(ItemInfo info);
- public static BaseDraggingActivity fromContext(Context context) {
- if (context instanceof BaseDraggingActivity) {
- return (BaseDraggingActivity) context;
- }
- return ((BaseDraggingActivity) ((ContextWrapper) context).getBaseContext());
- }
-
public Rect getViewBounds(View v) {
int[] pos = new int[2];
v.getLocationOnScreen(pos);
@@ -186,6 +200,7 @@
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
}
getUserEventDispatcher().logAppLaunch(v, intent);
+ getStatsLogManager().logAppLaunch(v, intent);
return true;
} catch (ActivityNotFoundException|SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index 74b9cfa..f300ef7 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -17,7 +17,6 @@
package com.android.launcher3;
import android.content.Context;
-import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -25,6 +24,8 @@
import com.android.launcher3.views.RecyclerViewFastScroller;
+import androidx.recyclerview.widget.RecyclerView;
+
/**
* A base {@link RecyclerView}, which does the following:
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index fb7c0ce..455fd18 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -16,6 +16,10 @@
package com.android.launcher3;
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -27,7 +31,6 @@
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.support.v4.graphics.ColorUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.Property;
@@ -39,8 +42,8 @@
import android.view.ViewDebug;
import android.widget.TextView;
-import com.android.launcher3.IconCache.IconLoadRequest;
-import com.android.launcher3.IconCache.ItemInfoUpdateReceiver;
+import com.android.launcher3.icons.IconCache.IconLoadRequest;
+import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.Launcher.OnResumeCallback;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.badge.BadgeRenderer;
@@ -111,10 +114,13 @@
@ViewDebug.ExportedProperty(category = "launcher")
private float mTextAlpha = 1;
+ @ViewDebug.ExportedProperty(category = "launcher")
private BadgeInfo mBadgeInfo;
private BadgeRenderer mBadgeRenderer;
private int mBadgeColor;
+ @ViewDebug.ExportedProperty(category = "launcher")
private float mBadgeScale;
+ private Animator mBadgeScaleAnim;
private boolean mForceHideBadge;
private Point mTempSpaceForBadgeOffset = new Point();
private Rect mTempIconBounds = new Rect();
@@ -187,10 +193,29 @@
public void reset() {
mBadgeInfo = null;
mBadgeColor = Color.TRANSPARENT;
+ cancelBadgeScaleAnim();
mBadgeScale = 0f;
mForceHideBadge = false;
}
+ private void cancelBadgeScaleAnim() {
+ if (mBadgeScaleAnim != null) {
+ mBadgeScaleAnim.cancel();
+ }
+ }
+
+ private void animateBadgeScale(float... badgeScales) {
+ cancelBadgeScaleAnim();
+ mBadgeScaleAnim = ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, badgeScales);
+ mBadgeScaleAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBadgeScaleAnim = null;
+ }
+ });
+ mBadgeScaleAnim.start();
+ }
+
public void applyFromShortcutInfo(ShortcutInfo info) {
applyFromShortcutInfo(info, false);
}
@@ -231,7 +256,8 @@
}
private void applyIconAndLabel(ItemInfoWithIcon info) {
- FastBitmapDrawable iconDrawable = DrawableFactory.get(getContext()).newIcon(info);
+ FastBitmapDrawable iconDrawable = DrawableFactory.INSTANCE.get(getContext())
+ .newIcon(getContext(), info);
mBadgeColor = IconPalette.getMutedColor(info.iconColor, 0.54f);
setIcon(iconDrawable);
@@ -246,8 +272,8 @@
/**
* Overrides the default long press timeout.
*/
- public void setLongPressTimeout(int longPressTimeout) {
- mLongPressHelper.setLongPressTimeout(longPressTimeout);
+ public void setLongPressTimeoutFactor(float longPressTimeoutFactor) {
+ mLongPressHelper.setLongPressTimeoutFactor(longPressTimeoutFactor);
}
@Override
@@ -377,7 +403,7 @@
if (forceHideBadge) {
invalidate();
} else if (hasBadge()) {
- ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, 0, 1).start();
+ animateBadgeScale(0, 1);
}
}
@@ -386,10 +412,14 @@
}
public void getIconBounds(Rect outBounds) {
- int top = getPaddingTop();
- int left = (getWidth() - mIconSize) / 2;
- int right = left + mIconSize;
- int bottom = top + mIconSize;
+ getIconBounds(this, outBounds, mIconSize);
+ }
+
+ public static void getIconBounds(View iconView, Rect outBounds, int iconSize) {
+ int top = iconView.getPaddingTop();
+ int left = (iconView.getWidth() - iconSize) / 2;
+ int right = left + iconSize;
+ int bottom = top + iconSize;
outBounds.set(left, top, right, bottom);
}
@@ -443,8 +473,7 @@
// Special case to prevent text shadows in high contrast mode
return Color.TRANSPARENT;
}
- return ColorUtils.setAlphaComponent(
- mTextColor, Math.round(Color.alpha(mTextColor) * mTextAlpha));
+ return setColorAlphaBound(mTextColor, Math.round(Color.alpha(mTextColor) * mTextAlpha));
}
/**
@@ -498,8 +527,8 @@
preloadDrawable = (PreloadIconDrawable) mIcon;
preloadDrawable.setLevel(progressLevel);
} else {
- preloadDrawable = DrawableFactory.get(getContext())
- .newPendingIcon(info, getContext());
+ preloadDrawable = DrawableFactory.INSTANCE.get(getContext())
+ .newPendingIcon(getContext(), info);
preloadDrawable.setLevel(progressLevel);
setIcon(preloadDrawable);
}
@@ -519,8 +548,9 @@
if (wasBadged || isBadged) {
// Animate when a badge is first added or when it is removed.
if (animate && (wasBadged ^ isBadged) && isShown()) {
- ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, newBadgeScale).start();
+ animateBadgeScale(newBadgeScale);
} else {
+ cancelBadgeScaleAnim();
mBadgeScale = newBadgeScale;
invalidate();
}
@@ -609,7 +639,7 @@
}
if (getTag() instanceof ItemInfoWithIcon) {
ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
- if (info.usingLowResIcon) {
+ if (info.usingLowResIcon()) {
mIconLoadRequest = LauncherAppState.getInstance(getContext()).getIconCache()
.updateIconInBackground(BubbleTextView.this, info);
}
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index ed8c42d..2b0da43 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -33,6 +33,7 @@
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.Property;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -55,6 +56,20 @@
public abstract class ButtonDropTarget extends TextView
implements DropTarget, DragController.DragListener, OnClickListener {
+ private static final Property<ButtonDropTarget, Integer> TEXT_COLOR =
+ new Property<ButtonDropTarget, Integer>(Integer.TYPE, "textColor") {
+
+ @Override
+ public Integer get(ButtonDropTarget target) {
+ return target.getTextColor();
+ }
+
+ @Override
+ public void set(ButtonDropTarget target, Integer value) {
+ target.setTextColor(value);
+ }
+ };
+
private static final int[] sTempCords = new int[2];
private static final int DRAG_VIEW_DROP_DURATION = 285;
@@ -206,7 +221,7 @@
});
mCurrentColorAnim.play(anim1);
- mCurrentColorAnim.play(ObjectAnimator.ofArgb(this, "textColor", targetColor));
+ mCurrentColorAnim.play(ObjectAnimator.ofArgb(this, TEXT_COLOR, targetColor));
mCurrentColorAnim.start();
}
@@ -264,6 +279,10 @@
*/
@Override
public void onDrop(final DragObject d, final DragOptions options) {
+ if (options.isFlingToDelete) {
+ // FlingAnimation handles the animation and then calls completeDrop().
+ return;
+ }
final DragLayer dragLayer = mLauncher.getDragLayer();
final Rect from = new Rect();
dragLayer.getViewRectRelativeToSelf(d.dragView, from);
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 6c2fd8e..92404d4 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -16,8 +16,11 @@
package com.android.launcher3;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
@@ -34,11 +37,10 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Parcelable;
-import android.support.annotation.IntDef;
-import android.support.v4.view.ViewCompat;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Property;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
@@ -70,6 +72,9 @@
import java.util.Comparator;
import java.util.Stack;
+import androidx.annotation.IntDef;
+import androidx.core.view.ViewCompat;
+
public class CellLayout extends ViewGroup {
public static final int WORKSPACE_ACCESSIBILITY_DRAG = 2;
public static final int FOLDER_ACCESSIBILITY_DRAG = 1;
@@ -243,7 +248,7 @@
for (int i = 0; i < mDragOutlineAnims.length; i++) {
final InterruptibleInOutAnimator anim =
- new InterruptibleInOutAnimator(this, duration, fromAlphaValue, toAlphaValue);
+ new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
anim.getAnimator().setInterpolator(mEaseOutInterpolator);
final int thisIndex = i;
anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
@@ -877,7 +882,7 @@
return true;
}
- ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
+ ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
va.setDuration(duration);
mReorderAnimators.put(lp, va);
@@ -1884,6 +1889,19 @@
}
}
+ private static final Property<ReorderPreviewAnimation, Float> ANIMATION_PROGRESS =
+ new Property<ReorderPreviewAnimation, Float>(float.class, "animationProgress") {
+ @Override
+ public Float get(ReorderPreviewAnimation anim) {
+ return anim.animationProgress;
+ }
+
+ @Override
+ public void set(ReorderPreviewAnimation anim, Float progress) {
+ anim.setAnimationProgress(progress);
+ }
+ };
+
// Class which represents the reorder preview animations. These animations show that an item is
// in a temporary state, and hint at where the item will return to.
class ReorderPreviewAnimation {
@@ -1904,7 +1922,8 @@
public static final int MODE_HINT = 0;
public static final int MODE_PREVIEW = 1;
- Animator a;
+ float animationProgress = 0;
+ ValueAnimator a;
public ReorderPreviewAnimation(View child, int mode, int cellX0, int cellY0, int cellX1,
int cellY1, int spanX, int spanY) {
@@ -1974,7 +1993,7 @@
if (noMovement) {
return;
}
- ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
+ ValueAnimator va = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS, 0, 1);
a = va;
// Animations are disabled in power save mode, causing the repeated animation to jump
@@ -1987,20 +2006,6 @@
va.setDuration(mode == MODE_HINT ? HINT_DURATION : PREVIEW_DURATION);
va.setStartDelay((int) (Math.random() * 60));
- va.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float r = (Float) animation.getAnimatedValue();
- float r1 = (mode == MODE_HINT && repeating) ? 1.0f : r;
- float x = r1 * finalDeltaX + (1 - r1) * initDeltaX;
- float y = r1 * finalDeltaY + (1 - r1) * initDeltaY;
- child.setTranslationX(x);
- child.setTranslationY(y);
- float s = r * finalScale + (1 - r) * initScale;
- child.setScaleX(s);
- child.setScaleY(s);
- }
- });
va.addListener(new AnimatorListenerAdapter() {
public void onAnimationRepeat(Animator animation) {
// We make sure to end only after a full period
@@ -2012,6 +2017,18 @@
va.start();
}
+ private void setAnimationProgress(float progress) {
+ animationProgress = progress;
+ float r1 = (mode == MODE_HINT && repeating) ? 1.0f : animationProgress;
+ float x = r1 * finalDeltaX + (1 - r1) * initDeltaX;
+ float y = r1 * finalDeltaY + (1 - r1) * initDeltaY;
+ child.setTranslationX(x);
+ child.setTranslationY(y);
+ float s = animationProgress * finalScale + (1 - animationProgress) * initScale;
+ child.setScaleX(s);
+ child.setScaleY(s);
+ }
+
private void cancel() {
if (a != null) {
a.cancel();
@@ -2024,14 +2041,14 @@
}
setInitialAnimationValues(true);
- a = LauncherAnimUtils.ofPropertyValuesHolder(child,
- new PropertyListBuilder()
- .scale(initScale)
- .translationX(initDeltaX)
- .translationY(initDeltaY)
- .build())
+ a = new PropertyListBuilder()
+ .scale(initScale)
+ .translationX(initDeltaX)
+ .translationY(initDeltaY)
+ .build(child)
.setDuration(REORDER_ANIMATION_DURATION);
- a.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f));
+ mLauncher.getDragController().addFirstFrameAnimationHelper(a);
+ a.setInterpolator(DEACCEL_1_5);
a.start();
}
}
@@ -2046,7 +2063,7 @@
private void commitTempPlacement() {
mTmpOccupied.copyTo(mOccupied);
- long screenId = mLauncher.getWorkspace().getIdForScreen(this);
+ int screenId = mLauncher.getWorkspace().getIdForScreen(this);
int container = Favorites.CONTAINER_DESKTOP;
if (mContainerType == HOTSEAT) {
@@ -2661,38 +2678,6 @@
public String toString() {
return "(" + this.cellX + ", " + this.cellY + ")";
}
-
- public void setWidth(int width) {
- this.width = width;
- }
-
- public int getWidth() {
- return width;
- }
-
- public void setHeight(int height) {
- this.height = height;
- }
-
- public int getHeight() {
- return height;
- }
-
- public void setX(int x) {
- this.x = x;
- }
-
- public int getX() {
- return x;
- }
-
- public void setY(int y) {
- this.y = y;
- }
-
- public int getY() {
- return y;
- }
}
// This class stores info for two purposes:
@@ -2703,8 +2688,8 @@
// the CellLayout that was long clicked
public static final class CellInfo extends CellAndSpan {
public final View cell;
- final long screenId;
- final long container;
+ final int screenId;
+ final int container;
public CellInfo(View v, ItemInfo info) {
cellX = info.cellX;
diff --git a/src/com/android/launcher3/CheckLongPressHelper.java b/src/com/android/launcher3/CheckLongPressHelper.java
index dde733c..639c173 100644
--- a/src/com/android/launcher3/CheckLongPressHelper.java
+++ b/src/com/android/launcher3/CheckLongPressHelper.java
@@ -17,17 +17,18 @@
package com.android.launcher3;
import android.view.View;
+import android.view.ViewConfiguration;
import com.android.launcher3.util.Thunk;
public class CheckLongPressHelper {
- public static final int DEFAULT_LONG_PRESS_TIMEOUT = 300;
+ public static final float DEFAULT_LONG_PRESS_TIMEOUT_FACTOR = 0.75f;
@Thunk View mView;
@Thunk View.OnLongClickListener mListener;
@Thunk boolean mHasPerformedLongPress;
- private int mLongPressTimeout = DEFAULT_LONG_PRESS_TIMEOUT;
+ private float mLongPressTimeoutFactor = DEFAULT_LONG_PRESS_TIMEOUT_FACTOR;
private CheckForLongPress mPendingCheckForLongPress;
class CheckForLongPress implements Runnable {
@@ -60,8 +61,8 @@
/**
* Overrides the default long press timeout.
*/
- public void setLongPressTimeout(int longPressTimeout) {
- mLongPressTimeout = longPressTimeout;
+ public void setLongPressTimeoutFactor(float longPressTimeoutFactor) {
+ mLongPressTimeoutFactor = longPressTimeoutFactor;
}
public void postCheckForLongPress() {
@@ -70,7 +71,8 @@
if (mPendingCheckForLongPress == null) {
mPendingCheckForLongPress = new CheckForLongPress();
}
- mView.postDelayed(mPendingCheckForLongPress, mLongPressTimeout);
+ mView.postDelayed(mPendingCheckForLongPress,
+ (long) (ViewConfiguration.getLongPressTimeout() * mLongPressTimeoutFactor));
}
public void cancelLongPress() {
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index 1ec30ba..44830e8 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -76,13 +76,13 @@
}
@Override
- protected void parseContainerAndScreen(XmlResourceParser parser, long[] out) {
+ protected void parseContainerAndScreen(XmlResourceParser parser, int[] out) {
out[0] = LauncherSettings.Favorites.CONTAINER_DESKTOP;
String strContainer = getAttributeValue(parser, ATTR_CONTAINER);
if (strContainer != null) {
- out[0] = Long.valueOf(strContainer);
+ out[0] = Integer.parseInt(strContainer);
}
- out[1] = Long.parseLong(getAttributeValue(parser, ATTR_SCREEN));
+ out[1] = Integer.parseInt(getAttributeValue(parser, ATTR_SCREEN));
}
/**
@@ -91,7 +91,7 @@
public class AppShortcutWithUriParser extends AppShortcutParser {
@Override
- protected long invalidPackageOrClass(XmlResourceParser parser) {
+ protected int invalidPackageOrClass(XmlResourceParser parser) {
final String uri = getAttributeValue(parser, ATTR_URI);
if (TextUtils.isEmpty(uri)) {
Log.e(TAG, "Skipping invalid <favorite> with no component or uri");
@@ -205,11 +205,11 @@
private final AppShortcutWithUriParser mChildParser = new AppShortcutWithUriParser();
@Override
- public long parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
+ public int parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
IOException {
final int groupDepth = parser.getDepth();
int type;
- long addedId = -1;
+ int addedId = -1;
while ((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > groupDepth) {
if (type != XmlPullParser.START_TAG || addedId > -1) {
@@ -233,7 +233,7 @@
@Thunk class PartnerFolderParser implements TagParser {
@Override
- public long parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
+ public int parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
IOException {
// Folder contents come from an external XML resource
final Partner partner = Partner.get(mPackageManager);
@@ -259,7 +259,7 @@
@Thunk class MyFolderParser extends FolderParser {
@Override
- public long parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
+ public int parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
IOException {
final int resId = getAttributeResourceValue(parser, ATTR_FOLDER_ITEMS, 0);
if (resId != 0) {
@@ -277,7 +277,7 @@
protected class AppWidgetParser extends PendingWidgetParser {
@Override
- protected long verifyAndInsert(ComponentName cn, Bundle extras) {
+ protected int verifyAndInsert(ComponentName cn, Bundle extras) {
try {
mPackageManager.getReceiverInfo(cn, 0);
} catch (Exception e) {
@@ -293,7 +293,7 @@
}
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
- long insertedId = -1;
+ int insertedId = -1;
try {
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 64a58fb..c80f96b 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -23,10 +23,11 @@
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.folder.Folder;
import com.android.launcher3.logging.LoggerUtils;
+import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+import com.android.launcher3.views.Snackbar;
public class DeleteDropTarget extends ButtonDropTarget {
@@ -81,13 +82,17 @@
*/
private void setTextBasedOnDragSource(ItemInfo item) {
if (!TextUtils.isEmpty(mText)) {
- mText = getResources().getString(item.id != ItemInfo.NO_ID
+ mText = getResources().getString(canRemove(item)
? R.string.remove_drop_target_label
: android.R.string.cancel);
requestLayout();
}
}
+ private boolean canRemove(ItemInfo item) {
+ return item.id != ItemInfo.NO_ID;
+ }
+
/**
* Set mControlType depending on the drag item.
*/
@@ -97,10 +102,21 @@
}
@Override
+ public void onDrop(DragObject d, DragOptions options) {
+ if (canRemove(d.dragInfo)) {
+ mLauncher.getModelWriter().prepareToUndoDelete();
+ }
+ super.onDrop(d, options);
+ }
+
+ @Override
public void completeDrop(DragObject d) {
ItemInfo item = d.dragInfo;
- if ((d.dragSource instanceof Workspace) || (d.dragSource instanceof Folder)) {
+ if (canRemove(item)) {
onAccessibilityDrop(null, item);
+ ModelWriter modelWriter = mLauncher.getModelWriter();
+ Snackbar.show(mLauncher, R.string.item_removed, R.string.undo,
+ modelWriter::commitDelete, modelWriter::abortDelete);
}
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 9839c12..256fd6c 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -30,7 +30,7 @@
import com.android.launcher3.CellLayout.ContainerType;
import com.android.launcher3.badge.BadgeRenderer;
-import com.android.launcher3.graphics.IconNormalizer;
+import com.android.launcher3.icons.IconNormalizer;
public class DeviceProfile {
@@ -373,7 +373,7 @@
updateFolderCellSize(1f, dm, res);
// Don't let the folder get too close to the edges of the screen.
- int folderMargin = edgeMarginPx;
+ int folderMargin = edgeMarginPx * 2;
Point totalWorkspacePadding = getTotalWorkspacePadding();
// Check if the icons fit within the available height.
diff --git a/src/com/android/launcher3/DragSource.java b/src/com/android/launcher3/DragSource.java
index 93f865c..d4d7b99 100644
--- a/src/com/android/launcher3/DragSource.java
+++ b/src/com/android/launcher3/DragSource.java
@@ -19,7 +19,7 @@
import android.view.View;
import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
+import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
/**
* Interface defining an object that can originate a drag.
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 9217ca9..daf587a 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -34,7 +34,7 @@
import android.util.Property;
import android.util.SparseArray;
-import com.android.launcher3.graphics.BitmapInfo;
+import com.android.launcher3.icons.BitmapInfo;
public class FastBitmapDrawable extends Drawable {
@@ -109,7 +109,7 @@
@Override
public final void draw(Canvas canvas) {
- if (mScaleAnimation != null) {
+ if (mScale != 1f) {
int count = canvas.save();
Rect bounds = getBounds();
canvas.scale(mScale, mScale, bounds.exactCenterX(), bounds.exactCenterY());
@@ -150,10 +150,23 @@
return mAlpha;
}
+ public void setScale(float scale) {
+ if (mScaleAnimation != null) {
+ mScaleAnimation.cancel();
+ mScaleAnimation = null;
+ }
+ mScale = scale;
+ invalidateSelf();
+ }
+
public float getAnimatedScale() {
return mScaleAnimation == null ? 1 : mScale;
}
+ public float getScale() {
+ return mScale;
+ }
+
@Override
public int getIntrinsicWidth() {
return mBitmap.getWidth();
diff --git a/src/com/android/launcher3/FirstFrameAnimatorHelper.java b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
index e7ca121..c967a96 100644
--- a/src/com/android/launcher3/FirstFrameAnimatorHelper.java
+++ b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
@@ -13,126 +13,124 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.android.launcher3;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
+import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+
import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.util.Log;
import android.view.View;
-import android.view.ViewPropertyAnimator;
-import android.view.ViewTreeObserver;
-import com.android.launcher3.util.Thunk;
-
-import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+import android.view.View.OnAttachStateChangeListener;
+import android.view.ViewTreeObserver.OnDrawListener;
/*
* This is a helper class that listens to updates from the corresponding animation.
* For the first two frames, it adjusts the current play time of the animation to
* prevent jank at the beginning of the animation
*/
-public class FirstFrameAnimatorHelper extends AnimatorListenerAdapter
- implements ValueAnimator.AnimatorUpdateListener {
+public class FirstFrameAnimatorHelper implements OnDrawListener, OnAttachStateChangeListener {
+
private static final String TAG = "FirstFrameAnimatorHlpr";
private static final boolean DEBUG = false;
private static final int MAX_DELAY = 1000;
- private final View mTarget;
- private long mStartFrame;
- private long mStartTime = -1;
- private boolean mHandlingOnAnimationUpdate;
- private boolean mAdjustedSecondFrameTime;
- private static ViewTreeObserver.OnDrawListener sGlobalDrawListener;
- @Thunk static long sGlobalFrameCounter;
- private static boolean sVisible;
+ private View mRootView;
+ private long mGlobalFrameCount;
- public FirstFrameAnimatorHelper(ValueAnimator animator, View target) {
- mTarget = target;
- animator.addUpdateListener(this);
- }
-
- public FirstFrameAnimatorHelper(ViewPropertyAnimator vpa, View target) {
- mTarget = target;
- vpa.setListener(this);
- }
-
- // only used for ViewPropertyAnimators
- public void onAnimationStart(Animator animation) {
- final ValueAnimator va = (ValueAnimator) animation;
- va.addUpdateListener(FirstFrameAnimatorHelper.this);
- onAnimationUpdate(va);
- }
-
- public static void setIsVisible(boolean visible) {
- sVisible = visible;
- }
-
- public static void initializeDrawListener(View view) {
- if (sGlobalDrawListener != null) {
- view.getViewTreeObserver().removeOnDrawListener(sGlobalDrawListener);
+ public FirstFrameAnimatorHelper(View target) {
+ target.addOnAttachStateChangeListener(this);
+ if (target.isAttachedToWindow()) {
+ onViewAttachedToWindow(target);
}
-
- sGlobalDrawListener = () -> sGlobalFrameCounter++;
- view.getViewTreeObserver().addOnDrawListener(sGlobalDrawListener);
- sVisible = true;
}
- public void onAnimationUpdate(final ValueAnimator animation) {
- final long currentTime = System.currentTimeMillis();
- if (mStartTime == -1) {
- mStartFrame = sGlobalFrameCounter;
- mStartTime = currentTime;
+ public <T extends ValueAnimator> T addTo(T anim) {
+ anim.addUpdateListener(new MyListener());
+ return anim;
+ }
+
+ @Override
+ public void onDraw() {
+ mGlobalFrameCount ++;
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View view) {
+ mRootView = view.getRootView();
+ mRootView.getViewTreeObserver().addOnDrawListener(this);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View view) {
+ if (mRootView != null) {
+ mRootView.getViewTreeObserver().removeOnDrawListener(this);
+ mRootView = null;
}
+ }
- final long currentPlayTime = animation.getCurrentPlayTime();
- boolean isFinalFrame = Float.compare(1f, animation.getAnimatedFraction()) == 0;
+ private class MyListener implements AnimatorUpdateListener {
- if (!mHandlingOnAnimationUpdate &&
- sVisible &&
- // If the current play time exceeds the duration, or the animated fraction is 1,
- // the animation will get finished, even if we call setCurrentPlayTime -- therefore
- // don't adjust the animation in that case
- currentPlayTime < animation.getDuration() && !isFinalFrame) {
- mHandlingOnAnimationUpdate = true;
- long frameNum = sGlobalFrameCounter - mStartFrame;
- // If we haven't drawn our first frame, reset the time to t = 0
- // (give up after MAX_DELAY ms of waiting though - might happen, for example, if we
- // are no longer in the foreground and no frames are being rendered ever)
- if (frameNum == 0 && currentTime < mStartTime + MAX_DELAY && currentPlayTime > 0) {
- // The first frame on animations doesn't always trigger an invalidate...
- // force an invalidate here to make sure the animation continues to advance
- mTarget.getRootView().invalidate();
- animation.setCurrentPlayTime(0);
- // For the second frame, if the first frame took more than 16ms,
- // adjust the start time and pretend it took only 16ms anyway. This
- // prevents a large jump in the animation due to an expensive first frame
- } else if (frameNum == 1 && currentTime < mStartTime + MAX_DELAY &&
- !mAdjustedSecondFrameTime &&
- currentTime > mStartTime + SINGLE_FRAME_MS &&
- currentPlayTime > SINGLE_FRAME_MS) {
- animation.setCurrentPlayTime(SINGLE_FRAME_MS);
- mAdjustedSecondFrameTime = true;
- } else {
- if (frameNum > 1) {
- mTarget.post(new Runnable() {
- public void run() {
- animation.removeUpdateListener(FirstFrameAnimatorHelper.this);
- }
- });
+ private long mStartFrame;
+ private long mStartTime = -1;
+ private boolean mHandlingOnAnimationUpdate;
+ private boolean mAdjustedSecondFrameTime;
+
+ @Override
+ public void onAnimationUpdate(final ValueAnimator animation) {
+ final long currentTime = System.currentTimeMillis();
+ if (mStartTime == -1) {
+ mStartFrame = mGlobalFrameCount;
+ mStartTime = currentTime;
+ }
+
+ final long currentPlayTime = animation.getCurrentPlayTime();
+ boolean isFinalFrame = Float.compare(1f, animation.getAnimatedFraction()) == 0;
+
+ if (!mHandlingOnAnimationUpdate &&
+ mRootView != null &&
+ mRootView.getWindowVisibility() == View.VISIBLE &&
+ // If the current play time exceeds the duration, or the animated fraction is 1,
+ // the animation will get finished, even if we call setCurrentPlayTime --
+ // therefore don't adjust the animation in that case
+ currentPlayTime < animation.getDuration() && !isFinalFrame) {
+ mHandlingOnAnimationUpdate = true;
+ long frameNum = mGlobalFrameCount - mStartFrame;
+
+ // If we haven't drawn our first frame, reset the time to t = 0
+ // (give up after MAX_DELAY ms of waiting though - might happen, for example, if we
+ // are no longer in the foreground and no frames are being rendered ever)
+ if (frameNum == 0 && currentTime < mStartTime + MAX_DELAY && currentPlayTime > 0) {
+ // The first frame on animations doesn't always trigger an invalidate...
+ // force an invalidate here to make sure the animation continues to advance
+ mRootView.invalidate();
+ animation.setCurrentPlayTime(0);
+ // For the second frame, if the first frame took more than 16ms,
+ // adjust the start time and pretend it took only 16ms anyway. This
+ // prevents a large jump in the animation due to an expensive first frame
+ } else if (frameNum == 1 && currentTime < mStartTime + MAX_DELAY &&
+ !mAdjustedSecondFrameTime &&
+ currentTime > mStartTime + SINGLE_FRAME_MS &&
+ currentPlayTime > SINGLE_FRAME_MS) {
+ animation.setCurrentPlayTime(SINGLE_FRAME_MS);
+ mAdjustedSecondFrameTime = true;
+ } else {
+ if (frameNum > 1) {
+ mRootView.post(() -> animation.removeUpdateListener(this));
+ }
+ if (DEBUG) print(animation);
}
+ mHandlingOnAnimationUpdate = false;
+ } else {
if (DEBUG) print(animation);
}
- mHandlingOnAnimationUpdate = false;
- } else {
- if (DEBUG) print(animation);
}
- }
- public void print(ValueAnimator animation) {
- float flatFraction = animation.getCurrentPlayTime() / (float) animation.getDuration();
- Log.d(TAG, sGlobalFrameCounter +
- "(" + (sGlobalFrameCounter - mStartFrame) + ") " + mTarget + " dirty? " +
- mTarget.isDirty() + " " + flatFraction + " " + this + " " + animation);
+ public void print(ValueAnimator animation) {
+ float flatFraction = animation.getCurrentPlayTime() / (float) animation.getDuration();
+ Log.d(TAG, mGlobalFrameCount +
+ "(" + (mGlobalFrameCount - mStartFrame) + ") " + mRootView + " dirty? " +
+ mRootView.isDirty() + " " + flatFraction + " " + this + " " + animation);
+ }
}
}
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 6668f2c..6b5db30 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -16,32 +16,23 @@
package com.android.launcher3;
-import static com.android.launcher3.LauncherState.ALL_APPS;
-
import android.content.Context;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import android.widget.TextView;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
+import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-public class Hotseat extends FrameLayout implements LogContainerProvider, Insettable {
+public class Hotseat extends CellLayout implements LogContainerProvider, Insettable {
private final Launcher mLauncher;
- private CellLayout mContent;
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mHasVerticalHotseat;
@@ -59,77 +50,23 @@
mLauncher = Launcher.getLauncher(context);
}
- public CellLayout getLayout() {
- return mContent;
- }
-
- /* Get the orientation invariant order of the item in the hotseat for persistence. */
- int getOrderInHotseat(int x, int y) {
- return mHasVerticalHotseat ? (mContent.getCountY() - y - 1) : x;
- }
-
/* Get the orientation specific coordinates given an invariant order in the hotseat. */
int getCellXFromOrder(int rank) {
return mHasVerticalHotseat ? 0 : rank;
}
int getCellYFromOrder(int rank) {
- return mHasVerticalHotseat ? (mContent.getCountY() - (rank + 1)) : 0;
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mContent = findViewById(R.id.layout);
+ return mHasVerticalHotseat ? (getCountY() - (rank + 1)) : 0;
}
void resetLayout(boolean hasVerticalHotseat) {
- mContent.removeAllViewsInLayout();
+ removeAllViewsInLayout();
mHasVerticalHotseat = hasVerticalHotseat;
InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv;
if (hasVerticalHotseat) {
- mContent.setGridSize(1, idp.numHotseatIcons);
+ setGridSize(1, idp.numHotseatIcons);
} else {
- mContent.setGridSize(idp.numHotseatIcons, 1);
- }
-
- if (!FeatureFlags.NO_ALL_APPS_ICON) {
- // Add the Apps button
- Context context = getContext();
- DeviceProfile grid = mLauncher.getDeviceProfile();
- int allAppsButtonRank = grid.inv.getAllAppsButtonRank();
-
- LayoutInflater inflater = LayoutInflater.from(context);
- TextView allAppsButton = (TextView)
- inflater.inflate(R.layout.all_apps_button, mContent, false);
- Drawable d = context.getResources().getDrawable(R.drawable.all_apps_button_icon);
- d.setBounds(0, 0, grid.iconSizePx, grid.iconSizePx);
-
- int scaleDownPx = getResources().getDimensionPixelSize(R.dimen.all_apps_button_scale_down);
- Rect bounds = d.getBounds();
- d.setBounds(bounds.left, bounds.top + scaleDownPx / 2, bounds.right - scaleDownPx,
- bounds.bottom - scaleDownPx / 2);
- allAppsButton.setCompoundDrawables(null, d, null, null);
-
- allAppsButton.setContentDescription(context.getString(R.string.all_apps_button_label));
- if (mLauncher != null) {
- allAppsButton.setOnClickListener((v) -> {
- if (!mLauncher.isInState(ALL_APPS)) {
- mLauncher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
- ControlType.ALL_APPS_BUTTON);
- mLauncher.getStateManager().goToState(ALL_APPS);
- }
- });
- allAppsButton.setOnFocusChangeListener(mLauncher.mFocusHandler);
- }
-
- // Note: We do this to ensure that the hotseat is always laid out in the orientation of
- // the hotseat in order regardless of which orientation they were added
- int x = getCellXFromOrder(allAppsButtonRank);
- int y = getCellYFromOrder(allAppsButtonRank);
- CellLayout.LayoutParams lp = new CellLayout.LayoutParams(x, y, 1, 1);
- lp.canReorder = false;
- mContent.addViewToCellLayout(allAppsButton, -1, allAppsButton.getId(), lp, true);
+ setGridSize(idp.numHotseatIcons, 1);
}
}
@@ -137,15 +74,16 @@
public boolean onInterceptTouchEvent(MotionEvent ev) {
// We don't want any clicks to go through to the hotseat unless the workspace is in
// the normal state or an accessible drag is in progress.
- return !mLauncher.getWorkspace().workspaceIconsCanBeDragged() &&
- !mLauncher.getAccessibilityDelegate().isInAccessibleDrag();
+ return (!mLauncher.getWorkspace().workspaceIconsCanBeDragged()
+ && !mLauncher.getAccessibilityDelegate().isInAccessibleDrag())
+ || super.onInterceptTouchEvent(ev);
}
@Override
public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) {
target.gridX = info.cellX;
target.gridY = info.cellY;
- targetParent.containerType = ContainerType.HOTSEAT;
+ targetParent.containerType = LauncherLogProto.ContainerType.HOTSEAT;
}
@Override
@@ -168,7 +106,7 @@
lp.height = grid.hotseatBarSizePx + insets.bottom;
}
Rect padding = grid.getHotseatLayoutPadding();
- getLayout().setPadding(padding.left, padding.top, padding.right, padding.bottom);
+ setPadding(padding.left, padding.top, padding.right, padding.bottom);
setLayoutParams(lp);
InsettableFrameLayout.dispatchInsets(this, insets);
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
deleted file mode 100644
index c5ca183..0000000
--- a/src/com/android/launcher3/IconCache.java
+++ /dev/null
@@ -1,895 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.ComponentName;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.LauncherActivityInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.Drawable;
-import android.os.Build.VERSION;
-import android.os.Handler;
-import android.os.Process;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.support.annotation.NonNull;
-import android.support.v4.graphics.ColorUtils;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.graphics.BitmapInfo;
-import com.android.launcher3.graphics.BitmapRenderer;
-import com.android.launcher3.graphics.LauncherIcons;
-import com.android.launcher3.model.PackageItemInfo;
-import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.InstantAppResolver;
-import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.Provider;
-import com.android.launcher3.util.SQLiteCacheHelper;
-import com.android.launcher3.util.Thunk;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.Stack;
-
-/**
- * Cache of application icons. Icons can be made from any thread.
- */
-public class IconCache {
-
- private static final String TAG = "Launcher.IconCache";
-
- private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
-
- // Empty class name is used for storing package default entry.
- public static final String EMPTY_CLASS_NAME = ".";
-
- private static final boolean DEBUG = false;
- private static final boolean DEBUG_IGNORE_CACHE = false;
-
- private static final int LOW_RES_SCALE_FACTOR = 5;
-
- @Thunk static final Object ICON_UPDATE_TOKEN = new Object();
-
- public static class CacheEntry extends BitmapInfo {
- public CharSequence title = "";
- public CharSequence contentDescription = "";
- public boolean isLowResIcon;
- }
-
- private final HashMap<UserHandle, BitmapInfo> mDefaultIcons = new HashMap<>();
- @Thunk final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
-
- private final Context mContext;
- private final PackageManager mPackageManager;
- private final IconProvider mIconProvider;
- @Thunk final UserManagerCompat mUserManager;
- private final LauncherAppsCompat mLauncherApps;
- private final HashMap<ComponentKey, CacheEntry> mCache =
- new HashMap<>(INITIAL_ICON_CACHE_CAPACITY);
- private final InstantAppResolver mInstantAppResolver;
- private final int mIconDpi;
- @Thunk final IconDB mIconDb;
-
- @Thunk final Handler mWorkerHandler;
-
- private final BitmapFactory.Options mLowResOptions;
- private final BitmapFactory.Options mHighResOptions;
-
- private int mPendingIconRequestCount = 0;
-
- public IconCache(Context context, InvariantDeviceProfile inv) {
- mContext = context;
- mPackageManager = context.getPackageManager();
- mUserManager = UserManagerCompat.getInstance(mContext);
- mLauncherApps = LauncherAppsCompat.getInstance(mContext);
- mInstantAppResolver = InstantAppResolver.newInstance(mContext);
- mIconDpi = inv.fillResIconDpi;
- mIconDb = new IconDB(context, inv.iconBitmapSize);
-
- mIconProvider = IconProvider.newInstance(context);
- mWorkerHandler = new Handler(LauncherModel.getWorkerLooper());
-
- mLowResOptions = new BitmapFactory.Options();
- // Always prefer RGB_565 config for low res. If the bitmap has transparency, it will
- // automatically be loaded as ALPHA_8888.
- mLowResOptions.inPreferredConfig = Bitmap.Config.RGB_565;
-
- if (BitmapRenderer.USE_HARDWARE_BITMAP) {
- mHighResOptions = new BitmapFactory.Options();
- mHighResOptions.inPreferredConfig = Bitmap.Config.HARDWARE;
- } else {
- mHighResOptions = null;
- }
- }
-
- private Drawable getFullResDefaultActivityIcon() {
- return getFullResIcon(Resources.getSystem(), Utilities.ATLEAST_OREO ?
- android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon);
- }
-
- private Drawable getFullResIcon(Resources resources, int iconId) {
- Drawable d;
- try {
- d = resources.getDrawableForDensity(iconId, mIconDpi);
- } catch (Resources.NotFoundException e) {
- d = null;
- }
-
- return (d != null) ? d : getFullResDefaultActivityIcon();
- }
-
- public Drawable getFullResIcon(String packageName, int iconId) {
- Resources resources;
- try {
- resources = mPackageManager.getResourcesForApplication(packageName);
- } catch (PackageManager.NameNotFoundException e) {
- resources = null;
- }
- if (resources != null) {
- if (iconId != 0) {
- return getFullResIcon(resources, iconId);
- }
- }
- return getFullResDefaultActivityIcon();
- }
-
- public Drawable getFullResIcon(ActivityInfo info) {
- Resources resources;
- try {
- resources = mPackageManager.getResourcesForApplication(
- info.applicationInfo);
- } catch (PackageManager.NameNotFoundException e) {
- resources = null;
- }
- if (resources != null) {
- int iconId = info.getIconResource();
- if (iconId != 0) {
- return getFullResIcon(resources, iconId);
- }
- }
-
- return getFullResDefaultActivityIcon();
- }
-
- public Drawable getFullResIcon(LauncherActivityInfo info) {
- return getFullResIcon(info, true);
- }
-
- public Drawable getFullResIcon(LauncherActivityInfo info, boolean flattenDrawable) {
- return mIconProvider.getIcon(info, mIconDpi, flattenDrawable);
- }
-
- protected BitmapInfo makeDefaultIcon(UserHandle user) {
- try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
- return li.createBadgedIconBitmap(
- getFullResDefaultActivityIcon(), user, VERSION.SDK_INT);
- }
- }
-
- /**
- * Remove any records for the supplied ComponentName.
- */
- public synchronized void remove(ComponentName componentName, UserHandle user) {
- mCache.remove(new ComponentKey(componentName, user));
- }
-
- /**
- * Remove any records for the supplied package name from memory.
- */
- private void removeFromMemCacheLocked(String packageName, UserHandle user) {
- HashSet<ComponentKey> forDeletion = new HashSet<>();
- for (ComponentKey key: mCache.keySet()) {
- if (key.componentName.getPackageName().equals(packageName)
- && key.user.equals(user)) {
- forDeletion.add(key);
- }
- }
- for (ComponentKey condemned: forDeletion) {
- mCache.remove(condemned);
- }
- }
-
- /**
- * Updates the entries related to the given package in memory and persistent DB.
- */
- public synchronized void updateIconsForPkg(String packageName, UserHandle user) {
- removeIconsForPkg(packageName, user);
- try {
- PackageInfo info = mPackageManager.getPackageInfo(packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
- long userSerial = mUserManager.getSerialNumberForUser(user);
- for (LauncherActivityInfo app : mLauncherApps.getActivityList(packageName, user)) {
- addIconToDBAndMemCache(app, info, userSerial, false /*replace existing*/);
- }
- } catch (NameNotFoundException e) {
- Log.d(TAG, "Package not found", e);
- }
- }
-
- /**
- * Removes the entries related to the given package in memory and persistent DB.
- */
- public synchronized void removeIconsForPkg(String packageName, UserHandle user) {
- removeFromMemCacheLocked(packageName, user);
- long userSerial = mUserManager.getSerialNumberForUser(user);
- mIconDb.delete(
- IconDB.COLUMN_COMPONENT + " LIKE ? AND " + IconDB.COLUMN_USER + " = ?",
- new String[]{packageName + "/%", Long.toString(userSerial)});
- }
-
- public void updateDbIcons(Set<String> ignorePackagesForMainUser) {
- // Remove all active icon update tasks.
- mWorkerHandler.removeCallbacksAndMessages(ICON_UPDATE_TOKEN);
-
- mIconProvider.updateSystemStateString(mContext);
- for (UserHandle user : mUserManager.getUserProfiles()) {
- // Query for the set of apps
- final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
- // Fail if we don't have any apps
- // TODO: Fix this. Only fail for the current user.
- if (apps == null || apps.isEmpty()) {
- return;
- }
-
- // Update icon cache. This happens in segments and {@link #onPackageIconsUpdated}
- // is called by the icon cache when the job is complete.
- updateDBIcons(user, apps, Process.myUserHandle().equals(user)
- ? ignorePackagesForMainUser : Collections.<String>emptySet());
- }
- }
-
- /**
- * Updates the persistent DB, such that only entries corresponding to {@param apps} remain in
- * the DB and are updated.
- * @return The set of packages for which icons have updated.
- */
- private void updateDBIcons(UserHandle user, List<LauncherActivityInfo> apps,
- Set<String> ignorePackages) {
- long userSerial = mUserManager.getSerialNumberForUser(user);
- PackageManager pm = mContext.getPackageManager();
- HashMap<String, PackageInfo> pkgInfoMap = new HashMap<>();
- for (PackageInfo info : pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES)) {
- pkgInfoMap.put(info.packageName, info);
- }
-
- HashMap<ComponentName, LauncherActivityInfo> componentMap = new HashMap<>();
- for (LauncherActivityInfo app : apps) {
- componentMap.put(app.getComponentName(), app);
- }
-
- HashSet<Integer> itemsToRemove = new HashSet<>();
- Stack<LauncherActivityInfo> appsToUpdate = new Stack<>();
-
- Cursor c = null;
- try {
- c = mIconDb.query(
- new String[]{IconDB.COLUMN_ROWID, IconDB.COLUMN_COMPONENT,
- IconDB.COLUMN_LAST_UPDATED, IconDB.COLUMN_VERSION,
- IconDB.COLUMN_SYSTEM_STATE},
- IconDB.COLUMN_USER + " = ? ",
- new String[]{Long.toString(userSerial)});
-
- final int indexComponent = c.getColumnIndex(IconDB.COLUMN_COMPONENT);
- final int indexLastUpdate = c.getColumnIndex(IconDB.COLUMN_LAST_UPDATED);
- final int indexVersion = c.getColumnIndex(IconDB.COLUMN_VERSION);
- final int rowIndex = c.getColumnIndex(IconDB.COLUMN_ROWID);
- final int systemStateIndex = c.getColumnIndex(IconDB.COLUMN_SYSTEM_STATE);
-
- while (c.moveToNext()) {
- String cn = c.getString(indexComponent);
- ComponentName component = ComponentName.unflattenFromString(cn);
- PackageInfo info = pkgInfoMap.get(component.getPackageName());
- if (info == null) {
- if (!ignorePackages.contains(component.getPackageName())) {
- remove(component, user);
- itemsToRemove.add(c.getInt(rowIndex));
- }
- continue;
- }
- if ((info.applicationInfo.flags & ApplicationInfo.FLAG_IS_DATA_ONLY) != 0) {
- // Application is not present
- continue;
- }
-
- long updateTime = c.getLong(indexLastUpdate);
- int version = c.getInt(indexVersion);
- LauncherActivityInfo app = componentMap.remove(component);
- if (version == info.versionCode && updateTime == info.lastUpdateTime &&
- TextUtils.equals(c.getString(systemStateIndex),
- mIconProvider.getIconSystemState(info.packageName))) {
- continue;
- }
- if (app == null) {
- remove(component, user);
- itemsToRemove.add(c.getInt(rowIndex));
- } else {
- appsToUpdate.add(app);
- }
- }
- } catch (SQLiteException e) {
- Log.d(TAG, "Error reading icon cache", e);
- // Continue updating whatever we have read so far
- } finally {
- if (c != null) {
- c.close();
- }
- }
- if (!itemsToRemove.isEmpty()) {
- mIconDb.delete(
- Utilities.createDbSelectionQuery(IconDB.COLUMN_ROWID, itemsToRemove), null);
- }
-
- // Insert remaining apps.
- if (!componentMap.isEmpty() || !appsToUpdate.isEmpty()) {
- Stack<LauncherActivityInfo> appsToAdd = new Stack<>();
- appsToAdd.addAll(componentMap.values());
- new SerializedIconUpdateTask(userSerial, pkgInfoMap,
- appsToAdd, appsToUpdate).scheduleNext();
- }
- }
-
- /**
- * Adds an entry into the DB and the in-memory cache.
- * @param replaceExisting if true, it will recreate the bitmap even if it already exists in
- * the memory. This is useful then the previous bitmap was created using
- * old data.
- */
- @Thunk synchronized void addIconToDBAndMemCache(LauncherActivityInfo app,
- PackageInfo info, long userSerial, boolean replaceExisting) {
- final ComponentKey key = new ComponentKey(app.getComponentName(), app.getUser());
- CacheEntry entry = null;
- if (!replaceExisting) {
- entry = mCache.get(key);
- // We can't reuse the entry if the high-res icon is not present.
- if (entry == null || entry.isLowResIcon || entry.icon == null) {
- entry = null;
- }
- }
- if (entry == null) {
- entry = new CacheEntry();
- LauncherIcons li = LauncherIcons.obtain(mContext);
- li.createBadgedIconBitmap(getFullResIcon(app), app.getUser(),
- app.getApplicationInfo().targetSdkVersion).applyTo(entry);
- li.recycle();
- }
- entry.title = app.getLabel();
- entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, app.getUser());
- mCache.put(key, entry);
-
- Bitmap lowResIcon = generateLowResIcon(entry.icon);
- ContentValues values = newContentValues(entry.icon, lowResIcon, entry.color,
- entry.title.toString(), app.getApplicationInfo().packageName);
- addIconToDB(values, app.getComponentName(), info, userSerial);
- }
-
- /**
- * Updates {@param values} to contain versioning information and adds it to the DB.
- * @param values {@link ContentValues} containing icon & title
- */
- private void addIconToDB(ContentValues values, ComponentName key,
- PackageInfo info, long userSerial) {
- values.put(IconDB.COLUMN_COMPONENT, key.flattenToString());
- values.put(IconDB.COLUMN_USER, userSerial);
- values.put(IconDB.COLUMN_LAST_UPDATED, info.lastUpdateTime);
- values.put(IconDB.COLUMN_VERSION, info.versionCode);
- mIconDb.insertOrReplace(values);
- }
-
- /**
- * Fetches high-res icon for the provided ItemInfo and updates the caller when done.
- * @return a request ID that can be used to cancel the request.
- */
- public IconLoadRequest updateIconInBackground(final ItemInfoUpdateReceiver caller,
- final ItemInfoWithIcon info) {
- Preconditions.assertUIThread();
- if (mPendingIconRequestCount <= 0) {
- LauncherModel.setWorkerPriority(Process.THREAD_PRIORITY_FOREGROUND);
- }
- mPendingIconRequestCount ++;
-
- IconLoadRequest request = new IconLoadRequest(mWorkerHandler, this::onIconRequestEnd) {
- @Override
- public void run() {
- if (info instanceof AppInfo || info instanceof ShortcutInfo) {
- getTitleAndIcon(info, false);
- } else if (info instanceof PackageItemInfo) {
- getTitleAndIconForApp((PackageItemInfo) info, false);
- }
- mMainThreadExecutor.execute(() -> {
- caller.reapplyItemInfo(info);
- onEnd();
- });
- }
- };
- Utilities.postAsyncCallback(mWorkerHandler, request);
- return request;
- }
-
- private void onIconRequestEnd() {
- mPendingIconRequestCount --;
- if (mPendingIconRequestCount <= 0) {
- LauncherModel.setWorkerPriority(Process.THREAD_PRIORITY_BACKGROUND);
- }
- }
-
- /**
- * Updates {@param application} only if a valid entry is found.
- */
- public synchronized void updateTitleAndIcon(AppInfo application) {
- CacheEntry entry = cacheLocked(application.componentName,
- Provider.<LauncherActivityInfo>of(null),
- application.user, false, application.usingLowResIcon);
- if (entry.icon != null && !isDefaultIcon(entry.icon, application.user)) {
- applyCacheEntry(entry, application);
- }
- }
-
- /**
- * Fill in {@param info} with the icon and label for {@param activityInfo}
- */
- public synchronized void getTitleAndIcon(ItemInfoWithIcon info,
- LauncherActivityInfo activityInfo, boolean useLowResIcon) {
- // If we already have activity info, no need to use package icon
- getTitleAndIcon(info, Provider.of(activityInfo), false, useLowResIcon);
- }
-
- /**
- * Fill in {@param info} with the icon and label. If the
- * corresponding activity is not found, it reverts to the package icon.
- */
- public synchronized void getTitleAndIcon(ItemInfoWithIcon info, boolean useLowResIcon) {
- // null info means not installed, but if we have a component from the intent then
- // we should still look in the cache for restored app icons.
- if (info.getTargetComponent() == null) {
- getDefaultIcon(info.user).applyTo(info);
- info.title = "";
- info.contentDescription = "";
- info.usingLowResIcon = false;
- } else {
- getTitleAndIcon(info, new ActivityInfoProvider(info.getIntent(), info.user),
- true, useLowResIcon);
- }
- }
-
- /**
- * Fill in {@param shortcutInfo} with the icon and label for {@param info}
- */
- private synchronized void getTitleAndIcon(
- @NonNull ItemInfoWithIcon infoInOut,
- @NonNull Provider<LauncherActivityInfo> activityInfoProvider,
- boolean usePkgIcon, boolean useLowResIcon) {
- CacheEntry entry = cacheLocked(infoInOut.getTargetComponent(), activityInfoProvider,
- infoInOut.user, usePkgIcon, useLowResIcon);
- applyCacheEntry(entry, infoInOut);
- }
-
- /**
- * Fill in {@param infoInOut} with the corresponding icon and label.
- */
- public synchronized void getTitleAndIconForApp(
- PackageItemInfo infoInOut, boolean useLowResIcon) {
- CacheEntry entry = getEntryForPackageLocked(
- infoInOut.packageName, infoInOut.user, useLowResIcon);
- applyCacheEntry(entry, infoInOut);
- }
-
- private void applyCacheEntry(CacheEntry entry, ItemInfoWithIcon info) {
- info.title = Utilities.trim(entry.title);
- info.contentDescription = entry.contentDescription;
- info.usingLowResIcon = entry.isLowResIcon;
- ((entry.icon == null) ? getDefaultIcon(info.user) : entry).applyTo(info);
- }
-
- public synchronized BitmapInfo getDefaultIcon(UserHandle user) {
- if (!mDefaultIcons.containsKey(user)) {
- mDefaultIcons.put(user, makeDefaultIcon(user));
- }
- return mDefaultIcons.get(user);
- }
-
- public boolean isDefaultIcon(Bitmap icon, UserHandle user) {
- return getDefaultIcon(user).icon == icon;
- }
-
- /**
- * Retrieves the entry from the cache. If the entry is not present, it creates a new entry.
- * This method is not thread safe, it must be called from a synchronized method.
- */
- protected CacheEntry cacheLocked(
- @NonNull ComponentName componentName,
- @NonNull Provider<LauncherActivityInfo> infoProvider,
- UserHandle user, boolean usePackageIcon, boolean useLowResIcon) {
- Preconditions.assertWorkerThread();
- ComponentKey cacheKey = new ComponentKey(componentName, user);
- CacheEntry entry = mCache.get(cacheKey);
- if (entry == null || (entry.isLowResIcon && !useLowResIcon)) {
- entry = new CacheEntry();
- mCache.put(cacheKey, entry);
-
- // Check the DB first.
- LauncherActivityInfo info = null;
- boolean providerFetchedOnce = false;
-
- if (!getEntryFromDB(cacheKey, entry, useLowResIcon) || DEBUG_IGNORE_CACHE) {
- info = infoProvider.get();
- providerFetchedOnce = true;
-
- if (info != null) {
- LauncherIcons li = LauncherIcons.obtain(mContext);
- li.createBadgedIconBitmap(getFullResIcon(info), info.getUser(),
- info.getApplicationInfo().targetSdkVersion).applyTo(entry);
- li.recycle();
- } else {
- if (usePackageIcon) {
- CacheEntry packageEntry = getEntryForPackageLocked(
- componentName.getPackageName(), user, false);
- if (packageEntry != null) {
- if (DEBUG) Log.d(TAG, "using package default icon for " +
- componentName.toShortString());
- packageEntry.applyTo(entry);
- entry.title = packageEntry.title;
- entry.contentDescription = packageEntry.contentDescription;
- }
- }
- if (entry.icon == null) {
- if (DEBUG) Log.d(TAG, "using default icon for " +
- componentName.toShortString());
- getDefaultIcon(user).applyTo(entry);
- }
- }
- }
-
- if (TextUtils.isEmpty(entry.title)) {
- if (info == null && !providerFetchedOnce) {
- info = infoProvider.get();
- providerFetchedOnce = true;
- }
- if (info != null) {
- entry.title = info.getLabel();
- entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
- }
- }
- }
- return entry;
- }
-
- public synchronized void clear() {
- Preconditions.assertWorkerThread();
- mIconDb.clear();
- }
-
- /**
- * Adds a default package entry in the cache. This entry is not persisted and will be removed
- * when the cache is flushed.
- */
- public synchronized void cachePackageInstallInfo(String packageName, UserHandle user,
- Bitmap icon, CharSequence title) {
- removeFromMemCacheLocked(packageName, user);
-
- ComponentKey cacheKey = getPackageKey(packageName, user);
- CacheEntry entry = mCache.get(cacheKey);
-
- // For icon caching, do not go through DB. Just update the in-memory entry.
- if (entry == null) {
- entry = new CacheEntry();
- }
- if (!TextUtils.isEmpty(title)) {
- entry.title = title;
- }
- if (icon != null) {
- LauncherIcons li = LauncherIcons.obtain(mContext);
- li.createIconBitmap(icon).applyTo(entry);
- li.recycle();
- }
- if (!TextUtils.isEmpty(title) && entry.icon != null) {
- mCache.put(cacheKey, entry);
- }
- }
-
- private static ComponentKey getPackageKey(String packageName, UserHandle user) {
- ComponentName cn = new ComponentName(packageName, packageName + EMPTY_CLASS_NAME);
- return new ComponentKey(cn, user);
- }
-
- /**
- * Gets an entry for the package, which can be used as a fallback entry for various components.
- * This method is not thread safe, it must be called from a synchronized method.
- */
- private CacheEntry getEntryForPackageLocked(String packageName, UserHandle user,
- boolean useLowResIcon) {
- Preconditions.assertWorkerThread();
- ComponentKey cacheKey = getPackageKey(packageName, user);
- CacheEntry entry = mCache.get(cacheKey);
-
- if (entry == null || (entry.isLowResIcon && !useLowResIcon)) {
- entry = new CacheEntry();
- boolean entryUpdated = true;
-
- // Check the DB first.
- if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) {
- try {
- int flags = Process.myUserHandle().equals(user) ? 0 :
- PackageManager.GET_UNINSTALLED_PACKAGES;
- PackageInfo info = mPackageManager.getPackageInfo(packageName, flags);
- ApplicationInfo appInfo = info.applicationInfo;
- if (appInfo == null) {
- throw new NameNotFoundException("ApplicationInfo is null");
- }
-
- LauncherIcons li = LauncherIcons.obtain(mContext);
- // Load the full res icon for the application, but if useLowResIcon is set, then
- // only keep the low resolution icon instead of the larger full-sized icon
- BitmapInfo iconInfo = li.createBadgedIconBitmap(
- appInfo.loadIcon(mPackageManager), user, appInfo.targetSdkVersion,
- mInstantAppResolver.isInstantApp(appInfo));
- li.recycle();
-
- Bitmap lowResIcon = generateLowResIcon(iconInfo.icon);
- entry.title = appInfo.loadLabel(mPackageManager);
- entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
- entry.icon = useLowResIcon ? lowResIcon : iconInfo.icon;
- entry.color = iconInfo.color;
- entry.isLowResIcon = useLowResIcon;
-
- // Add the icon in the DB here, since these do not get written during
- // package updates.
- ContentValues values = newContentValues(iconInfo.icon, lowResIcon, entry.color,
- entry.title.toString(), packageName);
- addIconToDB(values, cacheKey.componentName, info,
- mUserManager.getSerialNumberForUser(user));
-
- } catch (NameNotFoundException e) {
- if (DEBUG) Log.d(TAG, "Application not installed " + packageName);
- entryUpdated = false;
- }
- }
-
- // Only add a filled-out entry to the cache
- if (entryUpdated) {
- mCache.put(cacheKey, entry);
- }
- }
- return entry;
- }
-
- private boolean getEntryFromDB(ComponentKey cacheKey, CacheEntry entry, boolean lowRes) {
- Cursor c = null;
- try {
- c = mIconDb.query(
- new String[]{lowRes ? IconDB.COLUMN_ICON_LOW_RES : IconDB.COLUMN_ICON,
- IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL},
- IconDB.COLUMN_COMPONENT + " = ? AND " + IconDB.COLUMN_USER + " = ?",
- new String[]{cacheKey.componentName.flattenToString(),
- Long.toString(mUserManager.getSerialNumberForUser(cacheKey.user))});
- if (c.moveToNext()) {
- entry.icon = loadIconNoResize(c, 0, lowRes ? mLowResOptions : mHighResOptions);
- // Set the alpha to be 255, so that we never have a wrong color
- entry.color = ColorUtils.setAlphaComponent(c.getInt(1), 255);
- entry.isLowResIcon = lowRes;
- entry.title = c.getString(2);
- if (entry.title == null) {
- entry.title = "";
- entry.contentDescription = "";
- } else {
- entry.contentDescription = mUserManager.getBadgedLabelForUser(
- entry.title, cacheKey.user);
- }
- return true;
- }
- } catch (SQLiteException e) {
- Log.d(TAG, "Error reading icon cache", e);
- } finally {
- if (c != null) {
- c.close();
- }
- }
- return false;
- }
-
- public static abstract class IconLoadRequest implements Runnable {
- private final Handler mHandler;
- private final Runnable mEndRunnable;
-
- private boolean mEnded = false;
-
- IconLoadRequest(Handler handler, Runnable endRunnable) {
- mHandler = handler;
- mEndRunnable = endRunnable;
- }
-
- public void cancel() {
- mHandler.removeCallbacks(this);
- onEnd();
- }
-
- public void onEnd() {
- if (!mEnded) {
- mEnded = true;
- mEndRunnable.run();
- }
- }
- }
-
- /**
- * A runnable that updates invalid icons and adds missing icons in the DB for the provided
- * LauncherActivityInfo list. Items are updated/added one at a time, so that the
- * worker thread doesn't get blocked.
- */
- @Thunk class SerializedIconUpdateTask implements Runnable {
- private final long mUserSerial;
- private final HashMap<String, PackageInfo> mPkgInfoMap;
- private final Stack<LauncherActivityInfo> mAppsToAdd;
- private final Stack<LauncherActivityInfo> mAppsToUpdate;
- private final HashSet<String> mUpdatedPackages = new HashSet<>();
-
- @Thunk SerializedIconUpdateTask(long userSerial, HashMap<String, PackageInfo> pkgInfoMap,
- Stack<LauncherActivityInfo> appsToAdd,
- Stack<LauncherActivityInfo> appsToUpdate) {
- mUserSerial = userSerial;
- mPkgInfoMap = pkgInfoMap;
- mAppsToAdd = appsToAdd;
- mAppsToUpdate = appsToUpdate;
- }
-
- @Override
- public void run() {
- if (!mAppsToUpdate.isEmpty()) {
- LauncherActivityInfo app = mAppsToUpdate.pop();
- String pkg = app.getComponentName().getPackageName();
- PackageInfo info = mPkgInfoMap.get(pkg);
- addIconToDBAndMemCache(app, info, mUserSerial, true /*replace existing*/);
- mUpdatedPackages.add(pkg);
-
- if (mAppsToUpdate.isEmpty() && !mUpdatedPackages.isEmpty()) {
- // No more app to update. Notify model.
- LauncherAppState.getInstance(mContext).getModel().onPackageIconsUpdated(
- mUpdatedPackages, mUserManager.getUserForSerialNumber(mUserSerial));
- }
-
- // Let it run one more time.
- scheduleNext();
- } else if (!mAppsToAdd.isEmpty()) {
- LauncherActivityInfo app = mAppsToAdd.pop();
- PackageInfo info = mPkgInfoMap.get(app.getComponentName().getPackageName());
- // We do not check the mPkgInfoMap when generating the mAppsToAdd. Although every
- // app should have package info, this is not guaranteed by the api
- if (info != null) {
- addIconToDBAndMemCache(app, info, mUserSerial, false /*replace existing*/);
- }
-
- if (!mAppsToAdd.isEmpty()) {
- scheduleNext();
- }
- }
- }
-
- public void scheduleNext() {
- mWorkerHandler.postAtTime(this, ICON_UPDATE_TOKEN, SystemClock.uptimeMillis() + 1);
- }
- }
-
- private static final class IconDB extends SQLiteCacheHelper {
- private final static int RELEASE_VERSION = 24;
-
- private final static String TABLE_NAME = "icons";
- private final static String COLUMN_ROWID = "rowid";
- private final static String COLUMN_COMPONENT = "componentName";
- private final static String COLUMN_USER = "profileId";
- private final static String COLUMN_LAST_UPDATED = "lastUpdated";
- private final static String COLUMN_VERSION = "version";
- private final static String COLUMN_ICON = "icon";
- private final static String COLUMN_ICON_LOW_RES = "icon_low_res";
- private final static String COLUMN_ICON_COLOR = "icon_color";
- private final static String COLUMN_LABEL = "label";
- private final static String COLUMN_SYSTEM_STATE = "system_state";
-
- public IconDB(Context context, int iconPixelSize) {
- super(context, LauncherFiles.APP_ICONS_DB,
- (RELEASE_VERSION << 16) + iconPixelSize,
- TABLE_NAME);
- }
-
- @Override
- protected void onCreateTable(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" +
- COLUMN_COMPONENT + " TEXT NOT NULL, " +
- COLUMN_USER + " INTEGER NOT NULL, " +
- COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, " +
- COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, " +
- COLUMN_ICON + " BLOB, " +
- COLUMN_ICON_LOW_RES + " BLOB, " +
- COLUMN_ICON_COLOR + " INTEGER NOT NULL DEFAULT 0, " +
- COLUMN_LABEL + " TEXT, " +
- COLUMN_SYSTEM_STATE + " TEXT, " +
- "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ") " +
- ");");
- }
- }
-
- private ContentValues newContentValues(Bitmap icon, Bitmap lowResIcon, int iconColor,
- String label, String packageName) {
- ContentValues values = new ContentValues();
- values.put(IconDB.COLUMN_ICON, Utilities.flattenBitmap(icon));
- values.put(IconDB.COLUMN_ICON_LOW_RES, Utilities.flattenBitmap(lowResIcon));
- values.put(IconDB.COLUMN_ICON_COLOR, iconColor);
-
- values.put(IconDB.COLUMN_LABEL, label);
- values.put(IconDB.COLUMN_SYSTEM_STATE, mIconProvider.getIconSystemState(packageName));
-
- return values;
- }
-
- /**
- * Generates a new low-res icon given a high-res icon.
- */
- private Bitmap generateLowResIcon(Bitmap icon) {
- return Bitmap.createScaledBitmap(icon,
- icon.getWidth() / LOW_RES_SCALE_FACTOR,
- icon.getHeight() / LOW_RES_SCALE_FACTOR, true);
- }
-
- private static Bitmap loadIconNoResize(Cursor c, int iconIndex, BitmapFactory.Options options) {
- byte[] data = c.getBlob(iconIndex);
- try {
- return BitmapFactory.decodeByteArray(data, 0, data.length, options);
- } catch (Exception e) {
- return null;
- }
- }
-
- private class ActivityInfoProvider extends Provider<LauncherActivityInfo> {
-
- private final Intent mIntent;
- private final UserHandle mUser;
-
- public ActivityInfoProvider(Intent intent, UserHandle user) {
- mIntent = intent;
- mUser = user;
- }
-
- @Override
- public LauncherActivityInfo get() {
- return mLauncherApps.resolveActivity(mIntent, mUser);
- }
- }
-
- /**
- * Interface for receiving itemInfo with high-res icon.
- */
- public interface ItemInfoUpdateReceiver {
-
- void reapplyItemInfo(ItemInfoWithIcon info);
- }
-}
diff --git a/src/com/android/launcher3/IconProvider.java b/src/com/android/launcher3/IconProvider.java
index b469a8f..e1ef954 100644
--- a/src/com/android/launcher3/IconProvider.java
+++ b/src/com/android/launcher3/IconProvider.java
@@ -3,36 +3,19 @@
import android.content.Context;
import android.content.pm.LauncherActivityInfo;
import android.graphics.drawable.Drawable;
-import android.os.Build;
-import java.util.Locale;
+import com.android.launcher3.util.ResourceBasedOverride;
-public class IconProvider {
-
- protected String mSystemState;
+public class IconProvider implements ResourceBasedOverride {
public static IconProvider newInstance(Context context) {
- IconProvider provider = Utilities.getOverrideObject(
- IconProvider.class, context, R.string.icon_provider_class);
- provider.updateSystemStateString(context);
- return provider;
+ return Overrides.getObject(IconProvider.class, context, R.string.icon_provider_class);
}
public IconProvider() { }
- public void updateSystemStateString(Context context) {
- final String locale;
- if (Utilities.ATLEAST_NOUGAT) {
- locale = context.getResources().getConfiguration().getLocales().toLanguageTags();
- } else {
- locale = Locale.getDefault().toString();
- }
-
- mSystemState = locale + "," + Build.VERSION.SDK_INT;
- }
-
- public String getIconSystemState(String packageName) {
- return mSystemState;
+ public String getSystemStateForPackage(String systemState, String packageName) {
+ return systemState;
}
/**
diff --git a/src/com/android/launcher3/InsettableFrameLayout.java b/src/com/android/launcher3/InsettableFrameLayout.java
index 1db1fc0..faa18b8 100644
--- a/src/com/android/launcher3/InsettableFrameLayout.java
+++ b/src/com/android/launcher3/InsettableFrameLayout.java
@@ -68,7 +68,7 @@
}
public static class LayoutParams extends FrameLayout.LayoutParams {
- boolean ignoreInsets = false;
+ public boolean ignoreInsets = false;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index fe8a841..ea59fff 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -40,14 +40,14 @@
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.graphics.BitmapInfo;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.GraphicsUtils;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.Provider;
import com.android.launcher3.util.Thunk;
import org.json.JSONException;
@@ -458,7 +458,7 @@
.key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
.key(NAME_KEY).value(name);
if (icon != null) {
- byte[] iconByteArray = Utilities.flattenBitmap(icon);
+ byte[] iconByteArray = GraphicsUtils.flattenBitmap(icon);
json = json.key(ICON_KEY).value(
Base64.encodeToString(
iconByteArray, 0, iconByteArray.length, Base64.DEFAULT));
@@ -481,25 +481,22 @@
final LauncherAppState app = LauncherAppState.getInstance(mContext);
// Set default values until proper values is loaded.
appInfo.title = "";
- app.getIconCache().getDefaultIcon(user).applyTo(appInfo);
+ appInfo.applyFrom(app.getIconCache().getDefaultIcon(user));
final ShortcutInfo si = appInfo.makeShortcut();
if (Looper.myLooper() == LauncherModel.getWorkerLooper()) {
app.getIconCache().getTitleAndIcon(si, activityInfo, false /* useLowResIcon */);
} else {
- app.getModel().updateAndBindShortcutInfo(new Provider<ShortcutInfo>() {
- @Override
- public ShortcutInfo get() {
- app.getIconCache().getTitleAndIcon(
- si, activityInfo, false /* useLowResIcon */);
- return si;
- }
+ app.getModel().updateAndBindShortcutInfo(() -> {
+ app.getIconCache().getTitleAndIcon(
+ si, activityInfo, false /* useLowResIcon */);
+ return si;
});
}
return Pair.create((ItemInfo) si, (Object) activityInfo);
} else if (shortcutInfo != null) {
ShortcutInfo si = new ShortcutInfo(shortcutInfo, mContext);
LauncherIcons li = LauncherIcons.obtain(mContext);
- li.createShortcutIcon(shortcutInfo).applyTo(si);
+ si.applyFrom(li.createShortcutIcon(shortcutInfo));
li.recycle();
return Pair.create((ItemInfo) si, (Object) shortcutInfo);
} else if (providerInfo != null) {
@@ -660,11 +657,11 @@
if (iconInfo == null) {
iconInfo = app.getIconCache().getDefaultIcon(info.user);
}
- iconInfo.applyTo(info);
+ info.applyFrom(iconInfo);
info.title = Utilities.trim(name);
- info.contentDescription = UserManagerCompat.getInstance(app.getContext())
- .getBadgedLabelForUser(info.title, info.user);
+ info.contentDescription = app.getContext().getPackageManager()
+ .getUserBadgedLabel(info.title, info.user);
info.intent = intent;
return info;
}
diff --git a/src/com/android/launcher3/InterruptibleInOutAnimator.java b/src/com/android/launcher3/InterruptibleInOutAnimator.java
index 8501e24..f4395ca 100644
--- a/src/com/android/launcher3/InterruptibleInOutAnimator.java
+++ b/src/com/android/launcher3/InterruptibleInOutAnimator.java
@@ -18,7 +18,9 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
+import android.util.Property;
import android.view.View;
import com.android.launcher3.util.Thunk;
@@ -31,11 +33,27 @@
* interpolator in the same direction.
*/
public class InterruptibleInOutAnimator {
+
+ private static final Property<InterruptibleInOutAnimator, Float> VALUE =
+ new Property<InterruptibleInOutAnimator, Float>(Float.TYPE, "value") {
+ @Override
+ public Float get(InterruptibleInOutAnimator anim) {
+ return anim.mValue;
+ }
+
+ @Override
+ public void set(InterruptibleInOutAnimator anim, Float value) {
+ anim.mValue = value;
+ }
+ };
+
private long mOriginalDuration;
private float mOriginalFromValue;
private float mOriginalToValue;
private ValueAnimator mAnimator;
+ private float mValue;
+
private boolean mFirstRun = true;
private Object mTag = null;
@@ -47,8 +65,8 @@
// TODO: This isn't really necessary, but is here to help diagnose a bug in the drag viz
@Thunk int mDirection = STOPPED;
- public InterruptibleInOutAnimator(View view, long duration, float fromValue, float toValue) {
- mAnimator = LauncherAnimUtils.ofFloat(fromValue, toValue).setDuration(duration);
+ public InterruptibleInOutAnimator(long duration, float fromValue, float toValue) {
+ mAnimator = ObjectAnimator.ofFloat(this, VALUE, fromValue, toValue).setDuration(duration);
mOriginalDuration = duration;
mOriginalFromValue = fromValue;
mOriginalToValue = toValue;
@@ -64,8 +82,7 @@
private void animate(int direction) {
final long currentPlayTime = mAnimator.getCurrentPlayTime();
final float toValue = (direction == IN) ? mOriginalToValue : mOriginalFromValue;
- final float startValue = mFirstRun ? mOriginalFromValue :
- ((Float) mAnimator.getAnimatedValue()).floatValue();
+ final float startValue = mFirstRun ? mOriginalFromValue : mValue;
// Make sure it's stopped before we modify any values
cancel();
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index f63cce5..0b2f4d9 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -16,19 +16,22 @@
package com.android.launcher3;
+import static com.android.launcher3.config.FeatureFlags.APPLY_CONFIG_AT_RUNTIME;
+
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Point;
-import android.support.annotation.VisibleForTesting;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.Xml;
import android.view.Display;
import android.view.WindowManager;
-import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.ConfigMonitor;
+import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Thunk;
import org.xmlpull.v1.XmlPullParser;
@@ -39,13 +42,19 @@
import java.util.Collections;
import java.util.Comparator;
+import androidx.annotation.VisibleForTesting;
+
public class InvariantDeviceProfile {
- // This is a static that we use for the default icon size on a 4/5-inch phone
- private static float DEFAULT_ICON_SIZE_DP = 60;
+ // We do not need any synchronization for this variable as its only written on UI thread.
+ public static final MainThreadInitializedObject<InvariantDeviceProfile> INSTANCE =
+ new MainThreadInitializedObject<>(InvariantDeviceProfile::new);
private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
+ public static final int CHANGE_FLAG_GRID = 1 << 0;
+ public static final int CHANGE_FLAG_ICON_SIZE = 1 << 1;
+
// Constants that affects the interpolation curve between statically defined device profile
// buckets.
private static float KNEARESTNEIGHBOR = 3;
@@ -55,9 +64,9 @@
private static float WEIGHT_EFFICIENT = 100000f;
// Profile-defining invariant properties
- String name;
- float minWidthDps;
- float minHeightDps;
+ private String name;
+ private float minWidthDps;
+ private float minHeightDps;
/**
* Number of icons per row and column in the workspace.
@@ -89,9 +98,11 @@
public Point defaultWallpaperSize;
+ private final ArrayList<OnIDPChangeListener> mChangeListeners = new ArrayList<>();
+ private ConfigMonitor mConfigMonitor;
+
@VisibleForTesting
- public InvariantDeviceProfile() {
- }
+ public InvariantDeviceProfile() {}
private InvariantDeviceProfile(InvariantDeviceProfile p) {
this(p.name, p.minWidthDps, p.minHeightDps, p.numRows, p.numColumns,
@@ -118,7 +129,13 @@
}
@TargetApi(23)
- public InvariantDeviceProfile(Context context) {
+ private InvariantDeviceProfile(Context context) {
+ initGrid(context);
+ mConfigMonitor = new ConfigMonitor(context,
+ APPLY_CONFIG_AT_RUNTIME.get() ? this::onConfigChanged : this::killProcess);
+ }
+
+ private void initGrid(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
@@ -179,6 +196,44 @@
}
}
+ public void addOnChangeListener(OnIDPChangeListener listener) {
+ mChangeListeners.add(listener);
+ }
+
+ private void killProcess(Context context) {
+ Log.e("ConfigMonitor", "restarting launcher");
+ android.os.Process.killProcess(android.os.Process.myPid());
+ }
+
+ private void onConfigChanged(Context context) {
+ // Config changes, what shall we do?
+ InvariantDeviceProfile oldProfile = new InvariantDeviceProfile(this);
+
+ // Re-init grid
+ initGrid(context);
+
+ int changeFlags = 0;
+ if (numRows != oldProfile.numRows ||
+ numColumns != oldProfile.numColumns ||
+ numFolderColumns != oldProfile.numFolderColumns ||
+ numFolderRows != oldProfile.numFolderRows ||
+ numHotseatIcons != oldProfile.numHotseatIcons) {
+ changeFlags |= CHANGE_FLAG_GRID;
+ }
+
+ if (iconSize != oldProfile.iconSize || iconBitmapSize != oldProfile.iconBitmapSize) {
+ changeFlags |= CHANGE_FLAG_ICON_SIZE;
+ }
+
+ // Create a new config monitor
+ mConfigMonitor.unregister();
+ mConfigMonitor = new ConfigMonitor(context, this::onConfigChanged);
+
+ for (OnIDPChangeListener listener : mChangeListeners) {
+ listener.onIdpChanged(changeFlags, this);
+ }
+ }
+
ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles(Context context) {
ArrayList<InvariantDeviceProfile> profiles = new ArrayList<>();
try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
@@ -308,17 +363,6 @@
return this;
}
- public int getAllAppsButtonRank() {
- if (FeatureFlags.IS_DOGFOOD_BUILD && FeatureFlags.NO_ALL_APPS_ICON) {
- throw new IllegalAccessError("Accessing all apps rank when all-apps is disabled");
- }
- return numHotseatIcons / 2;
- }
-
- public boolean isAllAppsButtonRank(int rank) {
- return rank == getAllAppsButtonRank();
- }
-
public DeviceProfile getDeviceProfile(Context context) {
return context.getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE ? landscapeProfile : portraitProfile;
@@ -361,4 +405,8 @@
return x * aspectRatio + y;
}
+ public interface OnIDPChangeListener {
+
+ void onIdpChanged(int changeFlags, InvariantDeviceProfile profile);
+ }
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index fa3253c..bffdd72 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -34,7 +34,7 @@
/**
* The id in the settings database for this item
*/
- public long id = NO_ID;
+ public int id = NO_ID;
/**
* One of {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION},
@@ -52,14 +52,14 @@
* will be {@link #NO_ID} (since it is not stored in the settings DB). For user folders
* it will be the id of the folder.
*/
- public long container = NO_ID;
+ public int container = NO_ID;
/**
* Indicates the screen in which the shortcut appears if the container types is
* {@link LauncherSettings.Favorites#CONTAINER_DESKTOP}. (i.e., ignore if the container type is
* {@link LauncherSettings.Favorites#CONTAINER_HOTSEAT})
*/
- public long screenId = -1;
+ public int screenId = -1;
/**
* Indicates the X position of the associated cell.
@@ -158,8 +158,8 @@
public void readFromValues(ContentValues values) {
itemType = values.getAsInteger(LauncherSettings.Favorites.ITEM_TYPE);
- container = values.getAsLong(LauncherSettings.Favorites.CONTAINER);
- screenId = values.getAsLong(LauncherSettings.Favorites.SCREEN);
+ container = values.getAsInteger(LauncherSettings.Favorites.CONTAINER);
+ screenId = values.getAsInteger(LauncherSettings.Favorites.SCREEN);
cellX = values.getAsInteger(LauncherSettings.Favorites.CELLX);
cellY = values.getAsInteger(LauncherSettings.Favorites.CELLY);
spanX = values.getAsInteger(LauncherSettings.Favorites.SPANX);
diff --git a/src/com/android/launcher3/ItemInfoWithIcon.java b/src/com/android/launcher3/ItemInfoWithIcon.java
index 4677d31..e29f927 100644
--- a/src/com/android/launcher3/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/ItemInfoWithIcon.java
@@ -16,8 +16,12 @@
package com.android.launcher3;
+import static com.android.launcher3.icons.BitmapInfo.LOW_RES_ICON;
+
import android.graphics.Bitmap;
+import com.android.launcher3.icons.BitmapInfo;
+
/**
* Represents an ItemInfo which also holds an icon.
*/
@@ -34,11 +38,6 @@
public int iconColor;
/**
- * Indicates whether we're using a low res icon
- */
- public boolean usingLowResIcon;
-
- /**
* Indicates that the icon is disabled due to safe mode restrictions.
*/
public static final int FLAG_DISABLED_SAFEMODE = 1 << 0;
@@ -107,7 +106,6 @@
super(info);
iconBitmap = info.iconBitmap;
iconColor = info.iconColor;
- usingLowResIcon = info.usingLowResIcon;
runtimeStatusFlags = info.runtimeStatusFlags;
}
@@ -115,4 +113,17 @@
public boolean isDisabled() {
return (runtimeStatusFlags & FLAG_DISABLED_MASK) != 0;
}
+
+ /**
+ * Indicates whether we're using a low res icon
+ */
+ public boolean usingLowResIcon() {
+ return iconBitmap == LOW_RES_ICON;
+ }
+
+ public void applyFrom(BitmapInfo info) {
+ iconBitmap = info.icon;
+ iconColor = info.color;
+ }
+
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4fe3503..36967cd 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -16,9 +16,10 @@
package com.android.launcher3;
+import static android.content.pm.ActivityInfo.CONFIG_LOCALE;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
-
+import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -39,7 +40,6 @@
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
@@ -48,7 +48,6 @@
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Point;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -56,7 +55,6 @@
import android.os.Process;
import android.os.StrictMode;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
import android.util.Log;
@@ -74,11 +72,11 @@
import android.widget.Toast;
import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
+import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompatVO;
@@ -86,11 +84,14 @@
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.FolderIconPreviewVerifier;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.keyboard.CustomActionsPopup;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.logging.StatsLogUtils;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.logging.UserEventDispatcher.UserEventDelegate;
import com.android.launcher3.model.ModelWriter;
@@ -108,8 +109,8 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.ActivityResultInfo;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.PackageManagerHelper;
@@ -136,10 +137,13 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import androidx.annotation.Nullable;
+
/**
* Default launcher application.
*/
@@ -203,7 +207,6 @@
private final int[] mTmpAddItemCellCoordinates = new int[2];
@Thunk Hotseat mHotseat;
- @Nullable private View mHotseatSearchBox;
private DropTargetBar mDropTargetBar;
@@ -351,11 +354,17 @@
public void onEnterAnimationComplete() {
super.onEnterAnimationComplete();
UiFactory.onEnterAnimationComplete(this);
+ mAllAppsController.highlightWorkTabIfNecessary();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
int diff = newConfig.diff(mOldConfig);
+
+ if ((diff & CONFIG_LOCALE) != 0) {
+ Folder.setLocaleDependentFields(getResources(), true /* force */);
+ }
+
if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) {
mUserEventDispatcher = null;
initDeviceProfile(mDeviceProfile.inv);
@@ -482,9 +491,9 @@
* Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have
* a configuration step, this allows the proper animations to run after other transitions.
*/
- private long completeAdd(
+ private int completeAdd(
int requestCode, Intent intent, int appWidgetId, PendingRequestArgs info) {
- long screenId = info.screenId;
+ int screenId = info.screenId;
if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
// When the screen id represents an actual screen (as opposed to a rank) we make sure
// that the drop page actually exists.
@@ -686,7 +695,7 @@
* @param screenId the screen id to check
* @return the new screen, or screenId if it exists
*/
- private long ensurePendingDropLayoutExists(long screenId) {
+ private int ensurePendingDropLayoutExists(int screenId) {
CellLayout dropLayout = mWorkspace.getScreenWithId(screenId);
if (dropLayout == null) {
// it's possible that the add screen was removed because it was
@@ -734,8 +743,6 @@
@Override
protected void onStop() {
super.onStop();
- FirstFrameAnimatorHelper.setIsVisible(false);
-
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onStop();
}
@@ -756,14 +763,11 @@
@Override
protected void onStart() {
super.onStart();
- FirstFrameAnimatorHelper.setIsVisible(true);
-
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onStart();
}
mAppWidgetHost.setListenIfResumed(true);
NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
- UiFactory.onStart(this);
}
private void logOnDelayedResume() {
@@ -864,17 +868,6 @@
}
}
- public boolean hasSettings() {
- if (mLauncherCallbacks != null) {
- return mLauncherCallbacks.hasSettings();
- } else {
- // On O and above we there is always some setting present settings (add icon to
- // home screen or icon badging). On earlier APIs we will have the allow rotation
- // setting, on devices with a locked orientation,
- return Utilities.ATLEAST_OREO || !getResources().getBoolean(R.bool.allow_rotation);
- }
- }
-
public boolean isInState(LauncherState state) {
return mStateManager.getState() == state;
}
@@ -920,7 +913,6 @@
mWorkspace.initParentViews(mDragLayer);
mOverviewPanel = findViewById(R.id.overview_panel);
mHotseat = findViewById(R.id.hotseat);
- mHotseatSearchBox = findViewById(R.id.search_container_hotseat);
mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
@@ -981,7 +973,7 @@
*
* @param data The intent describing the shortcut.
*/
- private void completeAddShortcut(Intent data, long container, long screenId, int cellX,
+ private void completeAddShortcut(Intent data, int container, int screenId, int cellX,
int cellY, PendingRequestArgs args) {
if (args.getRequestCode() != REQUEST_CREATE_SHORTCUT
|| args.getPendingIntent().getComponent() == null) {
@@ -1057,13 +1049,8 @@
}
}
- public FolderIcon findFolderIcon(final long folderIconId) {
- return (FolderIcon) mWorkspace.getFirstMatch(new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View view) {
- return info != null && info.id == folderIconId;
- }
- });
+ public FolderIcon findFolderIcon(final int folderIconId) {
+ return (FolderIcon) mWorkspace.getHomescreenIconByItemId(folderIconId);
}
/**
@@ -1130,7 +1117,6 @@
public void onAttachedToWindow() {
super.onAttachedToWindow();
- FirstFrameAnimatorHelper.initializeDrawListener(getWindow().getDecorView());
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onAttachedToWindow();
}
@@ -1171,10 +1157,6 @@
return mHotseat;
}
- public View getHotseatSearchBox() {
- return mHotseatSearchBox;
- }
-
public <T extends View> T getOverviewPanel() {
return (T) mOverviewPanel;
}
@@ -1246,7 +1228,7 @@
mAppsView.reset(isStarted() /* animate */);
}
- if (shouldMoveToDefaultScreen && !mWorkspace.isTouchActive()) {
+ if (shouldMoveToDefaultScreen && !mWorkspace.isHandlingTouch()) {
mWorkspace.post(mWorkspace::moveToDefaultScreen);
}
}
@@ -1332,9 +1314,6 @@
}
TextKeyListener.getInstance().release();
-
- LauncherAnimUtils.onDestroyActivity();
-
clearPendingBinds();
if (mLauncherCallbacks != null) {
@@ -1429,7 +1408,7 @@
}
}
- public void addPendingItem(PendingAddItemInfo info, long container, long screenId,
+ public void addPendingItem(PendingAddItemInfo info, int container, int screenId,
int[] cell, int spanX, int spanY) {
info.container = container;
info.screenId = screenId;
@@ -1505,7 +1484,7 @@
}
}
- FolderIcon addFolder(CellLayout layout, long container, final long screenId, int cellX,
+ FolderIcon addFolder(CellLayout layout, int container, final int screenId, int cellX,
int cellY) {
final FolderInfo folderInfo = new FolderInfo();
folderInfo.title = getText(R.string.folder_name);
@@ -1554,7 +1533,7 @@
final LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) itemInfo;
mWorkspace.removeWorkspaceItem(v);
if (deleteFromDb) {
- deleteWidgetInfo(widgetInfo);
+ getModelWriter().deleteWidgetInfo(widgetInfo, getAppWidgetHost());
}
} else {
return false;
@@ -1562,23 +1541,7 @@
return true;
}
- /**
- * Deletes the widget info and the widget id.
- */
- private void deleteWidgetInfo(final LauncherAppWidgetInfo widgetInfo) {
- final LauncherAppWidgetHost appWidgetHost = getAppWidgetHost();
- if (appWidgetHost != null && !widgetInfo.isCustomWidget() && widgetInfo.isWidgetIdAllocated()) {
- // Deleting an app widget ID is a void call but writes to disk before returning
- // to the caller...
- new AsyncTask<Void, Void, Void>() {
- public Void doInBackground(Void ... args) {
- appWidgetHost.deleteAppWidgetId(widgetInfo.appWidgetId);
- return null;
- }
- }.executeOnExecutor(Utilities.THREAD_POOL_EXECUTOR);
- }
- getModelWriter().deleteItemFromDatabase(widgetInfo);
- }
+
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
@@ -1605,14 +1568,8 @@
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
if (topView != null && topView.onBackPressed()) {
// Handled by the floating view.
- } else if (!isInState(NORMAL)) {
- LauncherState lastState = mStateManager.getLastState();
- ued.logActionCommand(Action.Command.BACK, mStateManager.getState().containerType,
- lastState.containerType);
- mStateManager.goToState(lastState);
} else {
- // Back button is a no-op here, but give at least some feedback for the button press
- mWorkspace.showOutlinesTemporarily();
+ mStateManager.getState().onBackPressed(this);
}
}
@@ -1648,6 +1605,16 @@
}
@Override
+ public int getCurrentState() {
+ if(mStateManager.getState() == LauncherState.ALL_APPS) {
+ return StatsLogUtils.LAUNCHER_STATE_ALLAPPS;
+ } else if (mStateManager.getState() == LauncherState.OVERVIEW) {
+ return StatsLogUtils.LAUNCHER_STATE_OVERVIEW;
+ }
+ return StatsLogUtils.LAUNCHER_STATE_HOME;
+ }
+
+ @Override
public void modifyUserEvent(LauncherLogProto.LauncherEvent event) {
if (event.srcTarget != null && event.srcTarget.length > 0 &&
event.srcTarget[1].containerType == ContainerType.PREDICTION) {
@@ -1681,23 +1648,15 @@
boolean isHotseatLayout(View layout) {
// TODO: Remove this method
- return mHotseat != null && layout != null &&
- (layout instanceof CellLayout) && (layout == mHotseat.getLayout());
+ return mHotseat != null && (layout == mHotseat);
}
/**
* Returns the CellLayout of the specified container at the specified screen.
*/
- public CellLayout getCellLayout(long container, long screenId) {
- if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- if (mHotseat != null) {
- return mHotseat.getLayout();
- } else {
- return null;
- }
- } else {
- return mWorkspace.getScreenWithId(screenId);
- }
+ public CellLayout getCellLayout(int container, int screenId) {
+ return (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)
+ ? mHotseat : mWorkspace.getScreenWithId(screenId);
}
@Override
@@ -1788,14 +1747,15 @@
}
@Override
- public void bindScreens(ArrayList<Long> orderedScreenIds) {
+ public void bindScreens(IntArray orderedScreenIds) {
// Make sure the first screen is always at the start.
- if (FeatureFlags.QSB_ON_FIRST_SCREEN &&
+ if (FeatureFlags.QSB_ON_FIRST_SCREEN.get() &&
orderedScreenIds.indexOf(Workspace.FIRST_SCREEN_ID) != 0) {
- orderedScreenIds.remove(Workspace.FIRST_SCREEN_ID);
+ orderedScreenIds.removeValue(Workspace.FIRST_SCREEN_ID);
orderedScreenIds.add(0, Workspace.FIRST_SCREEN_ID);
LauncherModel.updateWorkspaceScreenOrder(this, orderedScreenIds);
- } else if (!FeatureFlags.QSB_ON_FIRST_SCREEN && orderedScreenIds.isEmpty()) {
+ } else if (!FeatureFlags.QSB_ON_FIRST_SCREEN.get()
+ && orderedScreenIds.isEmpty()) {
// If there are no screens, we need to have an empty screen
mWorkspace.addExtraEmptyScreen();
}
@@ -1807,11 +1767,11 @@
mWorkspace.unlockWallpaperFromDefaultPageOnNextLayout();
}
- private void bindAddScreens(ArrayList<Long> orderedScreenIds) {
+ private void bindAddScreens(IntArray orderedScreenIds) {
int count = orderedScreenIds.size();
for (int i = 0; i < count; i++) {
- long screenId = orderedScreenIds.get(i);
- if (!FeatureFlags.QSB_ON_FIRST_SCREEN || screenId != Workspace.FIRST_SCREEN_ID) {
+ int screenId = orderedScreenIds.get(i);
+ if (!FeatureFlags.QSB_ON_FIRST_SCREEN.get() || screenId != Workspace.FIRST_SCREEN_ID) {
// No need to bind the first screen, as its always bound.
mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(screenId);
}
@@ -1819,7 +1779,18 @@
}
@Override
- public void bindAppsAdded(ArrayList<Long> newScreens, ArrayList<ItemInfo> addNotAnimated,
+ public void preAddApps() {
+ // If there's an undo snackbar, force it to complete to ensure empty screens are removed
+ // before trying to add new items.
+ mModelWriter.commitDelete();
+ AbstractFloatingView snackbar = AbstractFloatingView.getOpenView(this, TYPE_SNACKBAR);
+ if (snackbar != null) {
+ snackbar.post(() -> snackbar.close(true));
+ }
+ }
+
+ @Override
+ public void bindAppsAdded(IntArray newScreens, ArrayList<ItemInfo> addNotAnimated,
ArrayList<ItemInfo> addAnimated) {
// Add the new screens
if (newScreens != null) {
@@ -1847,11 +1818,10 @@
@Override
public void bindItems(final List<ItemInfo> items, final boolean forceAnimateIcons) {
// Get the list of added items and intersect them with the set of items here
- final AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
final Collection<Animator> bounceAnims = new ArrayList<>();
final boolean animateIcons = forceAnimateIcons && canRunNewAppsAnimation();
Workspace workspace = mWorkspace;
- long newItemsScreenId = -1;
+ int newItemsScreenId = -1;
int end = items.size();
for (int i = 0; i < end; i++) {
final ItemInfo item = items.get(i);
@@ -1919,34 +1889,31 @@
}
}
- if (animateIcons) {
- // Animate to the correct page
- if (newItemsScreenId > -1) {
- long currentScreenId = mWorkspace.getScreenIdForPageIndex(mWorkspace.getNextPage());
- final int newScreenIndex = mWorkspace.getPageIndexForScreenId(newItemsScreenId);
- final Runnable startBounceAnimRunnable = new Runnable() {
- public void run() {
- anim.playTogether(bounceAnims);
- anim.start();
- }
- };
- if (newItemsScreenId != currentScreenId) {
- // We post the animation slightly delayed to prevent slowdowns
- // when we are loading right after we return to launcher.
- mWorkspace.postDelayed(new Runnable() {
- public void run() {
- if (mWorkspace != null) {
- AbstractFloatingView.closeAllOpenViews(Launcher.this, false);
+ // Animate to the correct page
+ if (animateIcons && newItemsScreenId > -1) {
+ AnimatorSet anim = new AnimatorSet();
+ anim.playTogether(bounceAnims);
- mWorkspace.snapToPage(newScreenIndex);
- mWorkspace.postDelayed(startBounceAnimRunnable,
- NEW_APPS_ANIMATION_DELAY);
- }
+ int currentScreenId = mWorkspace.getScreenIdForPageIndex(mWorkspace.getNextPage());
+ final int newScreenIndex = mWorkspace.getPageIndexForScreenId(newItemsScreenId);
+ final Runnable startBounceAnimRunnable = anim::start;
+
+ if (newItemsScreenId != currentScreenId) {
+ // We post the animation slightly delayed to prevent slowdowns
+ // when we are loading right after we return to launcher.
+ mWorkspace.postDelayed(new Runnable() {
+ public void run() {
+ if (mWorkspace != null) {
+ AbstractFloatingView.closeAllOpenViews(Launcher.this, false);
+
+ mWorkspace.snapToPage(newScreenIndex);
+ mWorkspace.postDelayed(startBounceAnimRunnable,
+ NEW_APPS_ANIMATION_DELAY);
}
- }, NEW_APPS_PAGE_MOVE_DELAY);
- } else {
- mWorkspace.postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY);
- }
+ }
+ }, NEW_APPS_PAGE_MOVE_DELAY);
+ } else {
+ mWorkspace.postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY);
}
}
workspace.requestLayout();
@@ -2055,7 +2022,7 @@
// Verify that we own the widget
if (appWidgetInfo == null) {
FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId);
- deleteWidgetInfo(item);
+ getModelWriter().deleteWidgetInfo(item, getAppWidgetHost());
return null;
}
@@ -2145,7 +2112,7 @@
*
* Implementation of the method from LauncherModel.Callbacks.
*/
- public void finishBindingItems() {
+ public void finishBindingItems(int currentScreen) {
TraceHelper.beginSection("finishBindingItems");
mWorkspace.restoreInstanceStateForRemainingPages();
@@ -2160,6 +2127,8 @@
InstallShortcutReceiver.disableAndFlushInstallQueue(
InstallShortcutReceiver.FLAG_LOADER_RUNNING, this);
+ mWorkspace.setCurrentPage(currentScreen);
+
TraceHelper.endSection("finishBindingItems");
}
@@ -2169,8 +2138,8 @@
}
private ValueAnimator createNewAppBounceAnimation(View v, int i) {
- ValueAnimator bounceAnim = LauncherAnimUtils.ofViewAlphaAndScale(v, 1, 1, 1);
- bounceAnim.setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION);
+ ValueAnimator bounceAnim = new PropertyListBuilder().alpha(1).scale(1).build(v)
+ .setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION);
bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY);
bounceAnim.setInterpolator(new OvershootInterpolator(BOUNCE_ANIMATION_TENSION));
return bounceAnim;
@@ -2190,11 +2159,11 @@
}
/**
- * Copies LauncherModel's map of activities to shortcut ids to Launcher's. This is necessary
+ * Copies LauncherModel's map of activities to shortcut counts to Launcher's. This is necessary
* because LauncherModel's map is updated in the background, while Launcher runs on the UI.
*/
@Override
- public void bindDeepShortcutMap(MultiHashMap<ComponentKey, String> deepShortcutMapCopy) {
+ public void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy) {
mPopupDataProvider.setDeepShortcutMap(deepShortcutMapCopy);
}
@@ -2298,7 +2267,7 @@
}
writer.println(prefix + " Hotseat");
- ViewGroup layout = mHotseat.getLayout().getShortcutsAndWidgets();
+ ViewGroup layout = mHotseat.getShortcutsAndWidgets();
for (int j = 0; j < layout.getChildCount(); j++) {
Object tag = layout.getChildAt(j).getTag();
if (tag != null) {
@@ -2312,6 +2281,8 @@
writer.print(" mPendingRequestArgs=" + mPendingRequestArgs);
writer.println(" mPendingActivityResult=" + mPendingActivityResult);
writer.println(" mRotationHelper: " + mRotationHelper);
+ // Extra logging for b/116853349
+ mDragLayer.dumpAlpha(writer);
dumpMisc(writer);
try {
@@ -2417,10 +2388,7 @@
}
public static Launcher getLauncher(Context context) {
- if (context instanceof Launcher) {
- return (Launcher) context;
- }
- return ((Launcher) ((ContextWrapper) context).getBaseContext());
+ return (Launcher) fromContext(context);
}
/**
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index 03ffded..aad3449 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -16,18 +16,10 @@
package com.android.launcher3;
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
import android.graphics.drawable.Drawable;
import android.util.Property;
import android.view.View;
-import android.view.ViewTreeObserver;
-
-import java.util.HashSet;
-import java.util.WeakHashMap;
+import android.view.ViewGroup.LayoutParams;
public class LauncherAnimUtils {
/**
@@ -42,105 +34,6 @@
// The progress of an animation to all apps must be at least this far along to snap to all apps.
public static final float MIN_PROGRESS_TO_ALL_APPS = 0.5f;
- static WeakHashMap<Animator, Object> sAnimators = new WeakHashMap<Animator, Object>();
- static Animator.AnimatorListener sEndAnimListener = new Animator.AnimatorListener() {
- public void onAnimationStart(Animator animation) {
- sAnimators.put(animation, null);
- }
-
- public void onAnimationRepeat(Animator animation) {
- }
-
- public void onAnimationEnd(Animator animation) {
- sAnimators.remove(animation);
- }
-
- public void onAnimationCancel(Animator animation) {
- sAnimators.remove(animation);
- }
- };
-
- public static void cancelOnDestroyActivity(Animator a) {
- a.addListener(sEndAnimListener);
- }
-
- // Helper method. Assumes a draw is pending, and that if the animation's duration is 0
- // it should be cancelled
- public static void startAnimationAfterNextDraw(final Animator animator, final View view) {
- view.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
- private boolean mStarted = false;
-
- public void onDraw() {
- if (mStarted) return;
- mStarted = true;
- // Use this as a signal that the animation was cancelled
- if (animator.getDuration() == 0) {
- return;
- }
- animator.start();
-
- final ViewTreeObserver.OnDrawListener listener = this;
- view.post(new Runnable() {
- public void run() {
- view.getViewTreeObserver().removeOnDrawListener(listener);
- }
- });
- }
- });
- }
-
- public static void onDestroyActivity() {
- HashSet<Animator> animators = new HashSet<Animator>(sAnimators.keySet());
- for (Animator a : animators) {
- if (a.isRunning()) {
- a.cancel();
- }
- sAnimators.remove(a);
- }
- }
-
- public static AnimatorSet createAnimatorSet() {
- AnimatorSet anim = new AnimatorSet();
- cancelOnDestroyActivity(anim);
- return anim;
- }
-
- public static ValueAnimator ofFloat(float... values) {
- ValueAnimator anim = new ValueAnimator();
- anim.setFloatValues(values);
- cancelOnDestroyActivity(anim);
- return anim;
- }
-
- public static ObjectAnimator ofFloat(View target, Property<View, Float> property,
- float... values) {
- ObjectAnimator anim = ObjectAnimator.ofFloat(target, property, values);
- cancelOnDestroyActivity(anim);
- new FirstFrameAnimatorHelper(anim, target);
- return anim;
- }
-
- public static ObjectAnimator ofViewAlphaAndScale(View target,
- float alpha, float scaleX, float scaleY) {
- return ofPropertyValuesHolder(target,
- PropertyValuesHolder.ofFloat(View.ALPHA, alpha),
- PropertyValuesHolder.ofFloat(View.SCALE_X, scaleX),
- PropertyValuesHolder.ofFloat(View.SCALE_Y, scaleY));
- }
-
- public static ObjectAnimator ofPropertyValuesHolder(View target,
- PropertyValuesHolder... values) {
- return ofPropertyValuesHolder(target, target, values);
- }
-
- public static ObjectAnimator ofPropertyValuesHolder(Object target,
- View view, PropertyValuesHolder... values) {
- ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(target, values);
- cancelOnDestroyActivity(anim);
- new FirstFrameAnimatorHelper(anim, view);
- return anim;
- }
-
public static final Property<Drawable, Integer> DRAWABLE_ALPHA =
new Property<Drawable, Integer>(Integer.TYPE, "drawableAlpha") {
@Override
@@ -172,4 +65,30 @@
public static int blockedFlingDurationFactor(float velocity) {
return (int) Utilities.boundToRange(Math.abs(velocity) / 2, 2f, 6f);
}
+
+ public static final Property<LayoutParams, Integer> LAYOUT_WIDTH =
+ new Property<LayoutParams, Integer>(Integer.TYPE, "width") {
+ @Override
+ public Integer get(LayoutParams lp) {
+ return lp.width;
+ }
+
+ @Override
+ public void set(LayoutParams lp, Integer width) {
+ lp.width = width;
+ }
+ };
+
+ public static final Property<LayoutParams, Integer> LAYOUT_HEIGHT =
+ new Property<LayoutParams, Integer>(Integer.TYPE, "height") {
+ @Override
+ public Integer get(LayoutParams lp) {
+ return lp.height;
+ }
+
+ @Override
+ public void set(LayoutParams lp, Integer height) {
+ lp.height = height;
+ }
+ };
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index a46692b..338c20b 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -16,64 +16,48 @@
package com.android.launcher3;
+import static com.android.launcher3.util.SecureSettingsObserver.newNotificationSettingsObserver;
+import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_SIZE;
+
import android.content.ComponentName;
import android.content.ContentProviderClient;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.os.Looper;
import android.util.Log;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.notification.NotificationListener;
-import com.android.launcher3.util.ConfigMonitor;
+import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.SettingsObserver;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-
-import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
+import com.android.launcher3.util.SecureSettingsObserver;
public class LauncherAppState {
public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher";
// We do not need any synchronization for this variable as its only written on UI thread.
- private static LauncherAppState INSTANCE;
+ private static final MainThreadInitializedObject<LauncherAppState> INSTANCE =
+ new MainThreadInitializedObject<>((c) -> new LauncherAppState(c));
private final Context mContext;
private final LauncherModel mModel;
private final IconCache mIconCache;
private final WidgetPreviewLoader mWidgetCache;
private final InvariantDeviceProfile mInvariantDeviceProfile;
- private final SettingsObserver mNotificationBadgingObserver;
+ private final SecureSettingsObserver mNotificationBadgingObserver;
public static LauncherAppState getInstance(final Context context) {
- if (INSTANCE == null) {
- if (Looper.myLooper() == Looper.getMainLooper()) {
- INSTANCE = new LauncherAppState(context.getApplicationContext());
- } else {
- try {
- return new MainThreadExecutor().submit(new Callable<LauncherAppState>() {
- @Override
- public LauncherAppState call() throws Exception {
- return LauncherAppState.getInstance(context);
- }
- }).get();
- } catch (InterruptedException|ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
- }
- return INSTANCE;
+ return INSTANCE.get(context);
}
public static LauncherAppState getInstanceNoCreate() {
- return INSTANCE;
+ return INSTANCE.getNoCreate();
}
public Context getContext() {
@@ -89,7 +73,7 @@
Preconditions.assertUIThread();
mContext = context;
- mInvariantDeviceProfile = new InvariantDeviceProfile(mContext);
+ mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(mContext);
mIconCache = new IconCache(mContext, mInvariantDeviceProfile);
mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext));
@@ -112,26 +96,39 @@
mContext.registerReceiver(mModel, filter);
UserManagerCompat.getInstance(mContext).enableAndResetCache();
- new ConfigMonitor(mContext).register();
+ mInvariantDeviceProfile.addOnChangeListener(this::onIdpChanged);
if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) {
mNotificationBadgingObserver = null;
} else {
// Register an observer to rebind the notification listener when badging is re-enabled.
- mNotificationBadgingObserver = new SettingsObserver.Secure(
- mContext.getContentResolver()) {
- @Override
- public void onSettingChanged(boolean isNotificationBadgingEnabled) {
- if (isNotificationBadgingEnabled) {
- NotificationListener.requestRebind(new ComponentName(
- mContext, NotificationListener.class));
- }
- }
- };
- mNotificationBadgingObserver.register(NOTIFICATION_BADGING);
+ mNotificationBadgingObserver =
+ newNotificationSettingsObserver(mContext, this::onNotificationSettingsChanged);
+ mNotificationBadgingObserver.register();
+ mNotificationBadgingObserver.dispatchOnChange();
}
}
+ protected void onNotificationSettingsChanged(boolean isNotificationBadgingEnabled) {
+ if (isNotificationBadgingEnabled) {
+ NotificationListener.requestRebind(new ComponentName(
+ mContext, NotificationListener.class));
+ }
+ }
+
+ private void onIdpChanged(int changeFlags, InvariantDeviceProfile idp) {
+ if (changeFlags == 0) {
+ return;
+ }
+
+ if ((changeFlags & CHANGE_FLAG_ICON_SIZE) != 0) {
+ LauncherIcons.clearPool();
+ mIconCache.updateIconParams(idp.fillResIconDpi, idp.iconBitmapSize);
+ }
+
+ mModel.forceReload();
+ }
+
/**
* Call from Application.onTerminate(), which is not guaranteed to ever be called.
*/
@@ -171,7 +168,7 @@
* Shorthand for {@link #getInvariantDeviceProfile()}
*/
public static InvariantDeviceProfile getIDP(Context context) {
- return LauncherAppState.getInstance(context).getInvariantDeviceProfile();
+ return InvariantDeviceProfile.INSTANCE.get(context);
}
private static LauncherProvider getLocalProvider(Context context) {
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
index 4037a23..970e558 100644
--- a/src/com/android/launcher3/LauncherAppTransitionManager.java
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -23,13 +23,15 @@
import android.graphics.drawable.Drawable;
import android.view.View;
+import com.android.launcher3.util.ResourceBasedOverride;
+
/**
* Manages the opening and closing app transitions from Launcher.
*/
-public class LauncherAppTransitionManager {
+public class LauncherAppTransitionManager implements ResourceBasedOverride {
public static LauncherAppTransitionManager newInstance(Context context) {
- return Utilities.getOverrideObject(LauncherAppTransitionManager.class,
+ return Overrides.getObject(LauncherAppTransitionManager.class,
context, R.string.app_transition_manager_class);
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
index 80758c9..228c07e 100644
--- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -2,11 +2,15 @@
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Parcel;
+import android.os.UserHandle;
+
+import com.android.launcher3.icons.ComponentWithLabel;
/**
* This class is a thin wrapper around the framework AppWidgetProviderInfo class. This class affords
@@ -14,7 +18,8 @@
* (who's implementation is owned by the launcher). This object represents a widget type / class,
* as opposed to a widget instance, and so should not be confused with {@link LauncherAppWidgetInfo}
*/
-public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo {
+public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo
+ implements ComponentWithLabel {
public static final String CLS_CUSTOM_WIDGET_PREFIX = "#custom-widget-";
@@ -53,19 +58,13 @@
public void initSpans(Context context) {
InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
- Point paddingLand = idp.landscapeProfile.getTotalWorkspacePadding();
- Point paddingPort = idp.portraitProfile.getTotalWorkspacePadding();
+ Point landCellSize = idp.landscapeProfile.getCellSize();
+ Point portCellSize = idp.portraitProfile.getCellSize();
// Always assume we're working with the smallest span to make sure we
// reserve enough space in both orientations.
- float smallestCellWidth = DeviceProfile.calculateCellWidth(Math.min(
- idp.landscapeProfile.widthPx - paddingLand.x,
- idp.portraitProfile.widthPx - paddingPort.x),
- idp.numColumns);
- float smallestCellHeight = DeviceProfile.calculateCellWidth(Math.min(
- idp.landscapeProfile.heightPx - paddingLand.y,
- idp.portraitProfile.heightPx - paddingPort.y),
- idp.numRows);
+ float smallestCellWidth = Math.min(landCellSize.x, portCellSize.x);
+ float smallestCellHeight = Math.min(landCellSize.y, portCellSize.y);
// We want to account for the extra amount of padding that we are adding to the widget
// to ensure that it gets the full amount of space that it has requested.
@@ -102,4 +101,14 @@
return 0;
}
}
- }
+
+ @Override
+ public final ComponentName getComponent() {
+ return provider;
+ }
+
+ @Override
+ public final UserHandle getUser() {
+ return getProfile();
+ }
+}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 37538ae..a5f97de 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -31,7 +31,6 @@
import android.os.Looper;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -39,7 +38,8 @@
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.AddWorkspaceItemsTask;
import com.android.launcher3.model.BaseModelUpdateTask;
import com.android.launcher3.model.BgDataModel;
@@ -55,8 +55,8 @@
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.Provider;
@@ -68,12 +68,15 @@
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Executor;
+import androidx.annotation.Nullable;
+
/**
* Maintains in-memory state of the Launcher. It is expected that there should be only one
* LauncherModel object held in a static. Also provide APIs for updating the database state
@@ -93,10 +96,12 @@
@Thunk boolean mIsLoaderTaskRunning;
@Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
+ private static final Looper mWorkerLooper;
static {
sWorkerThread.start();
+ mWorkerLooper = sWorkerThread.getLooper();
}
- @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());
+ @Thunk static final Handler sWorker = new Handler(mWorkerLooper);
// Indicates whether the current model data is valid or not.
// We start off with everything not loaded. After that, we assume that
@@ -141,14 +146,14 @@
public void clearPendingBinds();
public void startBinding();
public void bindItems(List<ItemInfo> shortcuts, boolean forceAnimateIcons);
- public void bindScreens(ArrayList<Long> orderedScreenIds);
+ public void bindScreens(IntArray orderedScreenIds);
public void finishFirstPageBind(ViewOnDrawExecutor executor);
- public void finishBindingItems();
+ public void finishBindingItems(int currentScreen);
public void bindAllApplications(ArrayList<AppInfo> apps);
public void bindAppsAddedOrUpdated(ArrayList<AppInfo> apps);
- public void bindAppsAdded(ArrayList<Long> newScreens,
- ArrayList<ItemInfo> addNotAnimated,
- ArrayList<ItemInfo> addAnimated);
+ public void preAddApps();
+ public void bindAppsAdded(IntArray newScreens,
+ ArrayList<ItemInfo> addNotAnimated, ArrayList<ItemInfo> addAnimated);
public void bindPromiseAppProgressUpdated(PromiseAppInfo app);
public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated, UserHandle user);
public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);
@@ -158,7 +163,7 @@
public void bindAllWidgets(ArrayList<WidgetListRowEntry> widgets);
public void onPageBoundSynchronously(int page);
public void executeOnNextDraw(ViewOnDrawExecutor executor);
- public void bindDeepShortcutMap(MultiHashMap<ComponentKey, String> deepShortcutMap);
+ public void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMap);
}
LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {
@@ -195,6 +200,10 @@
* Adds the provided items to the workspace.
*/
public void addAndBindAddedWorkspaceItems(List<Pair<ItemInfo, Object>> itemList) {
+ Callbacks callbacks = getCallback();
+ if (callbacks != null) {
+ callbacks.preAddApps();
+ }
enqueueModelUpdateTask(new AddWorkspaceItemsTask(itemList));
}
@@ -204,7 +213,12 @@
}
static void checkItemInfoLocked(
- final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {
+ final int itemId, final ItemInfo item, StackTraceElement[] stackTrace) {
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ "Checking item: " + android.util.Log.getStackTraceString(new Throwable()));
+ }
ItemInfo modelItem = sBgDataModel.itemsIdMap.get(itemId);
if (modelItem != null && item != modelItem) {
// check all the data is consistent
@@ -243,7 +257,7 @@
static void checkItemInfo(final ItemInfo item) {
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
- final long itemId = item.id;
+ final int itemId = item.id;
Runnable r = new Runnable() {
public void run() {
synchronized (sBgDataModel) {
@@ -258,17 +272,16 @@
* Update the order of the workspace screens in the database. The array list contains
* a list of screen ids in the order that they should appear.
*/
- public static void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {
- final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);
+ public static void updateWorkspaceScreenOrder(Context context, IntArray screens) {
final ContentResolver cr = context.getContentResolver();
final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
- // Remove any negative screen ids -- these aren't persisted
- Iterator<Long> iter = screensCopy.iterator();
- while (iter.hasNext()) {
- long id = iter.next();
- if (id < 0) {
- iter.remove();
+ // Create a copy with only non-negative values
+ final IntArray screensCopy = new IntArray();
+ for (int i = 0; i < screens.size(); i++) {
+ int id = screens.get(i);
+ if (id >= 0) {
+ screensCopy.add(id);
}
}
@@ -281,7 +294,7 @@
int count = screensCopy.size();
for (int i = 0; i < count; i++) {
ContentValues v = new ContentValues();
- long screenId = screensCopy.get(i);
+ int screenId = screensCopy.get(i);
v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());
@@ -440,6 +453,11 @@
* @return true if the page could be bound synchronously.
*/
public boolean startLoader(int synchronousBindPage) {
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ android.util.Log.getStackTraceString(new Throwable()));
+ }
// Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING);
synchronized (mLock) {
@@ -504,7 +522,7 @@
/**
* Loads the workspace screen ids in an ordered list.
*/
- public static ArrayList<Long> loadWorkspaceScreensDb(Context context) {
+ public static IntArray loadWorkspaceScreensDb(Context context) {
final ContentResolver contentResolver = context.getContentResolver();
final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
@@ -551,6 +569,11 @@
synchronized (mLock) {
// Everything loaded bind the data.
mModelLoaded = true;
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ android.util.Log.getStackTraceString(new Throwable()));
+ }
}
}
@@ -592,6 +615,19 @@
CacheDataUpdatedTask.OP_CACHE_UPDATE, user, updatedPackages));
}
+ /**
+ * Called when the labels for the widgets has updated in the icon cache.
+ */
+ public void onWidgetLabelsUpdated(HashSet<String> updatedPackages, UserHandle user) {
+ enqueueModelUpdateTask(new BaseModelUpdateTask() {
+ @Override
+ public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
+ dataModel.widgetsModel.onPackageIconsUpdated(updatedPackages, user, app);
+ bindUpdatedWidgets(dataModel);
+ }
+ });
+ }
+
public void enqueueModelUpdateTask(ModelUpdateTask task) {
task.init(mApp, this, sBgDataModel, mBgAllAppsList, mUiExecutor);
runOnWorkerThread(task);
@@ -620,15 +656,12 @@
}
public void updateAndBindShortcutInfo(final ShortcutInfo si, final ShortcutInfoCompat info) {
- updateAndBindShortcutInfo(new Provider<ShortcutInfo>() {
- @Override
- public ShortcutInfo get() {
- si.updateFromDeepShortcutInfo(info, mApp.getContext());
- LauncherIcons li = LauncherIcons.obtain(mApp.getContext());
- li.createShortcutIcon(info).applyTo(si);
- li.recycle();
- return si;
- }
+ updateAndBindShortcutInfo(() -> {
+ si.updateFromDeepShortcutInfo(info, mApp.getContext());
+ LauncherIcons li = LauncherIcons.obtain(mApp.getContext());
+ si.applyFrom(li.createShortcutIcon(info));
+ li.recycle();
+ return si;
});
}
@@ -677,7 +710,7 @@
* @return the looper for the worker thread which can be used to start background tasks.
*/
public static Looper getWorkerLooper() {
- return sWorkerThread.getLooper();
+ return mWorkerLooper;
}
public static void setWorkerPriority(final int priority) {
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 7d208d4..7d62ada 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -58,6 +58,8 @@
import com.android.launcher3.provider.LauncherDbUtils;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
import com.android.launcher3.provider.RestoreDbTask;
+import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.NoLocaleSQLiteHelper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.Thunk;
@@ -67,9 +69,7 @@
import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
+import java.util.Arrays;
public class LauncherProvider extends ContentProvider {
private static final String TAG = "LauncherProvider";
@@ -170,7 +170,7 @@
return result;
}
- @Thunk static long dbInsertAndCheck(DatabaseHelper helper,
+ @Thunk static int dbInsertAndCheck(DatabaseHelper helper,
SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) {
if (values == null) {
throw new RuntimeException("Error: attempting to insert null values");
@@ -179,7 +179,7 @@
throw new RuntimeException("Error: attempting to add item without specifying an id");
}
helper.checkId(table, values);
- return db.insert(table, nullColumnHack, values);
+ return (int) db.insert(table, nullColumnHack, values);
}
private void reloadLauncherIfExternal() {
@@ -205,7 +205,7 @@
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
addModifiedTime(initialValues);
- final long rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues);
+ final int rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues);
if (rowId < 0) return null;
uri = ContentUris.withAppendedId(uri, rowId);
@@ -230,7 +230,7 @@
private boolean initializeExternalAdd(ContentValues values) {
// 1. Ensure that externally added items have a valid item id
- long id = mOpenHelper.generateNewItemId();
+ int id = mOpenHelper.generateNewItemId();
values.put(LauncherSettings.Favorites._ID, id);
// 2. In the case of an app widget, and if no app widget id is specified, we
@@ -263,7 +263,7 @@
}
// Add screen id if not present
- long screenId = values.getAsLong(LauncherSettings.Favorites.SCREEN);
+ int screenId = values.getAsInteger(LauncherSettings.Favorites.SCREEN);
SQLiteStatement stmp = null;
try {
stmp = mOpenHelper.getWritableDatabase().compileStatement(
@@ -369,17 +369,18 @@
}
case LauncherSettings.Settings.METHOD_DELETE_EMPTY_FOLDERS: {
Bundle result = new Bundle();
- result.putSerializable(LauncherSettings.Settings.EXTRA_VALUE, deleteEmptyFolders());
+ result.putIntArray(LauncherSettings.Settings.EXTRA_VALUE, deleteEmptyFolders()
+ .toArray());
return result;
}
case LauncherSettings.Settings.METHOD_NEW_ITEM_ID: {
Bundle result = new Bundle();
- result.putLong(LauncherSettings.Settings.EXTRA_VALUE, mOpenHelper.generateNewItemId());
+ result.putInt(LauncherSettings.Settings.EXTRA_VALUE, mOpenHelper.generateNewItemId());
return result;
}
case LauncherSettings.Settings.METHOD_NEW_SCREEN_ID: {
Bundle result = new Bundle();
- result.putLong(LauncherSettings.Settings.EXTRA_VALUE, mOpenHelper.generateNewScreenId());
+ result.putInt(LauncherSettings.Settings.EXTRA_VALUE, mOpenHelper.generateNewScreenId());
return result;
}
case LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB: {
@@ -402,8 +403,8 @@
* Deletes any empty folder from the DB.
* @return Ids of deleted folders.
*/
- private ArrayList<Long> deleteEmptyFolders() {
- ArrayList<Long> folderIds = new ArrayList<>();
+ private IntArray deleteEmptyFolders() {
+ IntArray folderIds = new IntArray();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
// Select folders whose id do not match any container value.
@@ -542,8 +543,8 @@
public static class DatabaseHelper extends NoLocaleSQLiteHelper implements LayoutParserCallback {
private final Handler mWidgetHostResetHandler;
private final Context mContext;
- private long mMaxItemId = -1;
- private long mMaxScreenId = -1;
+ private int mMaxItemId = -1;
+ private int mMaxScreenId = -1;
DatabaseHelper(Context context, Handler widgetHostResetHandler) {
this(context, widgetHostResetHandler, LauncherFiles.LAUNCHER_DB);
@@ -789,7 +790,7 @@
convertShortcutsToLauncherActivities(db);
case 26:
// QSB was moved to the grid. Clear the first row on screen 0.
- if (FeatureFlags.QSB_ON_FIRST_SCREEN &&
+ if (FeatureFlags.QSB_ON_FIRST_SCREEN.get() &&
!LauncherDbUtils.prepareScreenZeroToHostQsb(mContext, db)) {
break;
}
@@ -844,7 +845,7 @@
Log.e(TAG, "getAppWidgetIds not supported", e);
return;
}
- final HashSet<Integer> validWidgets = new HashSet<>();
+ final IntSet validWidgets = new IntSet();
try (Cursor c = db.query(Favorites.TABLE_NAME,
new String[] {Favorites.APPWIDGET_ID },
"itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null, null, null)) {
@@ -899,7 +900,7 @@
continue;
}
- long id = c.getLong(idIndex);
+ int id = c.getInt(idIndex);
updateStmt.bindLong(1, id);
updateStmt.executeUpdateDelete();
}
@@ -914,15 +915,14 @@
*/
public boolean recreateWorkspaceTable(SQLiteDatabase db) {
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
- final ArrayList<Long> sortedIDs;
+ final IntArray sortedIDs;
try (Cursor c = db.query(WorkspaceScreens.TABLE_NAME,
new String[] {LauncherSettings.WorkspaceScreens._ID},
null, null, null, null,
LauncherSettings.WorkspaceScreens.SCREEN_RANK)) {
// Use LinkedHashSet so that ordering is preserved
- sortedIDs = new ArrayList<>(
- LauncherDbUtils.iterateCursor(c, 0, new LinkedHashSet<Long>()));
+ sortedIDs = LauncherDbUtils.getScreenIdsFromCursor(c);
}
db.execSQL("DROP TABLE IF EXISTS " + WorkspaceScreens.TABLE_NAME);
addWorkspacesTable(db, false);
@@ -937,7 +937,11 @@
db.insertOrThrow(WorkspaceScreens.TABLE_NAME, null, values);
}
t.commit();
- mMaxScreenId = sortedIDs.isEmpty() ? 0 : Collections.max(sortedIDs);
+
+ mMaxScreenId = 0;
+ for (int i = 0; i < sortedIDs.size(); i++) {
+ mMaxScreenId = Math.max(mMaxScreenId, sortedIDs.get(i));
+ }
} catch (SQLException ex) {
// Old version remains, which means we wipe old data
Log.e(TAG, ex.getMessage(), ex);
@@ -997,7 +1001,7 @@
// constructor is called, and we only pass a reference to LauncherProvider to LauncherApp
// after that point
@Override
- public long generateNewItemId() {
+ public int generateNewItemId() {
if (mMaxItemId < 0) {
throw new RuntimeException("Error: max item id was not initialized");
}
@@ -1010,12 +1014,12 @@
}
@Override
- public long insertAndCheck(SQLiteDatabase db, ContentValues values) {
+ public int insertAndCheck(SQLiteDatabase db, ContentValues values) {
return dbInsertAndCheck(this, db, Favorites.TABLE_NAME, null, values);
}
public void checkId(String table, ContentValues values) {
- long id = values.getAsLong(LauncherSettings.BaseLauncherColumns._ID);
+ int id = values.getAsInteger(LauncherSettings.BaseLauncherColumns._ID);
if (WorkspaceScreens.TABLE_NAME.equals(table)) {
mMaxScreenId = Math.max(id, mMaxScreenId);
} else {
@@ -1023,7 +1027,7 @@
}
}
- private long initializeMaxItemId(SQLiteDatabase db) {
+ private int initializeMaxItemId(SQLiteDatabase db) {
return getMaxId(db, Favorites.TABLE_NAME);
}
@@ -1032,7 +1036,7 @@
// call the constructor from the worker thread; however, this doesn't extend until after the
// constructor is called, and we only pass a reference to LauncherProvider to LauncherApp
// after that point
- public long generateNewScreenId() {
+ public int generateNewScreenId() {
if (mMaxScreenId < 0) {
throw new RuntimeException("Error: max screen id was not initialized");
}
@@ -1040,20 +1044,21 @@
return mMaxScreenId;
}
- private long initializeMaxScreenId(SQLiteDatabase db) {
+ private int initializeMaxScreenId(SQLiteDatabase db) {
return getMaxId(db, WorkspaceScreens.TABLE_NAME);
}
@Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
- ArrayList<Long> screenIds = new ArrayList<Long>();
+ IntArray screenIds = new IntArray();
// TODO: Use multiple loaders with fall-back and transaction.
int count = loader.loadLayout(db, screenIds);
// Add the screens specified by the items above
- Collections.sort(screenIds);
+ int[] sortedScreenIds = screenIds.toArray();
+ Arrays.sort(sortedScreenIds);
int rank = 0;
ContentValues values = new ContentValues();
- for (Long id : screenIds) {
+ for (int id : sortedScreenIds) {
values.clear();
values.put(LauncherSettings.WorkspaceScreens._ID, id);
values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, rank);
@@ -1075,12 +1080,12 @@
/**
* @return the max _id in the provided table.
*/
- @Thunk static long getMaxId(SQLiteDatabase db, String table) {
+ @Thunk static int getMaxId(SQLiteDatabase db, String table) {
Cursor c = db.rawQuery("SELECT MAX(_id) FROM " + table, null);
// get the result
- long id = -1;
+ int id = -1;
if (c != null && c.moveToNext()) {
- id = c.getLong(0);
+ id = c.getInt(0);
}
if (c != null) {
c.close();
diff --git a/src/com/android/launcher3/LauncherScroller.java b/src/com/android/launcher3/LauncherScroller.java
deleted file mode 100644
index a9b4955..0000000
--- a/src/com/android/launcher3/LauncherScroller.java
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.animation.TimeInterpolator;
-import android.content.Context;
-import android.hardware.SensorManager;
-import android.os.Build;
-import android.view.ViewConfiguration;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-/**
- * This class differs from the framework {@link android.widget.Scroller} in that
- * you can modify the Interpolator post-construction.
- */
-public class LauncherScroller {
- private int mMode;
-
- private int mStartX;
- private int mStartY;
- private int mFinalX;
- private int mFinalY;
-
- private int mMinX;
- private int mMaxX;
- private int mMinY;
- private int mMaxY;
-
- private int mCurrX;
- private int mCurrY;
- private long mStartTime;
- private int mDuration;
- private float mDurationReciprocal;
- private float mDeltaX;
- private float mDeltaY;
- private boolean mFinished;
- private TimeInterpolator mInterpolator;
- private boolean mFlywheel;
-
- private float mVelocity;
- private float mCurrVelocity;
- private int mDistance;
-
- private float mFlingFriction = ViewConfiguration.getScrollFriction();
-
- private static final int DEFAULT_DURATION = 250;
- private static final int SCROLL_MODE = 0;
- private static final int FLING_MODE = 1;
-
- private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
- private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)
- private static final float START_TENSION = 0.5f;
- private static final float END_TENSION = 1.0f;
- private static final float P1 = START_TENSION * INFLEXION;
- private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION);
-
- private static final int NB_SAMPLES = 100;
- private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1];
- private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1];
-
- private float mDeceleration;
- private final float mPpi;
-
- // A context-specific coefficient adjusted to physical values.
- private float mPhysicalCoeff;
-
- static {
- float x_min = 0.0f;
- float y_min = 0.0f;
- for (int i = 0; i < NB_SAMPLES; i++) {
- final float alpha = (float) i / NB_SAMPLES;
-
- float x_max = 1.0f;
- float x, tx, coef;
- while (true) {
- x = x_min + (x_max - x_min) / 2.0f;
- coef = 3.0f * x * (1.0f - x);
- tx = coef * ((1.0f - x) * P1 + x * P2) + x * x * x;
- if (Math.abs(tx - alpha) < 1E-5) break;
- if (tx > alpha) x_max = x;
- else x_min = x;
- }
- SPLINE_POSITION[i] = coef * ((1.0f - x) * START_TENSION + x) + x * x * x;
-
- float y_max = 1.0f;
- float y, dy;
- while (true) {
- y = y_min + (y_max - y_min) / 2.0f;
- coef = 3.0f * y * (1.0f - y);
- dy = coef * ((1.0f - y) * START_TENSION + y) + y * y * y;
- if (Math.abs(dy - alpha) < 1E-5) break;
- if (dy > alpha) y_max = y;
- else y_min = y;
- }
- SPLINE_TIME[i] = coef * ((1.0f - y) * P1 + y * P2) + y * y * y;
- }
- SPLINE_POSITION[NB_SAMPLES] = SPLINE_TIME[NB_SAMPLES] = 1.0f;
-
- // This controls the viscous fluid effect (how much of it)
- sViscousFluidScale = 8.0f;
- // must be set to 1.0 (used in viscousFluid())
- sViscousFluidNormalize = 1.0f;
- sViscousFluidNormalize = 1.0f / viscousFluid(1.0f);
-
- }
-
- private static float sViscousFluidScale;
- private static float sViscousFluidNormalize;
-
- public void setInterpolator(TimeInterpolator interpolator) {
- mInterpolator = interpolator;
- }
-
- /**
- * Create a Scroller with the default duration and interpolator.
- */
- public LauncherScroller(Context context) {
- this(context, null);
- }
-
- /**
- * Create a Scroller with the specified interpolator. If the interpolator is
- * null, the default (viscous) interpolator will be used. "Flywheel" behavior will
- * be in effect for apps targeting Honeycomb or newer.
- */
- public LauncherScroller(Context context, Interpolator interpolator) {
- this(context, interpolator,
- context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB);
- }
-
- /**
- * Create a Scroller with the specified interpolator. If the interpolator is
- * null, the default (viscous) interpolator will be used. Specify whether or
- * not to support progressive "flywheel" behavior in flinging.
- */
- public LauncherScroller(Context context, Interpolator interpolator, boolean flywheel) {
- mFinished = true;
- mInterpolator = interpolator;
- mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
- mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
- mFlywheel = flywheel;
-
- mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning
- }
-
- /**
- * The amount of friction applied to flings. The default value
- * is {@link ViewConfiguration#getScrollFriction}.
- *
- * @param friction A scalar dimension-less value representing the coefficient of
- * friction.
- */
- public final void setFriction(float friction) {
- mDeceleration = computeDeceleration(friction);
- mFlingFriction = friction;
- }
-
- private float computeDeceleration(float friction) {
- return SensorManager.GRAVITY_EARTH // g (m/s^2)
- * 39.37f // inch/meter
- * mPpi // pixels per inch
- * friction;
- }
-
- /**
- *
- * Returns whether the scroller has finished scrolling.
- *
- * @return True if the scroller has finished scrolling, false otherwise.
- */
- public final boolean isFinished() {
- return mFinished;
- }
-
- /**
- * Force the finished field to a particular value.
- *
- * @param finished The new finished value.
- */
- public final void forceFinished(boolean finished) {
- mFinished = finished;
- }
-
- /**
- * Returns how long the scroll event will take, in milliseconds.
- *
- * @return The duration of the scroll in milliseconds.
- */
- public final int getDuration() {
- return mDuration;
- }
-
- /**
- * Returns the current X offset in the scroll.
- *
- * @return The new X offset as an absolute distance from the origin.
- */
- public final int getCurrX() {
- return mCurrX;
- }
-
- /**
- * Returns the current Y offset in the scroll.
- *
- * @return The new Y offset as an absolute distance from the origin.
- */
- public final int getCurrY() {
- return mCurrY;
- }
-
- /**
- * Returns the current velocity.
- *
- * @return The original velocity less the deceleration. Result may be
- * negative.
- */
- public float getCurrVelocity() {
- return mMode == FLING_MODE ?
- mCurrVelocity : mVelocity - mDeceleration * timePassed() / 2000.0f;
- }
-
- /**
- * Returns the start X offset in the scroll.
- *
- * @return The start X offset as an absolute distance from the origin.
- */
- public final int getStartX() {
- return mStartX;
- }
-
- /**
- * Returns the start Y offset in the scroll.
- *
- * @return The start Y offset as an absolute distance from the origin.
- */
- public final int getStartY() {
- return mStartY;
- }
-
- /**
- * Returns where the scroll will end. Valid only for "fling" scrolls.
- *
- * @return The final X offset as an absolute distance from the origin.
- */
- public final int getFinalX() {
- return mFinalX;
- }
-
- /**
- * Returns where the scroll will end. Valid only for "fling" scrolls.
- *
- * @return The final Y offset as an absolute distance from the origin.
- */
- public final int getFinalY() {
- return mFinalY;
- }
-
- /**
- * Call this when you want to know the new location. If it returns true,
- * the animation is not yet finished.
- */
- public boolean computeScrollOffset() {
- if (mFinished) {
- return false;
- }
-
- int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
-
- if (timePassed < mDuration) {
- switch (mMode) {
- case SCROLL_MODE:
- float x = timePassed * mDurationReciprocal;
-
- if (mInterpolator == null)
- x = viscousFluid(x);
- else
- x = mInterpolator.getInterpolation(x);
-
- mCurrX = mStartX + Math.round(x * mDeltaX);
- mCurrY = mStartY + Math.round(x * mDeltaY);
- break;
- case FLING_MODE:
- final float t = (float) timePassed / mDuration;
- final int index = (int) (NB_SAMPLES * t);
- float distanceCoef = 1.f;
- float velocityCoef = 0.f;
- if (index < NB_SAMPLES) {
- final float t_inf = (float) index / NB_SAMPLES;
- final float t_sup = (float) (index + 1) / NB_SAMPLES;
- final float d_inf = SPLINE_POSITION[index];
- final float d_sup = SPLINE_POSITION[index + 1];
- velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
- distanceCoef = d_inf + (t - t_inf) * velocityCoef;
- }
-
- mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;
-
- mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
- // Pin to mMinX <= mCurrX <= mMaxX
- mCurrX = Math.min(mCurrX, mMaxX);
- mCurrX = Math.max(mCurrX, mMinX);
-
- mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
- // Pin to mMinY <= mCurrY <= mMaxY
- mCurrY = Math.min(mCurrY, mMaxY);
- mCurrY = Math.max(mCurrY, mMinY);
-
- if (mCurrX == mFinalX && mCurrY == mFinalY) {
- mFinished = true;
- }
-
- break;
- }
- }
- else {
- mCurrX = mFinalX;
- mCurrY = mFinalY;
- mFinished = true;
- }
- return true;
- }
-
- /**
- * Start scrolling by providing a starting point and the distance to travel.
- * The scroll will use the default value of 250 milliseconds for the
- * duration.
- *
- * @param startX Starting horizontal scroll offset in pixels. Positive
- * numbers will scroll the content to the left.
- * @param startY Starting vertical scroll offset in pixels. Positive numbers
- * will scroll the content up.
- * @param dx Horizontal distance to travel. Positive numbers will scroll the
- * content to the left.
- * @param dy Vertical distance to travel. Positive numbers will scroll the
- * content up.
- */
- public void startScroll(int startX, int startY, int dx, int dy) {
- startScroll(startX, startY, dx, dy, DEFAULT_DURATION);
- }
-
- /**
- * Start scrolling by providing a starting point, the distance to travel,
- * and the duration of the scroll.
- *
- * @param startX Starting horizontal scroll offset in pixels. Positive
- * numbers will scroll the content to the left.
- * @param startY Starting vertical scroll offset in pixels. Positive numbers
- * will scroll the content up.
- * @param dx Horizontal distance to travel. Positive numbers will scroll the
- * content to the left.
- * @param dy Vertical distance to travel. Positive numbers will scroll the
- * content up.
- * @param duration Duration of the scroll in milliseconds.
- */
- public void startScroll(int startX, int startY, int dx, int dy, int duration) {
- mMode = SCROLL_MODE;
- mFinished = false;
- mDuration = duration;
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
- mStartX = startX;
- mStartY = startY;
- mFinalX = startX + dx;
- mFinalY = startY + dy;
- mDeltaX = dx;
- mDeltaY = dy;
- mDurationReciprocal = 1.0f / (float) mDuration;
- }
-
- /**
- * Start scrolling based on a fling gesture. The distance travelled will
- * depend on the initial velocity of the fling.
- *
- * @param startX Starting point of the scroll (X)
- * @param startY Starting point of the scroll (Y)
- * @param velocityX Initial velocity of the fling (X) measured in pixels per
- * second.
- * @param velocityY Initial velocity of the fling (Y) measured in pixels per
- * second
- * @param minX Minimum X value. The scroller will not scroll past this
- * point.
- * @param maxX Maximum X value. The scroller will not scroll past this
- * point.
- * @param minY Minimum Y value. The scroller will not scroll past this
- * point.
- * @param maxY Maximum Y value. The scroller will not scroll past this
- * point.
- */
- public void fling(int startX, int startY, int velocityX, int velocityY,
- int minX, int maxX, int minY, int maxY) {
- // Continue a scroll or fling in progress
- if (mFlywheel && !mFinished) {
- float oldVel = getCurrVelocity();
-
- float dx = (float) (mFinalX - mStartX);
- float dy = (float) (mFinalY - mStartY);
- float hyp = (float) Math.hypot(dx, dy);
-
- float ndx = dx / hyp;
- float ndy = dy / hyp;
-
- float oldVelocityX = ndx * oldVel;
- float oldVelocityY = ndy * oldVel;
- if (Math.signum(velocityX) == Math.signum(oldVelocityX) &&
- Math.signum(velocityY) == Math.signum(oldVelocityY)) {
- velocityX += oldVelocityX;
- velocityY += oldVelocityY;
- }
- }
-
- mMode = FLING_MODE;
- mFinished = false;
-
- float velocity = (float) Math.hypot(velocityX, velocityY);
-
- mVelocity = velocity;
- mDuration = getSplineFlingDuration(velocity);
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
- mStartX = startX;
- mStartY = startY;
-
- float coeffX = velocity == 0 ? 1.0f : velocityX / velocity;
- float coeffY = velocity == 0 ? 1.0f : velocityY / velocity;
-
- double totalDistance = getSplineFlingDistance(velocity);
- mDistance = (int) (totalDistance * Math.signum(velocity));
-
- mMinX = minX;
- mMaxX = maxX;
- mMinY = minY;
- mMaxY = maxY;
-
- mFinalX = startX + (int) Math.round(totalDistance * coeffX);
- // Pin to mMinX <= mFinalX <= mMaxX
- mFinalX = Math.min(mFinalX, mMaxX);
- mFinalX = Math.max(mFinalX, mMinX);
-
- mFinalY = startY + (int) Math.round(totalDistance * coeffY);
- // Pin to mMinY <= mFinalY <= mMaxY
- mFinalY = Math.min(mFinalY, mMaxY);
- mFinalY = Math.max(mFinalY, mMinY);
- }
-
- private double getSplineDeceleration(float velocity) {
- return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff));
- }
-
- private int getSplineFlingDuration(float velocity) {
- final double l = getSplineDeceleration(velocity);
- final double decelMinusOne = DECELERATION_RATE - 1.0;
- return (int) (1000.0 * Math.exp(l / decelMinusOne));
- }
-
- private double getSplineFlingDistance(float velocity) {
- final double l = getSplineDeceleration(velocity);
- final double decelMinusOne = DECELERATION_RATE - 1.0;
- return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
- }
-
- static float viscousFluid(float x)
- {
- x *= sViscousFluidScale;
- if (x < 1.0f) {
- x -= (1.0f - (float)Math.exp(-x));
- } else {
- float start = 0.36787944117f; // 1/e == exp(-1)
- x = 1.0f - (float)Math.exp(1.0f - x);
- x = start + x * (1.0f - start);
- }
- x *= sViscousFluidNormalize;
- return x;
- }
-
- /**
- * Stops the animation. Contrary to {@link #forceFinished(boolean)},
- * aborting the animating cause the scroller to move to the final x and y
- * position
- *
- * @see #forceFinished(boolean)
- */
- public void abortAnimation() {
- mCurrX = mFinalX;
- mCurrY = mFinalY;
- mFinished = true;
- }
-
- /**
- * Extend the scroll animation. This allows a running animation to scroll
- * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.
- *
- * @param extend Additional time to scroll in milliseconds.
- * @see #setFinalX(int)
- * @see #setFinalY(int)
- */
- public void extendDuration(int extend) {
- int passed = timePassed();
- mDuration = passed + extend;
- mDurationReciprocal = 1.0f / mDuration;
- mFinished = false;
- }
-
- /**
- * Returns the time elapsed since the beginning of the scrolling.
- *
- * @return The elapsed time in milliseconds.
- */
- public int timePassed() {
- return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
- }
-
- /**
- * Sets the final position (X) for this scroller.
- *
- * @param newX The new X offset as an absolute distance from the origin.
- * @see #extendDuration(int)
- * @see #setFinalY(int)
- */
- public void setFinalX(int newX) {
- mFinalX = newX;
- mDeltaX = mFinalX - mStartX;
- mFinished = false;
- }
-
- /**
- * Sets the final position (Y) for this scroller.
- *
- * @param newY The new Y offset as an absolute distance from the origin.
- * @see #extendDuration(int)
- * @see #setFinalX(int)
- */
- public void setFinalY(int newY) {
- mFinalY = newY;
- mDeltaY = mFinalY - mStartY;
- mFinished = false;
- }
-
- /**
- * @hide
- */
- public boolean isScrollingInDirection(float xvel, float yvel) {
- return !mFinished && Math.signum(xvel) == Math.signum(mFinalX - mStartX) &&
- Math.signum(yvel) == Math.signum(mFinalY - mStartY);
- }
-}
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 3b337ef..0b12b15 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -128,7 +128,7 @@
*
* @return The unique content URL for the specified row.
*/
- public static Uri getContentUri(long id) {
+ public static Uri getContentUri(int id) {
return Uri.parse("content://" + LauncherProvider.AUTHORITY +
"/" + TABLE_NAME + "/" + id);
}
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 8a15b24..beef97e 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -22,14 +22,15 @@
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
-import android.graphics.Rect;
import android.view.animation.Interpolator;
import com.android.launcher3.states.SpringLoadedState;
import com.android.launcher3.uioverrides.AllAppsState;
+import com.android.launcher3.uioverrides.BackgroundAppState;
import com.android.launcher3.uioverrides.FastOverviewState;
import com.android.launcher3.uioverrides.OverviewState;
import com.android.launcher3.uioverrides.UiFactory;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import java.util.Arrays;
@@ -72,7 +73,7 @@
}
};
- private static final LauncherState[] sAllStates = new LauncherState[5];
+ private static final LauncherState[] sAllStates = new LauncherState[6];
/**
* TODO: Create a separate class for NORMAL state.
@@ -88,8 +89,7 @@
public static final LauncherState OVERVIEW = new OverviewState(2);
public static final LauncherState FAST_OVERVIEW = new FastOverviewState(3);
public static final LauncherState ALL_APPS = new AllAppsState(4);
-
- protected static final Rect sTempRect = new Rect();
+ public static final LauncherState BACKGROUND_APP = new BackgroundAppState(5);
public final int ordinal;
@@ -251,6 +251,16 @@
}
}
+ public void onBackPressed(Launcher launcher) {
+ if (this != NORMAL) {
+ LauncherStateManager lsm = launcher.getStateManager();
+ LauncherState lastState = lsm.getLastState();
+ launcher.getUserEventDispatcher().logActionCommand(Action.Command.BACK,
+ containerType, lastState.containerType);
+ lsm.goToState(lastState);
+ }
+ }
+
protected static void dispatchWindowStateChanged(Launcher launcher) {
launcher.getWindow().getDecorView().sendAccessibilityEvent(TYPE_WINDOW_STATE_CHANGED);
}
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 3c7c1aa..fe3df95 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -17,6 +17,7 @@
package com.android.launcher3;
import static android.view.View.VISIBLE;
+
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
@@ -34,7 +35,6 @@
import android.animation.AnimatorSet;
import android.os.Handler;
import android.os.Looper;
-import android.support.annotation.IntDef;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -47,6 +47,8 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import androidx.annotation.IntDef;
+
/**
* TODO: figure out what kind of tests we can write for this
*
@@ -306,7 +308,13 @@
*/
public AnimatorPlaybackController createAnimationToNewWorkspace(
LauncherState fromState, LauncherState state, long duration) {
+ // Since we are creating a state animation to a different state, temporarily prevent state
+ // change as part of config reset.
+ LauncherState originalRestState = mRestState;
+ mRestState = state;
mConfig.reset();
+ mRestState = originalRestState;
+
for (StateHandler handler : getStateHandlers()) {
handler.setState(fromState);
}
diff --git a/src/com/android/launcher3/MainProcessInitializer.java b/src/com/android/launcher3/MainProcessInitializer.java
index 462eadb..a253893 100644
--- a/src/com/android/launcher3/MainProcessInitializer.java
+++ b/src/com/android/launcher3/MainProcessInitializer.java
@@ -18,23 +18,28 @@
import android.content.Context;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.folder.FolderShape;
import com.android.launcher3.graphics.IconShapeOverride;
import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.util.ResourceBasedOverride;
/**
* Utility class to handle one time initializations of the main process
*/
-public class MainProcessInitializer {
+public class MainProcessInitializer implements ResourceBasedOverride {
public static void initialize(Context context) {
- Utilities.getOverrideObject(
+ Overrides.getObject(
MainProcessInitializer.class, context, R.string.main_process_initializer_class)
.init(context);
}
protected void init(Context context) {
FileLog.setDir(context.getApplicationContext().getFilesDir());
+ FeatureFlags.initialize(context);
IconShapeOverride.apply(context);
SessionCommitReceiver.applyDefaultUserPrefs(context);
+ FolderShape.init();
}
}
diff --git a/src/com/android/launcher3/OverviewButtonClickListener.java b/src/com/android/launcher3/OverviewButtonClickListener.java
deleted file mode 100644
index dd670d2..0000000
--- a/src/com/android/launcher3/OverviewButtonClickListener.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.android.launcher3;
-
-import android.view.View;
-
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-
-/**
- * A specialized listener for Overview buttons where both clicks and long clicks are logged
- * handled the same via {@link #handleViewClick(View)}.
- */
-public abstract class OverviewButtonClickListener implements View.OnClickListener,
- View.OnLongClickListener {
-
- private int mControlType; /** ControlType enum as defined in {@link Action.Touch} */
-
- public OverviewButtonClickListener(int controlType) {
- mControlType = controlType;
- }
-
- public void attachTo(View v) {
- v.setOnClickListener(this);
- v.setOnLongClickListener(this);
- }
-
- @Override
- public void onClick(View view) {
- if (shouldPerformClick(view)) {
- handleViewClick(view, Action.Touch.TAP);
- }
- }
-
- @Override
- public boolean onLongClick(View view) {
- if (shouldPerformClick(view)) {
- handleViewClick(view, Action.Touch.LONGPRESS);
- }
- return true;
- }
-
- private boolean shouldPerformClick(View view) {
- return !Launcher.getLauncher(view.getContext()).getWorkspace().isSwitchingState();
- }
-
- private void handleViewClick(View view, int action) {
- handleViewClick(view);
- Launcher.getLauncher(view.getContext()).getUserEventDispatcher()
- .logActionOnControl(action, mControlType);
- }
-
- public abstract void handleViewClick(View view);
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index db5dc66..9470635 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
+import static com.android.launcher3.touch.OverScroll.OVERSCROLL_DAMP_FACTOR;
import android.animation.LayoutTransition;
import android.animation.TimeInterpolator;
@@ -47,6 +48,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.touch.OverScroll;
+import com.android.launcher3.util.OverScroller;
import com.android.launcher3.util.Thunk;
import java.util.ArrayList;
@@ -63,7 +65,6 @@
protected static final ComputePageScrollsLogic SIMPLE_SCROLL_LOGIC = (v) -> v.getVisibility() != GONE;
public static final int PAGE_SNAP_ANIMATION_DURATION = 750;
- public static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
// OverScroll constants
private final static int OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION = 270;
@@ -83,7 +84,6 @@
public static final int INVALID_RESTORE_PAGE = -1001;
private boolean mFreeScroll = false;
- private boolean mSettleOnPageInFreeScroll = false;
protected int mFlingThresholdVelocity;
protected int mMinFlingVelocity;
@@ -97,7 +97,7 @@
@ViewDebug.ExportedProperty(category = "launcher")
protected int mNextPage = INVALID_PAGE;
protected int mMaxScrollX;
- protected LauncherScroller mScroller;
+ protected OverScroller mScroller;
private Interpolator mDefaultInterpolator;
private VelocityTracker mVelocityTracker;
protected int mPageSpacing = 0;
@@ -109,13 +109,7 @@
private float mTotalMotionX;
protected int[] mPageScrolls;
-
- protected final static int TOUCH_STATE_REST = 0;
- protected final static int TOUCH_STATE_SCROLLING = 1;
- protected final static int TOUCH_STATE_PREV_PAGE = 2;
- protected final static int TOUCH_STATE_NEXT_PAGE = 3;
-
- protected int mTouchState = TOUCH_STATE_REST;
+ private boolean mIsBeingDragged;
protected int mTouchSlop;
private int mMaximumVelocity;
@@ -129,11 +123,6 @@
protected boolean mWasInOverscroll = false;
- // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. Otherwise
- // it is equal to the scaled overscroll position. We use a separate value so as to prevent
- // the screens from continuing to translate beyond the normal bounds.
- protected int mOverScrollX;
-
protected int mUnboundedScrollX;
// Page Indicator
@@ -176,7 +165,7 @@
* Initializes various states for this workspace.
*/
protected void init() {
- mScroller = new LauncherScroller(getContext());
+ mScroller = new OverScroller(getContext());
setDefaultInterpolator(Interpolators.SCROLL);
mCurrentPage = 0;
@@ -251,7 +240,7 @@
newX = getScrollForPage(mCurrentPage);
}
scrollTo(newX, 0);
- mScroller.setFinalX(newX);
+ mScroller.startScroll(mScroller.getCurrPos(), newX - mScroller.getCurrPos());
forceFinishScroller(true);
}
@@ -356,17 +345,6 @@
@Override
public void scrollTo(int x, int y) {
- // In free scroll mode, we clamp the scrollX
- if (mFreeScroll) {
- // If the scroller is trying to move to a location beyond the maximum allowed
- // in the free scroll mode, we make sure to end the scroll operation.
- if (!mScroller.isFinished() && (x > mMaxScrollX || x < 0)) {
- forceFinishScroller(false);
- }
-
- x = Utilities.boundToRange(x, 0, mMaxScrollX);
- }
-
mUnboundedScrollX = x;
boolean isXBeforeFirstPage = mIsRtl ? (x > mMaxScrollX) : (x < 0);
@@ -396,9 +374,9 @@
overScroll(0);
mWasInOverscroll = false;
}
- mOverScrollX = x;
super.scrollTo(x, y);
}
+
}
private void sendScrollAccessibilityEvent() {
@@ -432,10 +410,9 @@
protected boolean computeScrollHelper(boolean shouldInvalidate) {
if (mScroller.computeScrollOffset()) {
// Don't bother scrolling if the page does not need to be moved
- if (getUnboundedScrollX() != mScroller.getCurrX()
- || getScrollY() != mScroller.getCurrY()
- || mOverScrollX != mScroller.getCurrX()) {
- scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
+ if (getUnboundedScrollX() != mScroller.getCurrPos()
+ || getScrollX() != mScroller.getCurrPos()) {
+ scrollTo(mScroller.getCurrPos(), 0);
}
if (shouldInvalidate) {
invalidate();
@@ -451,7 +428,7 @@
// We don't want to trigger a page end moving unless the page has settled
// and the user has stopped scrolling
- if (mTouchState == TOUCH_STATE_REST) {
+ if (!mIsBeingDragged) {
pageEndTransition();
}
@@ -648,6 +625,10 @@
mMaxScrollX = computeMaxScrollX();
}
+ public int getMaxScrollX() {
+ return mMaxScrollX;
+ }
+
protected int computeMaxScrollX() {
int childCount = getChildCount();
if (childCount > 0) {
@@ -663,6 +644,10 @@
requestLayout();
}
+ public int getPageSpacing() {
+ return mPageSpacing;
+ }
+
private void dispatchPageCountChanged() {
if (mPageIndicator != null) {
mPageIndicator.setMarkersCount(getChildCount());
@@ -812,9 +797,9 @@
}
/** Returns whether x and y originated within the buffered viewport */
- private boolean isTouchPointInViewportWithBuffer(int x, int y) {
+ private boolean isTouchPointInViewportWithBuffer(float x, float y) {
sTmpRect.set(-getMeasuredWidth() / 2, 0, 3 * getMeasuredWidth() / 2, getMeasuredHeight());
- return sTmpRect.contains(x, y);
+ return sTmpRect.contains((int) x, (int) y);
}
@Override
@@ -835,8 +820,7 @@
* motion.
*/
final int action = ev.getAction();
- if ((action == MotionEvent.ACTION_MOVE) &&
- (mTouchState == TOUCH_STATE_SCROLLING)) {
+ if ((action == MotionEvent.ACTION_MOVE) && mIsBeingDragged) {
return true;
}
@@ -873,21 +857,17 @@
* otherwise don't. mScroller.isFinished should be false when
* being flinged.
*/
- final int xDist = Math.abs(mScroller.getFinalX() - mScroller.getCurrX());
+ final int xDist = Math.abs(mScroller.getFinalPos() - mScroller.getCurrPos());
final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop / 3);
if (finishedScrolling) {
- mTouchState = TOUCH_STATE_REST;
+ mIsBeingDragged = false;
if (!mScroller.isFinished() && !mFreeScroll) {
setCurrentPage(getNextPage());
pageEndTransition();
}
} else {
- if (isTouchPointInViewportWithBuffer((int) mDownMotionX, (int) mDownMotionY)) {
- mTouchState = TOUCH_STATE_SCROLLING;
- } else {
- mTouchState = TOUCH_STATE_REST;
- }
+ mIsBeingDragged = isTouchPointInViewportWithBuffer(mDownMotionX, mDownMotionY);
}
break;
@@ -908,11 +888,11 @@
* The only time we want to intercept motion events is if we are in the
* drag mode.
*/
- return mTouchState != TOUCH_STATE_REST;
+ return mIsBeingDragged;
}
public boolean isHandlingTouch() {
- return mTouchState != TOUCH_STATE_REST;
+ return mIsBeingDragged;
}
protected void determineScrollingStart(MotionEvent ev) {
@@ -931,7 +911,7 @@
// Disallow scrolling if we started the gesture from outside the viewport
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
- if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return;
+ if (!isTouchPointInViewportWithBuffer(x, y)) return;
final int xDiff = (int) Math.abs(x - mLastMotionX);
@@ -940,7 +920,7 @@
if (xMoved) {
// Scroll if the user moved far enough along the X axis
- mTouchState = TOUCH_STATE_SCROLLING;
+ mIsBeingDragged = true;
mTotalMotionX += Math.abs(mLastMotionX - x);
mLastMotionX = x;
mLastMotionXRemainder = 0;
@@ -1008,31 +988,34 @@
}
}
- protected void dampedOverScroll(float amount) {
- if (Float.compare(amount, 0f) == 0) return;
+ protected void dampedOverScroll(int amount) {
+ if (amount == 0) return;
int overScrollAmount = OverScroll.dampedScroll(amount, getMeasuredWidth());
if (amount < 0) {
- mOverScrollX = overScrollAmount;
- super.scrollTo(mOverScrollX, getScrollY());
+ super.scrollTo(overScrollAmount, getScrollY());
} else {
- mOverScrollX = mMaxScrollX + overScrollAmount;
- super.scrollTo(mOverScrollX, getScrollY());
+ super.scrollTo(mMaxScrollX + overScrollAmount, getScrollY());
}
invalidate();
}
- protected void overScroll(float amount) {
- dampedOverScroll(amount);
+ protected void overScroll(int amount) {
+ if (amount == 0) return;
+
+ if (mFreeScroll && !mScroller.isFinished()) {
+ if (amount < 0) {
+ super.scrollTo(amount, getScrollY());
+ } else {
+ super.scrollTo(mMaxScrollX + amount, getScrollY());
+ }
+ } else {
+ dampedOverScroll(amount);
+ }
}
- protected void enableFreeScroll(boolean settleOnPageInFreeScroll) {
- setEnableFreeScroll(true);
- mSettleOnPageInFreeScroll = settleOnPageInFreeScroll;
- }
-
- private void setEnableFreeScroll(boolean freeScroll) {
+ protected void setEnableFreeScroll(boolean freeScroll) {
boolean wasFreeScroll = mFreeScroll;
mFreeScroll = freeScroll;
@@ -1041,8 +1024,6 @@
} else if (wasFreeScroll) {
snapToPage(getNextPage());
}
-
- setEnableOverscroll(!freeScroll);
}
protected void setEnableOverscroll(boolean enable) {
@@ -1077,14 +1058,14 @@
mTotalMotionX = 0;
mActivePointerId = ev.getPointerId(0);
- if (mTouchState == TOUCH_STATE_SCROLLING) {
+ if (mIsBeingDragged) {
onScrollInteractionBegin();
pageBeginTransition();
}
break;
case MotionEvent.ACTION_MOVE:
- if (mTouchState == TOUCH_STATE_SCROLLING) {
+ if (mIsBeingDragged) {
// Scroll to follow the motion event
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
@@ -1111,7 +1092,7 @@
break;
case MotionEvent.ACTION_UP:
- if (mTouchState == TOUCH_STATE_SCROLLING) {
+ if (mIsBeingDragged) {
final int activePointerId = mActivePointerId;
final int pointerIndex = ev.findPointerIndex(activePointerId);
final float x = ev.getX(pointerIndex);
@@ -1125,6 +1106,8 @@
mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
boolean isFling = mTotalMotionX > mTouchSlop && shouldFlingForVelocity(velocityX);
+ boolean isDeltaXLeft = mIsRtl ? deltaX > 0 : deltaX < 0;
+ boolean isVelocityXLeft = mIsRtl ? velocityX > 0 : velocityX < 0;
if (!mFreeScroll) {
// In the case that the page is moved far to one direction and then is flung
@@ -1140,8 +1123,7 @@
// We give flings precedence over large moves, which is why we short-circuit our
// test for a large move if a fling has been registered. That is, a large
// move to the left and fling to the right will register as a fling to the right.
- boolean isDeltaXLeft = mIsRtl ? deltaX > 0 : deltaX < 0;
- boolean isVelocityXLeft = mIsRtl ? velocityX > 0 : velocityX < 0;
+
if (((isSignificantMove && !isDeltaXLeft && !isFling) ||
(isFling && !isVelocityXLeft)) && mCurrentPage > 0) {
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
@@ -1159,60 +1141,44 @@
abortScrollerAnimation(true);
}
- float scaleX = getScaleX();
- int vX = (int) (-velocityX * scaleX);
- int initialScrollX = (int) (getScrollX() * scaleX);
+ int initialScrollX = getScrollX();
- mScroller.setInterpolator(mDefaultInterpolator);
- mScroller.fling(initialScrollX,
- getScrollY(), vX, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0);
- int unscaledScrollX = (int) (mScroller.getFinalX() / scaleX);
- mNextPage = getPageNearestToCenterOfScreen(unscaledScrollX);
- int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
- int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
- if (mSettleOnPageInFreeScroll && unscaledScrollX > 0
- && unscaledScrollX < mMaxScrollX) {
- // If scrolling ends in the half of the added space that is closer to the
- // end, settle to the end. Otherwise snap to the nearest page.
- // If flinging past one of the ends, don't change the velocity as it will
- // get stopped at the end anyway.
- final int finalX = unscaledScrollX < firstPageScroll / 2 ?
- 0 :
- unscaledScrollX > (lastPageScroll + mMaxScrollX) / 2 ?
- mMaxScrollX :
- getScrollForPage(mNextPage);
+ if (((initialScrollX >= mMaxScrollX) && (isVelocityXLeft || !isFling)) ||
+ ((initialScrollX <= 0) && (!isVelocityXLeft || !isFling))) {
+ mScroller.springBack(getScrollX(), 0, mMaxScrollX);
+ } else {
+ mScroller.setInterpolator(mDefaultInterpolator);
+ mScroller.fling(initialScrollX, -velocityX,
+ 0, mMaxScrollX,
+ Math.round(getWidth() * 0.5f * OVERSCROLL_DAMP_FACTOR));
- mScroller.setFinalX((int) (finalX * getScaleX()));
- // Ensure the scroll/snap doesn't happen too fast;
- int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
- - mScroller.getDuration();
- if (extraScrollDuration > 0) {
- mScroller.extendDuration(extraScrollDuration);
+ int finalX = mScroller.getFinalPos();
+ mNextPage = getPageNearestToCenterOfScreen(finalX);
+
+ int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
+ int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
+ if (finalX > 0 && finalX < mMaxScrollX) {
+ // If scrolling ends in the half of the added space that is closer to
+ // the end, settle to the end. Otherwise snap to the nearest page.
+ // If flinging past one of the ends, don't change the velocity as it
+ // will get stopped at the end anyway.
+ int pageSnappedX = finalX < firstPageScroll / 2 ? 0
+ : finalX > (lastPageScroll + mMaxScrollX) / 2
+ ? mMaxScrollX
+ : getScrollForPage(mNextPage);
+
+ mScroller.setFinalPos(pageSnappedX);
+ // Ensure the scroll/snap doesn't happen too fast;
+ int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
+ - mScroller.getDuration();
+ if (extraScrollDuration > 0) {
+ mScroller.extendDuration(extraScrollDuration);
+ }
}
}
invalidate();
}
onScrollInteractionEnd();
- } else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
- // at this point we have not moved beyond the touch slop
- // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
- // we can just page
- int nextPage = Math.max(0, mCurrentPage - 1);
- if (nextPage != mCurrentPage) {
- snapToPage(nextPage);
- } else {
- snapToDestination();
- }
- } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
- // at this point we have not moved beyond the touch slop
- // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
- // we can just page
- int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
- if (nextPage != mCurrentPage) {
- snapToPage(nextPage);
- } else {
- snapToDestination();
- }
}
// End any intermediate reordering states
@@ -1220,7 +1186,7 @@
break;
case MotionEvent.ACTION_CANCEL:
- if (mTouchState == TOUCH_STATE_SCROLLING) {
+ if (mIsBeingDragged) {
snapToDestination();
onScrollInteractionEnd();
}
@@ -1242,7 +1208,7 @@
private void resetTouchState() {
releaseVelocityTracker();
- mTouchState = TOUCH_STATE_REST;
+ mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
}
@@ -1356,7 +1322,7 @@
}
protected boolean isInOverScroll() {
- return (mOverScrollX > mMaxScrollX || mOverScrollX < 0);
+ return (getScrollX() > mMaxScrollX || getScrollX() < 0);
}
protected int getPageSnapDuration() {
@@ -1446,8 +1412,8 @@
}
if (FeatureFlags.IS_DOGFOOD_BUILD) {
- duration *= Settings.System.getFloat(getContext().getContentResolver(),
- Settings.System.WINDOW_ANIMATION_SCALE, 1);
+ duration *= Settings.Global.getFloat(getContext().getContentResolver(),
+ Settings.Global.WINDOW_ANIMATION_SCALE, 1);
}
whichPage = validateNewPage(whichPage);
@@ -1475,7 +1441,7 @@
mScroller.setInterpolator(mDefaultInterpolator);
}
- mScroller.startScroll(getUnboundedScrollX(), 0, delta, 0, duration);
+ mScroller.startScroll(getUnboundedScrollX(), delta, duration);
updatePageIndicator();
diff --git a/src/com/android/launcher3/PromiseAppInfo.java b/src/com/android/launcher3/PromiseAppInfo.java
index ea9f752..ea151cd 100644
--- a/src/com/android/launcher3/PromiseAppInfo.java
+++ b/src/com/android/launcher3/PromiseAppInfo.java
@@ -18,11 +18,12 @@
import android.content.Context;
import android.content.Intent;
-import android.support.annotation.NonNull;
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.util.PackageManagerHelper;
+import androidx.annotation.NonNull;
+
public class PromiseAppInfo extends AppInfo {
public int level = 0;
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 76e85e2..6083415 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -2,7 +2,6 @@
import static android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID;
import static android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE;
-
import static com.android.launcher3.ItemInfoWithIcon.FLAG_SYSTEM_MASK;
import static com.android.launcher3.ItemInfoWithIcon.FLAG_SYSTEM_NO;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
@@ -10,7 +9,6 @@
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.UNINSTALL;
import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
deleted file mode 100644
index 32c198a..0000000
--- a/src/com/android/launcher3/SettingsActivity.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
-import static com.android.launcher3.states.RotationHelper.getAllowRotationDefaultValue;
-
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.FragmentManager;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceScreen;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.view.View;
-import android.widget.Adapter;
-import android.widget.ListView;
-
-import com.android.launcher3.graphics.IconShapeOverride;
-import com.android.launcher3.notification.NotificationListener;
-import com.android.launcher3.util.ListViewHighlighter;
-import com.android.launcher3.util.SettingsObserver;
-import com.android.launcher3.views.ButtonPreference;
-
-import java.util.Objects;
-
-/**
- * Settings activity for Launcher. Currently implements the following setting: Allow rotation
- */
-public class SettingsActivity extends Activity {
-
- private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging";
- /** Hidden field Settings.Secure.NOTIFICATION_BADGING */
- public static final String NOTIFICATION_BADGING = "notification_badging";
- /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
- private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
-
- private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
- private static final String EXTRA_SHOW_FRAGMENT_ARGS = ":settings:show_fragment_args";
- private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600;
- private static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- if (savedInstanceState == null) {
- // Display the fragment as the main content.
- getFragmentManager().beginTransaction()
- .replace(android.R.id.content, getNewFragment())
- .commit();
- }
- }
-
- protected PreferenceFragment getNewFragment() {
- return new LauncherSettingsFragment();
- }
-
- /**
- * This fragment shows the launcher preferences.
- */
- public static class LauncherSettingsFragment extends PreferenceFragment {
-
- private IconBadgingObserver mIconBadgingObserver;
-
- private String mPreferenceKey;
- private boolean mPreferenceHighlighted = false;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (savedInstanceState != null) {
- mPreferenceHighlighted = savedInstanceState.getBoolean(SAVE_HIGHLIGHTED_KEY);
- }
-
- getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY);
- addPreferencesFromResource(R.xml.launcher_preferences);
-
- ContentResolver resolver = getActivity().getContentResolver();
-
- ButtonPreference iconBadgingPref =
- (ButtonPreference) findPreference(ICON_BADGING_PREFERENCE_KEY);
- if (!Utilities.ATLEAST_OREO) {
- getPreferenceScreen().removePreference(
- findPreference(SessionCommitReceiver.ADD_ICON_PREFERENCE_KEY));
- getPreferenceScreen().removePreference(iconBadgingPref);
- } else if (!getResources().getBoolean(R.bool.notification_badging_enabled)) {
- getPreferenceScreen().removePreference(iconBadgingPref);
- } else {
- // Listen to system notification badge settings while this UI is active.
- mIconBadgingObserver = new IconBadgingObserver(
- iconBadgingPref, resolver, getFragmentManager());
- mIconBadgingObserver.register(NOTIFICATION_BADGING, NOTIFICATION_ENABLED_LISTENERS);
- }
-
- Preference iconShapeOverride = findPreference(IconShapeOverride.KEY_PREFERENCE);
- if (iconShapeOverride != null) {
- if (IconShapeOverride.isSupported(getActivity())) {
- IconShapeOverride.handlePreferenceUi((ListPreference) iconShapeOverride);
- } else {
- getPreferenceScreen().removePreference(iconShapeOverride);
- }
- }
-
- // Setup allow rotation preference
- Preference rotationPref = findPreference(ALLOW_ROTATION_PREFERENCE_KEY);
- if (getResources().getBoolean(R.bool.allow_rotation)) {
- // Launcher supports rotation by default. No need to show this setting.
- getPreferenceScreen().removePreference(rotationPref);
- } else {
- // Initialize the UI once
- rotationPref.setDefaultValue(getAllowRotationDefaultValue());
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- Intent intent = getActivity().getIntent();
- mPreferenceKey = intent.getStringExtra(EXTRA_FRAGMENT_ARG_KEY);
- if (isAdded() && !mPreferenceHighlighted && !TextUtils.isEmpty(mPreferenceKey)) {
- getView().postDelayed(this::highlightPreference, DELAY_HIGHLIGHT_DURATION_MILLIS);
- }
- }
-
- private void highlightPreference() {
- Preference pref = findPreference(mPreferenceKey);
- if (pref == null || getPreferenceScreen() == null) {
- return;
- }
- PreferenceScreen screen = getPreferenceScreen();
- if (Utilities.ATLEAST_OREO) {
- screen = selectPreferenceRecursive(pref, screen);
- }
- if (screen == null) {
- return;
- }
-
- View root = screen.getDialog() != null
- ? screen.getDialog().getWindow().getDecorView() : getView();
- ListView list = root.findViewById(android.R.id.list);
- if (list == null || list.getAdapter() == null) {
- return;
- }
- Adapter adapter = list.getAdapter();
-
- // Find the position
- int position = -1;
- for (int i = adapter.getCount() - 1; i >= 0; i--) {
- if (pref == adapter.getItem(i)) {
- position = i;
- break;
- }
- }
- new ListViewHighlighter(list, position);
- mPreferenceHighlighted = true;
- }
-
- @Override
- public void onDestroy() {
- if (mIconBadgingObserver != null) {
- mIconBadgingObserver.unregister();
- mIconBadgingObserver = null;
- }
- super.onDestroy();
- }
-
- @TargetApi(Build.VERSION_CODES.O)
- private PreferenceScreen selectPreferenceRecursive(
- Preference pref, PreferenceScreen topParent) {
- if (!(pref.getParent() instanceof PreferenceScreen)) {
- return null;
- }
-
- PreferenceScreen parent = (PreferenceScreen) pref.getParent();
- if (Objects.equals(parent.getKey(), topParent.getKey())) {
- return parent;
- } else if (selectPreferenceRecursive(parent, topParent) != null) {
- ((PreferenceScreen) parent.getParent())
- .onItemClick(null, null, parent.getOrder(), 0);
- return parent;
- } else {
- return null;
- }
- }
- }
-
- /**
- * Content observer which listens for system badging setting changes,
- * and updates the launcher badging setting subtext accordingly.
- */
- private static class IconBadgingObserver extends SettingsObserver.Secure
- implements Preference.OnPreferenceClickListener {
-
- private final ButtonPreference mBadgingPref;
- private final ContentResolver mResolver;
- private final FragmentManager mFragmentManager;
-
- public IconBadgingObserver(ButtonPreference badgingPref, ContentResolver resolver,
- FragmentManager fragmentManager) {
- super(resolver);
- mBadgingPref = badgingPref;
- mResolver = resolver;
- mFragmentManager = fragmentManager;
- }
-
- @Override
- public void onSettingChanged(boolean enabled) {
- int summary = enabled ? R.string.icon_badging_desc_on : R.string.icon_badging_desc_off;
-
- boolean serviceEnabled = true;
- if (enabled) {
- // Check if the listener is enabled or not.
- String enabledListeners =
- Settings.Secure.getString(mResolver, NOTIFICATION_ENABLED_LISTENERS);
- ComponentName myListener =
- new ComponentName(mBadgingPref.getContext(), NotificationListener.class);
- serviceEnabled = enabledListeners != null &&
- (enabledListeners.contains(myListener.flattenToString()) ||
- enabledListeners.contains(myListener.flattenToShortString()));
- if (!serviceEnabled) {
- summary = R.string.title_missing_notification_access;
- }
- }
- mBadgingPref.setWidgetFrameVisible(!serviceEnabled);
- mBadgingPref.setOnPreferenceClickListener(serviceEnabled ? null : this);
- mBadgingPref.setSummary(summary);
-
- }
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- new NotificationAccessConfirmation().show(mFragmentManager, "notification_access");
- return true;
- }
- }
-
- public static class NotificationAccessConfirmation
- extends DialogFragment implements DialogInterface.OnClickListener {
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final Context context = getActivity();
- String msg = context.getString(R.string.msg_missing_notification_access,
- context.getString(R.string.derived_app_name));
- return new AlertDialog.Builder(context)
- .setTitle(R.string.title_missing_notification_access)
- .setMessage(msg)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(R.string.title_change_settings, this)
- .create();
- }
-
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- ComponentName cn = new ComponentName(getActivity(), NotificationListener.class);
- Bundle showFragmentArgs = new Bundle();
- showFragmentArgs.putString(EXTRA_FRAGMENT_ARG_KEY, cn.flattenToString());
-
- Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- .putExtra(EXTRA_FRAGMENT_ARG_KEY, cn.flattenToString())
- .putExtra(EXTRA_SHOW_FRAGMENT_ARGS, showFragmentArgs);
- getActivity().startActivity(intent);
- }
- }
-}
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 8588c7a..19c647f 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -24,7 +24,7 @@
import android.text.TextUtils;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.util.ContentWriter;
@@ -125,7 +125,7 @@
.put(LauncherSettings.BaseLauncherColumns.INTENT, getIntent())
.put(LauncherSettings.Favorites.RESTORED, status);
- if (!usingLowResIcon) {
+ if (!usingLowResIcon()) {
writer.putIcon(iconBitmap, user);
}
if (iconResource != null) {
@@ -171,8 +171,7 @@
if (TextUtils.isEmpty(label)) {
label = shortcutInfo.getShortLabel();
}
- contentDescription = UserManagerCompat.getInstance(context)
- .getBadgedLabelForUser(label, user);
+ contentDescription = context.getPackageManager().getUserBadgedLabel(label, user);
if (shortcutInfo.isEnabled()) {
runtimeStatusFlags &= ~FLAG_DISABLED_BY_PUBLISHER;
} else {
diff --git a/src/com/android/launcher3/TestProtocol.java b/src/com/android/launcher3/TestProtocol.java
new file mode 100644
index 0000000..0a3b86d
--- /dev/null
+++ b/src/com/android/launcher3/TestProtocol.java
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+/**
+ * Protocol for custom accessibility events for communication with UI Automation tests.
+ */
+public final class TestProtocol {
+ public static final String GET_SCROLL_MESSAGE = "TAPL_GET_SCROLL";
+ public static final String SCROLL_Y_FIELD = "scrollY";
+ public static final String SWITCHED_TO_STATE_MESSAGE = "TAPL_SWITCHED_TO_STATE";
+ public static final String RESPONSE_MESSAGE_POSTFIX = "_RESPONSE";
+}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 7fe8d35..65f0703 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import android.app.ActivityManager;
import android.app.WallpaperManager;
import android.content.ComponentName;
import android.content.Context;
@@ -51,11 +52,11 @@
import android.view.animation.Interpolator;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.IntArray;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
@@ -83,6 +84,10 @@
private static final Matrix sMatrix = new Matrix();
private static final Matrix sInverseMatrix = new Matrix();
+ public static final boolean ATLEAST_Q = Build.VERSION.CODENAME.length() == 1
+ && Build.VERSION.CODENAME.charAt(0) >= 'Q'
+ && Build.VERSION.CODENAME.charAt(0) <= 'Z';
+
public static final boolean ATLEAST_P =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
@@ -110,8 +115,9 @@
* Indicates if the device has a debug build. Should only be used to store additional info or
* add extra logging and not for changing the app behavior.
*/
- public static final boolean IS_DEBUG_DEVICE = Build.TYPE.toLowerCase().contains("debug")
- || Build.TYPE.toLowerCase().equals("eng");
+ public static final boolean IS_DEBUG_DEVICE =
+ Build.TYPE.toLowerCase(Locale.ROOT).contains("debug") ||
+ Build.TYPE.toLowerCase(Locale.ROOT).equals("eng");
// An intent extra to indicate the horizontal scroll of the wallpaper.
public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET";
@@ -131,6 +137,13 @@
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
+ public static boolean IS_RUNNING_IN_TEST_HARNESS =
+ ActivityManager.isRunningInTestHarness();
+
+ public static void enableRunningInTestHarnessForTests() {
+ IS_RUNNING_IN_TEST_HARNESS = true;
+ }
+
public static boolean isPropertyEnabled(String propertyName) {
return Log.isLoggable(propertyName, Log.VERBOSE);
}
@@ -344,25 +357,6 @@
}
/**
- * Compresses the bitmap to a byte array for serialization.
- */
- public static byte[] flattenBitmap(Bitmap bitmap) {
- // Try go guesstimate how much space the icon will take when serialized
- // to avoid unnecessary allocations/copies during the write.
- int size = bitmap.getWidth() * bitmap.getHeight() * 4;
- ByteArrayOutputStream out = new ByteArrayOutputStream(size);
- try {
- bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
- out.flush();
- out.close();
- return out.toByteArray();
- } catch (IOException e) {
- Log.w(TAG, "Could not write bitmap");
- return null;
- }
- }
-
- /**
* Trims the string, removing all whitespace at the beginning and end of the string.
* Non-breaking whitespaces are also removed.
*/
@@ -444,8 +438,8 @@
size, metrics));
}
- public static String createDbSelectionQuery(String columnName, Iterable<?> values) {
- return String.format(Locale.ENGLISH, "%s IN (%s)", columnName, TextUtils.join(", ", values));
+ public static String createDbSelectionQuery(String columnName, IntArray values) {
+ return String.format(Locale.ENGLISH, "%s IN (%s)", columnName, values.toConcatString());
}
public static boolean isBootCompleted() {
@@ -502,13 +496,6 @@
return spanned;
}
- /**
- * Replacement for Long.compare() which was added in API level 19.
- */
- public static int longCompare(long lhs, long rhs) {
- return lhs < rhs ? -1 : (lhs == rhs ? 0 : 1);
- }
-
public static SharedPreferences getPrefs(Context context) {
return context.getSharedPreferences(
LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE);
@@ -581,25 +568,6 @@
|| e.getCause() instanceof DeadObjectException;
}
- public static <T> T getOverrideObject(Class<T> clazz, Context context, int resId) {
- String className = context.getString(resId);
- if (!TextUtils.isEmpty(className)) {
- try {
- Class<?> cls = Class.forName(className);
- return (T) cls.getDeclaredConstructor(Context.class).newInstance(context);
- } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
- | ClassCastException | NoSuchMethodException | InvocationTargetException e) {
- Log.e(TAG, "Bad overriden class", e);
- }
- }
-
- try {
- return clazz.newInstance();
- } catch (InstantiationException|IllegalAccessException e) {
- throw new RuntimeException(e);
- }
- }
-
/**
* Returns a HashSet with a single element. We use this instead of Collections.singleton()
* because HashSet ensures all operations, such as remove, are supported.
@@ -618,4 +586,8 @@
msg.setAsynchronous(true);
handler.sendMessage(msg);
}
+
+ public interface Consumer<T> {
+ void accept(T var1);
+ }
}
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 7af4bf9..050849c 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -25,15 +25,16 @@
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import android.util.Log;
import android.util.LongSparseArray;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.ShortcutConfigActivityInfo;
import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.graphics.LauncherIcons;
-import com.android.launcher3.graphics.ShadowGenerator;
+import com.android.launcher3.icons.GraphicsUtils;
+import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.icons.ShadowGenerator;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageUserKey;
@@ -51,6 +52,8 @@
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
+import androidx.annotation.Nullable;
+
public class WidgetPreviewLoader {
private static final String TAG = "WidgetPreviewLoader";
@@ -147,7 +150,7 @@
values.put(CacheDb.COLUMN_PACKAGE, key.componentName.getPackageName());
values.put(CacheDb.COLUMN_VERSION, versions[0]);
values.put(CacheDb.COLUMN_LAST_UPDATED, versions[1]);
- values.put(CacheDb.COLUMN_PREVIEW_BITMAP, Utilities.flattenBitmap(preview));
+ values.put(CacheDb.COLUMN_PREVIEW_BITMAP, GraphicsUtils.flattenBitmap(preview));
mDb.insertOrReplace(values);
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 54d29c1..96df810 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -28,7 +28,6 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.SuppressLint;
@@ -54,6 +53,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;
import com.android.launcher3.Launcher.LauncherOverlay;
@@ -84,8 +84,10 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.WallpaperOffsetInterpolator;
@@ -125,21 +127,21 @@
private static final int DEFAULT_PAGE = 0;
- private static final boolean MAP_NO_RECURSE = false;
- private static final boolean MAP_RECURSE = true;
+ public static final boolean MAP_NO_RECURSE = false;
+ public static final boolean MAP_RECURSE = true;
// The screen id used for the empty screen always present to the right.
- public static final long EXTRA_EMPTY_SCREEN_ID = -201;
+ public static final int EXTRA_EMPTY_SCREEN_ID = -201;
// The is the first screen. It is always present, even if its empty.
- public static final long FIRST_SCREEN_ID = 0;
+ public static final int FIRST_SCREEN_ID = 0;
private LayoutTransition mLayoutTransition;
@Thunk final WallpaperManager mWallpaperManager;
private ShortcutAndWidgetContainer mDragSourceInternal;
- @Thunk final LongArrayMap<CellLayout> mWorkspaceScreens = new LongArrayMap<>();
- @Thunk final ArrayList<Long> mScreenOrder = new ArrayList<>();
+ @Thunk final IntSparseArrayMap<CellLayout> mWorkspaceScreens = new IntSparseArrayMap<>();
+ @Thunk final IntArray mScreenOrder = new IntArray();
@Thunk Runnable mRemoveEmptyScreenRunnable;
@Thunk boolean mDeferRemoveExtraEmptyScreen = false;
@@ -226,7 +228,7 @@
@Thunk int mLastReorderY = -1;
private SparseArray<Parcelable> mSavedStates;
- private final ArrayList<Integer> mRestoredPages = new ArrayList<>();
+ private final IntArray mRestoredPages = new IntArray();
private float mCurrentScale;
private float mTransitionProgress;
@@ -473,16 +475,12 @@
super.onViewAdded(child);
}
- public boolean isTouchActive() {
- return mTouchState != TOUCH_STATE_REST;
- }
-
/**
* Initializes and binds the first page
* @param qsb an existing qsb to recycle or null.
*/
public void bindAndInitFirstWorkspaceScreen(View qsb) {
- if (!FeatureFlags.QSB_ON_FIRST_SCREEN) {
+ if (!FeatureFlags.QSB_ON_FIRST_SCREEN.get()) {
return;
}
// Add the first page
@@ -526,7 +524,7 @@
enableLayoutTransitions();
}
- public void insertNewWorkspaceScreenBeforeEmptyScreen(long screenId) {
+ public void insertNewWorkspaceScreenBeforeEmptyScreen(int screenId) {
// Find the index to insert this view into. If the empty screen exists, then
// insert it before that.
int insertIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);
@@ -536,11 +534,11 @@
insertNewWorkspaceScreen(screenId, insertIndex);
}
- public void insertNewWorkspaceScreen(long screenId) {
+ public void insertNewWorkspaceScreen(int screenId) {
insertNewWorkspaceScreen(screenId, getChildCount());
}
- public CellLayout insertNewWorkspaceScreen(long screenId, int insertIndex) {
+ public CellLayout insertNewWorkspaceScreen(int screenId, int insertIndex) {
if (mWorkspaceScreens.containsKey(screenId)) {
throw new RuntimeException("Screen id " + screenId + " already exists!");
}
@@ -549,7 +547,6 @@
// created CellLayout.
CellLayout newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
R.layout.workspace_screen, this, false /* attachToRoot */);
- newScreen.getShortcutsAndWidgets().setId(R.id.workspace_page_container);
int paddingLeftRight = mLauncher.getDeviceProfile().cellLayoutPaddingLeftRightPx;
int paddingBottom = mLauncher.getDeviceProfile().cellLayoutBottomPaddingPx;
newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
@@ -608,7 +605,7 @@
}
if (hasExtraEmptyScreen() || mScreenOrder.size() == 0) return;
- long finalScreenId = mScreenOrder.get(mScreenOrder.size() - 1);
+ int finalScreenId = mScreenOrder.get(mScreenOrder.size() - 1);
CellLayout finalScreen = mWorkspaceScreens.get(finalScreenId);
@@ -616,7 +613,7 @@
if (finalScreen.getShortcutsAndWidgets().getChildCount() == 0 &&
!finalScreen.isDropPending()) {
mWorkspaceScreens.remove(finalScreenId);
- mScreenOrder.remove(finalScreenId);
+ mScreenOrder.removeValue(finalScreenId);
// if this is the last screen, convert it to the empty screen
mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, finalScreen);
@@ -675,9 +672,6 @@
private void fadeAndRemoveEmptyScreen(int delay, int duration, final Runnable onComplete,
final boolean stripEmptyScreens) {
// XXX: Do we need to update LM workspace screens below?
- PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f);
- PropertyValuesHolder bgAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", 0f);
-
final CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);
mRemoveEmptyScreenRunnable = new Runnable() {
@@ -685,7 +679,7 @@
public void run() {
if (hasExtraEmptyScreen()) {
mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);
- mScreenOrder.remove(EXTRA_EMPTY_SCREEN_ID);
+ mScreenOrder.removeValue(EXTRA_EMPTY_SCREEN_ID);
removeView(cl);
if (stripEmptyScreens) {
stripEmptyScreens();
@@ -696,7 +690,7 @@
}
};
- ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(cl, alpha, bgAlpha);
+ ObjectAnimator oa = ObjectAnimator.ofFloat(cl, ALPHA, 0f);
oa.setDuration(duration);
oa.setStartDelay(delay);
oa.addListener(new AnimatorListenerAdapter() {
@@ -717,7 +711,7 @@
return mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID) && getChildCount() > 1;
}
- public long commitExtraEmptyScreen() {
+ public int commitExtraEmptyScreen() {
if (mLauncher.isWorkspaceLoading()) {
// Invalid and dangerous operation if workspace is loading
return -1;
@@ -725,11 +719,11 @@
CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);
mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);
- mScreenOrder.remove(EXTRA_EMPTY_SCREEN_ID);
+ mScreenOrder.removeValue(EXTRA_EMPTY_SCREEN_ID);
- long newId = LauncherSettings.Settings.call(getContext().getContentResolver(),
+ int newId = LauncherSettings.Settings.call(getContext().getContentResolver(),
LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
- .getLong(LauncherSettings.Settings.EXTRA_VALUE);
+ .getInt(LauncherSettings.Settings.EXTRA_VALUE);
mWorkspaceScreens.put(newId, cl);
mScreenOrder.add(newId);
@@ -739,11 +733,11 @@
return newId;
}
- public CellLayout getScreenWithId(long screenId) {
+ public CellLayout getScreenWithId(int screenId) {
return mWorkspaceScreens.get(screenId);
}
- public long getIdForScreen(CellLayout layout) {
+ public int getIdForScreen(CellLayout layout) {
int index = mWorkspaceScreens.indexOfValue(layout);
if (index != -1) {
return mWorkspaceScreens.keyAt(index);
@@ -751,18 +745,18 @@
return -1;
}
- public int getPageIndexForScreenId(long screenId) {
+ public int getPageIndexForScreenId(int screenId) {
return indexOfChild(mWorkspaceScreens.get(screenId));
}
- public long getScreenIdForPageIndex(int index) {
+ public int getScreenIdForPageIndex(int index) {
if (0 <= index && index < mScreenOrder.size()) {
return mScreenOrder.get(index);
}
return -1;
}
- public ArrayList<Long> getScreenOrder() {
+ public IntArray getScreenOrder() {
return mScreenOrder;
}
@@ -779,13 +773,13 @@
}
int currentPage = getNextPage();
- ArrayList<Long> removeScreens = new ArrayList<>();
+ IntArray removeScreens = new IntArray();
int total = mWorkspaceScreens.size();
for (int i = 0; i < total; i++) {
- long id = mWorkspaceScreens.keyAt(i);
+ int id = mWorkspaceScreens.keyAt(i);
CellLayout cl = mWorkspaceScreens.valueAt(i);
// FIRST_SCREEN_ID can never be removed.
- if ((!FeatureFlags.QSB_ON_FIRST_SCREEN || id > FIRST_SCREEN_ID)
+ if ((!FeatureFlags.QSB_ON_FIRST_SCREEN.get() || id > FIRST_SCREEN_ID)
&& cl.getShortcutsAndWidgets().getChildCount() == 0) {
removeScreens.add(id);
}
@@ -798,10 +792,11 @@
int minScreens = 1;
int pageShift = 0;
- for (Long id: removeScreens) {
+ for (int i = 0; i < removeScreens.size(); i++) {
+ int id = removeScreens.get(i);
CellLayout cl = mWorkspaceScreens.get(id);
mWorkspaceScreens.remove(id);
- mScreenOrder.remove(id);
+ mScreenOrder.removeValue(id);
if (getChildCount() > minScreens) {
if (indexOfChild(cl) < currentPage) {
@@ -823,7 +818,9 @@
if (!removeScreens.isEmpty()) {
// Update the model if we have changed any screens
- LauncherModel.updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
+ mLauncher.getModelWriter().enqueueDeleteRunnable(
+ () -> LauncherModel.updateWorkspaceScreenOrder(mLauncher, mScreenOrder));
+
}
if (pageShift >= 0) {
@@ -848,7 +845,7 @@
/**
* Adds the specified child in the specified screen based on the {@param info}
- * See {@link #addInScreen(View, long, long, int, int, int, int)}.
+ * See {@link #addInScreen(View, int, int, int, int, int, int)}.
*/
public void addInScreen(View child, ItemInfo info) {
addInScreen(child, info.container, info.screenId, info.cellX, info.cellY,
@@ -866,7 +863,7 @@
* @param spanX The number of cells spanned horizontally by the child.
* @param spanY The number of cells spanned vertically by the child.
*/
- private void addInScreen(View child, long container, long screenId, int x, int y,
+ private void addInScreen(View child, int container, int screenId, int x, int y,
int spanX, int spanY) {
if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
if (getScreenWithId(screenId) == null) {
@@ -883,7 +880,7 @@
final CellLayout layout;
if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- layout = mLauncher.getHotseat().getLayout();
+ layout = mLauncher.getHotseat();
// Hide folder title in the hotseat
if (child instanceof FolderIcon) {
@@ -1036,7 +1033,7 @@
}
protected void onScrollInteractionBegin() {
- super.onScrollInteractionEnd();
+ super.onScrollInteractionBegin();
mScrollInteractionBegan = true;
}
@@ -1100,7 +1097,7 @@
}
@Override
- protected void overScroll(float amount) {
+ protected void overScroll(int amount) {
boolean shouldScrollOverlay = mLauncherOverlay != null &&
((amount <= 0 && !mIsRtl) || (amount >= 0 && mIsRtl));
@@ -1113,7 +1110,7 @@
mLauncherOverlay.onScrollInteractionBegin();
}
- mLastOverlayScroll = Math.abs(amount / getMeasuredWidth());
+ mLastOverlayScroll = Math.abs(((float) amount) / getMeasuredWidth());
mLauncherOverlay.onScrollChange(mLastOverlayScroll, mIsRtl);
} else {
dampedOverScroll(amount);
@@ -1291,12 +1288,6 @@
}
}
- public void showOutlinesTemporarily() {
- if (!mIsPageInTransition && !isTouchActive()) {
- snapToPage(mCurrentPage);
- }
- }
-
private void updatePageAlphaValues() {
// We need to check the isDragging case because updatePageAlphaValues is called between
// goToState(SPRING_LOADED) and onStartStateTransition.
@@ -1495,6 +1486,18 @@
}
}
+ @Override
+ public AccessibilityNodeInfo createAccessibilityNodeInfo() {
+ if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) {
+ // TAPL tests verify that workspace is not present in Overview and AllApps states.
+ // TAPL can work only if UIDevice is set up as setCompressedLayoutHeirarchy(false).
+ // Hiding workspace from the tests when it's
+ // IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS.
+ return null;
+ }
+ return super.createAccessibilityNodeInfo();
+ }
+
private void updateAccessibilityFlags(int accessibilityFlag, CellLayout page) {
page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
page.getShortcutsAndWidgets().setImportantForAccessibility(accessibilityFlag);
@@ -1514,7 +1517,7 @@
@Override
protected void enableAccessibleDrag(boolean enable) {
super.enableAccessibleDrag(enable);
- setEnableForLayout(mLauncher.getHotseat().getLayout(),enable);
+ setEnableForLayout(mLauncher.getHotseat(),enable);
}
});
}
@@ -1622,11 +1625,7 @@
mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
// We want the point to be mapped to the dragTarget.
- if (mLauncher.isHotseatLayout(dropTargetLayout)) {
- mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
- } else {
- mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter);
- }
+ mapPointFromDropLayout(dropTargetLayout, mDragViewVisualCenter);
int spanX;
int spanY;
@@ -1674,7 +1673,7 @@
}
}
- long screenId = getIdForScreen(dropTargetLayout);
+ int screenId = getIdForScreen(dropTargetLayout);
if (screenId == EXTRA_EMPTY_SCREEN_ID) {
commitExtraEmptyScreen();
}
@@ -1739,7 +1738,7 @@
return false;
}
- boolean createUserFolderIfNecessary(View newView, long container, CellLayout target,
+ boolean createUserFolderIfNecessary(View newView, int container, CellLayout target,
int[] targetCell, float distance, boolean external, DragView dragView) {
if (distance > mMaxDistanceForFolderCreation) return false;
View v = target.getChildAt(targetCell[0], targetCell[1]);
@@ -1753,7 +1752,7 @@
if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;
mCreateUserFolderOnDrop = false;
- final long screenId = getIdForScreen(target);
+ final int screenId = getIdForScreen(target);
boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);
@@ -1828,11 +1827,7 @@
// We want the point to be mapped to the dragTarget.
if (dropTargetLayout != null) {
- if (mLauncher.isHotseatLayout(dropTargetLayout)) {
- mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
- } else {
- mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter);
- }
+ mapPointFromDropLayout(dropTargetLayout, mDragViewVisualCenter);
}
boolean droppedOnOriginalCell = false;
@@ -1852,10 +1847,10 @@
// Move internally
boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout);
boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);
- long container = hasMovedIntoHotseat ?
+ int container = hasMovedIntoHotseat ?
LauncherSettings.Favorites.CONTAINER_HOTSEAT :
LauncherSettings.Favorites.CONTAINER_DESKTOP;
- long screenId = (mTargetCell[0] < 0) ?
+ int screenId = (mTargetCell[0] < 0) ?
mDragInfo.screenId : getIdForScreen(dropTargetLayout);
int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
@@ -2021,22 +2016,8 @@
}
public void onNoCellFound(View dropTargetLayout) {
- if (mLauncher.isHotseatLayout(dropTargetLayout)) {
- Hotseat hotseat = mLauncher.getHotseat();
- boolean droppedOnAllAppsIcon = !FeatureFlags.NO_ALL_APPS_ICON
- && mTargetCell != null && !mLauncher.getDeviceProfile().inv.isAllAppsButtonRank(
- hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell[1]));
- if (!droppedOnAllAppsIcon) {
- // Only show message when hotseat is full and drop target was not AllApps button
- showOutOfSpaceMessage(true);
- }
- } else {
- showOutOfSpaceMessage(false);
- }
- }
-
- private void showOutOfSpaceMessage(boolean isHotseatLayout) {
- int strId = (isHotseatLayout ? R.string.hotseat_out_of_space : R.string.out_of_space);
+ int strId = mLauncher.isHotseatLayout(dropTargetLayout)
+ ? R.string.hotseat_out_of_space : R.string.out_of_space;
Toast.makeText(mLauncher, mLauncher.getString(strId), Toast.LENGTH_SHORT).show();
}
@@ -2206,7 +2187,7 @@
* Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
* coordinate space. The argument xy is modified with the return result.
*/
- void mapPointFromSelfToChild(View v, float[] xy) {
+ private void mapPointFromSelfToChild(View v, float[] xy) {
xy[0] = xy[0] - v.getLeft();
xy[1] = xy[1] - v.getTop();
}
@@ -2222,14 +2203,23 @@
mTempXY[1] <= hotseat.getBottom();
}
- void mapPointFromSelfToHotseatLayout(Hotseat hotseat, float[] xy) {
- mTempXY[0] = (int) xy[0];
- mTempXY[1] = (int) xy[1];
- mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempXY, true);
- mLauncher.getDragLayer().mapCoordInSelfToDescendant(hotseat.getLayout(), mTempXY);
+ /**
+ * Updates the point in {@param xy} to point to the co-ordinate space of {@param layout}
+ * @param layout either hotseat of a page in workspace
+ * @param xy the point location in workspace co-ordinate space
+ */
+ private void mapPointFromDropLayout(CellLayout layout, float[] xy) {
+ if (mLauncher.isHotseatLayout(layout)) {
+ mTempXY[0] = (int) xy[0];
+ mTempXY[1] = (int) xy[1];
+ mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempXY, true);
+ mLauncher.getDragLayer().mapCoordInSelfToDescendant(layout, mTempXY);
- xy[0] = mTempXY[0];
- xy[1] = mTempXY[1];
+ xy[0] = mTempXY[0];
+ xy[1] = mTempXY[1];
+ } else {
+ mapPointFromSelfToChild(layout, xy);
+ }
}
private boolean isDragWidget(DragObject d) {
@@ -2265,11 +2255,7 @@
// Handle the drag over
if (mDragTargetLayout != null) {
// We want the point to be mapped to the dragTarget.
- if (mLauncher.isHotseatLayout(mDragTargetLayout)) {
- mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
- } else {
- mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter);
- }
+ mapPointFromDropLayout(mDragTargetLayout, mDragViewVisualCenter);
int minSpanX = item.spanX;
int minSpanY = item.spanY;
@@ -2340,7 +2326,7 @@
// Test to see if we are over the hotseat first
if (mLauncher.getHotseat() != null && !isDragWidget(d)) {
if (isPointInSelfOverHotseat(d.x, d.y)) {
- layout = mLauncher.getHotseat().getLayout();
+ layout = mLauncher.getHotseat();
}
}
@@ -2543,10 +2529,10 @@
spanY = mDragInfo.spanY;
}
- final long container = mLauncher.isHotseatLayout(cellLayout) ?
+ final int container = mLauncher.isHotseatLayout(cellLayout) ?
LauncherSettings.Favorites.CONTAINER_HOTSEAT :
LauncherSettings.Favorites.CONTAINER_DESKTOP;
- final long screenId = getIdForScreen(cellLayout);
+ final int screenId = getIdForScreen(cellLayout);
if (!mLauncher.isHotseatLayout(cellLayout)
&& screenId != getScreenIdForPageIndex(mCurrentPage)
&& !mLauncher.isInState(SPRING_LOADED)) {
@@ -2632,16 +2618,10 @@
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
- if (info.container == NO_ID) {
+ if (info.container == NO_ID && info instanceof AppInfo) {
// Came from all apps -- make a copy
- if (info instanceof AppInfo) {
- info = ((AppInfo) info).makeShortcut();
- d.dragInfo = info;
- } else if (info instanceof ShortcutInfo) {
- info = new ShortcutInfo((ShortcutInfo) info);
- d.dragInfo = info;
- }
-
+ info = ((AppInfo) info).makeShortcut();
+ d.dragInfo = info;
}
view = mLauncher.createShortcut(cellLayout, (ShortcutInfo) info);
break;
@@ -2866,7 +2846,6 @@
*/
public void onDropCompleted(final View target, final DragObject d,
final boolean success) {
-
if (success) {
if (target != this && mDragInfo != null) {
removeWorkspaceItem(mDragInfo.cell);
@@ -2985,8 +2964,7 @@
* Returns a specific CellLayout
*/
CellLayout getParentCellLayoutForView(View v) {
- ArrayList<CellLayout> layouts = getWorkspaceAndHotseatCellLayouts();
- for (CellLayout layout : layouts) {
+ for (CellLayout layout : getWorkspaceAndHotseatCellLayouts()) {
if (layout.getShortcutsAndWidgets().indexOfChild(v) > -1) {
return layout;
}
@@ -2995,66 +2973,31 @@
}
/**
- * Returns a list of all the CellLayouts in the workspace.
+ * Returns a list of all the CellLayouts on the Homescreen.
*/
- ArrayList<CellLayout> getWorkspaceAndHotseatCellLayouts() {
- ArrayList<CellLayout> layouts = new ArrayList<>();
+ private CellLayout[] getWorkspaceAndHotseatCellLayouts() {
int screenCount = getChildCount();
- for (int screen = 0; screen < screenCount; screen++) {
- layouts.add(((CellLayout) getChildAt(screen)));
- }
+ final CellLayout[] layouts;
if (mLauncher.getHotseat() != null) {
- layouts.add(mLauncher.getHotseat().getLayout());
+ layouts = new CellLayout[screenCount + 1];
+ layouts[screenCount] = mLauncher.getHotseat();
+ } else {
+ layouts = new CellLayout[screenCount];
+ }
+ for (int screen = 0; screen < screenCount; screen++) {
+ layouts[screen] = (CellLayout) getChildAt(screen);
}
return layouts;
}
- /**
- * We should only use this to search for specific children. Do not use this method to modify
- * ShortcutsAndWidgetsContainer directly. Includes ShortcutAndWidgetContainers from
- * the hotseat and workspace pages
- */
- ArrayList<ShortcutAndWidgetContainer> getAllShortcutAndWidgetContainers() {
- ArrayList<ShortcutAndWidgetContainer> childrenLayouts = new ArrayList<>();
- int screenCount = getChildCount();
- for (int screen = 0; screen < screenCount; screen++) {
- childrenLayouts.add(((CellLayout) getChildAt(screen)).getShortcutsAndWidgets());
- }
- if (mLauncher.getHotseat() != null) {
- childrenLayouts.add(mLauncher.getHotseat().getLayout().getShortcutsAndWidgets());
- }
- return childrenLayouts;
- }
-
- public View getHomescreenIconByItemId(final long id) {
- return getFirstMatch(new ItemOperator() {
-
- @Override
- public boolean evaluate(ItemInfo info, View v) {
- return info != null && info.id == id;
- }
- });
- }
-
- public View getViewForTag(final Object tag) {
- return getFirstMatch(new ItemOperator() {
-
- @Override
- public boolean evaluate(ItemInfo info, View v) {
- return info == tag;
- }
- });
+ public View getHomescreenIconByItemId(final int id) {
+ return getFirstMatch((info, v) -> info != null && info.id == id);
}
public LauncherAppWidgetHostView getWidgetForAppWidgetId(final int appWidgetId) {
- return (LauncherAppWidgetHostView) getFirstMatch(new ItemOperator() {
-
- @Override
- public boolean evaluate(ItemInfo info, View v) {
- return (info instanceof LauncherAppWidgetInfo) &&
- ((LauncherAppWidgetInfo) info).appWidgetId == appWidgetId;
- }
- });
+ return (LauncherAppWidgetHostView) getFirstMatch((info, v) ->
+ (info instanceof LauncherAppWidgetInfo) &&
+ ((LauncherAppWidgetInfo) info).appWidgetId == appWidgetId);
}
public View getFirstMatch(final ItemOperator operator) {
@@ -3091,11 +3034,10 @@
* shortcuts are not removed.
*/
public void removeItemsByMatcher(final ItemInfoMatcher matcher) {
- ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();
- for (final CellLayout layoutParent: cellLayouts) {
+ for (final CellLayout layoutParent: getWorkspaceAndHotseatCellLayouts()) {
final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
- LongArrayMap<View> idToViewMap = new LongArrayMap<>();
+ IntSparseArrayMap<View> idToViewMap = new IntSparseArrayMap<>();
ArrayList<ItemInfo> items = new ArrayList<>();
for (int j = 0; j < layout.getChildCount(); j++) {
final View view = layout.getChildAt(j);
@@ -3149,11 +3091,9 @@
* @param recurse true: iterate over folder children. false: op get the folders themselves.
* @param op the operator to map over the shortcuts
*/
- void mapOverItems(boolean recurse, ItemOperator op) {
- ArrayList<ShortcutAndWidgetContainer> containers = getAllShortcutAndWidgetContainers();
- final int containerCount = containers.size();
- for (int containerIdx = 0; containerIdx < containerCount; containerIdx++) {
- ShortcutAndWidgetContainer container = containers.get(containerIdx);
+ public void mapOverItems(boolean recurse, ItemOperator op) {
+ for (CellLayout layout : getWorkspaceAndHotseatCellLayouts()) {
+ ShortcutAndWidgetContainer container = layout.getShortcutsAndWidgets();
// map over all the shortcuts on the workspace
final int itemCount = container.getChildCount();
for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
@@ -3183,7 +3123,7 @@
void updateShortcuts(ArrayList<ShortcutInfo> shortcuts) {
int total = shortcuts.size();
final HashSet<ShortcutInfo> updates = new HashSet<>(total);
- final HashSet<Long> folderIds = new HashSet<>();
+ final IntSet folderIds = new IntSet();
for (int i = 0; i < total; i++) {
ShortcutInfo s = shortcuts.get(i);
@@ -3223,7 +3163,7 @@
public void updateIconBadges(final Set<PackageUserKey> updatedBadges) {
final PackageUserKey packageUserKey = new PackageUserKey(null, null);
- final HashSet<Long> folderIds = new HashSet<>();
+ final IntSet folderIds = new IntSet();
mapOverItems(MAP_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v) {
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index e734e70..3e09493 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -88,7 +88,7 @@
Interpolator scaleInterpolator = builder.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
- propertySetter.setViewAlpha(mLauncher.getHotseat().getLayout(), hotseatIconsAlpha,
+ propertySetter.setViewAlpha(mLauncher.getHotseat(), hotseatIconsAlpha,
fadeInterpolator);
propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
hotseatIconsAlpha, fadeInterpolator);
@@ -105,9 +105,6 @@
propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y,
scaleAndTranslation[2], translationInterpolator);
- propertySetter.setViewAlpha(mLauncher.getHotseatSearchBox(),
- (elements & HOTSEAT_SEARCH_BOX) != 0 ? 1 : 0, fadeInterpolator);
-
// Set scrim
WorkspaceAndHotseatScrim scrim = mLauncher.getDragLayer().getScrim();
propertySetter.setFloat(scrim, SCRIM_PROGRESS, state.getWorkspaceScrimAlpha(mLauncher),
diff --git a/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
index bd3bb4d..117296d 100644
--- a/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
@@ -19,8 +19,6 @@
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.widget.ExploreByTouchHelper;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.accessibility.AccessibilityEvent;
@@ -31,6 +29,9 @@
import java.util.List;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.customview.widget.ExploreByTouchHelper;
+
/**
* Helper class to make drag-and-drop in a {@link CellLayout} accessible.
*/
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 81a0e1d..84edb3d 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -39,6 +39,7 @@
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.touch.ItemLongClickListener;
+import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
@@ -159,7 +160,7 @@
beginAccessibleDrag(host, item);
} else if (action == ADD_TO_WORKSPACE) {
final int[] coordinates = new int[2];
- final long screenId = findSpaceOnWorkspace(item, coordinates);
+ final int screenId = findSpaceOnWorkspace(item, coordinates);
mLauncher.getStateManager().goToState(NORMAL, true, new Runnable() {
@Override
@@ -191,7 +192,7 @@
folder.getInfo().remove(info, false);
final int[] coordinates = new int[2];
- final long screenId = findSpaceOnWorkspace(item, coordinates);
+ final int screenId = findSpaceOnWorkspace(item, coordinates);
mLauncher.getModelWriter().moveItemInDatabase(info,
LauncherSettings.Favorites.CONTAINER_DESKTOP,
screenId, coordinates[0], coordinates[1]);
@@ -210,7 +211,7 @@
});
} else if (action == RESIZE) {
final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) item;
- final ArrayList<Integer> actions = getSupportedResizeActions(host, info);
+ final IntArray actions = getSupportedResizeActions(host, info);
CharSequence[] labels = new CharSequence[actions.size()];
for (int i = 0; i < actions.size(); i++) {
labels[i] = mLauncher.getText(actions.get(i));
@@ -242,8 +243,8 @@
return false;
}
- private ArrayList<Integer> getSupportedResizeActions(View host, LauncherAppWidgetInfo info) {
- ArrayList<Integer> actions = new ArrayList<>();
+ private IntArray getSupportedResizeActions(View host, LauncherAppWidgetInfo info) {
+ IntArray actions = new IntArray();
AppWidgetProviderInfo providerInfo = ((LauncherAppWidgetHostView) host).getAppWidgetInfo();
if (providerInfo == null) {
@@ -392,10 +393,10 @@
/**
* Find empty space on the workspace and returns the screenId.
*/
- protected long findSpaceOnWorkspace(ItemInfo info, int[] outCoordinates) {
+ protected int findSpaceOnWorkspace(ItemInfo info, int[] outCoordinates) {
Workspace workspace = mLauncher.getWorkspace();
- ArrayList<Long> workspaceScreens = workspace.getScreenOrder();
- long screenId;
+ IntArray workspaceScreens = workspace.getScreenOrder();
+ int screenId;
// First check if there is space on the current screen.
int screenIndex = workspace.getCurrentPage();
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
index cfb0520..f37f70b 100644
--- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -66,7 +66,7 @@
}
final ShortcutInfo info = ((DeepShortcutView) host.getParent()).getFinalInfo();
final int[] coordinates = new int[2];
- final long screenId = findSpaceOnWorkspace(item, coordinates);
+ final int screenId = findSpaceOnWorkspace(item, coordinates);
Runnable onComplete = new Runnable() {
@Override
public void run() {
diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
index e6f120f..1c088db 100644
--- a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
+++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.graphics.Rect;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.text.TextUtils;
import android.view.View;
@@ -32,6 +31,8 @@
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.DragType;
import com.android.launcher3.dragndrop.DragLayer;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+
/**
* Implementation of {@link DragAndDropAccessibilityDelegate} to support DnD on workspace.
*/
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index fdf32af..3d15c75 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -21,13 +21,8 @@
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.Process;
-import android.support.animation.DynamicAnimation;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.StringRes;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.util.AttributeSet;
@@ -47,7 +42,9 @@
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
+import com.android.launcher3.TestProtocol;
import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -57,6 +54,13 @@
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.SpringRelativeLayout;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
/**
* The all apps view container.
*/
@@ -388,6 +392,26 @@
}
}
+ // Used by tests only
+ private boolean isDescendantViewVisible(int viewId) {
+ final View view = findViewById(viewId);
+ if (view == null) return false;
+
+ if (!view.isShown()) return false;
+
+ return view.getGlobalVisibleRect(new Rect());
+ }
+
+ // Used by tests only
+ public boolean isPersonalTabVisible() {
+ return isDescendantViewVisible(R.id.tab_personal);
+ }
+
+ // Used by tests only
+ public boolean isWorkTabVisible() {
+ return isDescendantViewVisible(R.id.tab_work);
+ }
+
public AlphabeticalAppsList getApps() {
return mAH[AdapterHolder.MAIN].appsList;
}
@@ -462,8 +486,13 @@
}
public void onScrollUpEnd() {
+ highlightWorkTabIfNecessary();
+ }
+
+ void highlightWorkTabIfNecessary() {
if (mUsingTabs) {
- ((PersonalWorkSlidingTabStrip) findViewById(R.id.tabs)).highlightWorkTabIfNecessary();
+ ((PersonalWorkSlidingTabStrip) findViewById(R.id.tabs))
+ .highlightWorkTabIfNecessary();
}
}
@@ -549,4 +578,17 @@
&& verticalFadingEdge);
}
}
+
+ @Override
+ public boolean performAccessibilityAction(int action, Bundle arguments) {
+ if (AccessibilityManagerCompat.processTestRequest(
+ mLauncher, TestProtocol.GET_SCROLL_MESSAGE, action, arguments,
+ response ->
+ response.putInt(TestProtocol.SCROLL_Y_FIELD,
+ getActiveRecyclerView().getCurrentScrollY()))) {
+ return true;
+ }
+
+ return super.performAccessibilityAction(action, arguments);
+ }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
index e08cb15..3ee1293 100644
--- a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
+++ b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
@@ -15,13 +15,13 @@
*/
package com.android.launcher3.allapps;
-import android.support.v7.widget.RecyclerView;
-
import com.android.launcher3.util.Thunk;
import java.util.HashSet;
import java.util.List;
+import androidx.recyclerview.widget.RecyclerView;
+
public class AllAppsFastScrollHelper implements AllAppsGridAdapter.BindViewCallback {
private static final int INITIAL_TOUCH_SETTLING_DURATION = 100;
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 27fc53a..69b4bdb 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -18,16 +18,10 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.view.accessibility.AccessibilityRecordCompat;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.RecyclerView;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnFocusChangeListener;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.TextView;
@@ -44,6 +38,12 @@
import java.util.List;
+import androidx.core.view.accessibility.AccessibilityEventCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.core.view.accessibility.AccessibilityRecordCompat;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
/**
* The grid view adapter of all the apps.
*/
@@ -251,7 +251,7 @@
R.layout.all_apps_icon, parent, false);
icon.setOnClickListener(ItemClickHandler.INSTANCE);
icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS);
- icon.setLongPressTimeout(ViewConfiguration.getLongPressTimeout());
+ icon.setLongPressTimeoutFactor(1f);
icon.setOnFocusChangeListener(mIconFocusListener);
// Ensure the all apps icon height matches the workspace icons in portrait mode.
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index a6c1346..180ca48 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -21,7 +21,6 @@
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
-import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.SparseIntArray;
import android.view.MotionEvent;
@@ -34,13 +33,15 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.graphics.DrawableFactory;
-import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
+import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.views.RecyclerViewFastScroller;
import java.util.List;
+import androidx.recyclerview.widget.RecyclerView;
+
/**
* A RecyclerView with custom fast scroll support for the all apps view.
*/
@@ -151,8 +152,7 @@
if (mApps.hasNoFilteredResults()) {
if (mEmptySearchBackground == null) {
- mEmptySearchBackground = DrawableFactory.get(getContext())
- .getAllAppsBackground(getContext());
+ mEmptySearchBackground = new AllAppsBackgroundDrawable(getContext());
mEmptySearchBackground.setAlpha(0);
mEmptySearchBackground.setCallback(this);
updateEmptySearchBackgroundBounds();
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 24a8d51..2d6be7b 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -91,11 +91,6 @@
return mShiftRange;
}
- private void onProgressAnimationStart() {
- // Initialize values that should not change until #onDragEnd
- mAppsView.setVisibility(View.VISIBLE);
- }
-
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
mIsVerticalLayout = dp.isVerticalBarLayout();
@@ -195,16 +190,15 @@
PropertySetter setter = config == null ? NO_ANIM_PROPERTY_SETTER
: config.getPropertySetter(builder);
int visibleElements = toState.getVisibleElements(mLauncher);
- boolean hasHeader = (visibleElements & ALL_APPS_HEADER) != 0;
boolean hasHeaderExtra = (visibleElements & ALL_APPS_HEADER_EXTRA) != 0;
boolean hasContent = (visibleElements & ALL_APPS_CONTENT) != 0;
Interpolator allAppsFade = builder.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
- setter.setViewAlpha(mAppsView.getSearchView(), hasHeader ? 1 : 0, allAppsFade);
setter.setViewAlpha(mAppsView.getContentView(), hasContent ? 1 : 0, allAppsFade);
setter.setViewAlpha(mAppsView.getScrollBar(), hasContent ? 1 : 0, allAppsFade);
mAppsView.getFloatingHeaderView().setContentVisibility(hasHeaderExtra, hasContent, setter,
allAppsFade);
+ mAppsView.getSearchUiManager().setContentVisibility(visibleElements, setter, allAppsFade);
setter.setInt(mScrimView, ScrimView.DRAG_HANDLE_ALPHA,
(visibleElements & VERTICAL_SWIPE_INDICATOR) != 0 ? 255 : 0, LINEAR);
@@ -216,11 +210,6 @@
public void onAnimationSuccess(Animator animator) {
onProgressAnimationEnd();
}
-
- @Override
- public void onAnimationStart(Animator animation) {
- onProgressAnimationStart();
- }
};
}
@@ -247,13 +236,19 @@
*/
private void onProgressAnimationEnd() {
if (Float.compare(mProgress, 1f) == 0) {
- mAppsView.setVisibility(View.INVISIBLE);
mAppsView.reset(false /* animate */);
- } else if (Float.compare(mProgress, 0f) == 0) {
- mAppsView.setVisibility(View.VISIBLE);
+ } else if (isAllAppsExpanded()) {
mAppsView.onScrollUpEnd();
- } else {
- mAppsView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private boolean isAllAppsExpanded() {
+ return Float.compare(mProgress, 0f) == 0;
+ }
+
+ public void highlightWorkTabIfNecessary() {
+ if (isAllAppsExpanded()) {
+ mAppsView.highlightWorkTabIfNecessary();
}
}
}
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index 3c3c406..76b2565 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -125,7 +125,8 @@
private static void showForHomeIfNeeded(Launcher launcher, boolean withDelay) {
if (!launcher.isInState(NORMAL)
- || launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)
+ || (launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)
+ && !shouldShowForWorkProfile(launcher))
|| AbstractFloatingView.getTopOpenView(launcher) != null
|| UserManagerCompat.getInstance(launcher).isDemoUser()
|| ActivityManager.isRunningInTestHarness()) {
@@ -149,7 +150,8 @@
|| !launcher.hasBeenResumed()
|| launcher.isForceInvisible()
|| launcher.getDeviceProfile().isVerticalBarLayout()
- || launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)
+ || (launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)
+ && !shouldShowForWorkProfile(launcher))
|| UserManagerCompat.getInstance(launcher).isDemoUser()
|| ActivityManager.isRunningInTestHarness()) {
return;
@@ -189,4 +191,10 @@
mController.setProgress(progress - mDelta);
}
}
+
+ private static boolean shouldShowForWorkProfile(Launcher launcher) {
+ return !launcher.getSharedPrefs().getBoolean(
+ PersonalWorkSlidingTabStrip.KEY_SHOWED_PEEK_WORK_TAB, false)
+ && UserManagerCompat.getInstance(launcher).hasWorkProfile();
+ }
}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderRow.java b/src/com/android/launcher3/allapps/FloatingHeaderRow.java
new file mode 100644
index 0000000..922e4f1
--- /dev/null
+++ b/src/com/android/launcher3/allapps/FloatingHeaderRow.java
@@ -0,0 +1,58 @@
+/*
+ * 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.allapps;
+
+import android.graphics.Rect;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.anim.PropertySetter;
+
+/**
+ * A abstract representation of a row in all-apps view
+ */
+public interface FloatingHeaderRow {
+
+ FloatingHeaderRow[] NO_ROWS = new FloatingHeaderRow[0];
+
+ void setup(FloatingHeaderView parent, FloatingHeaderRow[] allRows, boolean tabsHidden);
+
+ void setInsets(Rect insets, DeviceProfile grid);
+
+ int getExpectedHeight();
+
+ /**
+ * Returns true if the row should draw based on its current position and layout.
+ */
+ boolean shouldDraw();
+
+ /**
+ * Returns true if the view has anything worth drawing. This is different than
+ * {@link #shouldDraw()} as this is called earlier in the layout to determine the view
+ * position.
+ */
+ boolean hasVisibleContent();
+
+ void setContentVisibility(boolean hasHeaderExtra, boolean hasContent,
+ PropertySetter setter, Interpolator fadeInterpolator);
+
+ /**
+ * Scrolls the content vertically.
+ */
+ void setVerticalScroll(int scroll, boolean isScrolledOut);
+
+ Class<? extends FloatingHeaderRow> getTypeClass();
+}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index eaa7774..66dced9 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -19,9 +19,7 @@
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -29,11 +27,26 @@
import android.view.animation.Interpolator;
import android.widget.LinearLayout;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Insettable;
+import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
+import com.android.systemui.plugins.AllAppsRow;
+import com.android.systemui.plugins.AllAppsRow.OnHeightUpdatedListener;
+import com.android.systemui.plugins.PluginListener;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
public class FloatingHeaderView extends LinearLayout implements
- ValueAnimator.AnimatorUpdateListener {
+ ValueAnimator.AnimatorUpdateListener, PluginListener<AllAppsRow>, Insettable,
+ OnHeightUpdatedListener {
private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
@@ -55,10 +68,14 @@
int current = -mCurrentRV.getCurrentScrollY();
moved(current);
- apply();
+ applyVerticalMove();
}
};
+ private final int mHeaderTopPadding;
+
+ protected final Map<AllAppsRow, PluginHeaderRow> mPluginRows = new ArrayMap<>();
+
protected ViewGroup mTabLayout;
private AllAppsRecyclerView mMainRV;
private AllAppsRecyclerView mWorkRV;
@@ -75,21 +92,112 @@
protected int mMaxTranslation;
private boolean mMainRVActive = true;
+ private boolean mCollapsed = false;
+
+ // This is initialized once during inflation and stays constant after that. Fixed views
+ // cannot be added or removed dynamically.
+ private FloatingHeaderRow[] mFixedRows = FloatingHeaderRow.NO_ROWS;
+
+ // Array of all fixed rows and plugin rows. This is initialized every time a plugin is
+ // enabled or disabled, and represent the current set of all rows.
+ private FloatingHeaderRow[] mAllRows = FloatingHeaderRow.NO_ROWS;
+
public FloatingHeaderView(@NonNull Context context) {
this(context, null);
}
public FloatingHeaderView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
+ mHeaderTopPadding = context.getResources()
+ .getDimensionPixelSize(R.dimen.all_apps_header_top_padding);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mTabLayout = findViewById(R.id.tabs);
+
+ // Find all floating header rows.
+ ArrayList<FloatingHeaderRow> rows = new ArrayList<>();
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ if (child instanceof FloatingHeaderRow) {
+ rows.add((FloatingHeaderRow) child);
+ }
+ }
+ mFixedRows = rows.toArray(new FloatingHeaderRow[rows.size()]);
+ mAllRows = mFixedRows;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ PluginManagerWrapper.INSTANCE.get(getContext()).addPluginListener(this,
+ AllAppsRow.class, true /* allowMultiple */);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener(this);
+ }
+
+ private void recreateAllRowsArray() {
+ int pluginCount = mPluginRows.size();
+ if (pluginCount == 0) {
+ mAllRows = mFixedRows;
+ } else {
+ int count = mFixedRows.length;
+ mAllRows = new FloatingHeaderRow[count + pluginCount];
+ for (int i = 0; i < count; i++) {
+ mAllRows[i] = mFixedRows[i];
+ }
+
+ for (PluginHeaderRow row : mPluginRows.values()) {
+ mAllRows[count] = row;
+ count++;
+ }
+ }
+ }
+
+ @Override
+ public void onPluginConnected(AllAppsRow allAppsRowPlugin, Context context) {
+ PluginHeaderRow headerRow = new PluginHeaderRow(allAppsRowPlugin, this);
+ addView(headerRow.mView, indexOfChild(mTabLayout));
+ mPluginRows.put(allAppsRowPlugin, headerRow);
+ recreateAllRowsArray();
+ allAppsRowPlugin.setOnHeightUpdatedListener(this);
+ }
+
+ @Override
+ public void onHeightUpdated() {
+ int oldMaxHeight = mMaxTranslation;
+ updateExpectedHeight();
+
+ if (mMaxTranslation != oldMaxHeight) {
+ AllAppsContainerView parent = (AllAppsContainerView) getParent();
+ if (parent != null) {
+ parent.setupHeader();
+ }
+ }
+ }
+
+ @Override
+ public void onPluginDisconnected(AllAppsRow plugin) {
+ PluginHeaderRow row = mPluginRows.get(plugin);
+ removeView(row.mView);
+ mPluginRows.remove(plugin);
+ recreateAllRowsArray();
+ onHeightUpdated();
}
public void setup(AllAppsContainerView.AdapterHolder[] mAH, boolean tabsHidden) {
+ for (FloatingHeaderRow row : mAllRows) {
+ row.setup(this, mAllRows, tabsHidden);
+ }
+ updateExpectedHeight();
+
mTabsHidden = tabsHidden;
mTabLayout.setVisibility(tabsHidden ? View.GONE : View.VISIBLE);
mMainRV = setupRV(mMainRV, mAH[AllAppsContainerView.AdapterHolder.MAIN].recyclerView);
@@ -106,6 +214,16 @@
return updated;
}
+ private void updateExpectedHeight() {
+ mMaxTranslation = 0;
+ if (mCollapsed) {
+ return;
+ }
+ for (FloatingHeaderRow row : mAllRows) {
+ mMaxTranslation += row.getExpectedHeight();
+ }
+ }
+
public void setMainActive(boolean active) {
mCurrentRV = active ? mMainRV : mWorkRV;
mMainRVActive = active;
@@ -149,12 +267,21 @@
}
}
- protected void applyScroll(int uncappedY, int currentY) { }
-
- protected void apply() {
+ protected void applyVerticalMove() {
int uncappedTranslationY = mTranslationY;
mTranslationY = Math.max(mTranslationY, -mMaxTranslation);
- applyScroll(uncappedTranslationY, mTranslationY);
+
+ if (mCollapsed || uncappedTranslationY < mTranslationY - mHeaderTopPadding) {
+ // we hide it completely if already capped (for opening search anim)
+ for (FloatingHeaderRow row : mAllRows) {
+ row.setVerticalScroll(0, true /* isScrolledOut */);
+ }
+ } else {
+ for (FloatingHeaderRow row : mAllRows) {
+ row.setVerticalScroll(uncappedTranslationY, false /* isScrolledOut */);
+ }
+ }
+
mTabLayout.setTranslationY(mTranslationY);
mClip.top = mMaxTranslation + mTranslationY;
// clipping on a draw might cause additional redraw
@@ -164,6 +291,16 @@
}
}
+ /**
+ * Hides all the floating rows
+ */
+ public void setCollapsed(boolean collapse) {
+ if (mCollapsed == collapse) return;
+
+ mCollapsed = collapse;
+ onHeightUpdated();
+ }
+
public void reset(boolean animate) {
if (mAnimator.isStarted()) {
mAnimator.cancel();
@@ -175,7 +312,7 @@
mAnimator.start();
} else {
mTranslationY = 0;
- apply();
+ applyVerticalMove();
}
mHeaderCollapsed = false;
mSnappedScrolledY = -mMaxTranslation;
@@ -189,7 +326,7 @@
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mTranslationY = (Integer) animation.getAnimatedValue();
- apply();
+ applyVerticalMove();
}
@Override
@@ -228,8 +365,12 @@
public void setContentVisibility(boolean hasHeader, boolean hasContent, PropertySetter setter,
Interpolator fadeInterpolator) {
- setter.setViewAlpha(this, hasContent ? 1 : 0, fadeInterpolator);
+ for (FloatingHeaderRow row : mAllRows) {
+ row.setContentVisibility(hasHeader, hasContent, setter, fadeInterpolator);
+ }
+
allowTouchForwarding(hasContent);
+ setter.setFloat(mTabLayout, ALPHA, hasContent ? 1 : 0, fadeInterpolator);
}
protected void allowTouchForwarding(boolean allow) {
@@ -237,6 +378,11 @@
}
public boolean hasVisibleContent() {
+ for (FloatingHeaderRow row : mAllRows) {
+ if (row.hasVisibleContent()) {
+ return true;
+ }
+ }
return false;
}
@@ -244,6 +390,23 @@
public boolean hasOverlappingRendering() {
return false;
}
+
+ @Override
+ public void setInsets(Rect insets) {
+ DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
+ for (FloatingHeaderRow row : mAllRows) {
+ row.setInsets(insets, grid);
+ }
+ }
+
+ public <T extends FloatingHeaderRow> T findFixedRowByType(Class<T> type) {
+ for (FloatingHeaderRow row : mAllRows) {
+ if (row.getTypeClass() == type) {
+ return (T) row;
+ }
+ }
+ return null;
+ }
}
diff --git a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
index a916697..decdcc0 100644
--- a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
@@ -19,8 +19,6 @@
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
@@ -32,6 +30,9 @@
import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.util.Themes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
/**
* Supports two indicator colors, dedicated for personal and work tabs.
*/
@@ -39,7 +40,7 @@
private static final int POSITION_PERSONAL = 0;
private static final int POSITION_WORK = 1;
- private static final String KEY_SHOWED_PEEK_WORK_TAB = "showed_peek_work_tab";
+ public static final String KEY_SHOWED_PEEK_WORK_TAB = "showed_peek_work_tab";
private final Paint mSelectedIndicatorPaint;
private final Paint mDividerPaint;
diff --git a/src/com/android/launcher3/allapps/PluginHeaderRow.java b/src/com/android/launcher3/allapps/PluginHeaderRow.java
new file mode 100644
index 0000000..b283ff4
--- /dev/null
+++ b/src/com/android/launcher3/allapps/PluginHeaderRow.java
@@ -0,0 +1,85 @@
+/*
+ * 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.allapps;
+
+import static android.view.View.ALPHA;
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+import android.graphics.Rect;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.anim.PropertySetter;
+import com.android.systemui.plugins.AllAppsRow;
+
+/**
+ * Wrapper over an {@link AllAppsRow} plugin with {@link FloatingHeaderRow} interface so that
+ * it can be easily added in {@link FloatingHeaderView}.
+ */
+public class PluginHeaderRow implements FloatingHeaderRow {
+
+ private final AllAppsRow mPlugin;
+ final View mView;
+
+ PluginHeaderRow(AllAppsRow plugin, FloatingHeaderView parent) {
+ mPlugin = plugin;
+ mView = mPlugin.setup(parent);
+ }
+
+ @Override
+ public void setup(FloatingHeaderView parent, FloatingHeaderRow[] allRows,
+ boolean tabsHidden) { }
+
+ @Override
+ public void setInsets(Rect insets, DeviceProfile grid) { }
+
+ @Override
+ public int getExpectedHeight() {
+ return mPlugin.getExpectedHeight();
+ }
+
+ @Override
+ public boolean shouldDraw() {
+ return true;
+ }
+
+ @Override
+ public boolean hasVisibleContent() {
+ return true;
+ }
+
+ @Override
+ public void setContentVisibility(boolean hasHeaderExtra, boolean hasContent,
+ PropertySetter setter, Interpolator fadeInterpolator) {
+ // Don't use setViewAlpha as we want to control the visibility ourselves.
+ setter.setFloat(mView, ALPHA, hasContent ? 1 : 0, fadeInterpolator);
+ }
+
+ @Override
+ public void setVerticalScroll(int scroll, boolean isScrolledOut) {
+ mView.setVisibility(isScrolledOut ? INVISIBLE : VISIBLE);
+ if (!isScrolledOut) {
+ mView.setTranslationY(scroll);
+ }
+ }
+
+ @Override
+ public Class<PluginHeaderRow> getTypeClass() {
+ return PluginHeaderRow.class;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java
index 68193f5..51b90f7 100644
--- a/src/com/android/launcher3/allapps/SearchUiManager.java
+++ b/src/com/android/launcher3/allapps/SearchUiManager.java
@@ -16,6 +16,9 @@
package com.android.launcher3.allapps;
import android.view.KeyEvent;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.anim.PropertySetter;
/**
* Interface for controlling the Apps search UI.
@@ -37,4 +40,10 @@
* some UI beforehand.
*/
void preDispatchKeyEvent(KeyEvent keyEvent);
+
+ /**
+ * Called as part of state transition to update the content UI
+ */
+ void setContentVisibility(int visibleElements, PropertySetter setter,
+ Interpolator interpolator);
}
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index e7cf092..717bbd4 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -20,10 +20,12 @@
import android.os.Process;
import android.os.UserHandle;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.widget.Switch;
import com.android.launcher3.compat.UserManagerCompat;
+import java.lang.ref.WeakReference;
import java.util.List;
public class WorkModeSwitch extends Switch {
@@ -60,35 +62,63 @@
setEnabled(true);
}
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ return ev.getActionMasked() == MotionEvent.ACTION_MOVE || super.onTouchEvent(ev);
+ }
+
private void trySetQuietModeEnabledToAllProfilesAsync(boolean enabled) {
- new AsyncTask<Void, Void, Boolean>() {
+ new SetQuietModeEnabledAsyncTask(enabled, new WeakReference<>(this)).execute();
+ }
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- setEnabled(false);
+ private static final class SetQuietModeEnabledAsyncTask
+ extends AsyncTask<Void, Void, Boolean> {
+
+ private final boolean enabled;
+ private final WeakReference<WorkModeSwitch> switchWeakReference;
+
+ SetQuietModeEnabledAsyncTask(boolean enabled,
+ WeakReference<WorkModeSwitch> switchWeakReference) {
+ this.enabled = enabled;
+ this.switchWeakReference = switchWeakReference;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ WorkModeSwitch workModeSwitch = switchWeakReference.get();
+ if (workModeSwitch != null) {
+ workModeSwitch.setEnabled(false);
}
+ }
- @Override
- protected Boolean doInBackground(Void... voids) {
- UserManagerCompat userManager = UserManagerCompat.getInstance(getContext());
- List<UserHandle> userProfiles = userManager.getUserProfiles();
- boolean showConfirm = false;
- for (UserHandle userProfile : userProfiles) {
- if (Process.myUserHandle().equals(userProfile)) {
- continue;
- }
- showConfirm |= !userManager.requestQuietModeEnabled(enabled, userProfile);
+ @Override
+ protected Boolean doInBackground(Void... voids) {
+ WorkModeSwitch workModeSwitch = switchWeakReference.get();
+ if (workModeSwitch == null) {
+ return false;
+ }
+ UserManagerCompat userManager =
+ UserManagerCompat.getInstance(workModeSwitch.getContext());
+ List<UserHandle> userProfiles = userManager.getUserProfiles();
+ boolean showConfirm = false;
+ for (UserHandle userProfile : userProfiles) {
+ if (Process.myUserHandle().equals(userProfile)) {
+ continue;
}
- return showConfirm;
+ showConfirm |= !userManager.requestQuietModeEnabled(enabled, userProfile);
}
+ return showConfirm;
+ }
- @Override
- protected void onPostExecute(Boolean showConfirm) {
- if (showConfirm) {
- setEnabled(true);
+ @Override
+ protected void onPostExecute(Boolean showConfirm) {
+ if (showConfirm) {
+ WorkModeSwitch workModeSwitch = switchWeakReference.get();
+ if (workModeSwitch != null) {
+ workModeSwitch.setEnabled(true);
}
}
- }.execute();
+ }
}
}
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index dcc4554..91be504 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3.allapps.search;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index ab6635e..b1e23d4 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -19,7 +19,8 @@
import static android.view.View.MeasureSpec.getSize;
import static android.view.View.MeasureSpec.makeMeasureSpec;
-import static com.android.launcher3.graphics.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
+import static com.android.launcher3.LauncherState.ALL_APPS_HEADER;
+import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
import android.content.Context;
import android.graphics.Rect;
@@ -32,6 +33,7 @@
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
+import android.view.animation.Interpolator;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ExtendedEditText;
@@ -42,6 +44,7 @@
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.allapps.AlphabeticalAppsList;
import com.android.launcher3.allapps.SearchUiManager;
+import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.graphics.TintedDrawableSpan;
import com.android.launcher3.util.ComponentKey;
@@ -214,4 +217,10 @@
insets.bottom + mlp.topMargin + mFixedTranslationY);
}
}
+
+ @Override
+ public void setContentVisibility(int visibleElements, PropertySetter setter,
+ Interpolator interpolator) {
+ setter.setViewAlpha(this, (visibleElements & ALL_APPS_HEADER) != 0 ? 1 : 0, interpolator);
+ }
}
diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
index 307f258..fdac5c8 100644
--- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java
+++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
@@ -20,8 +20,6 @@
import android.util.SparseArray;
import android.view.animation.Interpolator;
-import com.android.launcher3.LauncherAnimUtils;
-
import java.util.ArrayList;
import java.util.List;
@@ -56,7 +54,7 @@
}
public AnimatorSet build() {
- AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
+ AnimatorSet anim = new AnimatorSet();
anim.playTogether(mAnims);
if (!mOnFinishRunnables.isEmpty()) {
anim.addListener(new AnimationSuccessListener() {
diff --git a/src/com/android/launcher3/anim/PropertyListBuilder.java b/src/com/android/launcher3/anim/PropertyListBuilder.java
index 33e7f66..acc3b45 100644
--- a/src/com/android/launcher3/anim/PropertyListBuilder.java
+++ b/src/com/android/launcher3/anim/PropertyListBuilder.java
@@ -1,5 +1,6 @@
package com.android.launcher3.anim;
+import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.view.View;
@@ -44,7 +45,8 @@
return this;
}
- public PropertyValuesHolder[] build() {
- return mProperties.toArray(new PropertyValuesHolder[mProperties.size()]);
+ public ObjectAnimator build(View view) {
+ return ObjectAnimator.ofPropertyValuesHolder(view,
+ mProperties.toArray(new PropertyValuesHolder[mProperties.size()]));
}
}
diff --git a/src/com/android/launcher3/badge/BadgeRenderer.java b/src/com/android/launcher3/badge/BadgeRenderer.java
index 9487427..5d38aad 100644
--- a/src/com/android/launcher3/badge/BadgeRenderer.java
+++ b/src/com/android/launcher3/badge/BadgeRenderer.java
@@ -27,7 +27,7 @@
import android.graphics.Rect;
import android.util.Log;
-import com.android.launcher3.graphics.ShadowGenerator;
+import com.android.launcher3.icons.ShadowGenerator;
/**
* Contains parameters necessary to draw a badge for an icon (e.g. the size of the badge).
@@ -60,6 +60,7 @@
int size = (int) (DOT_SCALE * mDotCenterOffset);
ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.TRANSPARENT);
+ builder.ambientShadowAlpha = 88;
mBackgroundWithShadow = builder.setupBlurForSize(size).createPill(size, size);
mCircleRadius = builder.radius;
diff --git a/src/com/android/launcher3/badge/FolderBadgeInfo.java b/src/com/android/launcher3/badge/FolderBadgeInfo.java
index 3a1bf60..fa5e8a4 100644
--- a/src/com/android/launcher3/badge/FolderBadgeInfo.java
+++ b/src/com/android/launcher3/badge/FolderBadgeInfo.java
@@ -16,6 +16,8 @@
package com.android.launcher3.badge;
+import android.view.ViewDebug;
+
import com.android.launcher3.Utilities;
/**
@@ -56,6 +58,7 @@
return 0;
}
+ @ViewDebug.ExportedProperty(category = "launcher")
public boolean hasBadge() {
return mNumNotifications > 0;
}
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index 0c78381..02da861 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -17,9 +17,14 @@
package com.android.launcher3.compat;
import android.content.Context;
+import android.os.Bundle;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import com.android.launcher3.TestProtocol;
+import com.android.launcher3.Utilities;
public class AccessibilityManagerCompat {
@@ -44,4 +49,56 @@
private static AccessibilityManager getManager(Context context) {
return (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
}
+
+ public static void sendEventToTest(Context context, String eventTag) {
+ final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
+ if (accessibilityManager == null) return;
+
+ sendEventToTest(accessibilityManager, eventTag, null);
+ }
+
+ private static void sendEventToTest(
+ AccessibilityManager accessibilityManager, String eventTag, Bundle data) {
+ final AccessibilityEvent e = AccessibilityEvent.obtain(
+ AccessibilityEvent.TYPE_ANNOUNCEMENT);
+ e.setClassName(eventTag);
+ e.setParcelableData(data);
+ accessibilityManager.sendAccessibilityEvent(e);
+ }
+
+ /**
+ * Returns accessibility manager to be used for communication with UI Automation tests.
+ * The tests may exchange custom accessibility messages with the launcher; the accessibility
+ * manager is used in these communications.
+ *
+ * If the launcher runs not under a test, the return is null, and no attempt to process or send
+ * custom accessibility messages should be made.
+ */
+ private static AccessibilityManager getAccessibilityManagerForTest(Context context) {
+ // If not running in a test harness, don't participate in test exchanges.
+ if (!Utilities.IS_RUNNING_IN_TEST_HARNESS) return null;
+
+ final AccessibilityManager accessibilityManager = getManager(context);
+ if (!accessibilityManager.isEnabled()) return null;
+
+ return accessibilityManager;
+ }
+
+ public static boolean processTestRequest(Context context, String eventTag, int action,
+ Bundle request, Utilities.Consumer<Bundle> responseFiller) {
+ final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
+ if (accessibilityManager == null) return false;
+
+ // The test sends a request via a ACTION_SET_TEXT.
+ if (action == AccessibilityNodeInfo.ACTION_SET_TEXT &&
+ eventTag.equals(request.getCharSequence(
+ AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE))) {
+ final Bundle response = new Bundle();
+ responseFiller.accept(response);
+ AccessibilityManagerCompat.sendEventToTest(
+ accessibilityManager, eventTag + TestProtocol.RESPONSE_MESSAGE_POSTFIX, response);
+ return true;
+ }
+ return false;
+ }
}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
index fd1f0cc..3243256 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -22,7 +22,6 @@
import android.content.Context;
import android.os.Bundle;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
@@ -35,6 +34,8 @@
import java.util.HashMap;
import java.util.List;
+import androidx.annotation.Nullable;
+
public abstract class AppWidgetManagerCompat {
private static final Object sInstanceLock = new Object();
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
index 8430285..1065748 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -23,7 +23,6 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
-import android.support.annotation.Nullable;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
@@ -38,6 +37,8 @@
import java.util.Iterator;
import java.util.List;
+import androidx.annotation.Nullable;
+
class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
private final UserManager mUserManager;
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
index 44158ed..b7b0563 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
@@ -18,7 +18,6 @@
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
-import android.support.annotation.Nullable;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PackageUserKey;
@@ -26,6 +25,8 @@
import java.util.Collections;
import java.util.List;
+import androidx.annotation.Nullable;
+
class AppWidgetManagerCompatVO extends AppWidgetManagerCompatVL {
AppWidgetManagerCompatVO(Context context) {
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java
index 2cac536..407355c 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompat.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -24,12 +24,15 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
+
import com.android.launcher3.Utilities;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.util.PackageUserKey;
+
import java.util.List;
+import androidx.annotation.Nullable;
+
public abstract class LauncherAppsCompat {
public interface OnAppsChangedCallbackCompat {
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
index cc3e5a7..b641391 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
@@ -29,15 +29,18 @@
import android.os.Bundle;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.util.ArrayMap;
+
import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVL;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.util.PackageUserKey;
+
import java.util.ArrayList;
import java.util.List;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
public class LauncherAppsCompatVL extends LauncherAppsCompat {
protected final LauncherApps mLauncherApps;
@@ -197,7 +200,7 @@
pm.queryIntentActivities(new Intent(Intent.ACTION_CREATE_SHORTCUT), 0)) {
if (packageUser == null || packageUser.mPackageName
.equals(info.activityInfo.packageName)) {
- result.add(new ShortcutConfigActivityInfoVL(info.activityInfo, pm));
+ result.add(new ShortcutConfigActivityInfoVL(info.activityInfo));
}
}
return result;
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
index 173d0d1..82617fe 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
@@ -28,13 +28,12 @@
import android.os.Parcelable;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVO;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.PackageUserKey;
@@ -42,6 +41,8 @@
import java.util.ArrayList;
import java.util.List;
+import androidx.annotation.Nullable;
+
@TargetApi(26)
public class LauncherAppsCompatVO extends LauncherAppsCompatVL {
@@ -138,7 +139,7 @@
ShortcutInfo info = new ShortcutInfo(compat, context);
// Apply the unbadged icon and fetch the actual icon asynchronously.
LauncherIcons li = LauncherIcons.obtain(context);
- li.createShortcutIcon(compat, false /* badged */).applyTo(info);
+ info.applyFrom(li.createShortcutIcon(compat, false /* badged */));
li.recycle();
LauncherAppState.getInstance(context).getModel()
.updateAndBindShortcutInfo(info, compat);
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java
index 3270ba2..7dad7e9 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompat.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java
@@ -19,11 +19,12 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageInstaller;
-import android.support.annotation.NonNull;
import java.util.HashMap;
import java.util.List;
+import androidx.annotation.NonNull;
+
public abstract class PackageInstallerCompat {
public static final int STATUS_INSTALLED = 0;
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
index dd17916..fe7b4e5 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
@@ -27,7 +27,7 @@
import android.text.TextUtils;
import android.util.SparseArray;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.config.FeatureFlags;
diff --git a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
index 31c0087..76eec6d 100644
--- a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
+++ b/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
@@ -32,7 +32,8 @@
import android.util.Log;
import android.widget.Toast;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.icons.ComponentWithLabel;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
@@ -40,7 +41,7 @@
/**
* Wrapper class for representing a shortcut configure activity.
*/
-public abstract class ShortcutConfigActivityInfo {
+public abstract class ShortcutConfigActivityInfo implements ComponentWithLabel {
private static final String TAG = "SCActivityInfo";
@@ -52,10 +53,12 @@
mUser = user;
}
+ @Override
public ComponentName getComponent() {
return mCn;
}
+ @Override
public UserHandle getUser() {
return mUser;
}
@@ -64,8 +67,6 @@
return LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
}
- public abstract CharSequence getLabel();
-
public abstract Drawable getFullResIcon(IconCache cache);
/**
@@ -94,8 +95,8 @@
}
/**
- * Returns true if various properties ({@link #getLabel()}, {@link #getFullResIcon}) can
- * be safely persisted.
+ * Returns true if various properties ({@link #getLabel(PackageManager)},
+ * {@link #getFullResIcon}) can be safely persisted.
*/
public boolean isPersistable() {
return true;
@@ -104,18 +105,15 @@
static class ShortcutConfigActivityInfoVL extends ShortcutConfigActivityInfo {
private final ActivityInfo mInfo;
- private final PackageManager mPm;
-
- public ShortcutConfigActivityInfoVL(ActivityInfo info, PackageManager pm) {
+ public ShortcutConfigActivityInfoVL(ActivityInfo info) {
super(new ComponentName(info.packageName, info.name), Process.myUserHandle());
mInfo = info;
- mPm = pm;
}
@Override
- public CharSequence getLabel() {
- return mInfo.loadLabel(mPm);
+ public CharSequence getLabel(PackageManager pm) {
+ return mInfo.loadLabel(pm);
}
@Override
@@ -135,7 +133,7 @@
}
@Override
- public CharSequence getLabel() {
+ public CharSequence getLabel(PackageManager pm) {
return mInfo.getLabel();
}
diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java
index 03e3861..e13d2a6 100644
--- a/src/com/android/launcher3/compat/UserManagerCompat.java
+++ b/src/com/android/launcher3/compat/UserManagerCompat.java
@@ -57,11 +57,12 @@
public abstract List<UserHandle> getUserProfiles();
public abstract long getSerialNumberForUser(UserHandle user);
public abstract UserHandle getUserForSerialNumber(long serialNumber);
- public abstract CharSequence getBadgedLabelForUser(CharSequence label, UserHandle user);
public abstract boolean isQuietModeEnabled(UserHandle user);
public abstract boolean isUserUnlocked(UserHandle user);
public abstract boolean isDemoUser();
public abstract boolean requestQuietModeEnabled(boolean enableQuietMode, UserHandle user);
public abstract boolean isAnyProfileQuietModeEnabled();
+
+ public abstract boolean hasWorkProfile();
}
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java
index 1ff6981..4688052 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java
@@ -17,32 +17,26 @@
package com.android.launcher3.compat;
import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
-import com.android.launcher3.util.LongArrayMap;
+import android.util.LongSparseArray;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class UserManagerCompatVL extends UserManagerCompat {
- private static final String USER_CREATION_TIME_KEY = "user_creation_time_";
protected final UserManager mUserManager;
- private final PackageManager mPm;
- private final Context mContext;
- protected LongArrayMap<UserHandle> mUsers;
- // Create a separate reverse map as LongArrayMap.indexOfValue checks if objects are same
+ protected LongSparseArray<UserHandle> mUsers;
+ // Create a separate reverse map as LongSparseArray.indexOfValue checks if objects are same
// and not {@link Object#equals}
protected ArrayMap<UserHandle, Long> mUserToSerialMap;
UserManagerCompatVL(Context context) {
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- mPm = context.getPackageManager();
- mContext = context;
}
@Override
@@ -94,7 +88,7 @@
@Override
public void enableAndResetCache() {
synchronized (this) {
- mUsers = new LongArrayMap<>();
+ mUsers = new LongSparseArray<>();
mUserToSerialMap = new ArrayMap<>();
List<UserHandle> users = mUserManager.getUserProfiles();
if (users != null) {
@@ -120,11 +114,13 @@
}
@Override
- public CharSequence getBadgedLabelForUser(CharSequence label, UserHandle user) {
- if (user == null) {
- return label;
+ public boolean hasWorkProfile() {
+ synchronized (this) {
+ if (mUsers != null) {
+ return mUsers.size() > 1;
+ }
}
- return mPm.getUserBadgedLabel(label, user);
+ return getUserProfiles().size() > 1;
}
}
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index f4c6380..1ec7eec 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -16,32 +16,62 @@
package com.android.launcher3.config;
+import static androidx.core.util.Preconditions.checkNotNull;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.provider.Settings;
+import androidx.annotation.GuardedBy;
+import androidx.annotation.Keep;
+import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.Utilities;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
/**
* Defines a set of flags used to control various launcher behaviors.
*
- * All the flags should be defined here with appropriate default values. To override a value,
- * redefine it in {@link FeatureFlags}.
+ * <p>All the flags should be defined here with appropriate default values.
*
- * This class is kept package-private to prevent direct access.
+ * <p>This class is kept package-private to prevent direct access.
*/
+@Keep
abstract class BaseFlags {
- BaseFlags() {}
+ private static final Object sLock = new Object();
+ @GuardedBy("sLock")
+ private static final List<TogglableFlag> sFlags = new ArrayList<>();
+
+ static final String FLAGS_PREF_NAME = "featureFlags";
+
+ BaseFlags() {
+ throw new UnsupportedOperationException("Don't instantiate BaseFlags");
+ }
+
+ public static boolean showFlagTogglerUi(Context context) {
+ return Utilities.IS_DEBUG_DEVICE &&
+ Settings.Global.getInt(context.getApplicationContext().getContentResolver(),
+ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
+ }
public static final boolean IS_DOGFOOD_BUILD = false;
public static final String AUTHORITY = "com.android.launcher3.settings".intern();
- // When enabled allows to use any point on the fast scrollbar to start dragging.
- public static final boolean LAUNCHER3_DIRECT_SCROLL = true;
// When enabled the promise icon is visible in all apps while installation an app.
public static final boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = false;
- // When enabled allows use of spring motions on the icons.
- public static final boolean LAUNCHER3_SPRING_ICONS = true;
- // Feature flag to enable moving the QSB on the 0th screen of the workspace.
- public static final boolean QSB_ON_FIRST_SCREEN = true;
- // When enabled the all-apps icon is not added to the hotseat.
- public static final boolean NO_ALL_APPS_ICON = true;
+ public static final TogglableFlag QSB_ON_FIRST_SCREEN = new TogglableFlag("QSB_ON_FIRST_SCREEN",
+ true,
+ "Enable moving the QSB on the 0th screen of the workspace");
+
+ public static final TogglableFlag EXAMPLE_FLAG = new TogglableFlag("EXAMPLE_FLAG", true,
+ "An example flag that doesn't do anything. Useful for testing");
+
+ //Feature flag to enable pulling down navigation shade from workspace.
+ public static final boolean PULL_DOWN_STATUS_BAR = true;
// When true, custom widgets are loaded using CustomWidgetParser.
public static final boolean ENABLE_CUSTOM_WIDGETS = false;
@@ -55,4 +85,175 @@
// When true, overview shows screenshots in the orientation they were taken rather than
// trying to make them fit the orientation the device is in.
public static final boolean OVERVIEW_USE_SCREENSHOT_ORIENTATION = true;
+
+ public static final ToggleableGlobalSettingsFlag QUICK_SWITCH
+ = new ToggleableGlobalSettingsFlag("navbar_quick_switch_enabled", false,
+ "Swiping right on the nav bar while in an app switches to the previous app");
+
+ /**
+ * Feature flag to handle define config changes dynamically instead of killing the process.
+ */
+ public static final TogglableFlag APPLY_CONFIG_AT_RUNTIME = new TogglableFlag(
+ "APPLY_CONFIG_AT_RUNTIME", false, "Apply display changes dynamically");
+
+ public static void initialize(Context context) {
+ // Avoid the disk read for user builds
+ if (Utilities.IS_DEBUG_DEVICE) {
+ synchronized (sLock) {
+ for (TogglableFlag flag : sFlags) {
+ flag.initialize(context);
+ }
+ }
+ } else {
+ synchronized (sLock) {
+ for (TogglableFlag flag : sFlags) {
+ flag.currentValue = flag.defaultValue;
+ }
+ }
+ }
+ }
+
+ static List<TogglableFlag> getTogglableFlags() {
+ // By Java Language Spec 12.4.2
+ // https://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.2, the
+ // TogglableFlag instances on BaseFlags will be created before those on the FeatureFlags
+ // subclass. This code handles flags that are redeclared in FeatureFlags, ensuring the
+ // FeatureFlags one takes priority.
+ SortedMap<String, TogglableFlag> flagsByKey = new TreeMap<>();
+ synchronized (sLock) {
+ for (TogglableFlag flag : sFlags) {
+ flagsByKey.put(flag.key, flag);
+ }
+ }
+ return new ArrayList<>(flagsByKey.values());
+ }
+
+ public static class TogglableFlag {
+ private final String key;
+ private final boolean defaultValue;
+ private final String description;
+ private boolean currentValue;
+
+ TogglableFlag(
+ String key,
+ boolean defaultValue,
+ String description) {
+ this.key = checkNotNull(key);
+ this.defaultValue = defaultValue;
+ this.description = checkNotNull(description);
+ synchronized (sLock) {
+ sFlags.add(this);
+ }
+ }
+
+ /** Set the value of this flag. This should only be used in tests. */
+ @VisibleForTesting
+ void setForTests(boolean value) {
+ currentValue = value;
+ }
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ public String getKey() {
+ return key;
+ }
+ void initialize(Context context) {
+ currentValue = getFromStorage(context, defaultValue);
+ }
+
+ void updateStorage(Context context, boolean value) {
+ SharedPreferences.Editor editor = context.getSharedPreferences(FLAGS_PREF_NAME,
+ Context.MODE_PRIVATE).edit();
+ if (value == defaultValue) {
+ editor.remove(key).apply();
+ } else {
+ editor.putBoolean(key, value).apply();
+ }
+ }
+
+ boolean getFromStorage(Context context, boolean defaultValue) {
+ return context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE)
+ .getBoolean(key, defaultValue);
+ }
+
+ boolean getDefaultValue() {
+ return defaultValue;
+ }
+
+ /** Returns the value of the flag at process start, including any overrides present. */
+ public boolean get() {
+ return currentValue;
+ }
+
+ String getDescription() {
+ return description;
+ }
+
+ @Override
+ public String toString() {
+ return "TogglableFlag{"
+ + "key=" + key + ", "
+ + "defaultValue=" + defaultValue + ", "
+ + "description=" + description
+ + "}";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof TogglableFlag) {
+ TogglableFlag that = (TogglableFlag) o;
+ return (this.key.equals(that.getKey()))
+ && (this.defaultValue == that.getDefaultValue())
+ && (this.description.equals(that.getDescription()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ int h$ = 1;
+ h$ *= 1000003;
+ h$ ^= key.hashCode();
+ h$ *= 1000003;
+ h$ ^= defaultValue ? 1231 : 1237;
+ h$ *= 1000003;
+ h$ ^= description.hashCode();
+ return h$;
+ }
+ }
+
+ /**
+ * Stores the FeatureFlag's value in Settings.Global instead of our SharedPrefs.
+ * This is useful if we want to be able to control this flag from another process.
+ */
+ public static final class ToggleableGlobalSettingsFlag extends TogglableFlag {
+ private ContentResolver contentResolver;
+
+ ToggleableGlobalSettingsFlag(String key, boolean defaultValue, String description) {
+ super(key, defaultValue, description);
+ }
+
+ @Override
+ public void initialize(Context context) {
+ contentResolver = context.getContentResolver();
+ super.initialize(context);
+ }
+
+ @Override
+ void updateStorage(Context context, boolean value) {
+ Settings.Global.putInt(contentResolver, getKey(), value ? 1 : 0);
+ }
+
+ @Override
+ boolean getFromStorage(Context context, boolean defaultValue) {
+ return Settings.Global.getInt(contentResolver, getKey(), defaultValue ? 1 : 0) == 1;
+ }
+
+ @Override
+ public boolean get() {
+ return getFromStorage(null, getDefaultValue());
+ }
+ }
}
diff --git a/src/com/android/launcher3/config/FlagTogglerPrefUi.java b/src/com/android/launcher3/config/FlagTogglerPrefUi.java
new file mode 100644
index 0000000..5ecb186
--- /dev/null
+++ b/src/com/android/launcher3/config/FlagTogglerPrefUi.java
@@ -0,0 +1,149 @@
+/*
+ * 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.config;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Process;
+import android.text.Html;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.Toast;
+
+import com.android.launcher3.R;
+import com.android.launcher3.config.BaseFlags.TogglableFlag;
+
+import androidx.preference.PreferenceDataStore;
+import androidx.preference.PreferenceFragment;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.SwitchPreference;
+
+/**
+ * Dev-build only UI allowing developers to toggle flag settings. See {@link FeatureFlags}.
+ */
+public final class FlagTogglerPrefUi {
+
+ private static final String TAG = "FlagTogglerPrefFrag";
+
+ private final PreferenceFragment mFragment;
+ private final Context mContext;
+ private final SharedPreferences mSharedPreferences;
+
+ private final PreferenceDataStore mDataStore = new PreferenceDataStore() {
+
+ @Override
+ public void putBoolean(String key, boolean value) {
+ for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
+ if (flag.getKey().equals(key)) {
+ boolean prevValue = flag.get();
+ flag.updateStorage(mContext, value);
+ updateMenu();
+ if (flag.get() != prevValue) {
+ Toast.makeText(mContext, "Flag applied", Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean getBoolean(String key, boolean defaultValue) {
+ for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
+ if (flag.getKey().equals(key)) {
+ return flag.getFromStorage(mContext, defaultValue);
+ }
+ }
+ return defaultValue;
+ }
+ };
+
+ public FlagTogglerPrefUi(PreferenceFragment fragment) {
+ mFragment = fragment;
+ mContext = fragment.getActivity();
+ mSharedPreferences = mContext.getSharedPreferences(
+ FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE);
+ }
+
+ public void applyTo(PreferenceGroup parent) {
+ // For flag overrides we only want to store when the engineer chose to override the
+ // flag with a different value than the default. That way, when we flip flags in
+ // future, engineers will pick up the new value immediately. To accomplish this, we use a
+ // custom preference data store.
+ for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
+ SwitchPreference switchPreference = new SwitchPreference(mContext);
+ switchPreference.setKey(flag.getKey());
+ switchPreference.setDefaultValue(flag.getDefaultValue());
+ switchPreference.setChecked(getFlagStateFromSharedPrefs(flag));
+ switchPreference.setTitle(flag.getKey());
+ updateSummary(switchPreference, flag);
+ switchPreference.setPreferenceDataStore(mDataStore);
+ parent.addPreference(switchPreference);
+ }
+ updateMenu();
+ }
+
+ /**
+ * Updates the summary to show the description and whether the flag overrides the default value.
+ */
+ private void updateSummary(SwitchPreference switchPreference, TogglableFlag flag) {
+ String onWarning = flag.getDefaultValue() ? "" : "<b>OVERRIDDEN</b><br>";
+ String offWarning = flag.getDefaultValue() ? "<b>OVERRIDDEN</b><br>" : "";
+ switchPreference.setSummaryOn(Html.fromHtml(onWarning + flag.getDescription()));
+ switchPreference.setSummaryOff(Html.fromHtml(offWarning + flag.getDescription()));
+ }
+
+ private void updateMenu() {
+ mFragment.setHasOptionsMenu(anyChanged());
+ mFragment.getActivity().invalidateOptionsMenu();
+ }
+
+ public void onCreateOptionsMenu(Menu menu) {
+ if (anyChanged()) {
+ menu.add(0, R.id.menu_apply_flags, 0, "Apply")
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ }
+ }
+
+ public void onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.menu_apply_flags) {
+ mSharedPreferences.edit().commit();
+ Log.e(TAG,
+ "Killing launcher process " + Process.myPid() + " to apply new flag values");
+ System.exit(0);
+ }
+ }
+
+ public void onStop() {
+ if (anyChanged()) {
+ Toast.makeText(mContext, "Flag won't be applied until you restart launcher",
+ Toast.LENGTH_LONG).show();
+ }
+ }
+
+ private boolean getFlagStateFromSharedPrefs(TogglableFlag flag) {
+ return mDataStore.getBoolean(flag.getKey(), flag.getDefaultValue());
+ }
+
+ private boolean anyChanged() {
+ for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
+ if (getFlagStateFromSharedPrefs(flag) != flag.get()) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 278eefd..daf7dc6 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -32,6 +32,7 @@
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.view.MotionEvent;
@@ -46,6 +47,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetHost;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.LauncherModel;
import com.android.launcher3.R;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompatVO;
@@ -54,6 +56,8 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.InstantAppResolver;
+import com.android.launcher3.util.LooperExecutor;
+import com.android.launcher3.util.Provider;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.WidgetHostViewLoader;
@@ -78,7 +82,6 @@
// Widget request specific options.
private LauncherAppWidgetHost mAppWidgetHost;
private AppWidgetManagerCompat mAppWidgetManager;
- private PendingAddWidgetInfo mPendingWidgetInfo;
private int mPendingBindWidgetId;
private Bundle mWidgetOptions;
@@ -189,10 +192,9 @@
private void setupShortcut() {
PinShortcutRequestActivityInfo shortcutInfo =
new PinShortcutRequestActivityInfo(mRequest, this);
- WidgetItem item = new WidgetItem(shortcutInfo);
mWidgetCell.getWidgetView().setTag(new PendingAddShortcutInfo(shortcutInfo));
- mWidgetCell.applyFromCellItem(item, mApp.getWidgetCache());
- mWidgetCell.ensurePreview();
+ applyWidgetItemAsync(
+ () -> new WidgetItem(shortcutInfo, mApp.getIconCache(), getPackageManager()));
}
private boolean setupWidget() {
@@ -207,18 +209,32 @@
mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
mAppWidgetHost = new LauncherAppWidgetHost(this);
- mPendingWidgetInfo = new PendingAddWidgetInfo(widgetInfo);
- mPendingWidgetInfo.spanX = Math.min(mIdp.numColumns, widgetInfo.spanX);
- mPendingWidgetInfo.spanY = Math.min(mIdp.numRows, widgetInfo.spanY);
- mWidgetOptions = WidgetHostViewLoader.getDefaultOptionsForWidget(this, mPendingWidgetInfo);
+ PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(widgetInfo);
+ pendingInfo.spanX = Math.min(mIdp.numColumns, widgetInfo.spanX);
+ pendingInfo.spanY = Math.min(mIdp.numRows, widgetInfo.spanY);
+ mWidgetOptions = WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo);
+ mWidgetCell.getWidgetView().setTag(pendingInfo);
- WidgetItem item = new WidgetItem(widgetInfo, getPackageManager(), mIdp);
- mWidgetCell.getWidgetView().setTag(mPendingWidgetInfo);
- mWidgetCell.applyFromCellItem(item, mApp.getWidgetCache());
- mWidgetCell.ensurePreview();
+ applyWidgetItemAsync(() -> new WidgetItem(widgetInfo, mIdp, mApp.getIconCache()));
return true;
}
+ private void applyWidgetItemAsync(final Provider<WidgetItem> itemProvider) {
+ new AsyncTask<Void, Void, WidgetItem>() {
+ @Override
+ protected WidgetItem doInBackground(Void... voids) {
+ return itemProvider.get();
+ }
+
+ @Override
+ protected void onPostExecute(WidgetItem item) {
+ mWidgetCell.applyFromCellItem(item, mApp.getWidgetCache());
+ mWidgetCell.ensurePreview();
+ }
+ }.executeOnExecutor(new LooperExecutor(LauncherModel.getWorkerLooper()));
+ // TODO: Create a worker looper executor and reuse that everywhere.
+ }
+
/**
* Called when the cancel button is clicked.
*/
diff --git a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
index 1e84b41..e204c63 100644
--- a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
@@ -106,6 +106,10 @@
}
protected boolean onDragStart(DragEvent event) {
+ return onDragStart(event, this);
+ }
+
+ protected boolean onDragStart(DragEvent event, DragOptions.PreDragCondition preDragCondition) {
ClipDescription desc = event.getClipDescription();
if (desc == null || !desc.hasMimeType(getMimeType())) {
Log.e(TAG, "Someone started a dragAndDrop before us.");
@@ -115,7 +119,7 @@
Point downPos = new Point((int) event.getX(), (int) event.getY());
DragOptions options = new DragOptions();
options.systemDndStartPoint = downPos;
- options.preDragCondition = this;
+ options.preDragCondition = preDragCondition;
// We use drag event position as the screenPos for the preview image. Since mPreviewRect
// already includes the view position relative to the drag event on the source window,
@@ -123,7 +127,7 @@
// across windows, using drag position here give a good estimate for relative position
// to source window.
createDragHelper().startDrag(new Rect(mPreviewRect),
- mPreviewBitmapWidth, mPreviewViewWidth, downPos, this, options);
+ mPreviewBitmapWidth, mPreviewViewWidth, downPos, this, options);
mDragStartTime = SystemClock.uptimeMillis();
return true;
}
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 8a216fc..03dc66e 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -16,9 +16,11 @@
package com.android.launcher3.dragndrop;
+import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.NORMAL;
+import android.animation.ValueAnimator;
import android.content.ComponentName;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -31,6 +33,7 @@
import android.view.MotionEvent;
import android.view.View;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget;
import com.android.launcher3.ItemInfo;
@@ -145,6 +148,7 @@
// Hide soft keyboard, if visible
UiThreadHelper.hideKeyboardAsync(mLauncher, mWindowToken);
+ AbstractFloatingView.closeOpenViews(mLauncher, false, TYPE_DISCOVERY_BOUNCE);
mOptions = options;
if (mOptions.systemDndStartPoint != null) {
@@ -224,6 +228,12 @@
}
}
+ public void addFirstFrameAnimationHelper(ValueAnimator anim) {
+ if (mDragObject != null && mDragObject.dragView != null) {
+ mDragObject.dragView.mFirstFrameAnimatorHelper.addTo(anim);
+ }
+ }
+
/**
* Call this from a drag source view like this:
*
@@ -386,7 +396,7 @@
@Override
public void onDriverDragEnd(float x, float y) {
DropTarget dropTarget;
- Runnable flingAnimation = mFlingToDeleteHelper.getFlingAnimation(mDragObject);
+ Runnable flingAnimation = mFlingToDeleteHelper.getFlingAnimation(mDragObject, mOptions);
if (flingAnimation != null) {
dropTarget = mFlingToDeleteHelper.getDropTarget();
} else {
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 6d2d3cb..f005ce7 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -47,7 +47,6 @@
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.graphics.ViewScrim;
import com.android.launcher3.graphics.WorkspaceAndHotseatScrim;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.uioverrides.UiFactory;
@@ -125,15 +124,6 @@
}
@Override
- protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
- ViewScrim scrim = ViewScrim.get(child);
- if (scrim != null) {
- scrim.draw(canvas, getWidth(), getHeight());
- }
- return super.drawChild(canvas, child, drawingTime);
- }
-
- @Override
protected boolean findActiveController(MotionEvent ev) {
if (mActivity.getStateManager().getState().disableInteraction) {
// You Shall Not Pass!!!
diff --git a/src/com/android/launcher3/dragndrop/DragOptions.java b/src/com/android/launcher3/dragndrop/DragOptions.java
index f108f8b..2d19f36 100644
--- a/src/com/android/launcher3/dragndrop/DragOptions.java
+++ b/src/com/android/launcher3/dragndrop/DragOptions.java
@@ -37,6 +37,8 @@
/** Scale of the icons over the workspace icon size. */
public float intrinsicIconScaleFactor = 1f;
+ public boolean isFlingToDelete;
+
/**
* Specifies a condition that must be met before DragListener#onDragStart() is called.
* By default, there is no condition and onDragStart() is called immediately following
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 551567a..8f223a3 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -16,6 +16,8 @@
package com.android.launcher3.dragndrop;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.FloatArrayEvaluator;
@@ -39,27 +41,22 @@
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
-import android.support.animation.FloatPropertyCompat;
-import android.support.animation.SpringAnimation;
-import android.support.animation.SpringForce;
import android.view.View;
import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.FirstFrameAnimatorHelper;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.ShortcutConfigActivityInfo;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.graphics.IconNormalizer;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.shortcuts.ShortcutKey;
@@ -70,7 +67,9 @@
import java.util.Arrays;
import java.util.List;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
public class DragView extends View {
private static final ColorMatrix sTempMatrix1 = new ColorMatrix();
@@ -79,8 +78,6 @@
public static final int COLOR_CHANGE_DURATION = 120;
public static final int VIEW_ZOOM_DURATION = 150;
- @Thunk static float sDragAlpha = 1f;
-
private boolean mDrawBitmap = true;
private Bitmap mBitmap;
private Bitmap mCrossFadeBitmap;
@@ -97,6 +94,7 @@
private final Launcher mLauncher;
private final DragLayer mDragLayer;
@Thunk final DragController mDragController;
+ final FirstFrameAnimatorHelper mFirstFrameAnimatorHelper;
private boolean mHasDrawn = false;
@Thunk float mCrossFadeProgress = 0f;
private boolean mAnimationCancelled = false;
@@ -137,6 +135,7 @@
mLauncher = launcher;
mDragLayer = launcher.getDragLayer();
mDragController = launcher.getDragController();
+ mFirstFrameAnimatorHelper = new FirstFrameAnimatorHelper(this);
final float scale = (bitmap.getWidth() + finalScaleDps) / bitmap.getWidth();
@@ -145,22 +144,14 @@
setScaleY(initialScale);
// Animate the view into the correct position
- mAnim = LauncherAnimUtils.ofFloat(0f, 1f);
+ mAnim = ValueAnimator.ofFloat(0f, 1f);
mAnim.setDuration(VIEW_ZOOM_DURATION);
- mAnim.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final float value = (Float) animation.getAnimatedValue();
-
- setScaleX(initialScale + (value * (scale - initialScale)));
- setScaleY(initialScale + (value * (scale - initialScale)));
- if (sDragAlpha != 1f) {
- setAlpha(sDragAlpha * value + (1f - value));
- }
-
- if (getParent() == null) {
- animation.cancel();
- }
+ mAnim.addUpdateListener(animation -> {
+ final float value = (Float) animation.getAnimatedValue();
+ setScaleX(initialScale + (value * (scale - initialScale)));
+ setScaleY(initialScale + (value * (scale - initialScale)));
+ if (!isAttachedToWindow()) {
+ animation.cancel();
}
});
@@ -198,7 +189,7 @@
*/
@TargetApi(Build.VERSION_CODES.O)
public void setItemInfo(final ItemInfo info) {
- if (!(FeatureFlags.LAUNCHER3_SPRING_ICONS && Utilities.ATLEAST_OREO)) {
+ if (!Utilities.ATLEAST_OREO) {
return;
}
if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
@@ -213,7 +204,7 @@
public void run() {
LauncherAppState appState = LauncherAppState.getInstance(mLauncher);
Object[] outObj = new Object[1];
- final Drawable dr = getFullDrawable(info, appState, outObj);
+ Drawable dr = getFullDrawable(info, appState, outObj);
if (dr instanceof AdaptiveIconDrawable) {
int w = mBitmap.getWidth();
@@ -229,10 +220,20 @@
mBadge = getBadge(info, appState, outObj[0]);
mBadge.setBounds(badgeBounds);
- LauncherIcons li = LauncherIcons.obtain(mLauncher);
- Utilities.scaleRectAboutCenter(bounds,
- li.getNormalizer().getScale(dr, null, null, null));
- li.recycle();
+ // Do not draw the background in case of folder as its translucent
+ mDrawBitmap = !(dr instanceof FolderAdaptiveIcon);
+
+ try (LauncherIcons li = LauncherIcons.obtain(mLauncher)) {
+ Drawable nDr; // drawable to be normalized
+ if (mDrawBitmap) {
+ nDr = dr;
+ } else {
+ // Since we just want the scale, avoid heavy drawing operations
+ nDr = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK), null);
+ }
+ Utilities.scaleRectAboutCenter(bounds,
+ li.getNormalizer().getScale(nDr, null));
+ }
AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) dr;
// Shrink very tiny bit so that the clip path is smaller than the original bitmap
@@ -268,9 +269,6 @@
// Assign the variable on the UI thread to avoid race conditions.
mScaledMaskPath = mask;
- // Do not draw the background in case of folder as its translucent
- mDrawBitmap = !(dr instanceof FolderAdaptiveIcon);
-
if (info.isDisabled()) {
FastBitmapDrawable d = new FastBitmapDrawable((Bitmap) null);
d.setIsDisabled(true);
@@ -481,15 +479,12 @@
}
public void crossFade(int duration) {
- ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
+ ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
va.setDuration(duration);
va.setInterpolator(Interpolators.DEACCEL_1_5);
- va.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mCrossFadeProgress = animation.getAnimatedFraction();
- invalidate();
- }
+ va.addUpdateListener(a -> {
+ mCrossFadeProgress = a.getAnimatedFraction();
+ invalidate();
});
va.start();
}
diff --git a/src/com/android/launcher3/dragndrop/FlingToDeleteHelper.java b/src/com/android/launcher3/dragndrop/FlingToDeleteHelper.java
index e794744..589ad25 100644
--- a/src/com/android/launcher3/dragndrop/FlingToDeleteHelper.java
+++ b/src/com/android/launcher3/dragndrop/FlingToDeleteHelper.java
@@ -91,12 +91,13 @@
return mDropTarget;
}
- public Runnable getFlingAnimation(DropTarget.DragObject dragObject) {
+ public Runnable getFlingAnimation(DropTarget.DragObject dragObject, DragOptions options) {
PointF vel = isFlingingToDelete();
- if (vel == null) {
+ options.isFlingToDelete = vel != null;
+ if (!options.isFlingToDelete) {
return null;
}
- return new FlingAnimation(dragObject, vel, mDropTarget, mLauncher);
+ return new FlingAnimation(dragObject, vel, mDropTarget, mLauncher, options);
}
/**
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
index 5576d91..e40397b 100644
--- a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -36,7 +36,7 @@
import com.android.launcher3.R;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.PreviewBackground;
-import com.android.launcher3.graphics.BitmapRenderer;
+import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.util.Preconditions;
/**
@@ -65,7 +65,7 @@
}
public static FolderAdaptiveIcon createFolderAdaptiveIcon(
- Launcher launcher, long folderId, Point dragViewSize) {
+ Launcher launcher, int folderId, Point dragViewSize) {
Preconditions.assertNonUiThread();
int margin = launcher.getResources()
.getDimensionPixelSize(R.dimen.blur_size_medium_outline);
diff --git a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
index 52167bb..64655cc 100644
--- a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
+++ b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
@@ -22,13 +22,14 @@
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.PinItemRequest;
+import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Process;
import com.android.launcher3.FastBitmapDrawable;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
@@ -65,7 +66,7 @@
}
@Override
- public CharSequence getLabel() {
+ public CharSequence getLabel(PackageManager pm) {
return mInfo.getShortLabel();
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 6b13da7..94c8d45 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -26,6 +26,8 @@
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Path;
import android.graphics.Rect;
import android.text.InputType;
import android.text.Selection;
@@ -40,7 +42,6 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
-import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo;
@@ -152,6 +153,8 @@
// Cell ranks used for drag and drop
@Thunk int mTargetRank, mPrevTargetRank, mEmptyCellRank;
+ private Path mClipPath;
+
@ViewDebug.ExportedProperty(category = "launcher",
mapping = {
@ViewDebug.IntToString(from = STATE_NONE, to = "STATE_NONE"),
@@ -191,14 +194,9 @@
public Folder(Context context, AttributeSet attrs) {
super(context, attrs);
setAlwaysDrawnWithCacheEnabled(false);
- Resources res = getResources();
- if (sDefaultFolderName == null) {
- sDefaultFolderName = res.getString(R.string.folder_name);
- }
- if (sHintText == null) {
- sHintText = res.getString(R.string.folder_hint_text);
- }
+ setLocaleDependentFields(getResources(), false /* force */);
+
mLauncher = Launcher.getLauncher(context);
// We need this view to be focusable in touch mode so that when text editing of the folder
// name is complete, we have something to focus on, thus hiding the cursor and giving
@@ -648,7 +646,7 @@
mFolderIcon.mBackground.animateBackgroundStroke();
mFolderIcon.onFolderClose(mContent.getCurrentPage());
if (mFolderIcon.hasBadge()) {
- mFolderIcon.createBadgeScaleAnimator(0f, 1f).start();
+ mFolderIcon.animateBadgeScale(0f, 1f);
}
mFolderIcon.requestFocus();
}
@@ -1473,4 +1471,34 @@
}
return false;
}
+
+ public static void setLocaleDependentFields(Resources res, boolean force) {
+ if (sDefaultFolderName == null || force) {
+ sDefaultFolderName = res.getString(R.string.folder_name);
+ }
+ if (sHintText == null || force) {
+ sHintText = res.getString(R.string.folder_hint_text);
+ }
+ }
+
+ /**
+ * Alternative to using {@link #getClipToOutline()} as it only works with derivatives of
+ * rounded rect.
+ */
+ public void setClipPath(Path clipPath) {
+ mClipPath = clipPath;
+ invalidate();
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mClipPath != null) {
+ int count = canvas.save();
+ canvas.clipPath(mClipPath);
+ super.draw(canvas);
+ canvas.restoreToCount(count);
+ } else {
+ super.draw(canvas);
+ }
+ }
}
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 9ae3775..2461e28 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -19,6 +19,8 @@
import static com.android.launcher3.BubbleTextView.TEXT_ALPHA_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
+import static com.android.launcher3.folder.FolderShape.getShape;
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -27,10 +29,8 @@
import android.animation.TimeInterpolator;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
-import android.support.v4.graphics.ColorUtils;
import android.util.Property;
import android.view.View;
import android.view.animation.AnimationUtils;
@@ -38,12 +38,10 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PropertyResetListener;
-import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.util.Themes;
@@ -154,8 +152,9 @@
// Set up the Folder background.
final int finalColor = Themes.getAttrColor(mContext, android.R.attr.colorPrimary);
- final int initialColor =
- ColorUtils.setAlphaComponent(finalColor, mPreviewBackground.getBackgroundAlpha());
+ final int initialColor = setColorAlphaBound(
+ finalColor, mPreviewBackground.getBackgroundAlpha());
+ mFolderBackground.mutate();
mFolderBackground.setColor(mIsOpening ? initialColor : finalColor);
// Set up the reveal animation that clips the Folder.
@@ -166,11 +165,10 @@
Math.round((totalOffsetX + initialSize) / initialScale),
Math.round((paddingOffsetY + initialSize) / initialScale));
Rect endRect = new Rect(0, 0, lp.width, lp.height);
- float initialRadius = initialSize / initialScale / 2f;
float finalRadius = Utilities.pxFromDp(2, mContext.getResources().getDisplayMetrics());
// Create the animators.
- AnimatorSet a = LauncherAnimUtils.createAnimatorSet();
+ AnimatorSet a = new AnimatorSet();
// Initialize the Folder items' text.
PropertyResetListener colorResetListener =
@@ -189,14 +187,8 @@
play(a, getAnimator(mFolder, SCALE_PROPERTY, initialScale, finalScale));
play(a, getAnimator(mFolderBackground, "color", initialColor, finalColor));
play(a, mFolderIcon.mFolderName.createTextAlphaAnimator(!mIsOpening));
- RoundedRectRevealOutlineProvider outlineProvider = new RoundedRectRevealOutlineProvider(
- initialRadius, finalRadius, startRect, endRect) {
- @Override
- public boolean shouldRemoveElevationDuringAnimation() {
- return true;
- }
- };
- play(a, outlineProvider.createRevealAnimator(mFolder, !mIsOpening));
+ play(a, getShape().createRevealAnimator(
+ mFolder, startRect, endRect, finalRadius, !mIsOpening));
// Animate the elevation midway so that the shadow is not noticeable in the background.
int midDuration = mDuration / 2;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index cb5d872..429d44f 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -20,21 +20,20 @@
import static com.android.launcher3.folder.PreviewItemManager.INITIAL_ITEM_ANIMATION_DURATION;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.Region;
import android.graphics.drawable.Drawable;
-import android.os.Parcelable;
-import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Property;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.ViewDebug;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -70,14 +69,16 @@
import java.util.ArrayList;
import java.util.List;
+import androidx.annotation.NonNull;
+
/**
* An icon that can appear on in the workspace representing an {@link Folder}.
*/
public class FolderIcon extends FrameLayout implements FolderListener {
+
@Thunk Launcher mLauncher;
@Thunk Folder mFolder;
private FolderInfo mInfo;
- @Thunk static boolean sStaticValuesDirty = true;
private CheckLongPressHelper mLongPressHelper;
private StylusEventHelper mStylusEventHelper;
@@ -108,9 +109,12 @@
private Alarm mOpenAlarm = new Alarm();
+ @ViewDebug.ExportedProperty(category = "launcher", deepExport = true)
private FolderBadgeInfo mBadgeInfo = new FolderBadgeInfo();
private BadgeRenderer mBadgeRenderer;
+ @ViewDebug.ExportedProperty(category = "launcher")
private float mBadgeScale;
+ private Animator mBadgeScaleAnim;
private Point mTempSpaceForBadgeOffset = new Point();
private static final Property<FolderIcon, Float> BADGE_SCALE_PROPERTY
@@ -185,12 +189,6 @@
return icon;
}
- @Override
- protected Parcelable onSaveInstanceState() {
- sStaticValuesDirty = true;
- return super.onSaveInstanceState();
- }
-
public Folder getFolder() {
return mFolder;
}
@@ -401,15 +399,30 @@
float newBadgeScale = isBadged ? 1f : 0f;
// Animate when a badge is first added or when it is removed.
if ((wasBadged ^ isBadged) && isShown()) {
- createBadgeScaleAnimator(newBadgeScale).start();
+ animateBadgeScale(newBadgeScale);
} else {
+ cancelBadgeScaleAnim();
mBadgeScale = newBadgeScale;
invalidate();
}
}
- public Animator createBadgeScaleAnimator(float... badgeScales) {
- return ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, badgeScales);
+ private void cancelBadgeScaleAnim() {
+ if (mBadgeScaleAnim != null) {
+ mBadgeScaleAnim.cancel();
+ }
+ }
+
+ public void animateBadgeScale(float... badgeScales) {
+ cancelBadgeScaleAnim();
+ mBadgeScaleAnim = ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, badgeScales);
+ mBadgeScaleAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBadgeScaleAnim = null;
+ }
+ });
+ mBadgeScaleAnim.start();
}
public boolean hasBadge() {
@@ -465,20 +478,9 @@
if (mFolder == null) return;
if (mFolder.getItemCount() == 0 && !mAnimating) return;
- final int saveCount;
-
- if (canvas.isHardwareAccelerated()) {
- saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null);
- } else {
- saveCount = canvas.save();
- canvas.clipPath(mBackground.getClipPath());
- }
-
+ final int saveCount = canvas.save();
+ canvas.clipPath(mBackground.getClipPath());
mPreviewItemManager.draw(canvas);
-
- if (canvas.isHardwareAccelerated()) {
- mBackground.clipCanvasHardware(canvas);
- }
canvas.restoreToCount(saveCount);
if (!mBackground.drawingDelegated()) {
@@ -490,10 +492,7 @@
public void drawBadge(Canvas canvas) {
if ((mBadgeInfo != null && mBadgeInfo.hasBadge()) || mBadgeScale > 0) {
- int offsetX = mBackground.getOffsetX();
- int offsetY = mBackground.getOffsetY();
- int previewSize = (int) (mBackground.previewSize * mBackground.mScale);
- mTempBounds.set(offsetX, offsetY, offsetX + previewSize, offsetY + previewSize);
+ BubbleTextView.getIconBounds(this, mTempBounds, mLauncher.getDeviceProfile().iconSizePx);
// If we are animating to the accepting state, animate the badge out.
float badgeScale = Math.max(0, mBadgeScale - mBackground.getScaleProgress());
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 9be71f9..8439e79 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -493,7 +493,7 @@
int delta = scroll - getScrollX();
if (delta != 0) {
mScroller.setInterpolator(Interpolators.DEACCEL);
- mScroller.startScroll(getScrollX(), 0, delta, 0, Folder.SCROLL_HINT_DURATION);
+ mScroller.startScroll(getScrollX(), delta, Folder.SCROLL_HINT_DURATION);
invalidate();
}
}
diff --git a/src/com/android/launcher3/folder/FolderPreviewItemAnim.java b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
index be075bc..1e56f7d 100644
--- a/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
+++ b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
@@ -17,22 +17,41 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
+import android.animation.FloatArrayEvaluator;
+import android.animation.ObjectAnimator;
+import android.util.Property;
-import com.android.launcher3.LauncherAnimUtils;
+import java.util.Arrays;
/**
* Animates a Folder preview item.
*/
class FolderPreviewItemAnim {
+ private static final Property<FolderPreviewItemAnim, float[]> PARAMS =
+ new Property<FolderPreviewItemAnim, float[]>(float[].class, "params") {
+ @Override
+ public float[] get(FolderPreviewItemAnim anim) {
+ sTempParamsArray[0] = anim.mParams.scale;
+ sTempParamsArray[1] = anim.mParams.transX;
+ sTempParamsArray[2] = anim.mParams.transY;
+ return sTempParamsArray;
+ }
+
+ @Override
+ public void set(FolderPreviewItemAnim anim, float[] value) {
+ anim.setParams(value);
+ }
+ };
+
private static PreviewItemDrawingParams sTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
+ private static final float[] sTempParamsArray = new float[3];
- private ValueAnimator mValueAnimator;
+ private final ObjectAnimator mAnimator;
+ private final PreviewItemManager mItemManager;
+ private final PreviewItemDrawingParams mParams;
- float finalScale;
- float finalTransX;
- float finalTransY;
+ public final float[] finalState;
/**
* @param params layout params to animate
@@ -43,33 +62,21 @@
* @param duration duration in ms of the animation
* @param onCompleteRunnable runnable to execute upon animation completion
*/
- FolderPreviewItemAnim(final PreviewItemManager previewItemManager,
- final PreviewItemDrawingParams params, int index0, int items0, int index1, int items1,
+ FolderPreviewItemAnim(PreviewItemManager itemManager,
+ PreviewItemDrawingParams params, int index0, int items0, int index1, int items1,
int duration, final Runnable onCompleteRunnable) {
- previewItemManager.computePreviewItemDrawingParams(index1, items1, sTmpParams);
+ mItemManager = itemManager;
+ mParams = params;
- finalScale = sTmpParams.scale;
- finalTransX = sTmpParams.transX;
- finalTransY = sTmpParams.transY;
+ mItemManager.computePreviewItemDrawingParams(index1, items1, sTmpParams);
+ finalState = new float[] {sTmpParams.scale, sTmpParams.transX, sTmpParams.transY};
- previewItemManager.computePreviewItemDrawingParams(index0, items0, sTmpParams);
+ mItemManager.computePreviewItemDrawingParams(index0, items0, sTmpParams);
+ float[] startState = new float[] {sTmpParams.scale, sTmpParams.transX, sTmpParams.transY};
- final float scale0 = sTmpParams.scale;
- final float transX0 = sTmpParams.transX;
- final float transY0 = sTmpParams.transY;
-
- mValueAnimator = LauncherAnimUtils.ofFloat(0f, 1.0f);
- mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
- public void onAnimationUpdate(ValueAnimator animation) {
- float progress = animation.getAnimatedFraction();
-
- params.transX = transX0 + progress * (finalTransX - transX0);
- params.transY = transY0 + progress * (finalTransY - transY0);
- params.scale = scale0 + progress * (finalScale - scale0);
- previewItemManager.onParamsChanged();
- }
- });
- mValueAnimator.addListener(new AnimatorListenerAdapter() {
+ mAnimator = ObjectAnimator.ofObject(this, PARAMS, new FloatArrayEvaluator(),
+ startState, finalState);
+ mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (onCompleteRunnable != null) {
@@ -78,20 +85,26 @@
params.anim = null;
}
});
- mValueAnimator.setDuration(duration);
+ mAnimator.setDuration(duration);
+ }
+
+ private void setParams(float[] values) {
+ mParams.scale = values[0];
+ mParams.transX = values[1];
+ mParams.transY = values[2];
+ mItemManager.onParamsChanged();
}
public void start() {
- mValueAnimator.start();
+ mAnimator.start();
}
public void cancel() {
- mValueAnimator.cancel();
+ mAnimator.cancel();
}
public boolean hasEqualFinalState(FolderPreviewItemAnim anim) {
- return finalTransY == anim.finalTransY && finalTransX == anim.finalTransX &&
- finalScale == anim.finalScale;
+ return Arrays.equals(finalState, anim.finalState);
}
}
diff --git a/src/com/android/launcher3/folder/FolderShape.java b/src/com/android/launcher3/folder/FolderShape.java
new file mode 100644
index 0000000..ae279cb
--- /dev/null
+++ b/src/com/android/launcher3/folder/FolderShape.java
@@ -0,0 +1,422 @@
+/*
+ * 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.folder;
+
+import static com.android.launcher3.Workspace.MAP_NO_RECURSE;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.FloatArrayEvaluator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.Region.Op;
+import android.graphics.RegionIterator;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
+import android.view.ViewOutlineProvider;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
+
+/**
+ * Abstract representation of the shape of a folder icon
+ */
+public abstract class FolderShape {
+
+ private static FolderShape sInstance = new Circle();
+
+ public static FolderShape getShape() {
+ return sInstance;
+ }
+
+ private static FolderShape[] getAllShapes() {
+ return new FolderShape[] {
+ new Circle(),
+ new RoundedSquare(8f / 50), // Ratios based on path defined in config_icon_mask
+ new RoundedSquare(30f / 50),
+ new Square(),
+ new TearDrop(),
+ new Squircle()};
+ }
+
+ public abstract void drawShape(Canvas canvas, float offsetX, float offsetY, float radius,
+ Paint paint);
+
+ public abstract void addShape(Path path, float offsetX, float offsetY, float radius);
+
+ public abstract Animator createRevealAnimator(Folder target, Rect startRect, Rect endRect,
+ float endRadius, boolean isReversed);
+
+ /**
+ * Abstract shape where the reveal animation is a derivative of a round rect animation
+ */
+ private static abstract class SimpleRectShape extends FolderShape {
+
+ @Override
+ public final Animator createRevealAnimator(Folder target, Rect startRect, Rect endRect,
+ float endRadius, boolean isReversed) {
+ return new RoundedRectRevealOutlineProvider(
+ getStartRadius(startRect), endRadius, startRect, endRect) {
+ @Override
+ public boolean shouldRemoveElevationDuringAnimation() {
+ return true;
+ }
+ }.createRevealAnimator(target, isReversed);
+ }
+
+ protected abstract float getStartRadius(Rect startRect);
+ }
+
+ /**
+ * Abstract shape which draws using {@link Path}
+ */
+ private static abstract class PathShape extends FolderShape {
+
+ private final Path mTmpPath = new Path();
+
+ @Override
+ public final void drawShape(Canvas canvas, float offsetX, float offsetY, float radius,
+ Paint paint) {
+ mTmpPath.reset();
+ addShape(mTmpPath, offsetX, offsetY, radius);
+ canvas.drawPath(mTmpPath, paint);
+ }
+
+ protected abstract AnimatorUpdateListener newUpdateListener(
+ Rect startRect, Rect endRect, float endRadius, Path outPath);
+
+ @Override
+ public final Animator createRevealAnimator(Folder target, Rect startRect, Rect endRect,
+ float endRadius, boolean isReversed) {
+ Path path = new Path();
+ AnimatorUpdateListener listener =
+ newUpdateListener(startRect, endRect, endRadius, path);
+
+ ValueAnimator va =
+ isReversed ? ValueAnimator.ofFloat(1f, 0f) : ValueAnimator.ofFloat(0f, 1f);
+ va.addListener(new AnimatorListenerAdapter() {
+ private ViewOutlineProvider mOldOutlineProvider;
+
+ public void onAnimationStart(Animator animation) {
+ mOldOutlineProvider = target.getOutlineProvider();
+ target.setOutlineProvider(null);
+
+ target.setTranslationZ(-target.getElevation());
+ }
+
+ public void onAnimationEnd(Animator animation) {
+ target.setTranslationZ(0);
+ target.setClipPath(null);
+ target.setOutlineProvider(mOldOutlineProvider);
+ }
+ });
+
+ va.addUpdateListener((anim) -> {
+ path.reset();
+ listener.onAnimationUpdate(anim);
+ target.setClipPath(path);
+ });
+
+ return va;
+ }
+ }
+
+ public static final class Circle extends SimpleRectShape {
+
+ @Override
+ public void drawShape(Canvas canvas, float offsetX, float offsetY, float radius, Paint p) {
+ canvas.drawCircle(radius + offsetX, radius + offsetY, radius, p);
+ }
+
+ @Override
+ public void addShape(Path path, float offsetX, float offsetY, float radius) {
+ path.addCircle(radius + offsetX, radius + offsetY, radius, Path.Direction.CW);
+ }
+
+ @Override
+ protected float getStartRadius(Rect startRect) {
+ return startRect.width() / 2f;
+ }
+ }
+
+ public static class Square extends SimpleRectShape {
+
+ @Override
+ public void drawShape(Canvas canvas, float offsetX, float offsetY, float radius, Paint p) {
+ float cx = radius + offsetX;
+ float cy = radius + offsetY;
+ canvas.drawRect(cx - radius, cy - radius, cx + radius, cy + radius, p);
+ }
+
+ @Override
+ public void addShape(Path path, float offsetX, float offsetY, float radius) {
+ float cx = radius + offsetX;
+ float cy = radius + offsetY;
+ path.addRect(cx - radius, cy - radius, cx + radius, cy + radius, Path.Direction.CW);
+ }
+
+ @Override
+ protected float getStartRadius(Rect startRect) {
+ return 0;
+ }
+ }
+
+ public static class RoundedSquare extends SimpleRectShape {
+
+ /**
+ * Ratio of corner radius to half size. Based on the
+ */
+ private final float mRadiusFactor;
+
+ public RoundedSquare(float radiusFactor) {
+ mRadiusFactor = radiusFactor;
+ }
+
+ @Override
+ public void drawShape(Canvas canvas, float offsetX, float offsetY, float radius, Paint p) {
+ float cx = radius + offsetX;
+ float cy = radius + offsetY;
+ float cr = radius * mRadiusFactor;
+ canvas.drawRoundRect(cx - radius, cy - radius, cx + radius, cy + radius, cr, cr, p);
+ }
+
+ @Override
+ public void addShape(Path path, float offsetX, float offsetY, float radius) {
+ float cx = radius + offsetX;
+ float cy = radius + offsetY;
+ float cr = radius * mRadiusFactor;
+ path.addRoundRect(cx - radius, cy - radius, cx + radius, cy + radius, cr, cr,
+ Path.Direction.CW);
+ }
+
+ @Override
+ protected float getStartRadius(Rect startRect) {
+ return (startRect.width() / 2f) * mRadiusFactor;
+ }
+ }
+
+ public static class TearDrop extends PathShape {
+
+ /**
+ * Radio of short radius to large radius, based on the shape options defined in the config.
+ */
+ private static final float RADIUS_RATIO = 15f / 50;
+
+ private final float[] mTempRadii = new float[8];
+
+ @Override
+ public void addShape(Path p, float offsetX, float offsetY, float r1) {
+ float r2 = r1 * RADIUS_RATIO;
+ float cx = r1 + offsetX;
+ float cy = r1 + offsetY;
+
+ p.addRoundRect(cx - r1, cy - r1, cx + r1, cy + r1, getRadiiArray(r1, r2),
+ Path.Direction.CW);
+ }
+
+ private float[] getRadiiArray(float r1, float r2) {
+ mTempRadii[0] = mTempRadii [1] = mTempRadii[2] = mTempRadii[3] =
+ mTempRadii[6] = mTempRadii[7] = r1;
+ mTempRadii[4] = mTempRadii[5] = r2;
+ return mTempRadii;
+ }
+
+ @Override
+ protected AnimatorUpdateListener newUpdateListener(Rect startRect, Rect endRect,
+ float endRadius, Path outPath) {
+ float r1 = startRect.width() / 2f;
+ float r2 = r1 * RADIUS_RATIO;
+
+ float[] startValues = new float[] {
+ startRect.left, startRect.top, startRect.right, startRect.bottom, r1, r2};
+ float[] endValues = new float[] {
+ endRect.left, endRect.top, endRect.right, endRect.bottom, endRadius, endRadius};
+
+ FloatArrayEvaluator evaluator = new FloatArrayEvaluator(new float[6]);
+
+ return (anim) -> {
+ float progress = (Float) anim.getAnimatedValue();
+ float[] values = evaluator.evaluate(progress, startValues, endValues);
+ outPath.addRoundRect(
+ values[0], values[1], values[2], values[3],
+ getRadiiArray(values[4], values[5]), Path.Direction.CW);
+ };
+ }
+ }
+
+ public static class Squircle extends PathShape {
+
+ /**
+ * Radio of radius to circle radius, based on the shape options defined in the config.
+ */
+ private static final float RADIUS_RATIO = 10f / 50;
+
+ @Override
+ public void addShape(Path p, float offsetX, float offsetY, float r) {
+ float cx = r + offsetX;
+ float cy = r + offsetY;
+ float control = r - r * RADIUS_RATIO;
+
+ p.moveTo(cx, cy - r);
+ addLeftCurve(cx, cy, r, control, p);
+ addRightCurve(cx, cy, r, control, p);
+ addLeftCurve(cx, cy, -r, -control, p);
+ addRightCurve(cx, cy, -r, -control, p);
+ p.close();
+ }
+
+ private void addLeftCurve(float cx, float cy, float r, float control, Path path) {
+ path.cubicTo(
+ cx - control, cy - r,
+ cx - r, cy - control,
+ cx - r, cy);
+ }
+
+ private void addRightCurve(float cx, float cy, float r, float control, Path path) {
+ path.cubicTo(
+ cx - r, cy + control,
+ cx - control, cy + r,
+ cx, cy + r);
+ }
+
+ @Override
+ protected AnimatorUpdateListener newUpdateListener(Rect startRect, Rect endRect,
+ float endR, Path outPath) {
+
+ float startCX = startRect.exactCenterX();
+ float startCY = startRect.exactCenterY();
+ float startR = startRect.width() / 2f;
+ float startControl = startR - startR * RADIUS_RATIO;
+ float startHShift = 0;
+ float startVShift = 0;
+
+ float endCX = endRect.exactCenterX();
+ float endCY = endRect.exactCenterY();
+ // Approximate corner circle using bezier curves
+ // http://spencermortensen.com/articles/bezier-circle/
+ float endControl = endR * 0.551915024494f;
+ float endHShift = endRect.width() / 2f - endR;
+ float endVShift = endRect.height() / 2f - endR;
+
+ return (anim) -> {
+ float progress = (Float) anim.getAnimatedValue();
+
+ float cx = (1 - progress) * startCX + progress * endCX;
+ float cy = (1 - progress) * startCY + progress * endCY;
+ float r = (1 - progress) * startR + progress * endR;
+ float control = (1 - progress) * startControl + progress * endControl;
+ float hShift = (1 - progress) * startHShift + progress * endHShift;
+ float vShift = (1 - progress) * startVShift + progress * endVShift;
+
+ outPath.moveTo(cx, cy - vShift - r);
+ outPath.rLineTo(-hShift, 0);
+
+ addLeftCurve(cx - hShift, cy - vShift, r, control, outPath);
+ outPath.rLineTo(0, vShift + vShift);
+
+ addRightCurve(cx - hShift, cy + vShift, r, control, outPath);
+ outPath.rLineTo(hShift + hShift, 0);
+
+ addLeftCurve(cx + hShift, cy + vShift, -r, -control, outPath);
+ outPath.rLineTo(0, -vShift - vShift);
+
+ addRightCurve(cx + hShift, cy - vShift, -r, -control, outPath);
+ outPath.close();
+ };
+ }
+ }
+
+ /**
+ * Initializes the shape which is closest to closest to the {@link AdaptiveIconDrawable}
+ */
+ public static void init() {
+ if (!Utilities.ATLEAST_OREO) {
+ return;
+ }
+ new MainThreadExecutor().execute(FolderShape::pickShapeInBackground);
+ }
+
+ @TargetApi(Build.VERSION_CODES.O)
+ protected static void pickShapeInBackground() {
+ // Pick any large size
+ int size = 200;
+
+ Region full = new Region(0, 0, size, size);
+ Region iconR = new Region();
+ AdaptiveIconDrawable drawable = new AdaptiveIconDrawable(
+ new ColorDrawable(Color.BLACK), new ColorDrawable(Color.BLACK));
+ drawable.setBounds(0, 0, size, size);
+ iconR.setPath(drawable.getIconMask(), full);
+
+ Path shapePath = new Path();
+ Region shapeR = new Region();
+ Rect tempRect = new Rect();
+
+ // Find the shape with minimum area of divergent region.
+ int minArea = Integer.MAX_VALUE;
+ FolderShape closestShape = null;
+ for (FolderShape shape : getAllShapes()) {
+ shapePath.reset();
+ shape.addShape(shapePath, 0, 0, size / 2f);
+ shapeR.setPath(shapePath, full);
+ shapeR.op(iconR, Op.XOR);
+
+ RegionIterator itr = new RegionIterator(shapeR);
+ int area = 0;
+
+ while (itr.next(tempRect)) {
+ area += tempRect.width() * tempRect.height();
+ }
+ if (area < minArea) {
+ minArea = area;
+ closestShape = shape;
+ }
+ }
+
+ if (closestShape != null) {
+ FolderShape shape = closestShape;
+ new MainThreadExecutor().execute(() -> updateFolderShape(shape));
+ }
+ }
+
+ private static void updateFolderShape(FolderShape shape) {
+ sInstance = shape;
+ LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+ if (app == null) {
+ return;
+ }
+ Launcher launcher = (Launcher) app.getModel().getCallback();
+ if (launcher != null) {
+ launcher.getWorkspace().mapOverItems(MAP_NO_RECURSE, (i, v) -> {
+ if (v instanceof FolderIcon) {
+ v.invalidate();
+ }
+ return false;
+ });
+ }
+ }
+}
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index 069ec4b..f2683a5 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -16,6 +16,9 @@
package com.android.launcher3.folder;
+import static com.android.launcher3.folder.FolderShape.getShape;
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -30,14 +33,13 @@
import android.graphics.RadialGradient;
import android.graphics.Region;
import android.graphics.Shader;
-import android.support.v4.graphics.ColorUtils;
import android.util.Property;
import android.view.View;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.R;
import com.android.launcher3.util.Themes;
/**
@@ -48,16 +50,6 @@
private static final int CONSUMPTION_ANIMATION_DURATION = 100;
- private final PorterDuffXfermode mClipPorterDuffXfermode
- = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
- // Create a RadialGradient such that it draws a black circle and then extends with
- // transparent. To achieve this, we keep the gradient to black for the range [0, 1) and
- // just at the edge quickly change it to transparent.
- private final RadialGradient mClipShader = new RadialGradient(0, 0, 1,
- new int[] {Color.BLACK, Color.BLACK, Color.TRANSPARENT },
- new float[] {0, 0.999f, 1},
- Shader.TileMode.CLAMP);
-
private final PorterDuffXfermode mShadowPorterDuffXfermode
= new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
private RadialGradient mShadowShader = null;
@@ -70,6 +62,7 @@
float mScale = 1f;
private float mColorMultiplier = 1f;
private int mBgColor;
+ private int mBadgeColor;
private float mStrokeWidth;
private int mStrokeAlpha = MAX_BG_OPACITY;
private int mShadowAlpha = 255;
@@ -132,6 +125,7 @@
int availableSpaceX, int topPadding) {
mInvalidateDelegate = invalidateDelegate;
mBgColor = Themes.getAttrColor(launcher, android.R.attr.colorPrimary);
+ mBadgeColor = Themes.getAttrColor(launcher, R.attr.folderBadgeColor);
DeviceProfile grid = launcher.getDeviceProfile();
previewSize = grid.folderIconSizePx;
@@ -194,19 +188,18 @@
public int getBgColor() {
int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier);
- return ColorUtils.setAlphaComponent(mBgColor, alpha);
+ return setColorAlphaBound(mBgColor, alpha);
}
public int getBadgeColor() {
- return mBgColor;
+ return mBadgeColor;
}
public void drawBackground(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(getBgColor());
- drawCircle(canvas, 0 /* deltaRadius */);
-
+ getShape().drawShape(canvas, getOffsetX(), getOffsetY(), getScaledRadius(), mPaint);
drawShadow(canvas);
}
@@ -241,7 +234,7 @@
mPaint.setShader(null);
if (canvas.isHardwareAccelerated()) {
mPaint.setXfermode(mShadowPorterDuffXfermode);
- canvas.drawCircle(radius + offsetX, radius + offsetY, radius, mPaint);
+ getShape().drawShape(canvas, offsetX, offsetY, radius, mPaint);
mPaint.setXfermode(null);
}
@@ -281,10 +274,13 @@
}
public void drawBackgroundStroke(Canvas canvas) {
- mPaint.setColor(ColorUtils.setAlphaComponent(mBgColor, mStrokeAlpha));
+ mPaint.setColor(setColorAlphaBound(mBgColor, mStrokeAlpha));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mStrokeWidth);
- drawCircle(canvas, 1 /* deltaRadius */);
+
+ float inset = 1f;
+ getShape().drawShape(canvas,
+ getOffsetX() + inset, getOffsetY() + inset, getScaledRadius() - inset, mPaint);
}
public void drawLeaveBehind(Canvas canvas) {
@@ -293,40 +289,17 @@
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.argb(160, 245, 245, 245));
- drawCircle(canvas, 0 /* deltaRadius */);
+ getShape().drawShape(canvas, getOffsetX(), getOffsetY(), getScaledRadius(), mPaint);
mScale = originalScale;
}
- private void drawCircle(Canvas canvas,float deltaRadius) {
- float radius = getScaledRadius();
- canvas.drawCircle(radius + getOffsetX(), radius + getOffsetY(),
- radius - deltaRadius, mPaint);
- }
-
public Path getClipPath() {
mPath.reset();
- float r = getScaledRadius();
- mPath.addCircle(r + getOffsetX(), r + getOffsetY(), r, Path.Direction.CW);
+ getShape().addShape(mPath, getOffsetX(), getOffsetY(), getScaledRadius());
return mPath;
}
- // It is the callers responsibility to save and restore the canvas layers.
- void clipCanvasHardware(Canvas canvas) {
- mPaint.setColor(Color.BLACK);
- mPaint.setStyle(Paint.Style.FILL);
- mPaint.setXfermode(mClipPorterDuffXfermode);
-
- float radius = getScaledRadius();
- mShaderMatrix.setScale(radius, radius);
- mShaderMatrix.postTranslate(radius + getOffsetX(), radius + getOffsetY());
- mClipShader.setLocalMatrix(mShaderMatrix);
- mPaint.setShader(mClipShader);
- canvas.drawPaint(mPaint);
- mPaint.setXfermode(null);
- mPaint.setShader(null);
- }
-
private void delegateDrawing(CellLayout delegate, int cellX, int cellY) {
if (mDrawingDelegate != delegate) {
delegate.addFolderBackground(this);
@@ -365,7 +338,7 @@
mScaleAnimator.cancel();
}
- mScaleAnimator = LauncherAnimUtils.ofFloat(0f, 1.0f);
+ mScaleAnimator = ValueAnimator.ofFloat(0f, 1.0f);
mScaleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
@@ -397,37 +370,19 @@
mScaleAnimator.start();
}
- public void animateToAccept(final CellLayout cl, final int cellX, final int cellY) {
- Runnable onStart = new Runnable() {
- @Override
- public void run() {
- delegateDrawing(cl, cellX, cellY);
- }
- };
- animateScale(ACCEPT_SCALE_FACTOR, ACCEPT_COLOR_MULTIPLIER, onStart, null);
+ public void animateToAccept(CellLayout cl, int cellX, int cellY) {
+ animateScale(ACCEPT_SCALE_FACTOR, ACCEPT_COLOR_MULTIPLIER,
+ () -> delegateDrawing(cl, cellX, cellY), null);
}
public void animateToRest() {
// This can be called multiple times -- we need to make sure the drawing delegate
// is saved and restored at the beginning of the animation, since cancelling the
// existing animation can clear the delgate.
- final CellLayout cl = mDrawingDelegate;
- final int cellX = delegateCellX;
- final int cellY = delegateCellY;
-
- Runnable onStart = new Runnable() {
- @Override
- public void run() {
- delegateDrawing(cl, cellX, cellY);
- }
- };
- Runnable onEnd = new Runnable() {
- @Override
- public void run() {
- clearDrawingDelegate();
- }
- };
- animateScale(1f, 1f, onStart, onEnd);
+ CellLayout cl = mDrawingDelegate;
+ int cellX = delegateCellX;
+ int cellY = delegateCellY;
+ animateScale(1f, 1f, () -> delegateDrawing(cl, cellX, cellY), this::clearDrawingDelegate);
}
public int getBackgroundAlpha() {
diff --git a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
index 607b7ca..c818462 100644
--- a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
+++ b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
@@ -40,8 +40,8 @@
// We ensure the update will not interfere with an animation on the layout params
// If the final values differ, we cancel the animation.
if (anim != null) {
- if (anim.finalTransX == transX || anim.finalTransY == transY
- || anim.finalScale == scale) {
+ if (anim.finalState[1] == transX || anim.finalState[2] == transY
+ || anim.finalState[0] == scale) {
return;
}
anim.cancel();
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index 1f69f6e..0004e1e 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -16,13 +16,17 @@
package com.android.launcher3.folder;
+import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ENTER_INDEX;
+import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.EXIT_INDEX;
+import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
+import static com.android.launcher3.folder.FolderIcon.DROP_IN_ANIMATION_DURATION;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
import android.view.View;
import android.widget.TextView;
@@ -33,10 +37,7 @@
import java.util.ArrayList;
import java.util.List;
-import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ENTER_INDEX;
-import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.EXIT_INDEX;
-import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
-import static com.android.launcher3.folder.FolderIcon.DROP_IN_ANIMATION_DURATION;
+import androidx.annotation.NonNull;
/**
* Manages the drawing and animations of {@link PreviewItemDrawingParams} for a {@link FolderIcon}.
diff --git a/src/com/android/launcher3/graphics/BitmapRenderer.java b/src/com/android/launcher3/graphics/BitmapRenderer.java
deleted file mode 100644
index 3d11c44..0000000
--- a/src/com/android/launcher3/graphics/BitmapRenderer.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2017 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.graphics;
-
-import android.annotation.TargetApi;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Picture;
-import android.os.Build;
-
-import com.android.launcher3.Utilities;
-
-public class BitmapRenderer {
-
- public static final boolean USE_HARDWARE_BITMAP = Utilities.ATLEAST_P;
-
- public static Bitmap createSoftwareBitmap(int width, int height, Renderer renderer) {
- Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- renderer.draw(new Canvas(result));
- return result;
- }
-
- @TargetApi(Build.VERSION_CODES.P)
- public static Bitmap createHardwareBitmap(int width, int height, Renderer renderer) {
- if (!USE_HARDWARE_BITMAP) {
- return createSoftwareBitmap(width, height, renderer);
- }
-
- Picture picture = new Picture();
- renderer.draw(picture.beginRecording(width, height));
- picture.endRecording();
- return Bitmap.createBitmap(picture);
- }
-
- /**
- * Interface representing a bitmap draw operation.
- */
- public interface Renderer {
- void draw(Canvas out);
- }
-}
diff --git a/src/com/android/launcher3/graphics/ColorScrim.java b/src/com/android/launcher3/graphics/ColorScrim.java
deleted file mode 100644
index 96d93d8..0000000
--- a/src/com/android/launcher3/graphics/ColorScrim.java
+++ /dev/null
@@ -1,64 +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.graphics;
-
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.support.v4.graphics.ColorUtils;
-import android.view.View;
-import android.view.animation.Interpolator;
-
-import com.android.launcher3.R;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.uioverrides.WallpaperColorInfo;
-
-/**
- * Simple scrim which draws a color
- */
-public class ColorScrim extends ViewScrim {
-
- private final int mColor;
- private final Interpolator mInterpolator;
- private int mCurrentColor;
-
- public ColorScrim(View view, int color, Interpolator interpolator) {
- super(view);
- mColor = color;
- mInterpolator = interpolator;
- }
-
- @Override
- protected void onProgressChanged() {
- mCurrentColor = ColorUtils.setAlphaComponent(mColor,
- Math.round(mInterpolator.getInterpolation(mProgress) * Color.alpha(mColor)));
- }
-
- @Override
- public void draw(Canvas canvas, int width, int height) {
- if (mProgress > 0) {
- canvas.drawColor(mCurrentColor);
- }
- }
-
- public static ColorScrim createExtractedColorScrim(View view) {
- WallpaperColorInfo colors = WallpaperColorInfo.getInstance(view.getContext());
- int alpha = view.getResources().getInteger(R.integer.extracted_color_gradient_alpha);
- ColorScrim scrim = new ColorScrim(view, ColorUtils.setAlphaComponent(
- colors.getSecondaryColor(), alpha), Interpolators.LINEAR);
- scrim.attach();
- return scrim;
- }
-}
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 5094280..75d3425 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -33,6 +33,7 @@
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.util.UiThreadHelper;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java
index 34a4e2d..ce83a17 100644
--- a/src/com/android/launcher3/graphics/DrawableFactory.java
+++ b/src/com/android/launcher3/graphics/DrawableFactory.java
@@ -24,89 +24,87 @@
import android.graphics.Color;
import android.graphics.Path;
import android.graphics.Rect;
+import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.UiThread;
import android.util.ArrayMap;
-import android.util.Log;
+
import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsBackgroundDrawable;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.ResourceBasedOverride;
+
+import androidx.annotation.UiThread;
/**
* Factory for creating new drawables.
*/
-public class DrawableFactory {
+public class DrawableFactory implements ResourceBasedOverride {
- private static final String TAG = "DrawableFactory";
+ public static final MainThreadInitializedObject<DrawableFactory> INSTANCE =
+ new MainThreadInitializedObject<>(c -> {
+ DrawableFactory factory = Overrides.getObject(DrawableFactory.class,
+ c.getApplicationContext(), R.string.drawable_factory_class);
+ factory.mContext = c;
+ return factory;
+ });
- private static DrawableFactory sInstance;
- private static final Object LOCK = new Object();
+ private Context mContext;
private Path mPreloadProgressPath;
- public static DrawableFactory get(Context context) {
- synchronized (LOCK) {
- if (sInstance == null) {
- sInstance = Utilities.getOverrideObject(DrawableFactory.class,
- context.getApplicationContext(), R.string.drawable_factory_class);
- }
- return sInstance;
- }
- }
-
protected final UserHandle mMyUser = Process.myUserHandle();
protected final ArrayMap<UserHandle, Bitmap> mUserBadges = new ArrayMap<>();
/**
* Returns a FastBitmapDrawable with the icon.
*/
- public FastBitmapDrawable newIcon(ItemInfoWithIcon info) {
- FastBitmapDrawable drawable = new FastBitmapDrawable(info);
+ public FastBitmapDrawable newIcon(Context context, ItemInfoWithIcon info) {
+ FastBitmapDrawable drawable = info.usingLowResIcon()
+ ? new PlaceHolderIconDrawable(info, getPreloadProgressPath(), context)
+ : new FastBitmapDrawable(info);
drawable.setIsDisabled(info.isDisabled());
return drawable;
}
- public FastBitmapDrawable newIcon(BitmapInfo info, ActivityInfo target) {
- return new FastBitmapDrawable(info);
+ public FastBitmapDrawable newIcon(Context context, BitmapInfo info, ActivityInfo target) {
+ return info.isLowRes()
+ ? new PlaceHolderIconDrawable(info, getPreloadProgressPath(), context)
+ : new FastBitmapDrawable(info);
}
/**
* Returns a FastBitmapDrawable with the icon.
*/
- public PreloadIconDrawable newPendingIcon(ItemInfoWithIcon info, Context context) {
- if (mPreloadProgressPath == null) {
- mPreloadProgressPath = getPreloadProgressPath(context);
- }
- return new PreloadIconDrawable(info, mPreloadProgressPath, context);
+ public PreloadIconDrawable newPendingIcon(Context context, ItemInfoWithIcon info) {
+ return new PreloadIconDrawable(info, getPreloadProgressPath(), context);
}
- protected Path getPreloadProgressPath(Context context) {
+ protected Path getPreloadProgressPath() {
+ if (mPreloadProgressPath != null) {
+ return mPreloadProgressPath;
+ }
if (Utilities.ATLEAST_OREO) {
- try {
- // Try to load the path from Mask Icon
- Drawable icon = context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper);
- icon.setBounds(0, 0,
- PreloadIconDrawable.PATH_SIZE, PreloadIconDrawable.PATH_SIZE);
- return (Path) icon.getClass().getMethod("getIconMask").invoke(icon);
- } catch (Exception e) {
- Log.e(TAG, "Error loading mask icon", e);
- }
+ // Load the path from Mask Icon
+ AdaptiveIconDrawable icon = (AdaptiveIconDrawable)
+ mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper);
+ icon.setBounds(0, 0,
+ PreloadIconDrawable.PATH_SIZE, PreloadIconDrawable.PATH_SIZE);
+ mPreloadProgressPath = icon.getIconMask();
+ } else {
+
+ // Create a circle static from top center and going clockwise.
+ Path p = new Path();
+ p.moveTo(PreloadIconDrawable.PATH_SIZE / 2, 0);
+ p.addArc(0, 0, PreloadIconDrawable.PATH_SIZE, PreloadIconDrawable.PATH_SIZE, -90, 360);
+ mPreloadProgressPath = p;
}
-
- // Create a circle static from top center and going clockwise.
- Path p = new Path();
- p.moveTo(PreloadIconDrawable.PATH_SIZE / 2, 0);
- p.addArc(0, 0, PreloadIconDrawable.PATH_SIZE, PreloadIconDrawable.PATH_SIZE, -90, 360);
- return p;
- }
-
- public AllAppsBackgroundDrawable getAllAppsBackground(Context context) {
- return new AllAppsBackgroundDrawable(context);
+ return mPreloadProgressPath;
}
/**
diff --git a/src/com/android/launcher3/graphics/IconPalette.java b/src/com/android/launcher3/graphics/IconPalette.java
index 9c3b77e..3d4a100 100644
--- a/src/com/android/launcher3/graphics/IconPalette.java
+++ b/src/com/android/launcher3/graphics/IconPalette.java
@@ -16,15 +16,18 @@
package com.android.launcher3.graphics;
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
import android.app.Notification;
import android.content.Context;
import android.graphics.Color;
-import android.support.v4.graphics.ColorUtils;
import android.util.Log;
import com.android.launcher3.R;
import com.android.launcher3.util.Themes;
+import androidx.core.graphics.ColorUtils;
+
/**
* Contains colors based on the dominant color of an icon.
*/
@@ -146,7 +149,7 @@
}
public static int getMutedColor(int color, float whiteScrimAlpha) {
- int whiteScrim = ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * whiteScrimAlpha));
+ int whiteScrim = setColorAlphaBound(Color.WHITE, (int) (255 * whiteScrimAlpha));
return ColorUtils.compositeColors(whiteScrim, color);
}
}
diff --git a/src/com/android/launcher3/graphics/IconShapeOverride.java b/src/com/android/launcher3/graphics/IconShapeOverride.java
index 223243b..b636c6d 100644
--- a/src/com/android/launcher3/graphics/IconShapeOverride.java
+++ b/src/com/android/launcher3/graphics/IconShapeOverride.java
@@ -26,11 +26,7 @@
import android.content.res.Resources;
import android.os.Build;
import android.os.SystemClock;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
import android.provider.Settings;
-import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
@@ -42,6 +38,11 @@
import java.lang.reflect.Field;
+import androidx.annotation.NonNull;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.Preference.OnPreferenceChangeListener;
+
/**
* Utility class to override shape of {@link android.graphics.drawable.AdaptiveIconDrawable}.
*/
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
deleted file mode 100644
index f58a6d8..0000000
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.graphics;
-
-import static android.graphics.Paint.DITHER_FLAG;
-import static android.graphics.Paint.FILTER_BITMAP_FLAG;
-
-import static com.android.launcher3.graphics.ShadowGenerator.BLUR_FACTOR;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.Intent.ShortcutIconResource;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.PaintFlagsDrawFilter;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.PaintDrawable;
-import android.os.Build;
-import android.os.Process;
-import android.os.UserHandle;
-import android.support.annotation.Nullable;
-
-import com.android.launcher3.AppInfo;
-import com.android.launcher3.FastBitmapDrawable;
-import com.android.launcher3.IconCache;
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.ItemInfoWithIcon;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.model.PackageItemInfo;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
-import com.android.launcher3.shortcuts.ShortcutInfoCompat;
-import com.android.launcher3.util.Provider;
-import com.android.launcher3.util.Themes;
-
-/**
- * Helper methods for generating various launcher icons
- */
-public class LauncherIcons implements AutoCloseable {
-
- private static final int DEFAULT_WRAPPER_BACKGROUND = Color.WHITE;
-
- public static final Object sPoolSync = new Object();
- private static LauncherIcons sPool;
-
- /**
- * Return a new Message instance from the global pool. Allows us to
- * avoid allocating new objects in many cases.
- */
- public static LauncherIcons obtain(Context context) {
- synchronized (sPoolSync) {
- if (sPool != null) {
- LauncherIcons m = sPool;
- sPool = m.next;
- m.next = null;
- return m;
- }
- }
- return new LauncherIcons(context);
- }
-
- /**
- * Recycles a LauncherIcons that may be in-use.
- */
- public void recycle() {
- synchronized (sPoolSync) {
- // Clear any temporary state variables
- mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
-
- next = sPool;
- sPool = this;
- }
- }
-
- @Override
- public void close() {
- recycle();
- }
-
- private final Rect mOldBounds = new Rect();
- private final Context mContext;
- private final Canvas mCanvas;
- private final PackageManager mPm;
-
- private final int mFillResIconDpi;
- private final int mIconBitmapSize;
-
- private IconNormalizer mNormalizer;
- private ShadowGenerator mShadowGenerator;
-
- private Drawable mWrapperIcon;
- private int mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
-
- // sometimes we store linked lists of these things
- private LauncherIcons next;
-
- private LauncherIcons(Context context) {
- mContext = context.getApplicationContext();
- mPm = mContext.getPackageManager();
-
- InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
- mFillResIconDpi = idp.fillResIconDpi;
- mIconBitmapSize = idp.iconBitmapSize;
-
- mCanvas = new Canvas();
- mCanvas.setDrawFilter(new PaintFlagsDrawFilter(DITHER_FLAG, FILTER_BITMAP_FLAG));
- }
-
- public ShadowGenerator getShadowGenerator() {
- if (mShadowGenerator == null) {
- mShadowGenerator = new ShadowGenerator(mContext);
- }
- return mShadowGenerator;
- }
-
- public IconNormalizer getNormalizer() {
- if (mNormalizer == null) {
- mNormalizer = new IconNormalizer(mContext);
- }
- return mNormalizer;
- }
-
- /**
- * Returns a bitmap suitable for the all apps view. If the package or the resource do not
- * exist, it returns null.
- */
- public BitmapInfo createIconBitmap(ShortcutIconResource iconRes) {
- try {
- Resources resources = mPm.getResourcesForApplication(iconRes.packageName);
- if (resources != null) {
- final int id = resources.getIdentifier(iconRes.resourceName, null, null);
- // do not stamp old legacy shortcuts as the app may have already forgotten about it
- return createBadgedIconBitmap(
- resources.getDrawableForDensity(id, mFillResIconDpi),
- Process.myUserHandle() /* only available on primary user */,
- 0 /* do not apply legacy treatment */);
- }
- } catch (Exception e) {
- // Icon not found.
- }
- return null;
- }
-
- /**
- * Returns a bitmap which is of the appropriate size to be displayed as an icon
- */
- public BitmapInfo createIconBitmap(Bitmap icon) {
- if (mIconBitmapSize == icon.getWidth() && mIconBitmapSize == icon.getHeight()) {
- return BitmapInfo.fromBitmap(icon);
- }
- return BitmapInfo.fromBitmap(
- createIconBitmap(new BitmapDrawable(mContext.getResources(), icon), 1f));
- }
-
- /**
- * Returns a bitmap suitable for displaying as an icon at various launcher UIs like all apps
- * view or workspace. The icon is badged for {@param user}.
- * The bitmap is also visually normalized with other icons.
- */
- public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, int iconAppTargetSdk) {
- return createBadgedIconBitmap(icon, user, iconAppTargetSdk, false, null);
- }
-
- public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, int iconAppTargetSdk,
- boolean isInstantApp) {
- return createBadgedIconBitmap(icon, user, iconAppTargetSdk, isInstantApp, null);
- }
-
- /**
- * Returns a bitmap suitable for displaying as an icon at various launcher UIs like all apps
- * view or workspace. The icon is badged for {@param user}.
- * The bitmap is also visually normalized with other icons.
- */
- public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, int iconAppTargetSdk,
- boolean isInstantApp, float [] scale) {
- if (scale == null) {
- scale = new float[1];
- }
- icon = normalizeAndWrapToAdaptiveIcon(icon, iconAppTargetSdk, null, scale);
- Bitmap bitmap = createIconBitmap(icon, scale[0]);
- if (Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
- mCanvas.setBitmap(bitmap);
- getShadowGenerator().recreateIcon(Bitmap.createBitmap(bitmap), mCanvas);
- mCanvas.setBitmap(null);
- }
-
- final Bitmap result;
- if (user != null && !Process.myUserHandle().equals(user)) {
- BitmapDrawable drawable = new FixedSizeBitmapDrawable(bitmap);
- Drawable badged = mPm.getUserBadgedIcon(drawable, user);
- if (badged instanceof BitmapDrawable) {
- result = ((BitmapDrawable) badged).getBitmap();
- } else {
- result = createIconBitmap(badged, 1f);
- }
- } else if (isInstantApp) {
- badgeWithDrawable(bitmap, mContext.getDrawable(R.drawable.ic_instant_app_badge));
- result = bitmap;
- } else {
- result = bitmap;
- }
- return BitmapInfo.fromBitmap(result);
- }
-
- /**
- * Creates a normalized bitmap suitable for the all apps view. The bitmap is also visually
- * normalized with other icons and has enough spacing to add shadow.
- */
- public Bitmap createScaledBitmapWithoutShadow(Drawable icon, int iconAppTargetSdk) {
- RectF iconBounds = new RectF();
- float[] scale = new float[1];
- icon = normalizeAndWrapToAdaptiveIcon(icon, iconAppTargetSdk, iconBounds, scale);
- return createIconBitmap(icon,
- Math.min(scale[0], ShadowGenerator.getScaleForBounds(iconBounds)));
- }
-
- /**
- * Sets the background color used for wrapped adaptive icon
- */
- public void setWrapperBackgroundColor(int color) {
- mWrapperBackgroundColor = (Color.alpha(color) < 255) ? DEFAULT_WRAPPER_BACKGROUND : color;
- }
-
- private Drawable normalizeAndWrapToAdaptiveIcon(Drawable icon, int iconAppTargetSdk,
- RectF outIconBounds, float[] outScale) {
- float scale = 1f;
- if ((Utilities.ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O) ||
- Utilities.ATLEAST_P) {
- boolean[] outShape = new boolean[1];
- if (mWrapperIcon == null) {
- mWrapperIcon = mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper)
- .mutate();
- }
- AdaptiveIconDrawable dr = (AdaptiveIconDrawable) mWrapperIcon;
- dr.setBounds(0, 0, 1, 1);
- scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape);
- if (Utilities.ATLEAST_OREO && !outShape[0] && !(icon instanceof AdaptiveIconDrawable)) {
- FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground());
- fsd.setDrawable(icon);
- fsd.setScale(scale);
- icon = dr;
- scale = getNormalizer().getScale(icon, outIconBounds, null, null);
-
- ((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor);
- }
- } else {
- scale = getNormalizer().getScale(icon, outIconBounds, null, null);
- }
-
- outScale[0] = scale;
- return icon;
- }
-
- /**
- * Adds the {@param badge} on top of {@param target} using the badge dimensions.
- */
- public void badgeWithDrawable(Bitmap target, Drawable badge) {
- mCanvas.setBitmap(target);
- badgeWithDrawable(mCanvas, badge);
- mCanvas.setBitmap(null);
- }
-
- /**
- * Adds the {@param badge} on top of {@param target} using the badge dimensions.
- */
- private void badgeWithDrawable(Canvas target, Drawable badge) {
- int badgeSize = mContext.getResources().getDimensionPixelSize(R.dimen.profile_badge_size);
- badge.setBounds(mIconBitmapSize - badgeSize, mIconBitmapSize - badgeSize,
- mIconBitmapSize, mIconBitmapSize);
- badge.draw(target);
- }
-
- /**
- * @param scale the scale to apply before drawing {@param icon} on the canvas
- */
- private Bitmap createIconBitmap(Drawable icon, float scale) {
- Bitmap bitmap = Bitmap.createBitmap(mIconBitmapSize, mIconBitmapSize,
- Bitmap.Config.ARGB_8888);
- mCanvas.setBitmap(bitmap);
- mOldBounds.set(icon.getBounds());
-
- if (Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
- int offset = Math.max((int) Math.ceil(BLUR_FACTOR * mIconBitmapSize),
- Math.round(mIconBitmapSize * (1 - scale) / 2 ));
- icon.setBounds(offset, offset, mIconBitmapSize - offset, mIconBitmapSize - offset);
- icon.draw(mCanvas);
- } else {
- if (icon instanceof BitmapDrawable) {
- BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
- Bitmap b = bitmapDrawable.getBitmap();
- if (bitmap != null && b.getDensity() == Bitmap.DENSITY_NONE) {
- bitmapDrawable.setTargetDensity(mContext.getResources().getDisplayMetrics());
- }
- }
- int width = mIconBitmapSize;
- int height = mIconBitmapSize;
-
- int intrinsicWidth = icon.getIntrinsicWidth();
- int intrinsicHeight = icon.getIntrinsicHeight();
- if (intrinsicWidth > 0 && intrinsicHeight > 0) {
- // Scale the icon proportionally to the icon dimensions
- final float ratio = (float) intrinsicWidth / intrinsicHeight;
- if (intrinsicWidth > intrinsicHeight) {
- height = (int) (width / ratio);
- } else if (intrinsicHeight > intrinsicWidth) {
- width = (int) (height * ratio);
- }
- }
- final int left = (mIconBitmapSize - width) / 2;
- final int top = (mIconBitmapSize - height) / 2;
- icon.setBounds(left, top, left + width, top + height);
- mCanvas.save();
- mCanvas.scale(scale, scale, mIconBitmapSize / 2, mIconBitmapSize / 2);
- icon.draw(mCanvas);
- mCanvas.restore();
-
- }
- icon.setBounds(mOldBounds);
- mCanvas.setBitmap(null);
- return bitmap;
- }
-
- public BitmapInfo createShortcutIcon(ShortcutInfoCompat shortcutInfo) {
- return createShortcutIcon(shortcutInfo, true /* badged */);
- }
-
- public BitmapInfo createShortcutIcon(ShortcutInfoCompat shortcutInfo, boolean badged) {
- return createShortcutIcon(shortcutInfo, badged, null);
- }
-
- public BitmapInfo createShortcutIcon(ShortcutInfoCompat shortcutInfo,
- boolean badged, @Nullable Provider<Bitmap> fallbackIconProvider) {
- Drawable unbadgedDrawable = DeepShortcutManager.getInstance(mContext)
- .getShortcutIconDrawable(shortcutInfo, mFillResIconDpi);
- IconCache cache = LauncherAppState.getInstance(mContext).getIconCache();
-
- final Bitmap unbadgedBitmap;
- if (unbadgedDrawable != null) {
- unbadgedBitmap = createScaledBitmapWithoutShadow(unbadgedDrawable, 0);
- } else {
- if (fallbackIconProvider != null) {
- // Fallback icons are already badged and with appropriate shadow
- Bitmap fullIcon = fallbackIconProvider.get();
- if (fullIcon != null) {
- return createIconBitmap(fullIcon);
- }
- }
- unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle()).icon;
- }
-
- BitmapInfo result = new BitmapInfo();
- if (!badged) {
- result.color = Themes.getColorAccent(mContext);
- result.icon = unbadgedBitmap;
- return result;
- }
-
- final Bitmap unbadgedfinal = unbadgedBitmap;
- final ItemInfoWithIcon badge = getShortcutInfoBadge(shortcutInfo, cache);
-
- result.color = badge.iconColor;
- result.icon = BitmapRenderer.createHardwareBitmap(mIconBitmapSize, mIconBitmapSize, (c) -> {
- getShadowGenerator().recreateIcon(unbadgedfinal, c);
- badgeWithDrawable(c, new FastBitmapDrawable(badge));
- });
- return result;
- }
-
- public ItemInfoWithIcon getShortcutInfoBadge(ShortcutInfoCompat shortcutInfo, IconCache cache) {
- ComponentName cn = shortcutInfo.getActivity();
- String badgePkg = shortcutInfo.getBadgePackage(mContext);
- boolean hasBadgePkgSet = !badgePkg.equals(shortcutInfo.getPackage());
- if (cn != null && !hasBadgePkgSet) {
- // Get the app info for the source activity.
- AppInfo appInfo = new AppInfo();
- appInfo.user = shortcutInfo.getUserHandle();
- appInfo.componentName = cn;
- appInfo.intent = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_LAUNCHER)
- .setComponent(cn);
- cache.getTitleAndIcon(appInfo, false);
- return appInfo;
- } else {
- PackageItemInfo pkgInfo = new PackageItemInfo(badgePkg);
- cache.getTitleAndIconForApp(pkgInfo, false);
- return pkgInfo;
- }
- }
-
- /**
- * An extension of {@link BitmapDrawable} which returns the bitmap pixel size as intrinsic size.
- * This allows the badging to be done based on the action bitmap size rather than
- * the scaled bitmap size.
- */
- private static class FixedSizeBitmapDrawable extends BitmapDrawable {
-
- public FixedSizeBitmapDrawable(Bitmap bitmap) {
- super(null, bitmap);
- }
-
- @Override
- public int getIntrinsicHeight() {
- return getBitmap().getWidth();
- }
-
- @Override
- public int getIntrinsicWidth() {
- return getBitmap().getWidth();
- }
- }
-}
diff --git a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
index fc20926..5872689 100644
--- a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
+++ b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
@@ -33,7 +33,9 @@
private final Rect mSrc = new Rect();
private final RectF mDst = new RectF();
- public final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ // Enable filtering to always get a nice edge. This avoids jagged line, when bitmap is
+ // translated by half pixel.
+ public final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
/**
* Draws the bitmap split into three parts horizontally, with the middle part having width
diff --git a/src/com/android/launcher3/graphics/PlaceHolderIconDrawable.java b/src/com/android/launcher3/graphics/PlaceHolderIconDrawable.java
new file mode 100644
index 0000000..5f2fb59
--- /dev/null
+++ b/src/com/android/launcher3/graphics/PlaceHolderIconDrawable.java
@@ -0,0 +1,61 @@
+/*
+ * 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.graphics;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.graphics.Rect;
+
+import com.android.launcher3.FastBitmapDrawable;
+import com.android.launcher3.ItemInfoWithIcon;
+import com.android.launcher3.R;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.util.Themes;
+
+/**
+ * Subclass which draws a placeholder icon when the actual icon is not yet loaded
+ */
+public class PlaceHolderIconDrawable extends FastBitmapDrawable {
+
+ // Path in [0, 100] bounds.
+ private final Path mProgressPath;
+
+ public PlaceHolderIconDrawable(BitmapInfo info, Path progressPath, Context context) {
+ this(info.icon, info.color, progressPath, context);
+ }
+
+ public PlaceHolderIconDrawable(ItemInfoWithIcon info, Path progressPath, Context context) {
+ this(info.iconBitmap, info.iconColor, progressPath, context);
+ }
+
+ protected PlaceHolderIconDrawable(Bitmap b, int iconColor, Path progressPath, Context context) {
+ super(b, iconColor);
+
+ mProgressPath = progressPath;
+ mPaint.setColor(Themes.getAttrColor(context, R.attr.loadingIconColor));
+ }
+
+ @Override
+ protected void drawInternal(Canvas canvas, Rect bounds) {
+ int saveCount = canvas.save();
+ canvas.translate(bounds.left, bounds.top);
+ canvas.scale(bounds.width() / 100f, bounds.height() / 100f);
+ canvas.drawPath(mProgressPath, mPaint);
+ canvas.restoreToCount(saveCount);
+ }
+}
diff --git a/src/com/android/launcher3/graphics/ShadowDrawable.java b/src/com/android/launcher3/graphics/ShadowDrawable.java
index b40bf78..f10b972 100644
--- a/src/com/android/launcher3/graphics/ShadowDrawable.java
+++ b/src/com/android/launcher3/graphics/ShadowDrawable.java
@@ -32,7 +32,7 @@
import android.util.AttributeSet;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
+import com.android.launcher3.icons.BitmapRenderer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -146,7 +146,7 @@
d.draw(canvas);
}
- if (Utilities.ATLEAST_OREO) {
+ if (BitmapRenderer.USE_HARDWARE_BITMAP) {
bitmap = bitmap.copy(Bitmap.Config.HARDWARE, false);
}
mState.mLastDrawnBitmap = bitmap;
diff --git a/src/com/android/launcher3/graphics/TriangleShape.java b/src/com/android/launcher3/graphics/TriangleShape.java
index cce4e3c..2c15725 100644
--- a/src/com/android/launcher3/graphics/TriangleShape.java
+++ b/src/com/android/launcher3/graphics/TriangleShape.java
@@ -19,7 +19,8 @@
import android.graphics.Outline;
import android.graphics.Path;
import android.graphics.drawable.shapes.PathShape;
-import android.support.annotation.NonNull;
+
+import androidx.annotation.NonNull;
/**
* Wrapper around {@link android.graphics.drawable.shapes.PathShape}
diff --git a/src/com/android/launcher3/graphics/ViewScrim.java b/src/com/android/launcher3/graphics/ViewScrim.java
deleted file mode 100644
index e1727e0..0000000
--- a/src/com/android/launcher3/graphics/ViewScrim.java
+++ /dev/null
@@ -1,77 +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.graphics;
-
-import android.graphics.Canvas;
-import android.util.Property;
-import android.view.View;
-import android.view.ViewParent;
-
-import com.android.launcher3.R;
-
-/**
- * A utility class that can be used to draw a scrim behind a view
- */
-public abstract class ViewScrim<T extends View> {
-
- public static Property<ViewScrim, Float> PROGRESS =
- new Property<ViewScrim, Float>(Float.TYPE, "progress") {
- @Override
- public Float get(ViewScrim viewScrim) {
- return viewScrim.mProgress;
- }
-
- @Override
- public void set(ViewScrim object, Float value) {
- object.setProgress(value);
- }
- };
-
- protected final T mView;
- protected float mProgress = 0;
-
- public ViewScrim(T view) {
- mView = view;
- }
-
- public void attach() {
- mView.setTag(R.id.view_scrim, this);
- }
-
- public void setProgress(float progress) {
- if (mProgress != progress) {
- mProgress = progress;
- onProgressChanged();
- invalidate();
- }
- }
-
- public abstract void draw(Canvas canvas, int width, int height);
-
- protected void onProgressChanged() { }
-
- public void invalidate() {
- ViewParent parent = mView.getParent();
- if (parent != null) {
- ((View) parent).invalidate();
- }
- }
-
- public static ViewScrim get(View view) {
- return (ViewScrim) view.getTag(R.id.view_scrim);
- }
-}
diff --git a/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
index bc4a06d..66f9dbf 100644
--- a/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
+++ b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
@@ -19,6 +19,8 @@
import static android.content.Intent.ACTION_SCREEN_OFF;
import static android.content.Intent.ACTION_USER_PRESENT;
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
import android.animation.ObjectAnimator;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -34,7 +36,6 @@
import android.graphics.Region;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
-import android.support.v4.graphics.ColorUtils;
import android.util.DisplayMetrics;
import android.util.Property;
import android.view.View;
@@ -47,6 +48,8 @@
import com.android.launcher3.uioverrides.WallpaperColorInfo;
import com.android.launcher3.util.Themes;
+import androidx.core.graphics.ColorUtils;
+
/**
* View scrim which draws behind hotseat and workspace
*/
@@ -120,7 +123,6 @@
private Workspace mWorkspace;
- private final boolean mHasSysUiScrim;
private boolean mDrawTopScrim, mDrawBottomScrim;
private final RectF mFinalMaskRect = new RectF();
@@ -148,15 +150,9 @@
mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_BITMAP_DP,
view.getResources().getDisplayMetrics());
-
- mHasSysUiScrim = !mWallpaperColorInfo.supportsDarkText();
- if (mHasSysUiScrim) {
- mTopScrim = Themes.getAttrDrawable(view.getContext(), R.attr.workspaceStatusBarScrim);
- mBottomMask = createDitheredAlphaMask();
- } else {
- mTopScrim = null;
- mBottomMask = null;
- }
+ mTopScrim = Themes.getAttrDrawable(view.getContext(), R.attr.workspaceStatusBarScrim);
+ mBottomMask = mTopScrim == null ? null : createDitheredAlphaMask();
+ mHideSysUiScrim = mTopScrim == null;
view.addOnAttachStateChangeListener(this);
onExtractedColorsChanged(mWallpaperColorInfo);
@@ -173,18 +169,18 @@
mWorkspace.computeScrollWithoutInvalidation();
CellLayout currCellLayout = mWorkspace.getCurrentDragOverlappingLayout();
canvas.save();
- if (currCellLayout != null && currCellLayout != mLauncher.getHotseat().getLayout()) {
+ if (currCellLayout != null && currCellLayout != mLauncher.getHotseat()) {
// Cut a hole in the darkening scrim on the page that should be highlighted, if any.
mLauncher.getDragLayer()
.getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect);
canvas.clipRect(mHighlightRect, Region.Op.DIFFERENCE);
}
- canvas.drawColor(ColorUtils.setAlphaComponent(mFullScrimColor, mScrimAlpha));
+ canvas.drawColor(setColorAlphaBound(mFullScrimColor, mScrimAlpha));
canvas.restore();
}
- if (!mHideSysUiScrim && mHasSysUiScrim) {
+ if (!mHideSysUiScrim) {
if (mSysUiProgress <= 0) {
mAnimateScrimOnNextDraw = false;
return;
@@ -212,8 +208,9 @@
}
public void onInsetsChanged(Rect insets) {
- mDrawTopScrim = insets.top > 0;
- mDrawBottomScrim = !mLauncher.getDeviceProfile().isVerticalBarLayout();
+ mDrawTopScrim = mTopScrim != null && insets.top > 0;
+ mDrawBottomScrim = mBottomMask != null &&
+ !mLauncher.getDeviceProfile().isVerticalBarLayout();
}
private void setScrimProgress(float progress) {
@@ -229,7 +226,7 @@
mWallpaperColorInfo.addOnChangeListener(this);
onExtractedColorsChanged(mWallpaperColorInfo);
- if (mHasSysUiScrim) {
+ if (mTopScrim != null) {
IntentFilter filter = new IntentFilter(ACTION_SCREEN_OFF);
filter.addAction(ACTION_USER_PRESENT); // When the device wakes up + keyguard is gone
mRoot.getContext().registerReceiver(mReceiver, filter);
@@ -239,7 +236,7 @@
@Override
public void onViewDetachedFromWindow(View view) {
mWallpaperColorInfo.removeOnChangeListener(this);
- if (mHasSysUiScrim) {
+ if (mTopScrim != null) {
mRoot.getContext().unregisterReceiver(mReceiver);
}
}
@@ -258,14 +255,14 @@
}
public void setSize(int w, int h) {
- if (mHasSysUiScrim) {
+ if (mTopScrim != null) {
mTopScrim.setBounds(0, 0, w, h);
mFinalMaskRect.set(0, h - mMaskHeight, w, h);
}
}
public void hideSysUiScrim(boolean hideSysUiScrim) {
- mHideSysUiScrim = hideSysUiScrim;
+ mHideSysUiScrim = hideSysUiScrim || (mTopScrim == null);
if (!hideSysUiScrim) {
mAnimateScrimOnNextDraw = true;
}
@@ -280,18 +277,18 @@
}
private void reapplySysUiAlpha() {
- if (mHasSysUiScrim) {
- reapplySysUiAlphaNoInvalidate();
- if (!mHideSysUiScrim) {
- invalidate();
- }
+ reapplySysUiAlphaNoInvalidate();
+ if (!mHideSysUiScrim) {
+ invalidate();
}
}
private void reapplySysUiAlphaNoInvalidate() {
float factor = mSysUiProgress * mSysUiAnimMultiplier;
mBottomMaskPaint.setAlpha(Math.round(MAX_HOTSEAT_SCRIM_ALPHA * factor));
- mTopScrim.setAlpha(Math.round(255 * factor));
+ if (mTopScrim != null) {
+ mTopScrim.setAlpha(Math.round(255 * factor));
+ }
}
public void invalidate() {
@@ -308,7 +305,7 @@
LinearGradient lg = new LinearGradient(0, 0, 0, gradientHeight,
new int[]{
0x00FFFFFF,
- ColorUtils.setAlphaComponent(Color.WHITE, (int) (0xFF * 0.95)),
+ setColorAlphaBound(Color.WHITE, (int) (0xFF * 0.95)),
0xFFFFFFFF},
new float[]{0f, 0.8f, 1f},
Shader.TileMode.CLAMP);
diff --git a/src/com/android/launcher3/icons/ComponentWithLabel.java b/src/com/android/launcher3/icons/ComponentWithLabel.java
new file mode 100644
index 0000000..46b5002
--- /dev/null
+++ b/src/com/android/launcher3/icons/ComponentWithLabel.java
@@ -0,0 +1,64 @@
+/*
+ * 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.icons;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+
+import com.android.launcher3.icons.cache.CachingLogic;
+
+public interface ComponentWithLabel {
+
+ ComponentName getComponent();
+
+ UserHandle getUser();
+
+ CharSequence getLabel(PackageManager pm);
+
+
+ class ComponentCachingLogic implements CachingLogic<ComponentWithLabel> {
+
+ private final PackageManager mPackageManager;
+
+ public ComponentCachingLogic(Context context) {
+ mPackageManager = context.getPackageManager();
+ }
+
+ @Override
+ public ComponentName getComponent(ComponentWithLabel object) {
+ return object.getComponent();
+ }
+
+ @Override
+ public UserHandle getUser(ComponentWithLabel object) {
+ return object.getUser();
+ }
+
+ @Override
+ public CharSequence getLabel(ComponentWithLabel object) {
+ return object.getLabel(mPackageManager);
+ }
+
+ @Override
+ public void loadIcon(Context context,
+ ComponentWithLabel object, BitmapInfo target) {
+ // Do not load icon.
+ target.icon = BitmapInfo.LOW_RES_ICON;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
new file mode 100644
index 0000000..4b54bc3
--- /dev/null
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2008 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.icons;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.IconProvider;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.ItemInfoWithIcon;
+import com.android.launcher3.LauncherFiles;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
+import com.android.launcher3.icons.cache.BaseIconCache;
+import com.android.launcher3.icons.cache.CachingLogic;
+import com.android.launcher3.icons.cache.HandlerRunnable;
+import com.android.launcher3.model.PackageItemInfo;
+import com.android.launcher3.util.InstantAppResolver;
+import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.Provider;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Cache of application icons. Icons can be made from any thread.
+ */
+public class IconCache extends BaseIconCache {
+
+ private static final String TAG = "Launcher.IconCache";
+
+ private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
+
+ private final CachingLogic<ComponentWithLabel> mComponentWithLabelCachingLogic;
+ private final CachingLogic<LauncherActivityInfo> mLauncherActivityInfoCachingLogic;
+
+ private final LauncherAppsCompat mLauncherApps;
+ private final UserManagerCompat mUserManager;
+ private final InstantAppResolver mInstantAppResolver;
+ private final IconProvider mIconProvider;
+
+ private int mPendingIconRequestCount = 0;
+
+ public IconCache(Context context, InvariantDeviceProfile inv) {
+ super(context, LauncherFiles.APP_ICONS_DB, LauncherModel.getWorkerLooper(),
+ inv.fillResIconDpi, inv.iconBitmapSize, true /* inMemoryCache */);
+ mComponentWithLabelCachingLogic = new ComponentCachingLogic(context);
+ mLauncherActivityInfoCachingLogic = new LauncherActivtiyCachingLogic(this);
+ mLauncherApps = LauncherAppsCompat.getInstance(mContext);
+ mUserManager = UserManagerCompat.getInstance(mContext);
+ mInstantAppResolver = InstantAppResolver.newInstance(mContext);
+ mIconProvider = IconProvider.newInstance(context);
+ }
+
+ @Override
+ protected long getSerialNumberForUser(UserHandle user) {
+ return mUserManager.getSerialNumberForUser(user);
+ }
+
+ @Override
+ protected boolean isInstantApp(ApplicationInfo info) {
+ return mInstantAppResolver.isInstantApp(info);
+ }
+
+ @Override
+ protected BaseIconFactory getIconFactory() {
+ return LauncherIcons.obtain(mContext);
+ }
+
+ /**
+ * Updates the entries related to the given package in memory and persistent DB.
+ */
+ public synchronized void updateIconsForPkg(String packageName, UserHandle user) {
+ removeIconsForPkg(packageName, user);
+ try {
+ PackageInfo info = mPackageManager.getPackageInfo(packageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ long userSerial = mUserManager.getSerialNumberForUser(user);
+ for (LauncherActivityInfo app : mLauncherApps.getActivityList(packageName, user)) {
+ addIconToDBAndMemCache(app, mLauncherActivityInfoCachingLogic, info, userSerial,
+ false /*replace existing*/);
+ }
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, "Package not found", e);
+ }
+ }
+
+ /**
+ * Fetches high-res icon for the provided ItemInfo and updates the caller when done.
+ * @return a request ID that can be used to cancel the request.
+ */
+ public IconLoadRequest updateIconInBackground(final ItemInfoUpdateReceiver caller,
+ final ItemInfoWithIcon info) {
+ Preconditions.assertUIThread();
+ if (mPendingIconRequestCount <= 0) {
+ LauncherModel.setWorkerPriority(Process.THREAD_PRIORITY_FOREGROUND);
+ }
+ mPendingIconRequestCount ++;
+
+ IconLoadRequest request = new IconLoadRequest(mWorkerHandler, this::onIconRequestEnd) {
+ @Override
+ public void run() {
+ if (info instanceof AppInfo || info instanceof ShortcutInfo) {
+ getTitleAndIcon(info, false);
+ } else if (info instanceof PackageItemInfo) {
+ getTitleAndIconForApp((PackageItemInfo) info, false);
+ }
+ mMainThreadExecutor.execute(() -> {
+ caller.reapplyItemInfo(info);
+ onEnd();
+ });
+ }
+ };
+ Utilities.postAsyncCallback(mWorkerHandler, request);
+ return request;
+ }
+
+ private void onIconRequestEnd() {
+ mPendingIconRequestCount --;
+ if (mPendingIconRequestCount <= 0) {
+ LauncherModel.setWorkerPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ }
+ }
+
+ /**
+ * Updates {@param application} only if a valid entry is found.
+ */
+ public synchronized void updateTitleAndIcon(AppInfo application) {
+ CacheEntry entry = cacheLocked(application.componentName,
+ application.user, Provider.of(null), mLauncherActivityInfoCachingLogic,
+ false, application.usingLowResIcon());
+ if (entry.icon != null && !isDefaultIcon(entry.icon, application.user)) {
+ applyCacheEntry(entry, application);
+ }
+ }
+
+ /**
+ * Fill in {@param info} with the icon and label for {@param activityInfo}
+ */
+ public synchronized void getTitleAndIcon(ItemInfoWithIcon info,
+ LauncherActivityInfo activityInfo, boolean useLowResIcon) {
+ // If we already have activity info, no need to use package icon
+ getTitleAndIcon(info, Provider.of(activityInfo), false, useLowResIcon);
+ }
+
+ /**
+ * Fill in {@param info} with the icon and label. If the
+ * corresponding activity is not found, it reverts to the package icon.
+ */
+ public synchronized void getTitleAndIcon(ItemInfoWithIcon info, boolean useLowResIcon) {
+ // null info means not installed, but if we have a component from the intent then
+ // we should still look in the cache for restored app icons.
+ if (info.getTargetComponent() == null) {
+ info.applyFrom(getDefaultIcon(info.user));
+ info.title = "";
+ info.contentDescription = "";
+ } else {
+ Intent intent = info.getIntent();
+ getTitleAndIcon(info, () -> mLauncherApps.resolveActivity(intent, info.user),
+ true, useLowResIcon);
+ }
+ }
+
+ public synchronized String getTitleNoCache(ComponentWithLabel info) {
+ CacheEntry entry = cacheLocked(info.getComponent(), info.getUser(), Provider.of(info),
+ mComponentWithLabelCachingLogic, false /* usePackageIcon */,
+ true /* useLowResIcon */, false /* addToMemCache */);
+ return Utilities.trim(entry.title);
+ }
+
+ /**
+ * Fill in {@param shortcutInfo} with the icon and label for {@param info}
+ */
+ private synchronized void getTitleAndIcon(
+ @NonNull ItemInfoWithIcon infoInOut,
+ @NonNull Provider<LauncherActivityInfo> activityInfoProvider,
+ boolean usePkgIcon, boolean useLowResIcon) {
+ CacheEntry entry = cacheLocked(infoInOut.getTargetComponent(), infoInOut.user,
+ activityInfoProvider, mLauncherActivityInfoCachingLogic, usePkgIcon, useLowResIcon);
+ applyCacheEntry(entry, infoInOut);
+ }
+
+
+ /**
+ * Fill in {@param infoInOut} with the corresponding icon and label.
+ */
+ public synchronized void getTitleAndIconForApp(
+ PackageItemInfo infoInOut, boolean useLowResIcon) {
+ CacheEntry entry = getEntryForPackageLocked(
+ infoInOut.packageName, infoInOut.user, useLowResIcon);
+ applyCacheEntry(entry, infoInOut);
+ }
+
+ protected void applyCacheEntry(CacheEntry entry, ItemInfoWithIcon info) {
+ info.title = Utilities.trim(entry.title);
+ info.contentDescription = entry.contentDescription;
+ info.applyFrom((entry.icon == null) ? getDefaultIcon(info.user) : entry);
+ }
+
+ public Drawable getFullResIcon(LauncherActivityInfo info) {
+ return getFullResIcon(info, true);
+ }
+
+ public Drawable getFullResIcon(LauncherActivityInfo info, boolean flattenDrawable) {
+ return mIconProvider.getIcon(info, mIconDpi, flattenDrawable);
+ }
+
+ @Override
+ protected String getIconSystemState(String packageName) {
+ return mIconProvider.getSystemStateForPackage(mSystemState, packageName);
+ }
+
+ public static abstract class IconLoadRequest extends HandlerRunnable {
+ IconLoadRequest(Handler handler, Runnable endRunnable) {
+ super(handler, endRunnable);
+ }
+ }
+
+ /**
+ * Interface for receiving itemInfo with high-res icon.
+ */
+ public interface ItemInfoUpdateReceiver {
+
+ void reapplyItemInfo(ItemInfoWithIcon info);
+ }
+}
diff --git a/src/com/android/launcher3/icons/LauncherActivtiyCachingLogic.java b/src/com/android/launcher3/icons/LauncherActivtiyCachingLogic.java
new file mode 100644
index 0000000..7c99633
--- /dev/null
+++ b/src/com/android/launcher3/icons/LauncherActivtiyCachingLogic.java
@@ -0,0 +1,56 @@
+/*
+ * 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.icons;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.LauncherActivityInfo;
+import android.os.UserHandle;
+
+import com.android.launcher3.icons.cache.CachingLogic;
+
+public class LauncherActivtiyCachingLogic implements CachingLogic<LauncherActivityInfo> {
+
+ private final IconCache mCache;
+
+ public LauncherActivtiyCachingLogic(IconCache cache) {
+ mCache = cache;
+ }
+
+ @Override
+ public ComponentName getComponent(LauncherActivityInfo object) {
+ return object.getComponentName();
+ }
+
+ @Override
+ public UserHandle getUser(LauncherActivityInfo object) {
+ return object.getUser();
+ }
+
+ @Override
+ public CharSequence getLabel(LauncherActivityInfo object) {
+ return object.getLabel();
+ }
+
+ @Override
+ public void loadIcon(Context context, LauncherActivityInfo object,
+ BitmapInfo target) {
+ LauncherIcons li = LauncherIcons.obtain(context);
+ li.createBadgedIconBitmap(mCache.getFullResIcon(object),
+ object.getUser(), object.getApplicationInfo().targetSdkVersion).applyTo(target);
+ li.recycle();
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
new file mode 100644
index 0000000..4b869cf
--- /dev/null
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.icons;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.os.Process;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.FastBitmapDrawable;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.ItemInfoWithIcon;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.model.PackageItemInfo;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.util.Provider;
+import com.android.launcher3.util.Themes;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
+ * that are threadsafe.
+ */
+public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
+
+ private static final Object sPoolSync = new Object();
+ private static LauncherIcons sPool;
+ private static int sPoolId = 0;
+
+ /**
+ * Return a new Message instance from the global pool. Allows us to
+ * avoid allocating new objects in many cases.
+ */
+ public static LauncherIcons obtain(Context context) {
+ int poolId;
+ synchronized (sPoolSync) {
+ if (sPool != null) {
+ LauncherIcons m = sPool;
+ sPool = m.next;
+ m.next = null;
+ return m;
+ }
+ poolId = sPoolId;
+ }
+
+ InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
+ return new LauncherIcons(context, idp.fillResIconDpi, idp.iconBitmapSize, poolId);
+ }
+
+ public static void clearPool() {
+ synchronized (sPoolSync) {
+ sPool = null;
+ sPoolId++;
+ }
+ }
+
+ private final int mPoolId;
+
+ private LauncherIcons next;
+
+ private LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) {
+ super(context, fillResIconDpi, iconBitmapSize);
+ mPoolId = poolId;
+ }
+
+ /**
+ * Recycles a LauncherIcons that may be in-use.
+ */
+ public void recycle() {
+ synchronized (sPoolSync) {
+ if (sPoolId != mPoolId) {
+ return;
+ }
+ // Clear any temporary state variables
+ clear();
+
+ next = sPool;
+ sPool = this;
+ }
+ }
+
+ @Override
+ public void close() {
+ recycle();
+ }
+
+ // below methods should also migrate to BaseIconFactory
+
+ public BitmapInfo createShortcutIcon(ShortcutInfoCompat shortcutInfo) {
+ return createShortcutIcon(shortcutInfo, true /* badged */);
+ }
+
+ public BitmapInfo createShortcutIcon(ShortcutInfoCompat shortcutInfo, boolean badged) {
+ return createShortcutIcon(shortcutInfo, badged, null);
+ }
+
+ public BitmapInfo createShortcutIcon(ShortcutInfoCompat shortcutInfo,
+ boolean badged, @Nullable Provider<Bitmap> fallbackIconProvider) {
+ Drawable unbadgedDrawable = DeepShortcutManager.getInstance(mContext)
+ .getShortcutIconDrawable(shortcutInfo, mFillResIconDpi);
+ IconCache cache = LauncherAppState.getInstance(mContext).getIconCache();
+
+ final Bitmap unbadgedBitmap;
+ if (unbadgedDrawable != null) {
+ unbadgedBitmap = createScaledBitmapWithoutShadow(unbadgedDrawable, 0);
+ } else {
+ if (fallbackIconProvider != null) {
+ // Fallback icons are already badged and with appropriate shadow
+ Bitmap fullIcon = fallbackIconProvider.get();
+ if (fullIcon != null) {
+ return createIconBitmap(fullIcon);
+ }
+ }
+ unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle()).icon;
+ }
+
+ BitmapInfo result = new BitmapInfo();
+ if (!badged) {
+ result.color = Themes.getColorAccent(mContext);
+ result.icon = unbadgedBitmap;
+ return result;
+ }
+
+ final Bitmap unbadgedfinal = unbadgedBitmap;
+ final ItemInfoWithIcon badge = getShortcutInfoBadge(shortcutInfo, cache);
+
+ result.color = badge.iconColor;
+ result.icon = BitmapRenderer.createHardwareBitmap(mIconBitmapSize, mIconBitmapSize, (c) -> {
+ getShadowGenerator().recreateIcon(unbadgedfinal, c);
+ badgeWithDrawable(c, new FastBitmapDrawable(badge));
+ });
+ return result;
+ }
+
+ public ItemInfoWithIcon getShortcutInfoBadge(ShortcutInfoCompat shortcutInfo, IconCache cache) {
+ ComponentName cn = shortcutInfo.getActivity();
+ String badgePkg = shortcutInfo.getBadgePackage(mContext);
+ boolean hasBadgePkgSet = !badgePkg.equals(shortcutInfo.getPackage());
+ if (cn != null && !hasBadgePkgSet) {
+ // Get the app info for the source activity.
+ AppInfo appInfo = new AppInfo();
+ appInfo.user = shortcutInfo.getUserHandle();
+ appInfo.componentName = cn;
+ appInfo.intent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setComponent(cn);
+ cache.getTitleAndIcon(appInfo, false);
+ return appInfo;
+ } else {
+ PackageItemInfo pkgInfo = new PackageItemInfo(badgePkg);
+ cache.getTitleAndIconForApp(pkgInfo, false);
+ return pkgInfo;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/keyboard/FocusedItemDecorator.java b/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
index 05ae406..2476a6f 100644
--- a/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
+++ b/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
@@ -17,14 +17,15 @@
package com.android.launcher3.keyboard;
import android.graphics.Canvas;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.ItemDecoration;
-import android.support.v7.widget.RecyclerView.State;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.ItemDecoration;
+import androidx.recyclerview.widget.RecyclerView.State;
+
/**
* {@link ItemDecoration} for drawing and animating focused view background.
*/
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index 83593aa..4ef8626 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -40,6 +40,7 @@
/**
* Helper methods for logging.
*/
+@Deprecated
public class LoggerUtils {
private static final ArrayMap<Class, SparseArray<String>> sNameCache = new ArrayMap<>();
private static final String UNKNOWN = "UNKNOWN";
@@ -144,7 +145,7 @@
}
public static Target newItemTarget(View v, InstantAppResolver instantAppResolver) {
- return (v.getTag() instanceof ItemInfo)
+ return (v != null) && (v.getTag() instanceof ItemInfo)
? newItemTarget((ItemInfo) v.getTag(), instantAppResolver)
: newTarget(Target.Type.ITEM);
}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
new file mode 100644
index 0000000..9b9543e
--- /dev/null
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -0,0 +1,44 @@
+/*
+ * 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.logging;
+
+import android.content.Context;
+import android.content.Intent;
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.logging.StatsLogUtils.LogStateProvider;
+
+/**
+ * Handles the user event logging in Q.
+ */
+public class StatsLogManager implements ResourceBasedOverride {
+
+ protected LogStateProvider mStateProvider;
+ public static StatsLogManager newInstance(Context context, LogStateProvider stateProvider) {
+ StatsLogManager mgr = Overrides.getObject(StatsLogManager.class,
+ context.getApplicationContext(), R.string.stats_log_manager_class);
+ mgr.mStateProvider = stateProvider;
+ mgr.verify();
+ return mgr;
+ }
+
+ public void logAppLaunch(View v, Intent intent) { }
+ public void logTaskLaunch(View v, ComponentKey key) { }
+ public void verify() {} // TODO: should move into robo tests
+}
diff --git a/src/com/android/launcher3/logging/StatsLogUtils.java b/src/com/android/launcher3/logging/StatsLogUtils.java
new file mode 100644
index 0000000..647f255
--- /dev/null
+++ b/src/com/android/launcher3/logging/StatsLogUtils.java
@@ -0,0 +1,67 @@
+package com.android.launcher3.logging;
+
+import android.view.View;
+import android.view.ViewParent;
+
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+
+import androidx.annotation.Nullable;
+
+
+public class StatsLogUtils {
+
+ // Defined in android.stats.launcher.nano
+ // As they cannot be linked in this file, defining again.
+ public final static int LAUNCHER_STATE_BACKGROUND = 0;
+ public final static int LAUNCHER_STATE_HOME = 1;
+ public final static int LAUNCHER_STATE_OVERVIEW = 2;
+ public final static int LAUNCHER_STATE_ALLAPPS = 3;
+
+ private final static int MAXIMUM_VIEW_HIERARCHY_LEVEL = 5;
+
+ public interface LogStateProvider {
+ int getCurrentState();
+ }
+
+ /**
+ * Implemented by containers to provide a container source for a given child.
+ *
+ * Currently,
+ */
+ public interface LogContainerProvider {
+
+ /**
+ * Copies data from the source to the destination proto.
+ *
+ * @param v source of the data
+ * @param info source of the data
+ * @param target dest of the data
+ * @param targetParent dest of the data
+ */
+ void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent);
+ }
+
+ /**
+ * Recursively finds the parent of the given child which implements IconLogInfoProvider
+ */
+ public static LogContainerProvider getLaunchProviderRecursive(@Nullable View v) {
+ ViewParent parent;
+ if (v != null) {
+ parent = v.getParent();
+ } else {
+ return null;
+ }
+
+ // Optimization to only check up to 5 parents.
+ int count = MAXIMUM_VIEW_HIERARCHY_LEVEL;
+ while (parent != null && count-- > 0) {
+ if (parent instanceof LogContainerProvider) {
+ return (LogContainerProvider) parent;
+ } else {
+ parent = parent.getParent();
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index d1e1051..e115168 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -32,45 +32,45 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.SystemClock;
-import android.support.annotation.Nullable;
import android.util.Log;
import android.view.View;
import android.view.ViewParent;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DropTarget;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.util.LogConfig;
+import com.android.launcher3.util.ResourceBasedOverride;
import java.util.Locale;
import java.util.UUID;
+import androidx.annotation.Nullable;
+
/**
* Manages the creation of {@link LauncherEvent}.
* To debug this class, execute following command before side loading a new apk.
*
* $ adb shell setprop log.tag.UserEvent VERBOSE
*/
-public class UserEventDispatcher {
-
- private final static int MAXIMUM_VIEW_HIERARCHY_LEVEL = 5;
+@Deprecated
+public class UserEventDispatcher implements ResourceBasedOverride {
private static final String TAG = "UserEvent";
private static final boolean IS_VERBOSE =
FeatureFlags.IS_DOGFOOD_BUILD && Utilities.isPropertyEnabled(LogConfig.USEREVENT);
private static final String UUID_STORAGE = "uuid";
- public static UserEventDispatcher newInstance(Context context, DeviceProfile dp,
+ public static UserEventDispatcher newInstance(Context context,
UserEventDelegate delegate) {
SharedPreferences sharedPrefs = Utilities.getDevicePrefs(context);
String uuidStr = sharedPrefs.getString(UUID_STORAGE, null);
@@ -78,18 +78,16 @@
uuidStr = UUID.randomUUID().toString();
sharedPrefs.edit().putString(UUID_STORAGE, uuidStr).apply();
}
- UserEventDispatcher ued = Utilities.getOverrideObject(UserEventDispatcher.class,
+ UserEventDispatcher ued = Overrides.getObject(UserEventDispatcher.class,
context.getApplicationContext(), R.string.user_event_dispatcher_class);
ued.mDelegate = delegate;
- ued.mIsInLandscapeMode = dp.isVerticalBarLayout();
- ued.mIsInMultiWindowMode = dp.isMultiWindowMode;
ued.mUuidStr = uuidStr;
ued.mInstantAppResolver = InstantAppResolver.newInstance(context);
return ued;
}
- public static UserEventDispatcher newInstance(Context context, DeviceProfile dp) {
- return newInstance(context, dp, null);
+ public static UserEventDispatcher newInstance(Context context) {
+ return newInstance(context, null);
}
public interface UserEventDelegate {
@@ -97,50 +95,25 @@
}
/**
- * Implemented by containers to provide a container source for a given child.
+ * Fills in the container data on the given event if the given view is not null.
+ * @return whether container data was added.
*/
- public interface LogContainerProvider {
-
- /**
- * Copies data from the source to the destination proto.
- *
- * @param v source of the data
- * @param info source of the data
- * @param target dest of the data
- * @param targetParent dest of the data
- */
- void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent);
- }
-
- /**
- * Recursively finds the parent of the given child which implements IconLogInfoProvider
- */
- public static LogContainerProvider getLaunchProviderRecursive(@Nullable View v) {
- ViewParent parent;
- if (v != null) {
- parent = v.getParent();
- } else {
- return null;
+ @Deprecated
+ public static boolean fillInLogContainerData(LauncherLogProto.LauncherEvent event, @Nullable View v) {
+ // Fill in grid(x,y), pageIndex of the child and container type of the parent
+ LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(v);
+ if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) {
+ return false;
}
-
- // Optimization to only check up to 5 parents.
- int count = MAXIMUM_VIEW_HIERARCHY_LEVEL;
- while (parent != null && count-- > 0) {
- if (parent instanceof LogContainerProvider) {
- return (LogContainerProvider) parent;
- } else {
- parent = parent.getParent();
- }
- }
- return null;
+ ItemInfo itemInfo = (ItemInfo) v.getTag();
+ provider.fillInLogContainerData(v, itemInfo, event.srcTarget[0], event.srcTarget[1]);
+ return true;
}
private boolean mSessionStarted;
private long mElapsedContainerMillis;
private long mElapsedSessionMillis;
private long mActionDurationMillis;
- private boolean mIsInMultiWindowMode;
- private boolean mIsInLandscapeMode;
private String mUuidStr;
protected InstantAppResolver mInstantAppResolver;
private boolean mAppOrTaskLaunch;
@@ -153,21 +126,7 @@
// intentHash required
// --------------------------------------------------------------
- /**
- * Fills in the container data on the given event if the given view is not null.
- * @return whether container data was added.
- */
- protected boolean fillInLogContainerData(LauncherEvent event, @Nullable View v) {
- // Fill in grid(x,y), pageIndex of the child and container type of the parent
- LogContainerProvider provider = getLaunchProviderRecursive(v);
- if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) {
- return false;
- }
- ItemInfo itemInfo = (ItemInfo) v.getTag();
- provider.fillInLogContainerData(v, itemInfo, event.srcTarget[0], event.srcTarget[1]);
- return true;
- }
-
+ @Deprecated
public void logAppLaunch(View v, Intent intent) {
LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP),
newItemTarget(v, mInstantAppResolver), newTarget(Target.Type.CONTAINER));
@@ -184,6 +143,7 @@
public void logActionTip(int actionType, int viewType) { }
+ @Deprecated
public void logTaskLaunchOrDismiss(int action, int direction, int taskIndex,
ComponentKey componentKey) {
LauncherEvent event = newLauncherEvent(newTouchAction(action), // TAP or SWIPE or FLING
@@ -366,7 +326,7 @@
}
public void logDeepShortcutsOpen(View icon) {
- LogContainerProvider provider = getLaunchProviderRecursive(icon);
+ LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(icon);
if (icon == null || !(icon.getTag() instanceof ItemInfo)) {
return;
}
@@ -379,15 +339,6 @@
resetElapsedContainerMillis("deep shortcut open");
}
- /* Currently we are only interested in whether this event happens or not and don't
- * care about which screen moves to where. */
- public void logOverviewReorder() {
- LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.DRAGDROP),
- newContainerTarget(ContainerType.WORKSPACE),
- newContainerTarget(ContainerType.OVERVIEW));
- dispatchUserEvent(event, null);
- }
-
public void logDragNDrop(DropTarget.DragObject dragObj, View dropTargetAsView) {
LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.DRAGDROP),
newItemTarget(dragObj.originalDragInfo, mInstantAppResolver),
@@ -434,8 +385,6 @@
public void dispatchUserEvent(LauncherEvent ev, Intent intent) {
mAppOrTaskLaunch = false;
- ev.isInLandscapeMode = mIsInLandscapeMode;
- ev.isInMultiWindowMode = mIsInMultiWindowMode;
ev.elapsedContainerMillis = SystemClock.uptimeMillis() - mElapsedContainerMillis;
ev.elapsedSessionMillis = SystemClock.uptimeMillis() - mElapsedSessionMillis;
@@ -455,8 +404,6 @@
ev.elapsedContainerMillis,
ev.elapsedSessionMillis,
ev.actionDurationMillis);
- log += "\n isInLandscapeMode " + ev.isInLandscapeMode;
- log += "\n isInMultiWindowMode " + ev.isInMultiWindowMode;
log += "\n\n";
Log.d(TAG, log);
}
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index fefe07d..756d44e 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -34,6 +34,8 @@
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.GridOccupancy;
+import com.android.launcher3.util.IntArray;
+
import java.util.ArrayList;
import java.util.List;
@@ -59,12 +61,12 @@
Context context = app.getContext();
final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
- final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<>();
+ final IntArray addedWorkspaceScreensFinal = new IntArray();
// Get the list of workspace screens. We need to append to this list and
// can not use sBgWorkspaceScreens because loadWorkspace() may not have been
// called.
- ArrayList<Long> workspaceScreens = LauncherModel.loadWorkspaceScreensDb(context);
+ IntArray workspaceScreens = LauncherModel.loadWorkspaceScreensDb(context);
synchronized(dataModel) {
List<ItemInfo> filteredItems = new ArrayList<>();
@@ -90,10 +92,9 @@
for (ItemInfo item : filteredItems) {
// Find appropriate space for the item.
- Pair<Long, int[]> coords = findSpaceForItem(app, dataModel, workspaceScreens,
+ int[] coords = findSpaceForItem(app, dataModel, workspaceScreens,
addedWorkspaceScreensFinal, item.spanX, item.spanY);
- long screenId = coords.first;
- int[] cordinates = coords.second;
+ int screenId = coords[0];
ItemInfo itemInfo;
if (item instanceof ShortcutInfo || item instanceof FolderInfo ||
@@ -108,7 +109,7 @@
// Add the shortcut to the db
getModelWriter().addItemToDatabase(itemInfo,
LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId,
- cordinates[0], cordinates[1]);
+ coords[1], coords[2]);
// Save the ShortcutInfo for binding in the workspace
addedItemsFinal.add(itemInfo);
@@ -126,7 +127,7 @@
final ArrayList<ItemInfo> addNotAnimated = new ArrayList<>();
if (!addedItemsFinal.isEmpty()) {
ItemInfo info = addedItemsFinal.get(addedItemsFinal.size() - 1);
- long lastScreenId = info.screenId;
+ int lastScreenId = info.screenId;
for (ItemInfo i : addedItemsFinal) {
if (i.screenId == lastScreenId) {
addAnimated.add(i);
@@ -142,7 +143,7 @@
}
}
- protected void updateScreens(Context context, ArrayList<Long> workspaceScreens) {
+ protected void updateScreens(Context context, IntArray workspaceScreens) {
LauncherModel.updateWorkspaceScreenOrder(context, workspaceScreens);
}
@@ -204,13 +205,10 @@
/**
* Find a position on the screen for the given size or adds a new screen.
- * @return screenId and the coordinates for the item.
+ * @return screenId and the coordinates for the item in an int array of size 3.
*/
- protected Pair<Long, int[]> findSpaceForItem(
- LauncherAppState app, BgDataModel dataModel,
- ArrayList<Long> workspaceScreens,
- ArrayList<Long> addedWorkspaceScreensFinal,
- int spanX, int spanY) {
+ protected int[] findSpaceForItem( LauncherAppState app, BgDataModel dataModel,
+ IntArray workspaceScreens, IntArray addedWorkspaceScreensFinal, int spanX, int spanY) {
LongSparseArray<ArrayList<ItemInfo>> screenItems = new LongSparseArray<>();
// Use sBgItemsIdMap as all the items are already loaded.
@@ -228,7 +226,7 @@
}
// Find appropriate space for the item.
- long screenId = 0;
+ int screenId = 0;
int[] cordinates = new int[2];
boolean found = false;
@@ -258,7 +256,7 @@
// Still no position found. Add a new screen to the end.
screenId = LauncherSettings.Settings.call(app.getContext().getContentResolver(),
LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
- .getLong(LauncherSettings.Settings.EXTRA_VALUE);
+ .getInt(LauncherSettings.Settings.EXTRA_VALUE);
// Save the screen id for binding in the workspace
workspaceScreens.add(screenId);
@@ -270,7 +268,7 @@
throw new RuntimeException("Can't find space to add the item");
}
}
- return Pair.create(screenId, cordinates);
+ return new int[] {screenId, cordinates[0], cordinates[1]};
}
private boolean findNextAvailableIconSpaceInScreen(
diff --git a/src/com/android/launcher3/model/LoaderResults.java b/src/com/android/launcher3/model/BaseLoaderResults.java
similarity index 79%
rename from src/com/android/launcher3/model/LoaderResults.java
rename to src/com/android/launcher3/model/BaseLoaderResults.java
index 0fd9b73..d3dc91f 100644
--- a/src/com/android/launcher3/model/LoaderResults.java
+++ b/src/com/android/launcher3/model/BaseLoaderResults.java
@@ -29,49 +29,45 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.PagedView;
-import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.LooperIdleLock;
-import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.ViewOnDrawExecutor;
-import com.android.launcher3.widget.WidgetListRowEntry;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashSet;
import java.util.Iterator;
-import java.util.Set;
import java.util.concurrent.Executor;
/**
- * Helper class to handle results of {@link com.android.launcher3.model.LoaderTask}.
+ * Base Helper class to handle results of {@link com.android.launcher3.model.LoaderTask}.
*/
-public class LoaderResults {
+public abstract class BaseLoaderResults {
- private static final String TAG = "LoaderResults";
- private static final long INVALID_SCREEN_ID = -1L;
+ protected static final String TAG = "LoaderResults";
+ protected static final int INVALID_SCREEN_ID = -1;
private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
- private final Executor mUiExecutor;
+ protected final Executor mUiExecutor;
- private final LauncherAppState mApp;
- private final BgDataModel mBgDataModel;
+ protected final LauncherAppState mApp;
+ protected final BgDataModel mBgDataModel;
private final AllAppsList mBgAllAppsList;
- private final int mPageToBindFirst;
+ protected final int mPageToBindFirst;
- private final WeakReference<Callbacks> mCallbacks;
+ protected final WeakReference<Callbacks> mCallbacks;
- public LoaderResults(LauncherAppState app, BgDataModel dataModel,
+ public BaseLoaderResults(LauncherAppState app, BgDataModel dataModel,
AllAppsList allAppsList, int pageToBindFirst, WeakReference<Callbacks> callbacks) {
mUiExecutor = new MainThreadExecutor();
mApp = app;
mBgDataModel = dataModel;
mBgAllAppsList = allAppsList;
mPageToBindFirst = pageToBindFirst;
- mCallbacks = callbacks == null ? new WeakReference<Callbacks>(null) : callbacks;
+ mCallbacks = callbacks == null ? new WeakReference<>(null) : callbacks;
}
/**
@@ -92,7 +88,7 @@
// Save a copy of all the bg-thread collections
ArrayList<ItemInfo> workspaceItems = new ArrayList<>();
ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>();
- final ArrayList<Long> orderedScreenIds = new ArrayList<>();
+ final IntArray orderedScreenIds = new IntArray();
synchronized (mBgDataModel) {
workspaceItems.addAll(mBgDataModel.workspaceItems);
@@ -112,7 +108,7 @@
currentScreen = currScreen;
}
final boolean validFirstPage = currentScreen >= 0;
- final long currentScreenId =
+ final int currentScreenId =
validFirstPage ? orderedScreenIds.get(currentScreen) : INVALID_SCREEN_ID;
// Separate the items that are on the current screen, and all the other remaining items
@@ -153,8 +149,8 @@
Executor mainExecutor = mUiExecutor;
// Load items on the current page.
- bindWorkspaceItems(currentWorkspaceItems, currentAppWidgets, mainExecutor);
-
+ bindWorkspaceItems(currentWorkspaceItems, mainExecutor);
+ bindAppWidgets(currentAppWidgets, mainExecutor);
// In case of validFirstPage, only bind the first screen, and defer binding the
// remaining screens after first onDraw (and an optional the fade animation whichever
// happens later).
@@ -174,14 +170,14 @@
}
});
- bindWorkspaceItems(otherWorkspaceItems, otherAppWidgets, deferredExecutor);
-
+ bindWorkspaceItems(otherWorkspaceItems, deferredExecutor);
+ bindAppWidgets(otherAppWidgets, deferredExecutor);
// Tell the workspace that we're done binding items
r = new Runnable() {
public void run() {
Callbacks callbacks = mCallbacks.get();
if (callbacks != null) {
- callbacks.finishBindingItems();
+ callbacks.finishBindingItems(currentScreen);
}
}
};
@@ -209,7 +205,7 @@
/** Filters the set of items who are directly or indirectly (via another container) on the
* specified screen. */
- public static <T extends ItemInfo> void filterCurrentWorkspaceItems(long currentScreenId,
+ public static <T extends ItemInfo> void filterCurrentWorkspaceItems(int currentScreenId,
ArrayList<T> allWorkspaceItems,
ArrayList<T> currentScreenItems,
ArrayList<T> otherScreenItems) {
@@ -225,13 +221,10 @@
// Order the set of items by their containers first, this allows use to walk through the
// list sequentially, build up a list of containers that are in the specified screen,
// as well as all items in those containers.
- Set<Long> itemsOnScreen = new HashSet<>();
- Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {
- @Override
- public int compare(ItemInfo lhs, ItemInfo rhs) {
- return Utilities.longCompare(lhs.container, rhs.container);
- }
- });
+ IntSet itemsOnScreen = new IntSet();
+ Collections.sort(allWorkspaceItems,
+ (lhs, rhs) -> Integer.compare(lhs.container, rhs.container));
+
for (T info : allWorkspaceItems) {
if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
if (info.screenId == currentScreenId) {
@@ -256,7 +249,7 @@
/** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to
* right) */
- private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {
+ protected void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {
final InvariantDeviceProfile profile = mApp.getInvariantDeviceProfile();
final int screenCols = profile.numColumns;
final int screenCellCount = profile.numColumns * profile.numRows;
@@ -267,15 +260,15 @@
// Within containers, order by their spatial position in that container
switch ((int) lhs.container) {
case LauncherSettings.Favorites.CONTAINER_DESKTOP: {
- long lr = (lhs.screenId * screenCellCount +
+ int lr = (lhs.screenId * screenCellCount +
lhs.cellY * screenCols + lhs.cellX);
- long rr = (rhs.screenId * screenCellCount +
+ int rr = (rhs.screenId * screenCellCount +
rhs.cellY * screenCols + rhs.cellX);
- return Utilities.longCompare(lr, rr);
+ return Integer.compare(lr, rr);
}
case LauncherSettings.Favorites.CONTAINER_HOTSEAT: {
// We currently use the screen id as the rank
- return Utilities.longCompare(lhs.screenId, rhs.screenId);
+ return Integer.compare(lhs.screenId, rhs.screenId);
}
default:
if (FeatureFlags.IS_DOGFOOD_BUILD) {
@@ -286,16 +279,19 @@
}
} else {
// Between containers, order by hotseat, desktop
- return Utilities.longCompare(lhs.container, rhs.container);
+ return Integer.compare(lhs.container, rhs.container);
}
}
});
}
- private void bindWorkspaceItems(final ArrayList<ItemInfo> workspaceItems,
- final ArrayList<LauncherAppWidgetInfo> appWidgets,
+ protected void bindWorkspaceItems(final ArrayList<ItemInfo> workspaceItems,
final Executor executor) {
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ Log.d("b/117332845", Log.getStackTraceString(new Throwable()));
+ }
// Bind the workspace items
int N = workspaceItems.size();
for (int i = 0; i < N; i += ITEMS_CHUNK) {
@@ -306,22 +302,25 @@
public void run() {
Callbacks callbacks = mCallbacks.get();
if (callbacks != null) {
- callbacks.bindItems(workspaceItems.subList(start, start+chunkSize), false);
+ callbacks.bindItems(workspaceItems.subList(start, start + chunkSize),
+ false);
}
}
};
executor.execute(r);
}
+ }
- // Bind the widgets, one at a time
+ private void bindAppWidgets(ArrayList<LauncherAppWidgetInfo> appWidgets, Executor executor) {
+ int N;// Bind the widgets, one at a time
N = appWidgets.size();
for (int i = 0; i < N; i++) {
final ItemInfo widget = appWidgets.get(i);
final Runnable r = new Runnable() {
public void run() {
- Callbacks callbacks = mCallbacks.get();
- if (callbacks != null) {
- callbacks.bindItems(Collections.singletonList(widget), false);
+ Callbacks callbacks = mCallbacks.get();
+ if (callbacks != null) {
+ callbacks.bindItems(Collections.singletonList(widget), false);
}
}
};
@@ -329,22 +328,7 @@
}
}
- public void bindDeepShortcuts() {
- final MultiHashMap<ComponentKey, String> shortcutMapCopy;
- synchronized (mBgDataModel) {
- shortcutMapCopy = mBgDataModel.deepShortcutMap.clone();
- }
- Runnable r = new Runnable() {
- @Override
- public void run() {
- Callbacks callbacks = mCallbacks.get();
- if (callbacks != null) {
- callbacks.bindDeepShortcutMap(shortcutMapCopy);
- }
- }
- };
- mUiExecutor.execute(r);
- }
+ public abstract void bindDeepShortcuts();
public void bindAllApps() {
// shallow copy
@@ -362,19 +346,7 @@
mUiExecutor.execute(r);
}
- public void bindWidgets() {
- final ArrayList<WidgetListRowEntry> widgets =
- mBgDataModel.widgetsModel.getWidgetsList(mApp.getContext());
- Runnable r = new Runnable() {
- public void run() {
- Callbacks callbacks = mCallbacks.get();
- if (callbacks != null) {
- callbacks.bindAllWidgets(widgets);
- }
- }
- };
- mUiExecutor.execute(r);
- }
+ public abstract void bindWidgets();
public LooperIdleLock newIdleLock(Object lock) {
LooperIdleLock idleLock = new LooperIdleLock(lock, Looper.getMainLooper());
diff --git a/src/com/android/launcher3/model/BaseModelUpdateTask.java b/src/com/android/launcher3/model/BaseModelUpdateTask.java
index fcdc088..c9d8e3e 100644
--- a/src/com/android/launcher3/model/BaseModelUpdateTask.java
+++ b/src/com/android/launcher3/model/BaseModelUpdateTask.java
@@ -27,10 +27,10 @@
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.widget.WidgetListRowEntry;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.concurrent.Executor;
/**
@@ -107,13 +107,9 @@
}
public void bindDeepShortcuts(BgDataModel dataModel) {
- final MultiHashMap<ComponentKey, String> shortcutMapCopy = dataModel.deepShortcutMap.clone();
- scheduleCallbackTask(new CallbackTask() {
- @Override
- public void execute(Callbacks callbacks) {
- callbacks.bindDeepShortcutMap(shortcutMapCopy);
- }
- });
+ final HashMap<ComponentKey, Integer> shortcutMapCopy =
+ new HashMap<>(dataModel.deepShortcutMap);
+ scheduleCallbackTask(callbacks -> callbacks.bindDeepShortcutMap(shortcutMapCopy));
}
public void bindUpdatedWidgets(BgDataModel dataModel) {
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index fff1e69..151d6f4 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -36,8 +36,8 @@
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.LongArrayMap;
-import com.android.launcher3.util.MultiHashMap;
+import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSparseArrayMap;
import com.google.protobuf.nano.MessageNano;
import java.io.FileDescriptor;
@@ -62,7 +62,7 @@
* Map of all the ItemInfos (shortcuts, folders, and widgets) created by
* LauncherModel to their ids
*/
- public final LongArrayMap<ItemInfo> itemsIdMap = new LongArrayMap<>();
+ public final IntSparseArrayMap<ItemInfo> itemsIdMap = new IntSparseArrayMap<>();
/**
* List of all the folders and shortcuts directly on the home screen (no widgets
@@ -78,12 +78,12 @@
/**
* Map of id to FolderInfos of all the folders created by LauncherModel
*/
- public final LongArrayMap<FolderInfo> folders = new LongArrayMap<>();
+ public final IntSparseArrayMap<FolderInfo> folders = new IntSparseArrayMap<>();
/**
* Ordered list of workspace screens ids.
*/
- public final ArrayList<Long> workspaceScreens = new ArrayList<>();
+ public final IntArray workspaceScreens = new IntArray();
/**
* Map of ShortcutKey to the number of times it is pinned.
@@ -96,9 +96,9 @@
public boolean hasShortcutHostPermission;
/**
- * Maps all launcher activities to the id's of their shortcuts (if they have any).
+ * Maps all launcher activities to counts of their shortcuts.
*/
- public final MultiHashMap<ComponentKey, String> deepShortcutMap = new MultiHashMap<>();
+ public final HashMap<ComponentKey, Integer> deepShortcutMap = new HashMap<>();
/**
* Entire list of widgets.
@@ -132,7 +132,7 @@
writer.println(prefix + "Data Model:");
writer.print(prefix + " ---- workspace screens: ");
for (int i = 0; i < workspaceScreens.size(); i++) {
- writer.print(" " + workspaceScreens.get(i).toString());
+ writer.print(" " + workspaceScreens.get(i));
}
writer.println();
writer.println(prefix + " ---- workspace items ");
@@ -153,14 +153,11 @@
}
if (args.length > 0 && TextUtils.equals(args[0], "--all")) {
- writer.println(prefix + "shortcuts");
- for (ArrayList<String> map : deepShortcutMap.values()) {
- writer.print(prefix + " ");
- for (String str : map) {
- writer.print(str + ", ");
- }
- writer.println();
+ writer.println(prefix + "shortcut counts ");
+ for (Integer count : deepShortcutMap.values()) {
+ writer.print(count + ", ");
}
+ writer.println();
}
}
@@ -169,7 +166,7 @@
// Add top parent nodes. (L1)
DumpTargetWrapper hotseat = new DumpTargetWrapper(ContainerType.HOTSEAT, 0);
- LongArrayMap<DumpTargetWrapper> workspaces = new LongArrayMap<>();
+ IntSparseArrayMap<DumpTargetWrapper> workspaces = new IntSparseArrayMap<>();
for (int i = 0; i < workspaceScreens.size(); i++) {
workspaces.put(workspaceScreens.get(i),
new DumpTargetWrapper(ContainerType.WORKSPACE, i));
@@ -346,7 +343,7 @@
* Return an existing FolderInfo object if we have encountered this ID previously,
* or make a new one.
*/
- public synchronized FolderInfo findOrMakeFolder(long id) {
+ public synchronized FolderInfo findOrMakeFolder(int id) {
// See if a placeholder was created for us already
FolderInfo folderInfo = folders.get(id);
if (folderInfo == null) {
@@ -358,9 +355,9 @@
}
/**
- * Clear all the deep shortcuts for the given package, and re-add the new shortcuts.
+ * Clear all the deep shortcut counts for the given package, and re-add the new shortcut counts.
*/
- public synchronized void updateDeepShortcutMap(
+ public synchronized void updateDeepShortcutCounts(
String packageName, UserHandle user, List<ShortcutInfoCompat> shortcuts) {
if (packageName != null) {
Iterator<ComponentKey> keysIter = deepShortcutMap.keySet().iterator();
@@ -380,7 +377,9 @@
if (shouldShowInContainer) {
ComponentKey targetComponent
= new ComponentKey(shortcut.getActivity(), shortcut.getUserHandle());
- deepShortcutMap.addToList(targetComponent, shortcut.getId());
+
+ Integer previousCount = deepShortcutMap.get(targetComponent);
+ deepShortcutMap.put(targetComponent, previousCount == null ? 1 : previousCount + 1);
}
}
}
diff --git a/src/com/android/launcher3/model/CacheDataUpdatedTask.java b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
index 0139bd9..be83d36 100644
--- a/src/com/android/launcher3/model/CacheDataUpdatedTask.java
+++ b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
@@ -20,7 +20,7 @@
import com.android.launcher3.AllAppsList;
import com.android.launcher3.AppInfo;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel.CallbackTask;
@@ -64,7 +64,7 @@
if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
&& isValidShortcut(si) && cn != null
&& mPackages.contains(cn.getPackageName())) {
- iconCache.getTitleAndIcon(si, si.usingLowResIcon);
+ iconCache.getTitleAndIcon(si, si.usingLowResIcon());
updatedShortcuts.add(si);
}
}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index d9b1a3f..2c1aa74 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -11,8 +11,8 @@
import android.database.Cursor;
import android.graphics.Point;
import android.net.Uri;
-import android.text.TextUtils;
import android.util.Log;
+
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
@@ -27,7 +27,9 @@
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.GridOccupancy;
-import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSparseArrayMap;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@@ -59,7 +61,7 @@
private final InvariantDeviceProfile mIdp;
private final ContentValues mTempValues = new ContentValues();
- protected final ArrayList<Long> mEntryToRemove = new ArrayList<>();
+ protected final IntArray mEntryToRemove = new IntArray();
private final ArrayList<ContentProviderOperation> mUpdateOperations = new ArrayList<>();
protected final ArrayList<DbEntry> mCarryOver = new ArrayList<>();
private final HashSet<String> mValidPackages;
@@ -108,6 +110,7 @@
/**
* Applied all the pending DB operations
+ *
* @return true if any DB operation was commited.
*/
private boolean applyOperations() throws Exception {
@@ -118,7 +121,7 @@
if (!mEntryToRemove.isEmpty()) {
if (DEBUG) {
- Log.d(TAG, "Removing items: " + TextUtils.join(", ", mEntryToRemove));
+ Log.d(TAG, "Removing items: " + mEntryToRemove.toConcatString());
}
mContext.getContentResolver().delete(LauncherSettings.Favorites.CONTENT_URI,
Utilities.createDbSelectionQuery(
@@ -134,14 +137,12 @@
* entries is more than what can fit in the new hotseat, we drop the entries with least weight.
* For weight calculation {@see #WT_SHORTCUT}, {@see #WT_APPLICATION}
* & {@see #WT_FOLDER_FACTOR}.
+ *
* @return true if any DB change was made
*/
protected boolean migrateHotseat() throws Exception {
ArrayList<DbEntry> items = loadHotseatEntries();
-
- int requiredCount = FeatureFlags.NO_ALL_APPS_ICON ? mDestHotseatSize : mDestHotseatSize - 1;
-
- while (items.size() > requiredCount) {
+ while (items.size() > mDestHotseatSize) {
// Pick the center item by default.
DbEntry toRemove = items.get(items.size() / 2);
@@ -171,9 +172,6 @@
}
newScreenId++;
- if (!FeatureFlags.NO_ALL_APPS_ICON && mIdp.isAllAppsButtonRank(newScreenId)) {
- newScreenId++;
- }
}
return applyOperations();
@@ -183,12 +181,13 @@
* @return true if any DB change was made
*/
protected boolean migrateWorkspace() throws Exception {
- ArrayList<Long> allScreens = LauncherModel.loadWorkspaceScreensDb(mContext);
+ IntArray allScreens = LauncherModel.loadWorkspaceScreensDb(mContext);
if (allScreens.isEmpty()) {
throw new Exception("Unable to get workspace screens");
}
- for (long screenId : allScreens) {
+ for (int i = 0; i < allScreens.size(); i++) {
+ int screenId = allScreens.get(i);
if (DEBUG) {
Log.d(TAG, "Migrating " + screenId);
}
@@ -196,7 +195,7 @@
}
if (!mCarryOver.isEmpty()) {
- LongArrayMap<DbEntry> itemMap = new LongArrayMap<>();
+ IntSparseArrayMap<DbEntry> itemMap = new IntSparseArrayMap<>();
for (DbEntry e : mCarryOver) {
itemMap.put(e.id, e);
}
@@ -211,10 +210,10 @@
new GridOccupancy(mTrgX, mTrgY), deepCopy(mCarryOver), 0, true);
placement.find();
if (placement.finalPlacedItems.size() > 0) {
- long newScreenId = LauncherSettings.Settings.call(
+ int newScreenId = LauncherSettings.Settings.call(
mContext.getContentResolver(),
LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
- .getLong(LauncherSettings.Settings.EXTRA_VALUE);
+ .getInt(LauncherSettings.Settings.EXTRA_VALUE);
allScreens.add(newScreenId);
for (DbEntry item : placement.finalPlacedItems) {
@@ -236,10 +235,11 @@
int count = allScreens.size();
for (int i = 0; i < count; i++) {
ContentValues v = new ContentValues();
- long screenId = allScreens.get(i);
+ int screenId = allScreens.get(i);
v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
- mUpdateOperations.add(ContentProviderOperation.newInsert(uri).withValues(v).build());
+ mUpdateOperations.add(ContentProviderOperation.newInsert(uri).withValues(
+ v).build());
}
}
return applyOperations();
@@ -255,9 +255,10 @@
* 3) If all those items from the above list can be placed on this screen, place them
* (otherwise they are placed on a new screen).
*/
- protected void migrateScreen(long screenId) {
+ protected void migrateScreen(int screenId) {
// If we are migrating the first screen, do not touch the first row.
- int startY = (FeatureFlags.QSB_ON_FIRST_SCREEN && screenId == Workspace.FIRST_SCREEN_ID)
+ int startY =
+ (FeatureFlags.QSB_ON_FIRST_SCREEN.get() && screenId == Workspace.FIRST_SCREEN_ID)
? 1 : 0;
ArrayList<DbEntry> items = loadWorkspaceEntries(screenId);
@@ -282,9 +283,11 @@
for (int y = mSrcY - 1; y >= startY; y--) {
// Use a deep copy when trying out a particular combination as it can change
// the underlying object.
- ArrayList<DbEntry> itemsOnScreen = tryRemove(x, y, startY, deepCopy(items), outLoss);
+ ArrayList<DbEntry> itemsOnScreen = tryRemove(x, y, startY, deepCopy(items),
+ outLoss);
- if ((outLoss[0] < removeWt) || ((outLoss[0] == removeWt) && (outLoss[1] < moveWt))) {
+ if ((outLoss[0] < removeWt) || ((outLoss[0] == removeWt) && (outLoss[1]
+ < moveWt))) {
removeWt = outLoss[0];
moveWt = outLoss[1];
removedCol = mShouldRemoveX ? x : removedCol;
@@ -308,7 +311,7 @@
removedRow, removedCol, screenId));
}
- LongArrayMap<DbEntry> itemMap = new LongArrayMap<>();
+ IntSparseArrayMap<DbEntry> itemMap = new IntSparseArrayMap<>();
for (DbEntry e : deepCopy(items)) {
itemMap.put(e.id, e);
}
@@ -365,6 +368,7 @@
/**
* Tries the remove the provided row and column.
+ *
* @param items all the items on the screen under operation
* @param outLoss array of size 2. The first entry is filled with weight loss, and the second
* with the overall item movement.
@@ -440,6 +444,7 @@
/**
* Recursively finds a placement for the provided items.
+ *
* @param index the position in {@link #itemsToPlace} to start looking at.
* @param weightLoss total weight loss upto this point
* @param moveCost total move cost upto this point
@@ -552,7 +557,8 @@
for (int x = 0; x < mTrgX; x++) {
if (!occupied.cells[x][y]) {
int dist = ignoreMove ? 0 :
- ((me.cellX - x) * (me.cellX - x) + (me.cellY - y) * (me.cellY - y));
+ ((me.cellX - x) * (me.cellX - x) + (me.cellY - y) * (me.cellY
+ - y));
if (dist < newDistance) {
newX = x;
newY = y;
@@ -619,9 +625,9 @@
ArrayList<DbEntry> entries = new ArrayList<>();
while (c.moveToNext()) {
DbEntry entry = new DbEntry();
- entry.id = c.getLong(indexId);
+ entry.id = c.getInt(indexId);
entry.itemType = c.getInt(indexItemType);
- entry.screenId = c.getLong(indexScreen);
+ entry.screenId = c.getInt(indexScreen);
if (entry.screenId >= mSrcHotseatSize) {
mEntryToRemove.add(entry.id);
@@ -667,7 +673,7 @@
/**
* Loads entries for a particular screen id.
*/
- protected ArrayList<DbEntry> loadWorkspaceEntries(long screen) {
+ protected ArrayList<DbEntry> loadWorkspaceEntries(int screen) {
Cursor c = queryWorkspace(
new String[]{
Favorites._ID, // 0
@@ -695,7 +701,7 @@
ArrayList<DbEntry> entries = new ArrayList<>();
while (c.moveToNext()) {
DbEntry entry = new DbEntry();
- entry.id = c.getLong(indexId);
+ entry.id = c.getInt(indexId);
entry.itemType = c.getInt(indexItemType);
entry.cellX = c.getInt(indexCellX);
entry.cellY = c.getInt(indexCellY);
@@ -768,7 +774,7 @@
/**
* @return the number of valid items in the folder.
*/
- private int getFolderItemsCount(long folderId) {
+ private int getFolderItemsCount(int folderId) {
Cursor c = queryWorkspace(
new String[]{Favorites._ID, Favorites.INTENT},
Favorites.CONTAINER + " = " + folderId);
@@ -779,7 +785,7 @@
verifyIntent(c.getString(1));
total++;
} catch (Exception e) {
- mEntryToRemove.add(c.getLong(0));
+ mEntryToRemove.add(c.getInt(0));
}
}
c.close();
@@ -817,7 +823,8 @@
public float weight;
- public DbEntry() { }
+ public DbEntry() {
+ }
public DbEntry copy() {
DbEntry entry = new DbEntry();
@@ -889,6 +896,7 @@
/**
* Migrates the workspace and hotseat in case their sizes changed.
+ *
* @return false if the migration failed.
*/
public static boolean migrateGridIfNeeded(Context context) {
@@ -898,7 +906,8 @@
String gridSizeString = getPointString(idp.numColumns, idp.numRows);
if (gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, "")) &&
- idp.numHotseatIcons == prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)) {
+ idp.numHotseatIcons == prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT,
+ idp.numHotseatIcons)) {
// Skip if workspace and hotseat sizes have not changed.
return true;
}
@@ -909,7 +918,8 @@
HashSet<String> validPackages = getValidPackages(context);
// Hotseat
- int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons);
+ int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT,
+ idp.numHotseatIcons);
if (srcHotseatCount != idp.numHotseatIcons) {
// Migrate hotseat.
@@ -922,7 +932,8 @@
Point sourceSize = parsePoint(prefs.getString(
KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString));
- if (new MultiStepMigrationTask(validPackages, context).migrate(sourceSize, targetSize)) {
+ if (new MultiStepMigrationTask(validPackages, context).migrate(sourceSize,
+ targetSize)) {
dbChanged = true;
}
@@ -972,9 +983,11 @@
/**
* Removes any broken item from the hotseat.
+ *
* @return a map with occupied hotseat position set to non-null value.
*/
- public static LongArrayMap<Object> removeBrokenHotseatItems(Context context) throws Exception {
+ public static IntSparseArrayMap<Object> removeBrokenHotseatItems(Context context)
+ throws Exception {
GridSizeMigrationTask task = new GridSizeMigrationTask(
context, LauncherAppState.getIDP(context), getValidPackages(context),
Integer.MAX_VALUE, Integer.MAX_VALUE);
@@ -983,7 +996,7 @@
ArrayList<DbEntry> items = task.loadHotseatEntries();
// Delete any entry marked for deletion by above load.
task.applyOperations();
- LongArrayMap<Object> positions = new LongArrayMap<>();
+ IntSparseArrayMap<Object> positions = new IntSparseArrayMap<>();
for (DbEntry item : items) {
positions.put(item.screenId, item);
}
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 6378ea1..3aeb1c0 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -22,9 +22,9 @@
import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
import android.content.pm.LauncherActivityInfo;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.CursorWrapper;
-import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.UserHandle;
import android.provider.BaseColumns;
@@ -33,7 +33,7 @@
import android.util.LongSparseArray;
import com.android.launcher3.AppInfo;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
@@ -42,18 +42,17 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.graphics.BitmapInfo;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.GridOccupancy;
-import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSparseArrayMap;
import java.net.URISyntaxException;
import java.security.InvalidParameterException;
-import java.util.ArrayList;
/**
* Extension of {@link Cursor} with utility methods for workspace loading.
@@ -65,13 +64,13 @@
public final LongSparseArray<UserHandle> allUsers = new LongSparseArray<>();
private final Context mContext;
- private final UserManagerCompat mUserManager;
+ private final PackageManager mPM;
private final IconCache mIconCache;
private final InvariantDeviceProfile mIDP;
- private final ArrayList<Long> itemsToRemove = new ArrayList<>();
- private final ArrayList<Long> restoredRows = new ArrayList<>();
- private final LongArrayMap<GridOccupancy> occupied = new LongArrayMap<>();
+ private final IntArray itemsToRemove = new IntArray();
+ private final IntArray restoredRows = new IntArray();
+ private final IntSparseArrayMap<GridOccupancy> occupied = new IntSparseArrayMap<>();
private final int iconPackageIndex;
private final int iconResourceIndex;
@@ -91,8 +90,8 @@
// Properties loaded per iteration
public long serialNumber;
public UserHandle user;
- public long id;
- public long container;
+ public int id;
+ public int container;
public int itemType;
public int restoreFlag;
@@ -101,7 +100,7 @@
mContext = app.getContext();
mIconCache = app.getIconCache();
mIDP = app.getInvariantDeviceProfile();
- mUserManager = UserManagerCompat.getInstance(mContext);
+ mPM = mContext.getPackageManager();
// Init column indices
iconIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
@@ -127,7 +126,7 @@
// Load common properties.
itemType = getInt(itemTypeIndex);
container = getInt(containerIndex);
- id = getLong(idIndex);
+ id = getInt(idIndex);
serialNumber = getInt(profileIdIndex);
user = allUsers.get(serialNumber);
restoreFlag = getInt(restoredIndex);
@@ -154,7 +153,7 @@
info.title = getTitle();
// the fallback icon
if (!loadIcon(info)) {
- mIconCache.getDefaultIcon(info.user).applyTo(info);
+ info.applyFrom(mIconCache.getDefaultIcon(info.user));
}
// TODO: If there's an explicit component and we can't install that, delete it.
@@ -177,7 +176,7 @@
BitmapInfo iconInfo = li.createIconBitmap(info.iconResource);
li.recycle();
if (iconInfo != null) {
- iconInfo.applyTo(info);
+ info.applyFrom(iconInfo);
return true;
}
}
@@ -186,7 +185,7 @@
// Failed to load from resource, try loading from DB.
byte[] data = getBlob(iconIndex);
try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
- li.createIconBitmap(BitmapFactory.decodeByteArray(data, 0, data.length)).applyTo(info);
+ info.applyFrom(li.createIconBitmap(BitmapFactory.decodeByteArray(data, 0, data.length)));
return true;
} catch (Exception e) {
Log.e(TAG, "Failed to load icon for info " + info, e);
@@ -229,7 +228,7 @@
throw new InvalidParameterException("Invalid restoreType " + restoreFlag);
}
- info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);
+ info.contentDescription = mPM.getUserBadgedLabel(info.title, info.user);
info.itemType = itemType;
info.status = restoreFlag;
return info;
@@ -285,7 +284,7 @@
info.title = componentName.getClassName();
}
- info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);
+ info.contentDescription = mPM.getUserBadgedLabel(info.title, info.user);
return info;
}
@@ -294,7 +293,7 @@
*/
public ContentWriter updater() {
return new ContentWriter(mContext, new ContentWriter.CommitParams(
- BaseColumns._ID + "= ?", new String[]{Long.toString(id)}));
+ BaseColumns._ID + "= ?", new String[]{Integer.toString(id)}));
}
/**
@@ -384,20 +383,11 @@
/**
* check & update map of what's occupied; used to discard overlapping/invalid items
*/
- protected boolean checkItemPlacement(ItemInfo item, ArrayList<Long> workspaceScreens) {
- long containerIndex = item.screenId;
+ protected boolean checkItemPlacement(ItemInfo item, IntArray workspaceScreens) {
+ int containerIndex = item.screenId;
if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- // Return early if we detect that an item is under the hotseat button
- if (!FeatureFlags.NO_ALL_APPS_ICON &&
- mIDP.isAllAppsButtonRank((int) item.screenId)) {
- Log.e(TAG, "Error loading shortcut into hotseat " + item
- + " into position (" + item.screenId + ":" + item.cellX + ","
- + item.cellY + ") occupied by all apps");
- return false;
- }
-
final GridOccupancy hotseatOccupancy =
- occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);
+ occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT);
if (item.screenId >= mIDP.numHotseatIcons) {
Log.e(TAG, "Error loading shortcut " + item
@@ -414,17 +404,17 @@
+ item.cellY + ") already occupied");
return false;
} else {
- hotseatOccupancy.cells[(int) item.screenId][0] = true;
+ hotseatOccupancy.cells[item.screenId][0] = true;
return true;
}
} else {
final GridOccupancy occupancy = new GridOccupancy(mIDP.numHotseatIcons, 1);
- occupancy.cells[(int) item.screenId][0] = true;
- occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, occupancy);
+ occupancy.cells[item.screenId][0] = true;
+ occupied.put(LauncherSettings.Favorites.CONTAINER_HOTSEAT, occupancy);
return true;
}
} else if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- if (!workspaceScreens.contains((Long) item.screenId)) {
+ if (!workspaceScreens.contains(item.screenId)) {
// The item has an invalid screen id.
return false;
}
@@ -450,7 +440,8 @@
if (item.screenId == Workspace.FIRST_SCREEN_ID) {
// Mark the first row as occupied (if the feature is enabled)
// in order to account for the QSB.
- screen.markCells(0, 0, countX + 1, 1, FeatureFlags.QSB_ON_FIRST_SCREEN);
+ screen.markCells(0, 0, countX + 1, 1,
+ FeatureFlags.QSB_ON_FIRST_SCREEN.get());
}
occupied.put(item.screenId, screen);
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 06da843..2ecebb7 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -43,7 +43,10 @@
import com.android.launcher3.AllAppsList;
import com.android.launcher3.AppInfo;
import com.android.launcher3.FolderInfo;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.icons.ComponentWithLabel;
+import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
+import com.android.launcher3.icons.cache.IconCacheUpdateHandler;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.InstallShortcutReceiver;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
@@ -59,13 +62,15 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIconPreviewVerifier;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.icons.LauncherActivtiyCachingLogic;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.provider.ImportDataTask;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.LooperIdleLock;
import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageManagerHelper;
@@ -120,6 +125,11 @@
mPackageInstaller = PackageInstallerCompat.getInstance(mApp.getContext());
mAppWidgetManager = AppWidgetManagerCompat.getInstance(mApp.getContext());
mIconCache = mApp.getIconCache();
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ android.util.Log.getStackTraceString(new Throwable()));
+ }
}
protected synchronized void waitForIdle() {
@@ -146,7 +156,7 @@
allItems.addAll(mBgDataModel.workspaceItems);
allItems.addAll(mBgDataModel.appWidgets);
}
- long firstScreen = mBgDataModel.workspaceScreens.isEmpty()
+ int firstScreen = mBgDataModel.workspaceScreens.isEmpty()
? -1 // In this case, we can still look at the items in the hotseat.
: mBgDataModel.workspaceScreens.get(0);
filterCurrentWorkspaceItems(firstScreen, allItems, firstScreenItems,
@@ -182,7 +192,7 @@
// second step
TraceHelper.partitionSection(TAG, "step 2.1: loading all apps");
- loadAllApps();
+ List<LauncherActivityInfo> allActivityList = loadAllApps();
TraceHelper.partitionSection(TAG, "step 2.2: Binding all apps");
verifyNotStopped();
@@ -190,7 +200,11 @@
verifyNotStopped();
TraceHelper.partitionSection(TAG, "step 2.3: Update icon cache");
- updateIconCache();
+ IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();
+ setIgnorePackages(updateHandler);
+ updateHandler.updateIcons(allActivityList,
+ new LauncherActivtiyCachingLogic(mApp.getIconCache()),
+ mApp.getModel()::onPackageIconsUpdated);
// Take a break
TraceHelper.partitionSection(TAG, "step 2 completed, wait for idle");
@@ -212,12 +226,21 @@
// fourth step
TraceHelper.partitionSection(TAG, "step 4.1: loading widgets");
- mBgDataModel.widgetsModel.update(mApp, null);
+ List<ComponentWithLabel> allWidgetsList = mBgDataModel.widgetsModel.update(mApp, null);
verifyNotStopped();
TraceHelper.partitionSection(TAG, "step 4.2: Binding widgets");
mResults.bindWidgets();
+ verifyNotStopped();
+ TraceHelper.partitionSection(TAG, "step 4.3: Update icon cache");
+ updateHandler.updateIcons(allWidgetsList, new ComponentCachingLogic(mApp.getContext()),
+ mApp.getModel()::onWidgetLabelsUpdated);
+
+ verifyNotStopped();
+ TraceHelper.partitionSection(TAG, "step 5: Finish icon cache update");
+ updateHandler.finish();
+
transaction.commit();
} catch (CancellationException e) {
// Loader stopped, ignore
@@ -381,24 +404,16 @@
// no special handling necessary for this item
c.markRestored();
} else {
- if (c.hasRestoreFlag(ShortcutInfo.FLAG_AUTOINSTALL_ICON)) {
- // We allow auto install apps to have their intent
- // updated after an install.
- intent = pmHelper.getAppLaunchIntent(targetPkg, c.user);
- if (intent != null) {
- c.restoreFlag = 0;
- c.updater().put(
- LauncherSettings.Favorites.INTENT,
- intent.toUri(0)).commit();
- cn = intent.getComponent();
- } else {
- c.markDeleted("Unable to find a launch target");
- continue;
- }
+ // Gracefully try to find a fallback activity.
+ intent = pmHelper.getAppLaunchIntent(targetPkg, c.user);
+ if (intent != null) {
+ c.restoreFlag = 0;
+ c.updater().put(
+ LauncherSettings.Favorites.INTENT,
+ intent.toUri(0)).commit();
+ cn = intent.getComponent();
} else {
- // The app is installed but the component is no
- // longer available.
- c.markDeleted("Invalid component removed: " + cn);
+ c.markDeleted("Unable to find a launch target");
continue;
}
}
@@ -478,18 +493,14 @@
}
info = new ShortcutInfo(pinnedShortcut, context);
final ShortcutInfo finalInfo = info;
- Provider<Bitmap> fallbackIconProvider = new Provider<Bitmap>() {
- @Override
- public Bitmap get() {
- // If the pinned deep shortcut is no longer published,
- // use the last saved icon instead of the default.
- return c.loadIcon(finalInfo)
- ? finalInfo.iconBitmap : null;
- }
- };
+ // If the pinned deep shortcut is no longer published,
+ // use the last saved icon instead of the default.
+ Provider<Bitmap> fallbackIconProvider = () ->
+ c.loadIcon(finalInfo) ? finalInfo.iconBitmap : null;
+
LauncherIcons li = LauncherIcons.obtain(context);
- li.createShortcutIcon(pinnedShortcut,
- true /* badged */, fallbackIconProvider).applyTo(info);
+ info.applyFrom(li.createShortcutIcon(pinnedShortcut,
+ true /* badged */, fallbackIconProvider));
li.recycle();
if (pmHelper.isAppSuspended(
pinnedShortcut.getPackage(), info.user)) {
@@ -710,11 +721,11 @@
// Remove dead items
if (c.commitDeleted()) {
// Remove any empty folder
- ArrayList<Long> deletedFolderIds = (ArrayList<Long>) LauncherSettings.Settings
+ int[] deletedFolderIds = LauncherSettings.Settings
.call(contentResolver,
LauncherSettings.Settings.METHOD_DELETE_EMPTY_FOLDERS)
- .getSerializable(LauncherSettings.Settings.EXTRA_VALUE);
- for (long folderId : deletedFolderIds) {
+ .getIntArray(LauncherSettings.Settings.EXTRA_VALUE);
+ for (int folderId : deletedFolderIds) {
mBgDataModel.workspaceItems.remove(mBgDataModel.folders.get(folderId));
mBgDataModel.folders.remove(folderId);
mBgDataModel.itemsIdMap.remove(folderId);
@@ -746,7 +757,7 @@
int numItemsInPreview = 0;
for (ShortcutInfo info : folder.contents) {
- if (info.usingLowResIcon
+ if (info.usingLowResIcon()
&& info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
&& verifier.isItemInPreview(info.rank)) {
mIconCache.getTitleAndIcon(info, false);
@@ -769,24 +780,24 @@
}
// Remove any empty screens
- ArrayList<Long> unusedScreens = new ArrayList<>(mBgDataModel.workspaceScreens);
+ IntArray unusedScreens = mBgDataModel.workspaceScreens.clone();
for (ItemInfo item: mBgDataModel.itemsIdMap) {
- long screenId = item.screenId;
+ int screenId = item.screenId;
if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
unusedScreens.contains(screenId)) {
- unusedScreens.remove(screenId);
+ unusedScreens.removeValue(screenId);
}
}
// If there are any empty screens remove them, and update.
if (unusedScreens.size() != 0) {
- mBgDataModel.workspaceScreens.removeAll(unusedScreens);
+ mBgDataModel.workspaceScreens.removeAllValues(unusedScreens);
LauncherModel.updateWorkspaceScreenOrder(context, mBgDataModel.workspaceScreens);
}
}
}
- private void updateIconCache() {
+ private void setIgnorePackages(IconCacheUpdateHandler updateHandler) {
// Ignore packages which have a promise icon.
HashSet<String> packagesToIgnore = new HashSet<>();
synchronized (mBgDataModel) {
@@ -804,12 +815,12 @@
}
}
}
- mIconCache.updateDbIcons(packagesToIgnore);
+ updateHandler.setPackagesToIgnore(Process.myUserHandle(), packagesToIgnore);
}
- private void loadAllApps() {
+ private List<LauncherActivityInfo> loadAllApps() {
final List<UserHandle> profiles = mUserManager.getUserProfiles();
-
+ List<LauncherActivityInfo> allActivityList = new ArrayList<>();
// Clear the list of apps
mBgAllAppsList.clear();
for (UserHandle user : profiles) {
@@ -818,7 +829,7 @@
// Fail if we don't have any apps
// TODO: Fix this. Only fail for the current user.
if (apps == null || apps.isEmpty()) {
- return;
+ return allActivityList;
}
boolean quietMode = mUserManager.isQuietModeEnabled(user);
// Create the ApplicationInfos
@@ -827,6 +838,7 @@
// This builds the icon bitmaps.
mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
}
+ allActivityList.addAll(apps);
}
if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
@@ -839,6 +851,7 @@
}
mBgAllAppsList.added = new ArrayList<>();
+ return allActivityList;
}
private void loadDeepShortcuts() {
@@ -849,7 +862,7 @@
if (mUserManager.isUserUnlocked(user)) {
List<ShortcutInfoCompat> shortcuts =
mShortcutManager.queryForAllShortcuts(user);
- mBgDataModel.updateDeepShortcutMap(null, user, shortcuts);
+ mBgDataModel.updateDeepShortcutCounts(null, user, shortcuts);
}
}
}
diff --git a/src/com/android/launcher3/model/ModelPreload.java b/src/com/android/launcher3/model/ModelPreload.java
index f186e95..b353810 100644
--- a/src/com/android/launcher3/model/ModelPreload.java
+++ b/src/com/android/launcher3/model/ModelPreload.java
@@ -16,7 +16,6 @@
package com.android.launcher3.model;
import android.content.Context;
-import android.support.annotation.WorkerThread;
import android.util.Log;
import com.android.launcher3.AllAppsList;
@@ -26,6 +25,8 @@
import java.util.concurrent.Executor;
+import androidx.annotation.WorkerThread;
+
/**
* Utility class to preload LauncherModel
*/
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index eba7515..f7961d5d 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -28,6 +28,8 @@
import com.android.launcher3.FolderInfo;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetHost;
+import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherModel.Callbacks;
import com.android.launcher3.LauncherProvider;
@@ -35,13 +37,14 @@
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.LauncherSettings.Settings;
import com.android.launcher3.ShortcutInfo;
-import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LooperExecutor;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.Executor;
/**
@@ -60,6 +63,10 @@
private final boolean mHasVerticalHotseat;
private final boolean mVerifyChanges;
+ // Keep track of delete operations that occur when an Undo option is present; we may not commit.
+ private final List<Runnable> mDeleteRunnables = new ArrayList<>();
+ private boolean mPreparingToUndo;
+
public ModelWriter(Context context, LauncherModel model, BgDataModel dataModel,
boolean hasVerticalHotseat, boolean verifyChanges) {
mContext = context;
@@ -72,7 +79,7 @@
}
private void updateItemInfoProps(
- ItemInfo item, long container, long screenId, int cellX, int cellY) {
+ ItemInfo item, int container, int screenId, int cellX, int cellY) {
item.container = container;
item.cellX = cellX;
item.cellY = cellY;
@@ -91,7 +98,7 @@
* <container, screen, cellX, cellY>
*/
public void addOrMoveItemInDatabase(ItemInfo item,
- long container, long screenId, int cellX, int cellY) {
+ int container, int screenId, int cellX, int cellY) {
if (item.container == ItemInfo.NO_ID) {
// From all apps
addItemToDatabase(item, container, screenId, cellX, cellY);
@@ -101,7 +108,12 @@
}
}
- private void checkItemInfoLocked(long itemId, ItemInfo item, StackTraceElement[] stackTrace) {
+ private void checkItemInfoLocked(int itemId, ItemInfo item, StackTraceElement[] stackTrace) {
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ "Checking item: " + android.util.Log.getStackTraceString(new Throwable()));
+ }
ItemInfo modelItem = mBgDataModel.itemsIdMap.get(itemId);
if (modelItem != null && item != modelItem) {
// check all the data is consistent
@@ -142,7 +154,7 @@
* Move an item in the DB to a new <container, screen, cellX, cellY>
*/
public void moveItemInDatabase(final ItemInfo item,
- long container, long screenId, int cellX, int cellY) {
+ int container, int screenId, int cellX, int cellY) {
updateItemInfoProps(item, container, screenId, cellX, cellY);
final ContentWriter writer = new ContentWriter(mContext)
@@ -152,14 +164,14 @@
.put(Favorites.RANK, item.rank)
.put(Favorites.SCREEN, item.screenId);
- mWorkerExecutor.execute(new UpdateItemRunnable(item, writer));
+ enqueueDeleteRunnable(new UpdateItemRunnable(item, writer));
}
/**
* Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the
* cellX, cellY have already been updated on the ItemInfos.
*/
- public void moveItemsInDatabase(final ArrayList<ItemInfo> items, long container, int screen) {
+ public void moveItemsInDatabase(final ArrayList<ItemInfo> items, int container, int screen) {
ArrayList<ContentValues> contentValues = new ArrayList<>();
int count = items.size();
@@ -176,14 +188,14 @@
contentValues.add(values);
}
- mWorkerExecutor.execute(new UpdateItemsRunnable(items, contentValues));
+ enqueueDeleteRunnable(new UpdateItemsRunnable(items, contentValues));
}
/**
* Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>
*/
public void modifyItemInDatabase(final ItemInfo item,
- long container, long screenId, int cellX, int cellY, int spanX, int spanY) {
+ int container, int screenId, int cellX, int cellY, int spanX, int spanY) {
updateItemInfoProps(item, container, screenId, cellX, cellY);
item.spanX = spanX;
item.spanY = spanY;
@@ -214,14 +226,14 @@
* cellY fields of the item. Also assigns an ID to the item.
*/
public void addItemToDatabase(final ItemInfo item,
- long container, long screenId, int cellX, int cellY) {
+ int container, int screenId, int cellX, int cellY) {
updateItemInfoProps(item, container, screenId, cellX, cellY);
final ContentWriter writer = new ContentWriter(mContext);
final ContentResolver cr = mContext.getContentResolver();
item.onAddToDatabase(writer);
- item.id = Settings.call(cr, Settings.METHOD_NEW_ITEM_ID).getLong(Settings.EXTRA_VALUE);
+ item.id = Settings.call(cr, Settings.METHOD_NEW_ITEM_ID).getInt(Settings.EXTRA_VALUE);
writer.put(Favorites._ID, item.id);
ModelVerifier verifier = new ModelVerifier();
@@ -258,7 +270,7 @@
public void deleteItemsFromDatabase(final Iterable<? extends ItemInfo> items) {
ModelVerifier verifier = new ModelVerifier();
- mWorkerExecutor.execute(() -> {
+ enqueueDeleteRunnable(() -> {
for (ItemInfo item : items) {
final Uri uri = Favorites.getContentUri(item.id);
mContext.getContentResolver().delete(uri, null, null);
@@ -275,7 +287,7 @@
public void deleteFolderAndContentsFromDatabase(final FolderInfo info) {
ModelVerifier verifier = new ModelVerifier();
- mWorkerExecutor.execute(() -> {
+ enqueueDeleteRunnable(() -> {
ContentResolver cr = mContext.getContentResolver();
cr.delete(LauncherSettings.Favorites.CONTENT_URI,
LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
@@ -288,12 +300,74 @@
});
}
+ /**
+ * Deletes the widget info and the widget id.
+ */
+ public void deleteWidgetInfo(final LauncherAppWidgetInfo info, LauncherAppWidgetHost host) {
+ if (host != null && !info.isCustomWidget() && info.isWidgetIdAllocated()) {
+ // Deleting an app widget ID is a void call but writes to disk before returning
+ // to the caller...
+ enqueueDeleteRunnable(() -> host.deleteAppWidgetId(info.appWidgetId));
+ }
+ deleteItemFromDatabase(info);
+ }
+
+ /**
+ * Delete operations tracked using {@link #enqueueDeleteRunnable} will only be called
+ * if {@link #commitDelete} is called. Note that one of {@link #commitDelete()} or
+ * {@link #abortDelete()} MUST be called after this method, or else all delete
+ * operations will remain uncommitted indefinitely.
+ */
+ public void prepareToUndoDelete() {
+ if (!mPreparingToUndo) {
+ if (!mDeleteRunnables.isEmpty() && FeatureFlags.IS_DOGFOOD_BUILD) {
+ throw new IllegalStateException("There are still uncommitted delete operations!");
+ }
+ mDeleteRunnables.clear();
+ mPreparingToUndo = true;
+ }
+ }
+
+ /**
+ * If {@link #prepareToUndoDelete} has been called, we store the Runnable to be run when
+ * {@link #commitDelete()} is called (or abandoned if {@link #abortDelete()} is called).
+ * Otherwise, we run the Runnable immediately.
+ */
+ public void enqueueDeleteRunnable(Runnable r) {
+ if (mPreparingToUndo) {
+ mDeleteRunnables.add(r);
+ } else {
+ mWorkerExecutor.execute(r);
+ }
+ }
+
+ public void commitDelete() {
+ mPreparingToUndo = false;
+ for (Runnable runnable : mDeleteRunnables) {
+ mWorkerExecutor.execute(runnable);
+ }
+ mDeleteRunnables.clear();
+ }
+
+ public void abortDelete() {
+ mPreparingToUndo = false;
+ mDeleteRunnables.clear();
+ // We do a full reload here instead of just a rebind because Folders change their internal
+ // state when dragging an item out, which clobbers the rebind unless we load from the DB.
+ mModel.forceReload();
+ }
+
private class UpdateItemRunnable extends UpdateItemBaseRunnable {
private final ItemInfo mItem;
private final ContentWriter mWriter;
- private final long mItemId;
+ private final int mItemId;
UpdateItemRunnable(ItemInfo item, ContentWriter writer) {
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ android.util.Log.getStackTraceString(new Throwable()));
+ }
mItem = item;
mWriter = writer;
mItemId = item.id;
@@ -322,7 +396,7 @@
int count = mItems.size();
for (int i = 0; i < count; i++) {
ItemInfo item = mItems.get(i);
- final long itemId = item.id;
+ final int itemId = item.id;
final Uri uri = Favorites.getContentUri(itemId);
ContentValues values = mValues.get(i);
@@ -345,7 +419,7 @@
mStackTrace = new Throwable().getStackTrace();
}
- protected void updateItemArrays(ItemInfo item, long itemId) {
+ protected void updateItemArrays(ItemInfo item, int itemId) {
// Lock on mBgLock *after* the db operation
synchronized (mBgDataModel) {
checkItemInfoLocked(itemId, item, mStackTrace);
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 977dcd7..0f67f0c 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -20,12 +20,11 @@
import android.content.Intent;
import android.os.Process;
import android.os.UserHandle;
-import android.util.ArrayMap;
import android.util.Log;
import com.android.launcher3.AllAppsList;
import com.android.launcher3.AppInfo;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.InstallShortcutReceiver;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
@@ -39,14 +38,14 @@
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.graphics.BitmapInfo;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.util.FlagOp;
+import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
@@ -159,19 +158,20 @@
appsList.added.clear();
addedOrModified.addAll(appsList.modified);
appsList.modified.clear();
+ if (!addedOrModified.isEmpty()) {
+ scheduleCallbackTask((callbacks) -> callbacks.bindAppsAddedOrUpdated(addedOrModified));
+ }
final ArrayList<AppInfo> removedApps = new ArrayList<>(appsList.removed);
appsList.removed.clear();
-
- final ArrayMap<ComponentName, AppInfo> addedOrUpdatedApps = new ArrayMap<>();
- if (!addedOrModified.isEmpty()) {
- scheduleCallbackTask((callbacks) -> callbacks.bindAppsAddedOrUpdated(addedOrModified));
- for (AppInfo ai : addedOrModified) {
- addedOrUpdatedApps.put(ai.componentName, ai);
+ final HashSet<ComponentName> removedComponents = new HashSet<>();
+ if (mOp == OP_UPDATE) {
+ for (AppInfo ai : removedApps) {
+ removedComponents.add(ai.componentName);
}
}
- final LongArrayMap<Boolean> removedShortcuts = new LongArrayMap<>();
+ final IntSparseArrayMap<Boolean> removedShortcuts = new IntSparseArrayMap<>();
// Update shortcut infos
if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
@@ -194,14 +194,14 @@
BitmapInfo iconInfo = li.createIconBitmap(si.iconResource);
li.recycle();
if (iconInfo != null) {
- iconInfo.applyTo(si);
+ si.applyFrom(iconInfo);
infoUpdated = true;
}
}
ComponentName cn = si.getTargetComponent();
if (cn != null && matcher.matches(si, cn)) {
- AppInfo appInfo = addedOrUpdatedApps.get(cn);
+ String packageName = cn.getPackageName();
if (si.hasStatusFlag(ShortcutInfo.FLAG_SUPPORTS_WEB_UI)) {
removedShortcuts.put(si.id, false);
@@ -227,26 +227,13 @@
isTargetValid = LauncherAppsCompat.getInstance(context)
.isActivityEnabledForProfile(cn, mUser);
}
-
- if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINSTALL_ICON)) {
- // Auto install icon
- if (!isTargetValid) {
- // Try to find the best match activity.
- Intent intent = new PackageManagerHelper(context)
- .getAppLaunchIntent(cn.getPackageName(), mUser);
- if (intent != null) {
- cn = intent.getComponent();
- appInfo = addedOrUpdatedApps.get(cn);
- }
-
- if (intent != null && appInfo != null) {
- si.intent = intent;
- si.status = ShortcutInfo.DEFAULT;
- infoUpdated = true;
- } else if (si.hasPromiseIconUi()) {
- removedShortcuts.put(si.id, true);
- continue;
- }
+ if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINSTALL_ICON)
+ && !isTargetValid) {
+ if (updateShortcutIntent(context, si, packageName)) {
+ infoUpdated = true;
+ } else if (si.hasPromiseIconUi()) {
+ removedShortcuts.put(si.id, true);
+ continue;
}
} else if (!isTargetValid) {
removedShortcuts.put(si.id, true);
@@ -257,11 +244,15 @@
si.status = ShortcutInfo.DEFAULT;
infoUpdated = true;
}
+ } else if (isNewApkAvailable && removedComponents.contains(cn)) {
+ if (updateShortcutIntent(context, si, packageName)) {
+ infoUpdated = true;
+ }
}
if (isNewApkAvailable &&
si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
- iconCache.getTitleAndIcon(si, si.usingLowResIcon);
+ iconCache.getTitleAndIcon(si, si.usingLowResIcon());
infoUpdated = true;
}
@@ -315,7 +306,6 @@
}
final HashSet<String> removedPackages = new HashSet<>();
- final HashSet<ComponentName> removedComponents = new HashSet<>();
if (mOp == OP_REMOVE) {
// Mark all packages in the broadcast to be removed
Collections.addAll(removedPackages, packages);
@@ -330,11 +320,6 @@
removedPackages.add(packages[i]);
}
}
-
- // Update removedComponents as some components can get removed during package update
- for (AppInfo info : removedApps) {
- removedComponents.add(info.componentName);
- }
}
if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
@@ -366,4 +351,19 @@
bindUpdatedWidgets(dataModel);
}
}
+
+ /**
+ * Updates {@param si}'s intent to point to a new ComponentName.
+ * @return Whether the shortcut intent was changed.
+ */
+ private boolean updateShortcutIntent(Context context, ShortcutInfo si, String packageName) {
+ // Try to find the best match activity.
+ Intent intent = new PackageManagerHelper(context).getAppLaunchIntent(packageName, mUser);
+ if (intent != null) {
+ si.intent = intent;
+ si.status = ShortcutInfo.DEFAULT;
+ return true;
+ }
+ return false;
+ }
}
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 59f3d1c..e99fed9 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -23,7 +23,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.ShortcutInfo;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.shortcuts.ShortcutKey;
@@ -96,8 +96,8 @@
// If the shortcut is pinned but no longer has an icon in the system,
// keep the current icon instead of reverting to the default icon.
LauncherIcons li = LauncherIcons.obtain(context);
- li.createShortcutIcon(fullDetails, true, Provider.of(shortcutInfo.iconBitmap))
- .applyTo(shortcutInfo);
+ shortcutInfo.applyFrom(li.createShortcutIcon(fullDetails, true,
+ Provider.of(shortcutInfo.iconBitmap)));
li.recycle();
updatedShortcutInfos.add(shortcutInfo);
}
@@ -116,7 +116,7 @@
if (mUpdateIdMap) {
// Update the deep shortcut map if the list of ids has changed for an activity.
- dataModel.updateDeepShortcutMap(mPackageName, mUser, mShortcuts);
+ dataModel.updateDeepShortcutCounts(mPackageName, mUser, mShortcuts);
bindDeepShortcuts(dataModel);
}
}
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index 9521a9e..8e7557a 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -26,7 +26,7 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.shortcuts.ShortcutKey;
@@ -95,7 +95,7 @@
// If the shortcut is pinned but no longer has an icon in the system,
// keep the current icon instead of reverting to the default icon.
LauncherIcons li = LauncherIcons.obtain(context);
- li.createShortcutIcon(shortcut, true, Provider.of(si.iconBitmap)).applyTo(si);
+ si.applyFrom(li.createShortcutIcon(shortcut, true, Provider.of(si.iconBitmap)));
li.recycle();
} else {
si.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
@@ -117,7 +117,7 @@
}
if (isUserUnlocked) {
- dataModel.updateDeepShortcutMap(
+ dataModel.updateDeepShortcutCounts(
null, mUser, deepShortcutManager.queryForAllShortcuts(mUser));
}
bindDeepShortcuts(dataModel);
diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java
index 1e96dec..e38529b 100644
--- a/src/com/android/launcher3/model/WidgetItem.java
+++ b/src/com/android/launcher3/model/WidgetItem.java
@@ -9,6 +9,7 @@
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.ShortcutConfigActivityInfo;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.util.ComponentKey;
import java.text.Collator;
@@ -29,11 +30,11 @@
public final String label;
public final int spanX, spanY;
- public WidgetItem(LauncherAppWidgetProviderInfo info, PackageManager pm,
- InvariantDeviceProfile idp) {
+ public WidgetItem(LauncherAppWidgetProviderInfo info,
+ InvariantDeviceProfile idp, IconCache iconCache) {
super(info.provider, info.getProfile());
- label = Utilities.trim(info.getLabel(pm));
+ label = iconCache.getTitleNoCache(info);
widgetInfo = info;
activityInfo = null;
@@ -41,9 +42,10 @@
spanY = Math.min(info.spanY, idp.numRows);
}
- public WidgetItem(ShortcutConfigActivityInfo info) {
+ public WidgetItem(ShortcutConfigActivityInfo info, IconCache iconCache, PackageManager pm) {
super(info.getComponent(), info.getUser());
- label = Utilities.trim(info.getLabel());
+ label = info.isPersistable() ? iconCache.getTitleNoCache(info) :
+ Utilities.trim(info.getLabel(pm));
widgetInfo = null;
activityInfo = info;
spanX = spanY = 1;
diff --git a/src/com/android/launcher3/notification/NotificationFooterLayout.java b/src/com/android/launcher3/notification/NotificationFooterLayout.java
index 1216a27..c7de5b0 100644
--- a/src/com/android/launcher3/notification/NotificationFooterLayout.java
+++ b/src/com/android/launcher3/notification/NotificationFooterLayout.java
@@ -29,7 +29,6 @@
import android.widget.FrameLayout;
import android.widget.LinearLayout;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PropertyListBuilder;
@@ -151,15 +150,16 @@
public void animateFirstNotificationTo(Rect toBounds,
final IconAnimationEndListener callback) {
- AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
+ AnimatorSet animation = new AnimatorSet();
final View firstNotification = mIconRow.getChildAt(mIconRow.getChildCount() - 1);
Rect fromBounds = sTempRect;
firstNotification.getGlobalVisibleRect(fromBounds);
float scale = (float) toBounds.height() / fromBounds.height();
- Animator moveAndScaleIcon = LauncherAnimUtils.ofPropertyValuesHolder(firstNotification,
- new PropertyListBuilder().scale(scale).translationY(toBounds.top - fromBounds.top
- + (fromBounds.height() * scale - fromBounds.height()) / 2).build());
+ Animator moveAndScaleIcon = new PropertyListBuilder().scale(scale)
+ .translationY(toBounds.top - fromBounds.top
+ + (fromBounds.height() * scale - fromBounds.height()) / 2)
+ .build(firstNotification);
moveAndScaleIcon.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/src/com/android/launcher3/notification/NotificationKeyData.java b/src/com/android/launcher3/notification/NotificationKeyData.java
index bf7ae1a..508cf87 100644
--- a/src/com/android/launcher3/notification/NotificationKeyData.java
+++ b/src/com/android/launcher3/notification/NotificationKeyData.java
@@ -18,11 +18,12 @@
import android.app.Notification;
import android.service.notification.StatusBarNotification;
-import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
+import androidx.annotation.NonNull;
+
/**
* The key data associated with the notification, used to determine what to include
* in badges and dummy popup views before they are populated.
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index b527b6a..f27b728 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -16,7 +16,7 @@
package com.android.launcher3.notification;
-import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
+import static com.android.launcher3.util.SecureSettingsObserver.newNotificationSettingsObserver;
import android.annotation.TargetApi;
import android.app.Notification;
@@ -27,15 +27,14 @@
import android.os.Message;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
-import android.support.annotation.Nullable;
import android.text.TextUtils;
-import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import com.android.launcher3.LauncherModel;
+import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.SettingsObserver;
+import com.android.launcher3.util.SecureSettingsObserver;
import java.util.ArrayList;
import java.util.Arrays;
@@ -43,7 +42,8 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
+
+import androidx.annotation.Nullable;
/**
* A {@link NotificationListenerService} that sends updates to its
@@ -77,7 +77,7 @@
/** The last notification key that was dismissed from launcher UI */
private String mLastKeyDismissedByLauncher;
- private SettingsObserver mNotificationBadgingObserver;
+ private SecureSettingsObserver mNotificationBadgingObserver;
private final Handler.Callback mWorkerCallback = new Handler.Callback() {
@Override
@@ -194,19 +194,20 @@
super.onListenerConnected();
sIsConnected = true;
- mNotificationBadgingObserver = new SettingsObserver.Secure(getContentResolver()) {
- @Override
- public void onSettingChanged(boolean isNotificationBadgingEnabled) {
- if (!isNotificationBadgingEnabled) {
- requestUnbind();
- }
- }
- };
- mNotificationBadgingObserver.register(NOTIFICATION_BADGING);
+ mNotificationBadgingObserver =
+ newNotificationSettingsObserver(this, this::onNotificationBadgingChanged);
+ mNotificationBadgingObserver.register();
+ mNotificationBadgingObserver.dispatchOnChange();
onNotificationFullRefresh();
}
+ private void onNotificationBadgingChanged(boolean isNotificationBadgingEnabled) {
+ if (!isNotificationBadgingEnabled && sIsConnected) {
+ requestUnbind();
+ }
+ }
+
private void onNotificationFullRefresh() {
mWorkerHandler.obtainMessage(MSG_NOTIFICATION_FULL_REFRESH).sendToTarget();
}
@@ -345,7 +346,7 @@
private List<StatusBarNotification> filterNotifications(
StatusBarNotification[] notifications) {
if (notifications == null) return null;
- Set<Integer> removedNotifications = new ArraySet<>();
+ IntSet removedNotifications = new IntSet();
for (int i = 0; i < notifications.length; i++) {
if (shouldBeFilteredOut(notifications[i])) {
removedNotifications.add(i);
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java
index 5c0e259..78627ec 100644
--- a/src/com/android/launcher3/notification/NotificationMainView.java
+++ b/src/com/android/launcher3/notification/NotificationMainView.java
@@ -179,7 +179,7 @@
@Override
- public boolean onDrag(float displacement, float velocity) {
+ public boolean onDrag(float displacement) {
setContentTranslation(canChildBeDismissed()
? displacement : OverScroll.dampedScroll(displacement, getWidth()));
mContentTranslateAnimator.cancel();
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index 709975f..f7c730a 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -244,7 +244,7 @@
float startX = (getWidth() - mNumPages * circleGap + mDotRadius) / 2;
float x = startX + mDotRadius;
- float y = canvas.getHeight() / 2;
+ float y = getHeight() / 2;
if (mEntryAnimationRadiusFactors != null) {
// During entry animation, only draw the circles
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index be666a6..0bb5e2a 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -16,6 +16,8 @@
package com.android.launcher3.popup;
+import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -35,9 +37,10 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
-import android.view.animation.AccelerateDecelerateInterpolator;
+import android.widget.FrameLayout;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
@@ -47,6 +50,7 @@
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.graphics.TriangleShape;
import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.BaseDragLayer;
import java.util.ArrayList;
import java.util.Collections;
@@ -63,7 +67,7 @@
protected final Launcher mLauncher;
protected final boolean mIsRtl;
- private final int mArrayOffset;
+ private final int mArrowOffset;
private final View mArrow;
protected boolean mIsLeftAligned;
@@ -96,7 +100,7 @@
final int arrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height);
mArrow = new View(context);
mArrow.setLayoutParams(new DragLayer.LayoutParams(arrowWidth, arrowHeight));
- mArrayOffset = resources.getDimensionPixelSize(R.dimen.popup_arrow_vertical_offset);
+ mArrowOffset = resources.getDimensionPixelSize(R.dimen.popup_arrow_vertical_offset);
}
public ArrowPopup(Context context, AttributeSet attrs) {
@@ -134,7 +138,7 @@
protected void reorderAndShow(int viewsToFlip) {
setVisibility(View.INVISIBLE);
mIsOpen = true;
- mLauncher.getDragLayer().addView(this);
+ getPopupContainer().addView(this);
orientAboutObject();
boolean reverseOrder = mIsAboveIcon;
@@ -163,7 +167,7 @@
? R.dimen.popup_arrow_horizontal_center_start
: R.dimen.popup_arrow_horizontal_center_end);
final int halfArrowWidth = res.getDimensionPixelSize(R.dimen.popup_arrow_width) / 2;
- mLauncher.getDragLayer().addView(mArrow);
+ getPopupContainer().addView(mArrow);
DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams();
if (mIsLeftAligned) {
mArrow.setX(getX() + arrowCenterOffset - halfArrowWidth);
@@ -179,16 +183,22 @@
ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create(
arrowLp.width, arrowLp.height, !mIsAboveIcon));
Paint arrowPaint = arrowDrawable.getPaint();
- arrowPaint.setColor(Themes.getAttrColor(mLauncher, R.attr.popupColorPrimary));
+ arrowPaint.setColor(Themes.getAttrColor(getContext(), R.attr.popupColorPrimary));
// The corner path effect won't be reflected in the shadow, but shouldn't be noticeable.
int radius = getResources().getDimensionPixelSize(R.dimen.popup_arrow_corner_radius);
arrowPaint.setPathEffect(new CornerPathEffect(radius));
mArrow.setBackground(arrowDrawable);
+ // Clip off the part of the arrow that is underneath the popup.
+ if (mIsAboveIcon) {
+ mArrow.setClipBounds(new Rect(0, -mArrowOffset, arrowLp.width, arrowLp.height));
+ } else {
+ mArrow.setClipBounds(new Rect(0, 0, arrowLp.width, arrowLp.height + mArrowOffset));
+ }
mArrow.setElevation(getElevation());
}
mArrow.setPivotX(arrowLp.width / 2);
- mArrow.setPivotY(mIsAboveIcon ? 0 : arrowLp.height);
+ mArrow.setPivotY(mIsAboveIcon ? arrowLp.height : 0);
animateOpen();
}
@@ -217,12 +227,12 @@
protected void orientAboutObject() {
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int width = getMeasuredWidth();
- int extraVerticalSpace = mArrow.getLayoutParams().height + mArrayOffset
+ int extraVerticalSpace = mArrow.getLayoutParams().height + mArrowOffset
+ getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding);
int height = getMeasuredHeight() + extraVerticalSpace;
getTargetObjectLocation(mTempRect);
- DragLayer dragLayer = mLauncher.getDragLayer();
+ InsettableFrameLayout dragLayer = getPopupContainer();
Rect insets = dragLayer.getInsets();
// Align left (right in RTL) if there is room.
@@ -301,17 +311,16 @@
return;
}
- DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
- DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams();
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+ FrameLayout.LayoutParams arrowLp = (FrameLayout.LayoutParams) mArrow.getLayoutParams();
if (mIsAboveIcon) {
arrowLp.gravity = lp.gravity = Gravity.BOTTOM;
- lp.bottomMargin =
- mLauncher.getDragLayer().getHeight() - y - getMeasuredHeight() - insets.top;
- arrowLp.bottomMargin = lp.bottomMargin - arrowLp.height - mArrayOffset - insets.bottom;
+ lp.bottomMargin = getPopupContainer().getHeight() - y - getMeasuredHeight() - insets.top;
+ arrowLp.bottomMargin = lp.bottomMargin - arrowLp.height - mArrowOffset - insets.bottom;
} else {
arrowLp.gravity = lp.gravity = Gravity.TOP;
lp.topMargin = y + insets.top;
- arrowLp.topMargin = lp.topMargin - insets.top - arrowLp.height - mArrayOffset;
+ arrowLp.topMargin = lp.topMargin - insets.top - arrowLp.height - mArrowOffset;
}
}
@@ -320,7 +329,7 @@
super.onLayout(changed, l, t, r, b);
// enforce contained is within screen
- DragLayer dragLayer = mLauncher.getDragLayer();
+ ViewGroup dragLayer = getPopupContainer();
if (getTranslationX() + l < 0 || getTranslationX() + r > dragLayer.getWidth()) {
// If we are still off screen, center horizontally too.
mGravity |= Gravity.CENTER_HORIZONTAL;
@@ -338,10 +347,11 @@
private void animateOpen() {
setVisibility(View.VISIBLE);
- final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet();
+ final AnimatorSet openAnim = new AnimatorSet();
final Resources res = getResources();
final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration);
- final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
+ final long arrowDuration = res.getInteger(R.integer.config_popupArrowOpenCloseDuration);
+ final TimeInterpolator revealInterpolator = ACCEL_DEACCEL;
// Rectangular reveal.
final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
@@ -349,16 +359,21 @@
revealAnim.setDuration(revealDuration);
revealAnim.setInterpolator(revealInterpolator);
- Animator fadeIn = ObjectAnimator.ofFloat(this, ALPHA, 0, 1);
- fadeIn.setDuration(revealDuration);
+ ValueAnimator fadeIn = ValueAnimator.ofFloat(0, 1);
+ fadeIn.setDuration(revealDuration + arrowDuration);
fadeIn.setInterpolator(revealInterpolator);
+ fadeIn.addUpdateListener(anim -> {
+ float alpha = (float) anim.getAnimatedValue();
+ mArrow.setAlpha(alpha);
+ setAlpha(revealAnim.isStarted() ? alpha : 0);
+ });
openAnim.play(fadeIn);
// Animate the arrow.
mArrow.setScaleX(0);
mArrow.setScaleY(0);
Animator arrowScale = ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 1)
- .setDuration(res.getInteger(R.integer.config_popupArrowOpenDuration));
+ .setDuration(arrowDuration);
openAnim.addListener(new AnimatorListenerAdapter() {
@Override
@@ -369,7 +384,7 @@
});
mOpenCloseAnimator = openAnim;
- openAnim.playSequentially(revealAnim, arrowScale);
+ openAnim.playSequentially(arrowScale, revealAnim);
openAnim.start();
}
@@ -386,26 +401,35 @@
}
mIsOpen = false;
- final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet();
- // Hide the arrow
- closeAnim.play(ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 0));
- closeAnim.play(ObjectAnimator.ofFloat(mArrow, ALPHA, 0));
+ final AnimatorSet closeAnim = new AnimatorSet();
final Resources res = getResources();
- final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
+ final TimeInterpolator revealInterpolator = ACCEL_DEACCEL;
+ final long revealDuration = res.getInteger(R.integer.config_popupOpenCloseDuration);
+ final long arrowDuration = res.getInteger(R.integer.config_popupArrowOpenCloseDuration);
+
+ // Hide the arrow
+ Animator scaleArrow = ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 0)
+ .setDuration(arrowDuration);
// Rectangular reveal (reversed).
final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
.createRevealAnimator(this, true);
+ revealAnim.setDuration(revealDuration);
revealAnim.setInterpolator(revealInterpolator);
- closeAnim.play(revealAnim);
+ closeAnim.playSequentially(revealAnim, scaleArrow);
- Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0);
+ ValueAnimator fadeOut = ValueAnimator.ofFloat(getAlpha(), 0);
+ fadeOut.setDuration(revealDuration + arrowDuration);
fadeOut.setInterpolator(revealInterpolator);
+ fadeOut.addUpdateListener(anim -> {
+ float alpha = (float) anim.getAnimatedValue();
+ mArrow.setAlpha(alpha);
+ setAlpha(scaleArrow.isStarted() ? 0 : alpha);
+ });
closeAnim.play(fadeOut);
onCreateCloseAnimation(closeAnim);
- closeAnim.setDuration((long) res.getInteger(R.integer.config_popupOpenCloseDuration));
closeAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -427,21 +451,25 @@
protected void onCreateCloseAnimation(AnimatorSet anim) { }
private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
- int arrowCenterX = getResources().getDimensionPixelSize(mIsLeftAligned ^ mIsRtl ?
+ Resources res = getResources();
+ int arrowCenterX = res.getDimensionPixelSize(mIsLeftAligned ^ mIsRtl ?
R.dimen.popup_arrow_horizontal_center_start:
R.dimen.popup_arrow_horizontal_center_end);
+ int halfArrowWidth = res.getDimensionPixelSize(R.dimen.popup_arrow_width) / 2;
+ float arrowCornerRadius = res.getDimension(R.dimen.popup_arrow_corner_radius);
if (!mIsLeftAligned) {
arrowCenterX = getMeasuredWidth() - arrowCenterX;
}
int arrowCenterY = mIsAboveIcon ? getMeasuredHeight() : 0;
- mStartRect.set(arrowCenterX, arrowCenterY, arrowCenterX, arrowCenterY);
+ mStartRect.set(arrowCenterX - halfArrowWidth, arrowCenterY, arrowCenterX + halfArrowWidth,
+ arrowCenterY);
if (mEndRect.isEmpty()) {
mEndRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
}
return new RoundedRectRevealOutlineProvider
- (mOutlineRadius, mOutlineRadius, mStartRect, mEndRect);
+ (arrowCornerRadius, mOutlineRadius, mStartRect, mEndRect);
}
/**
@@ -454,7 +482,11 @@
}
mIsOpen = false;
mDeferContainerRemoval = false;
- mLauncher.getDragLayer().removeView(this);
- mLauncher.getDragLayer().removeView(mArrow);
+ getPopupContainer().removeView(this);
+ getPopupContainer().removeView(mArrow);
+ }
+
+ protected BaseDragLayer getPopupContainer() {
+ return mLauncher.getDragLayer();
}
}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 172cf41..12319f7 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -55,7 +55,6 @@
import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.dragndrop.DragController;
-import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.logging.LoggerUtils;
@@ -65,8 +64,10 @@
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
+import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.views.BaseDragLayer;
import java.util.ArrayList;
import java.util.List;
@@ -83,7 +84,7 @@
private final List<DeepShortcutView> mShortcuts = new ArrayList<>();
private final PointF mInterceptTouchDown = new PointF();
- private final Point mIconLastTouchPos = new Point();
+ protected final Point mIconLastTouchPos = new Point();
private final int mStartDragThreshold;
private final LauncherAccessibilityDelegate mAccessibilityDelegate;
@@ -146,10 +147,14 @@
command, mOriginalIcon, ContainerType.DEEPSHORTCUTS);
}
+ public OnClickListener getItemClickListener() {
+ return ItemClickHandler.INSTANCE;
+ }
+
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- DragLayer dl = mLauncher.getDragLayer();
+ BaseDragLayer dl = getPopupContainer();
if (!dl.isEventOverView(this, ev)) {
mLauncher.getUserEventDispatcher().logActionTapOutside(
LoggerUtils.newContainerTarget(ContainerType.DEEPSHORTCUTS));
@@ -179,17 +184,10 @@
return null;
}
- PopupDataProvider popupDataProvider = launcher.getPopupDataProvider();
- List<String> shortcutIds = popupDataProvider.getShortcutIdsForItem(itemInfo);
- List<NotificationKeyData> notificationKeys = popupDataProvider
- .getNotificationKeysForItem(itemInfo);
- List<SystemShortcut> systemShortcuts = popupDataProvider
- .getEnabledSystemShortcutsForItem(itemInfo);
-
final PopupContainerWithArrow container =
(PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
R.layout.popup_container, launcher.getDragLayer(), false);
- container.populateAndShow(icon, shortcutIds, notificationKeys, systemShortcuts);
+ container.populateAndShow(icon, itemInfo, SystemShortcutFactory.INSTANCE.get(launcher));
return container;
}
@@ -214,8 +212,21 @@
}
}
+ protected void populateAndShow(
+ BubbleTextView icon, ItemInfo item, SystemShortcutFactory factory) {
+ PopupDataProvider popupDataProvider = mLauncher.getPopupDataProvider();
+ populateAndShow(icon,
+ popupDataProvider.getShortcutCountForItem(item),
+ popupDataProvider.getNotificationKeysForItem(item),
+ factory.getEnabledShortcuts(mLauncher, item));
+ }
+
+ public ViewGroup getSystemShortcutContainerForTesting() {
+ return mSystemShortcutContainer;
+ }
+
@TargetApi(Build.VERSION_CODES.P)
- private void populateAndShow(final BubbleTextView originalIcon, final List<String> shortcutIds,
+ protected void populateAndShow(final BubbleTextView originalIcon, int shortcutCount,
final List<NotificationKeyData> notificationKeys, List<SystemShortcut> systemShortcuts) {
mNumNotifications = notificationKeys.size();
mOriginalIcon = originalIcon;
@@ -233,12 +244,12 @@
int viewsToFlip = getChildCount();
mSystemShortcutContainer = this;
- if (!shortcutIds.isEmpty()) {
+ if (shortcutCount > 0) {
if (mNotificationItemView != null) {
mNotificationItemView.addGutter();
}
- for (int i = shortcutIds.size(); i > 0; i--) {
+ for (int i = shortcutCount; i > 0; i--) {
mShortcuts.add(inflateAndAdd(R.layout.deep_shortcut, this));
}
updateHiddenShortcuts();
@@ -277,7 +288,7 @@
final Looper workerLooper = LauncherModel.getWorkerLooper();
new Handler(workerLooper).postAtFrontOfQueue(PopupPopulator.createUpdateRunnable(
mLauncher, originalItemInfo, new Handler(Looper.getMainLooper()),
- this, shortcutIds, mShortcuts, notificationKeys));
+ this, mShortcuts, notificationKeys));
}
private String getTitleForAccessibility() {
@@ -293,7 +304,7 @@
@Override
protected void getTargetObjectLocation(Rect outPos) {
- mLauncher.getDragLayer().getDescendantRectRelativeToSelf(mOriginalIcon, outPos);
+ getPopupContainer().getDescendantRectRelativeToSelf(mOriginalIcon, outPos);
outPos.top += mOriginalIcon.getPaddingTop();
outPos.left += mOriginalIcon.getPaddingLeft();
outPos.right -= mOriginalIcon.getPaddingRight();
@@ -384,13 +395,10 @@
if (view instanceof DeepShortcutView) {
// Expanded system shortcut, with both icon and text shown on white background.
final DeepShortcutView shortcutView = (DeepShortcutView) view;
- shortcutView.getIconView().setBackgroundResource(info.iconResId);
- shortcutView.getBubbleText().setText(info.labelResId);
+ info.setIconAndLabelFor(shortcutView.getIconView(), shortcutView.getBubbleText());
} else if (view instanceof ImageView) {
// Only the system shortcut icon shows on a gray background header.
- final ImageView shortcutIcon = (ImageView) view;
- shortcutIcon.setImageResource(info.iconResId);
- shortcutIcon.setContentDescription(getContext().getText(info.labelResId));
+ info.setIconAndContentDescriptionFor((ImageView) view);
}
view.setTag(info);
view.setOnClickListener(info.getOnClickListener(mLauncher,
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index f1b8ec0..3206503 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -18,7 +18,6 @@
import android.content.ComponentName;
import android.service.notification.StatusBarNotification;
-import android.support.annotation.NonNull;
import android.util.Log;
import com.android.launcher3.ItemInfo;
@@ -30,7 +29,6 @@
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.widget.WidgetListRowEntry;
@@ -41,6 +39,8 @@
import java.util.List;
import java.util.Map;
+import androidx.annotation.NonNull;
+
/**
* Provides data for the popup menu that appears after long-clicking on apps.
*/
@@ -49,17 +49,10 @@
private static final boolean LOGD = false;
private static final String TAG = "PopupDataProvider";
- /** Note that these are in order of priority. */
- private static final SystemShortcut[] SYSTEM_SHORTCUTS = new SystemShortcut[] {
- new SystemShortcut.AppInfo(),
- new SystemShortcut.Widgets(),
- new SystemShortcut.Install()
- };
-
private final Launcher mLauncher;
- /** Maps launcher activity components to their list of shortcut ids. */
- private MultiHashMap<ComponentKey, String> mDeepShortcutMap = new MultiHashMap<>();
+ /** Maps launcher activity components to a count of how many shortcuts they have. */
+ private HashMap<ComponentKey, Integer> mDeepShortcutMap = new HashMap<>();
/** Maps packages to their BadgeInfo's . */
private Map<PackageUserKey, BadgeInfo> mPackageUserToBadgeInfos = new HashMap<>();
/** Maps packages to their Widgets */
@@ -152,22 +145,22 @@
}
}
- public void setDeepShortcutMap(MultiHashMap<ComponentKey, String> deepShortcutMapCopy) {
+ public void setDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy) {
mDeepShortcutMap = deepShortcutMapCopy;
if (LOGD) Log.d(TAG, "bindDeepShortcutMap: " + mDeepShortcutMap);
}
- public List<String> getShortcutIdsForItem(ItemInfo info) {
+ public int getShortcutCountForItem(ItemInfo info) {
if (!DeepShortcutManager.supportsShortcuts(info)) {
- return Collections.EMPTY_LIST;
+ return 0;
}
ComponentName component = info.getTargetComponent();
if (component == null) {
- return Collections.EMPTY_LIST;
+ return 0;
}
- List<String> ids = mDeepShortcutMap.get(new ComponentKey(component, info.user));
- return ids == null ? Collections.EMPTY_LIST : ids;
+ Integer count = mDeepShortcutMap.get(new ComponentKey(component, info.user));
+ return count == null ? 0 : count;
}
public BadgeInfo getBadgeInfoForItem(ItemInfo info) {
@@ -191,16 +184,6 @@
: notificationListener.getNotificationsForKeys(notificationKeys);
}
- public @NonNull List<SystemShortcut> getEnabledSystemShortcutsForItem(ItemInfo info) {
- List<SystemShortcut> systemShortcuts = new ArrayList<>();
- for (SystemShortcut systemShortcut : SYSTEM_SHORTCUTS) {
- if (systemShortcut.getOnClickListener(mLauncher, info) != null) {
- systemShortcuts.add(systemShortcut);
- }
- }
- return systemShortcuts;
- }
-
public void cancelNotification(String notificationKey) {
NotificationListener notificationListener = NotificationListener.getInstanceIfConnected();
if (notificationListener == null) {
diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java
index b295bb2..2c59202 100644
--- a/src/com/android/launcher3/popup/PopupPopulator.java
+++ b/src/com/android/launcher3/popup/PopupPopulator.java
@@ -20,13 +20,11 @@
import android.os.Handler;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.ShortcutInfo;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.notification.NotificationInfo;
import com.android.launcher3.notification.NotificationKeyData;
import com.android.launcher3.shortcuts.DeepShortcutManager;
@@ -40,6 +38,9 @@
import java.util.Iterator;
import java.util.List;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
/**
* Contains logic relevant to populating a {@link PopupContainerWithArrow}. In particular,
* this class determines which items appear in the container, and in what order.
@@ -123,7 +124,7 @@
public static Runnable createUpdateRunnable(final Launcher launcher, final ItemInfo originalInfo,
final Handler uiHandler, final PopupContainerWithArrow container,
- final List<String> shortcutIds, final List<DeepShortcutView> shortcutViews,
+ final List<DeepShortcutView> shortcutViews,
final List<NotificationKeyData> notificationKeys) {
final ComponentName activity = originalInfo.getTargetComponent();
final UserHandle user = originalInfo.user;
@@ -140,7 +141,7 @@
}
List<ShortcutInfoCompat> shortcuts = DeepShortcutManager.getInstance(launcher)
- .queryForShortcutsContainer(activity, shortcutIds, user);
+ .queryForShortcutsContainer(activity, user);
String shortcutIdToDeDupe = notificationKeys.isEmpty() ? null
: notificationKeys.get(0).shortcutId;
shortcuts = PopupPopulator.sortAndFilterShortcuts(shortcuts, shortcutIdToDeDupe);
@@ -149,7 +150,7 @@
final ShortcutInfo si = new ShortcutInfo(shortcut, launcher);
// Use unbadged icon for the menu.
LauncherIcons li = LauncherIcons.obtain(launcher);
- li.createShortcutIcon(shortcut, false /* badged */).applyTo(si);
+ si.applyFrom(li.createShortcutIcon(shortcut, false /* badged */));
li.recycle();
si.rank = i;
diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java
new file mode 100644
index 0000000..c76fb96
--- /dev/null
+++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java
@@ -0,0 +1,79 @@
+/*
+ * 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.popup;
+
+import android.app.PendingIntent;
+import android.app.RemoteAction;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+
+public class RemoteActionShortcut extends SystemShortcut<Launcher> {
+ private static final String TAG = "RemoteActionShortcut";
+
+ private final RemoteAction mAction;
+
+ public RemoteActionShortcut(RemoteAction action) {
+ super(action.getIcon(), action.getTitle(), action.getContentDescription(),
+ R.id.action_remote_action_shortcut);
+ mAction = action;
+ }
+
+ @Override
+ public View.OnClickListener getOnClickListener(
+ final Launcher launcher, final ItemInfo itemInfo) {
+ return view -> {
+ AbstractFloatingView.closeAllOpenViews(launcher);
+
+ try {
+ mAction.getActionIntent().send(
+ launcher,
+ 0,
+ new Intent().putExtra(
+ Intent.EXTRA_PACKAGE_NAME,
+ itemInfo.getTargetComponent().getPackageName()),
+ (pendingIntent, intent, resultCode, resultData, resultExtras) -> {
+ if (resultData != null && !resultData.isEmpty()) {
+ Log.e(TAG, "Remote action returned result: " + mAction.getTitle()
+ + " : " + resultData);
+ Toast.makeText(launcher, resultData, Toast.LENGTH_SHORT).show();
+ }
+ },
+ new Handler(Looper.getMainLooper()));
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Remote action canceled: " + mAction.getTitle(), e);
+ Toast.makeText(launcher, launcher.getString(
+ R.string.remote_action_failed,
+ mAction.getTitle()),
+ Toast.LENGTH_SHORT)
+ .show();
+ }
+
+ launcher.getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.Touch.TAP,
+ LauncherLogProto.ControlType.REMOTE_ACTION_SHORTCUT, view);
+ };
+ }
+}
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 693e532..f9a2007 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -3,10 +3,17 @@
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
+import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
+import android.graphics.drawable.Icon;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.ImageView;
+import android.widget.TextView;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
@@ -23,18 +30,86 @@
import java.util.List;
/**
- * Represents a system shortcut for a given app. The shortcut should have a static label and
- * icon, and an onClickListener that depends on the item that the shortcut services.
+ * Represents a system shortcut for a given app. The shortcut should have a label and icon, and an
+ * onClickListener that depends on the item that the shortcut services.
*
* Example system shortcuts, defined as inner classes, include Widgets and AppInfo.
*/
public abstract class SystemShortcut<T extends BaseDraggingActivity> extends ItemInfo {
- public final int iconResId;
- public final int labelResId;
+ private final int mIconResId;
+ private final int mLabelResId;
+ private final Icon mIcon;
+ private final CharSequence mLabel;
+ private final CharSequence mContentDescription;
+ private final int mAccessibilityActionId;
public SystemShortcut(int iconResId, int labelResId) {
- this.iconResId = iconResId;
- this.labelResId = labelResId;
+ mIconResId = iconResId;
+ mLabelResId = labelResId;
+ mAccessibilityActionId = labelResId;
+ mIcon = null;
+ mLabel = null;
+ mContentDescription = null;
+ }
+
+ public SystemShortcut(Icon icon, CharSequence label, CharSequence contentDescription,
+ int accessibilityActionId) {
+ mIcon = icon;
+ mLabel = label;
+ mContentDescription = contentDescription;
+ mAccessibilityActionId = accessibilityActionId;
+ mIconResId = 0;
+ mLabelResId = 0;
+ }
+
+ public SystemShortcut(SystemShortcut other) {
+ mIconResId = other.mIconResId;
+ mLabelResId = other.mLabelResId;
+ mIcon = other.mIcon;
+ mLabel = other.mLabel;
+ mContentDescription = other.mContentDescription;
+ mAccessibilityActionId = other.mAccessibilityActionId;
+ }
+
+ public void setIconAndLabelFor(View iconView, TextView labelView) {
+ if (mIcon != null) {
+ mIcon.loadDrawableAsync(iconView.getContext(),
+ iconView::setBackground,
+ new Handler(Looper.getMainLooper()));
+ } else {
+ iconView.setBackgroundResource(mIconResId);
+ }
+
+ if (mLabel != null) {
+ labelView.setText(mLabel);
+ } else {
+ labelView.setText(mLabelResId);
+ }
+ }
+
+ public void setIconAndContentDescriptionFor(ImageView view) {
+ if (mIcon != null) {
+ mIcon.loadDrawableAsync(view.getContext(),
+ view::setImageDrawable,
+ new Handler(Looper.getMainLooper()));
+ } else {
+ view.setImageResource(mIconResId);
+ }
+
+ view.setContentDescription(getContentDescription(view.getContext()));
+ }
+
+ private CharSequence getContentDescription(Context context) {
+ return mContentDescription != null ? mContentDescription : context.getText(mLabelResId);
+ }
+
+ public AccessibilityNodeInfo.AccessibilityAction createAccessibilityAction(Context context) {
+ return new AccessibilityNodeInfo.AccessibilityAction(mAccessibilityActionId,
+ getContentDescription(context));
+ }
+
+ public boolean hasHandlerForAction(int action) {
+ return mAccessibilityActionId == action;
}
public abstract View.OnClickListener getOnClickListener(T activity, ItemInfo itemInfo);
diff --git a/src/com/android/launcher3/popup/SystemShortcutFactory.java b/src/com/android/launcher3/popup/SystemShortcutFactory.java
new file mode 100644
index 0000000..516fafa
--- /dev/null
+++ b/src/com/android/launcher3/popup/SystemShortcutFactory.java
@@ -0,0 +1,57 @@
+/*
+ * 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.popup;
+
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.ResourceBasedOverride;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+
+public class SystemShortcutFactory implements ResourceBasedOverride {
+
+ public static final MainThreadInitializedObject<SystemShortcutFactory> INSTANCE =
+ new MainThreadInitializedObject<>(c -> Overrides.getObject(
+ SystemShortcutFactory.class, c, R.string.system_shortcut_factory_class));
+
+ /** Note that these are in order of priority. */
+ private final SystemShortcut[] mAllShortcuts;
+
+ @SuppressWarnings("unused")
+ public SystemShortcutFactory() {
+ this(new SystemShortcut.AppInfo(),
+ new SystemShortcut.Widgets(), new SystemShortcut.Install());
+ }
+
+ protected SystemShortcutFactory(SystemShortcut... shortcuts) {
+ mAllShortcuts = shortcuts;
+ }
+
+ public @NonNull List<SystemShortcut> getEnabledShortcuts(Launcher launcher, ItemInfo info) {
+ List<SystemShortcut> systemShortcuts = new ArrayList<>();
+ for (SystemShortcut systemShortcut : mAllShortcuts) {
+ if (systemShortcut.getOnClickListener(launcher, info) != null) {
+ systemShortcuts.add(systemShortcut);
+ }
+ }
+ return systemShortcuts;
+ }
+}
diff --git a/src/com/android/launcher3/provider/ImportDataTask.java b/src/com/android/launcher3/provider/ImportDataTask.java
index b1dd003..e1b2698 100644
--- a/src/com/android/launcher3/provider/ImportDataTask.java
+++ b/src/com/android/launcher3/provider/ImportDataTask.java
@@ -32,8 +32,9 @@
import android.os.Process;
import android.text.TextUtils;
import android.util.ArrayMap;
-import android.util.LongSparseArray;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
import com.android.launcher3.DefaultLayoutParser;
import com.android.launcher3.LauncherAppState;
@@ -50,7 +51,9 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.GridSizeMigrationTask;
-import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSparseArrayMap;
+
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;
@@ -85,7 +88,7 @@
}
public boolean importWorkspace() throws Exception {
- ArrayList<Long> allScreens = LauncherDbUtils.getScreenIdsFromCursor(
+ IntArray allScreens = LauncherDbUtils.getScreenIdsFromCursor(
mContext.getContentResolver().query(mOtherScreensUri, null, null, null,
LauncherSettings.WorkspaceScreens.SCREEN_RANK));
FileLog.d(TAG, "Importing DB from " + mOtherFavoritesUri);
@@ -102,12 +105,12 @@
// Build screen update
ArrayList<ContentProviderOperation> screenOps = new ArrayList<>();
int count = allScreens.size();
- LongSparseArray<Long> screenIdMap = new LongSparseArray<>(count);
+ SparseIntArray screenIdMap = new SparseIntArray(count);
for (int i = 0; i < count; i++) {
ContentValues v = new ContentValues();
v.put(LauncherSettings.WorkspaceScreens._ID, i);
v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
- screenIdMap.put(allScreens.get(i), (long) i);
+ screenIdMap.put(allScreens.get(i), i);
screenOps.add(ContentProviderOperation.newInsert(
LauncherSettings.WorkspaceScreens.CONTENT_URI).withValues(v).build());
}
@@ -128,16 +131,16 @@
* 3) In the end fills any holes in hotseat with items from default hotseat layout.
*/
private void importWorkspaceItems(
- long firsetScreenId, LongSparseArray<Long> screenIdMap) throws Exception {
+ int firstScreenId, SparseIntArray screenIdMap) throws Exception {
String profileId = Long.toString(UserManagerCompat.getInstance(mContext)
.getSerialNumberForUser(Process.myUserHandle()));
boolean createEmptyRowOnFirstScreen;
- if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
+ if (FeatureFlags.QSB_ON_FIRST_SCREEN.get()) {
try (Cursor c = mContext.getContentResolver().query(mOtherFavoritesUri, null,
// get items on the first row of the first screen
"profileId = ? AND container = -100 AND screen = ? AND cellY = 0",
- new String[]{profileId, Long.toString(firsetScreenId)},
+ new String[]{profileId, Integer.toString(firstScreenId)},
null)) {
// First row of first screen is not empty
createEmptyRowOnFirstScreen = c.moveToNext();
@@ -190,7 +193,7 @@
int type = c.getInt(itemTypeIndex);
int container = c.getInt(containerIndex);
- long screen = c.getLong(screenIndex);
+ int screen = c.getInt(screenIndex);
int cellX = c.getInt(cellXIndex);
int cellY = c.getInt(cellYIndex);
@@ -199,7 +202,7 @@
switch (container) {
case Favorites.CONTAINER_DESKTOP: {
- Long newScreenId = screenIdMap.get(screen);
+ Integer newScreenId = screenIdMap.get(screen);
if (newScreenId == null) {
FileLog.d(TAG, String.format("Skipping item %d, type %d not on a valid screen %d", id, type, screen));
continue;
@@ -306,18 +309,15 @@
insertOperations.clear();
}
- LongArrayMap<Object> hotseatItems = GridSizeMigrationTask.removeBrokenHotseatItems(mContext);
+ IntSparseArrayMap<Object> hotseatItems = GridSizeMigrationTask.removeBrokenHotseatItems(mContext);
int myHotseatCount = LauncherAppState.getIDP(mContext).numHotseatIcons;
- if (!FeatureFlags.NO_ALL_APPS_ICON) {
- myHotseatCount--;
- }
if (hotseatItems.size() < myHotseatCount) {
// Insufficient hotseat items. Add a few more.
HotseatParserCallback parserCallback = new HotseatParserCallback(
hotseatTargetApps, hotseatItems, insertOperations, maxId + 1, myHotseatCount);
new HotseatLayoutParser(mContext,
- parserCallback).loadLayout(null, new ArrayList<Long>());
- mHotseatSize = (int) hotseatItems.keyAt(hotseatItems.size() - 1) + 1;
+ parserCallback).loadLayout(null, new IntArray());
+ mHotseatSize = hotseatItems.keyAt(hotseatItems.size() - 1) + 1;
if (!insertOperations.isEmpty()) {
mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY,
@@ -408,13 +408,13 @@
*/
private static class HotseatParserCallback implements LayoutParserCallback {
private final HashSet<String> mExistingApps;
- private final LongArrayMap<Object> mExistingItems;
+ private final IntSparseArrayMap<Object> mExistingItems;
private final ArrayList<ContentProviderOperation> mOutOps;
private final int mRequiredSize;
private int mStartItemId;
HotseatParserCallback(
- HashSet<String> existingApps, LongArrayMap<Object> existingItems,
+ HashSet<String> existingApps, IntSparseArrayMap<Object> existingItems,
ArrayList<ContentProviderOperation> outOps, int startItemId, int requiredSize) {
mExistingApps = existingApps;
mExistingItems = existingItems;
@@ -424,12 +424,12 @@
}
@Override
- public long generateNewItemId() {
+ public int generateNewItemId() {
return mStartItemId++;
}
@Override
- public long insertAndCheck(SQLiteDatabase db, ContentValues values) {
+ public int insertAndCheck(SQLiteDatabase db, ContentValues values) {
if (mExistingItems.size() >= mRequiredSize) {
// No need to add more items.
return 0;
@@ -448,7 +448,7 @@
mExistingApps.add(pkg);
// find next vacant spot.
- long screen = 0;
+ int screen = 0;
while (mExistingItems.get(screen) != null) {
screen++;
}
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index 74373d3..ab0703f 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -26,6 +26,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.LauncherSettings.WorkspaceScreens;
+import com.android.launcher3.util.IntArray;
import java.util.ArrayList;
import java.util.Collection;
@@ -47,7 +48,7 @@
public static boolean prepareScreenZeroToHostQsb(Context context, SQLiteDatabase db) {
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
// Get the existing screens
- ArrayList<Long> screenIds = getScreenIdsFromCursor(db.query(WorkspaceScreens.TABLE_NAME,
+ IntArray screenIds = getScreenIdsFromCursor(db.query(WorkspaceScreens.TABLE_NAME,
null, null, null, null, null, WorkspaceScreens.SCREEN_RANK));
if (screenIds.isEmpty()) {
@@ -57,10 +58,10 @@
}
if (screenIds.get(0) != 0) {
// First screen is not 0, we need to rename screens
- if (screenIds.indexOf(0L) > -1) {
+ if (screenIds.contains(0)) {
// There is already a screen 0. First rename it to a different screen.
- long newScreenId = 1;
- while (screenIds.indexOf(newScreenId) > -1) newScreenId++;
+ int newScreenId = 1;
+ while (screenIds.contains(newScreenId)) newScreenId++;
renameScreen(db, 0, newScreenId);
}
@@ -86,8 +87,8 @@
}
}
- private static void renameScreen(SQLiteDatabase db, long oldScreen, long newScreen) {
- String[] whereParams = new String[] { Long.toString(oldScreen) };
+ private static void renameScreen(SQLiteDatabase db, int oldScreen, int newScreen) {
+ String[] whereParams = new String[] { Integer.toString(oldScreen) };
ContentValues values = new ContentValues();
values.put(WorkspaceScreens._ID, newScreen);
@@ -101,19 +102,18 @@
/**
* Parses the cursor containing workspace screens table and returns the list of screen IDs
*/
- public static ArrayList<Long> getScreenIdsFromCursor(Cursor sc) {
+ public static IntArray getScreenIdsFromCursor(Cursor sc) {
try {
return iterateCursor(sc,
- sc.getColumnIndexOrThrow(WorkspaceScreens._ID),
- new ArrayList<Long>());
+ sc.getColumnIndexOrThrow(WorkspaceScreens._ID), new IntArray());
} finally {
sc.close();
}
}
- public static <T extends Collection<Long>> T iterateCursor(Cursor c, int columnIndex, T out) {
+ public static IntArray iterateCursor(Cursor c, int columnIndex, IntArray out) {
while (c.moveToNext()) {
- out.add(c.getLong(columnIndex));
+ out.add(c.getInt(columnIndex));
}
return out;
}
diff --git a/src/com/android/launcher3/provider/LossyScreenMigrationTask.java b/src/com/android/launcher3/provider/LossyScreenMigrationTask.java
index 51890d1..9166b83 100644
--- a/src/com/android/launcher3/provider/LossyScreenMigrationTask.java
+++ b/src/com/android/launcher3/provider/LossyScreenMigrationTask.java
@@ -27,7 +27,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.model.GridSizeMigrationTask;
-import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.IntSparseArrayMap;
import java.util.ArrayList;
@@ -39,8 +39,8 @@
private final SQLiteDatabase mDb;
- private final LongArrayMap<DbEntry> mOriginalItems;
- private final LongArrayMap<DbEntry> mUpdates;
+ private final IntSparseArrayMap<DbEntry> mOriginalItems;
+ private final IntSparseArrayMap<DbEntry> mUpdates;
protected LossyScreenMigrationTask(
Context context, InvariantDeviceProfile idp, SQLiteDatabase db) {
@@ -50,8 +50,8 @@
new Point(idp.numColumns, idp.numRows));
mDb = db;
- mOriginalItems = new LongArrayMap<>();
- mUpdates = new LongArrayMap<>();
+ mOriginalItems = new IntSparseArrayMap<>();
+ mUpdates = new IntSparseArrayMap<>();
}
@Override
@@ -65,7 +65,7 @@
}
@Override
- protected ArrayList<DbEntry> loadWorkspaceEntries(long screen) {
+ protected ArrayList<DbEntry> loadWorkspaceEntries(int screen) {
ArrayList<DbEntry> result = super.loadWorkspaceEntries(screen);
for (DbEntry entry : result) {
mOriginalItems.put(entry.id, entry.copy());
@@ -90,7 +90,7 @@
tempValues.clear();
update.addToContentValues(tempValues);
mDb.update(Favorites.TABLE_NAME, tempValues, "_id = ?",
- new String[] {Long.toString(update.id)});
+ new String[] {Integer.toString(update.id)});
}
}
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 5230160..17c66b4 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -92,7 +92,7 @@
new String[]{Integer.toString(Favorites.ITEM_TYPE_APPWIDGET)});
long myProfileId = helper.getDefaultUserSerial();
- if (Utilities.longCompare(oldProfileId, myProfileId) != 0) {
+ if (myProfileId != oldProfileId) {
FileLog.d(TAG, "Changing primary user id from " + oldProfileId + " to " + myProfileId);
migrateProfileId(db, myProfileId);
}
diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java
index 5b8ae58..ac1fafb 100644
--- a/src/com/android/launcher3/qsb/QsbContainerView.java
+++ b/src/com/android/launcher3/qsb/QsbContainerView.java
@@ -213,7 +213,7 @@
}
public boolean isQsbEnabled() {
- return FeatureFlags.QSB_ON_FIRST_SCREEN;
+ return FeatureFlags.QSB_ON_FIRST_SCREEN.get();
}
protected Bundle createBindOptions() {
diff --git a/src/com/android/launcher3/qsb/QsbWidgetHostView.java b/src/com/android/launcher3/qsb/QsbWidgetHostView.java
index cff5126..f5ecda3 100644
--- a/src/com/android/launcher3/qsb/QsbWidgetHostView.java
+++ b/src/com/android/launcher3/qsb/QsbWidgetHostView.java
@@ -16,7 +16,6 @@
package com.android.launcher3.qsb;
-import android.appwidget.AppWidgetHostView;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
@@ -26,17 +25,20 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
+import com.android.launcher3.widget.NavigableAppWidgetHostView;
/**
* Appwidget host view with QSB specific logic.
*/
-public class QsbWidgetHostView extends AppWidgetHostView {
+public class QsbWidgetHostView extends NavigableAppWidgetHostView {
@ViewDebug.ExportedProperty(category = "launcher")
private int mPreviousOrientation;
public QsbWidgetHostView(Context context) {
super(context);
+ setFocusable(true);
+ setBackgroundResource(R.drawable.qsb_host_view_focus_bg);
}
@Override
@@ -89,4 +91,9 @@
Launcher.getLauncher(v2.getContext()).startSearch("", false, null, true));
return v;
}
+
+ @Override
+ protected boolean shouldAllowDirectClick() {
+ return true;
+ }
}
diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
new file mode 100644
index 0000000..a9242f9
--- /dev/null
+++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
@@ -0,0 +1,287 @@
+/*
+ * 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.settings;
+
+import static com.android.launcher3.uioverrides.plugins.PluginManagerWrapper.PLUGIN_CHANGED;
+import static com.android.launcher3.uioverrides.plugins.PluginManagerWrapper.pluginEnabledKey;
+
+import android.annotation.TargetApi;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.config.FlagTogglerPrefUi;
+import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
+
+import java.util.List;
+import java.util.Set;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceDataStore;
+import androidx.preference.PreferenceFragment;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.PreferenceViewHolder;
+import androidx.preference.SwitchPreference;
+
+/**
+ * Dev-build only UI allowing developers to toggle flag settings and plugins.
+ * See {@link FeatureFlags}.
+ */
+@TargetApi(Build.VERSION_CODES.O)
+public class DeveloperOptionsFragment extends PreferenceFragment {
+
+ private static final String ACTION_PLUGIN_SETTINGS = "com.android.systemui.action.PLUGIN_SETTINGS";
+ private static final String PLUGIN_PERMISSION = "com.android.systemui.permission.PLUGIN";
+
+ private final BroadcastReceiver mPluginReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ loadPluginPrefs();
+ }
+ };
+
+ private PreferenceScreen mPreferenceScreen;
+
+ private PreferenceCategory mPluginsCategory;
+ private FlagTogglerPrefUi mFlagTogglerPrefUi;
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ getContext().registerReceiver(mPluginReceiver, filter);
+ getContext().registerReceiver(mPluginReceiver,
+ new IntentFilter(Intent.ACTION_USER_UNLOCKED));
+
+ mPreferenceScreen = getPreferenceManager().createPreferenceScreen(getContext());
+ setPreferenceScreen(mPreferenceScreen);
+
+ initFlags();
+ loadPluginPrefs();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ getContext().unregisterReceiver(mPluginReceiver);
+ }
+
+ private PreferenceCategory newCategory(String title) {
+ PreferenceCategory category = new PreferenceCategory(getContext());
+ category.setOrder(Preference.DEFAULT_ORDER);
+ category.setTitle(title);
+ mPreferenceScreen.addPreference(category);
+ return category;
+ }
+
+ private void initFlags() {
+ if (!FeatureFlags.showFlagTogglerUi(getContext())) {
+ return;
+ }
+
+ mFlagTogglerPrefUi = new FlagTogglerPrefUi(this);
+ mFlagTogglerPrefUi.applyTo(newCategory("Feature flags"));
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ if (mFlagTogglerPrefUi != null) {
+ mFlagTogglerPrefUi.onCreateOptionsMenu(menu);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (mFlagTogglerPrefUi != null) {
+ mFlagTogglerPrefUi.onOptionsItemSelected(item);
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onStop() {
+ if (mFlagTogglerPrefUi != null) {
+ mFlagTogglerPrefUi.onStop();
+ }
+ super.onStop();
+ }
+
+ private void loadPluginPrefs() {
+ if (mPluginsCategory != null) {
+ mPreferenceScreen.removePreference(mPluginsCategory);
+ }
+ if (!PluginManagerWrapper.hasPlugins(getActivity())) {
+ mPluginsCategory = null;
+ return;
+ }
+ mPluginsCategory = newCategory("Plugins");
+
+ PluginManagerWrapper manager = PluginManagerWrapper.INSTANCE.get(getContext());
+ Context prefContext = getContext();
+ PackageManager pm = getContext().getPackageManager();
+
+ Set<String> pluginActions = manager.getPluginActions();
+ ArrayMap<String, ArraySet<String>> plugins = new ArrayMap<>();
+ for (String action : pluginActions) {
+ String name = toName(action);
+ List<ResolveInfo> result = pm.queryIntentServices(
+ new Intent(action), PackageManager.MATCH_DISABLED_COMPONENTS);
+ for (ResolveInfo info : result) {
+ String packageName = info.serviceInfo.packageName;
+ if (!plugins.containsKey(packageName)) {
+ plugins.put(packageName, new ArraySet<>());
+ }
+ plugins.get(packageName).add(name);
+ }
+ }
+
+ List<PackageInfo> apps = pm.getPackagesHoldingPermissions(new String[]{PLUGIN_PERMISSION},
+ PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_SERVICES);
+ PreferenceDataStore enabled = manager.getPluginEnabler();
+ apps.forEach(app -> {
+ if (!plugins.containsKey(app.packageName)) return;
+ SwitchPreference pref = new PluginPreference(prefContext, app, enabled);
+ pref.setSummary("Plugins: " + toString(plugins.get(app.packageName)));
+ mPluginsCategory.addPreference(pref);
+ });
+ }
+
+ private String toString(ArraySet<String> plugins) {
+ StringBuilder b = new StringBuilder();
+ for (String string : plugins) {
+ if (b.length() != 0) {
+ b.append(", ");
+ }
+ b.append(string);
+ }
+ return b.toString();
+ }
+
+ private String toName(String action) {
+ String str = action.replace("com.android.systemui.action.PLUGIN_", "");
+ StringBuilder b = new StringBuilder();
+ for (String s : str.split("_")) {
+ if (b.length() != 0) {
+ b.append(' ');
+ }
+ b.append(s.substring(0, 1));
+ b.append(s.substring(1).toLowerCase());
+ }
+ return b.toString();
+ }
+
+ private static class PluginPreference extends SwitchPreference {
+ private final boolean mHasSettings;
+ private final PackageInfo mInfo;
+ private final PreferenceDataStore mPluginEnabler;
+
+ public PluginPreference(Context prefContext, PackageInfo info,
+ PreferenceDataStore pluginEnabler) {
+ super(prefContext);
+ PackageManager pm = prefContext.getPackageManager();
+ mHasSettings = pm.resolveActivity(new Intent(ACTION_PLUGIN_SETTINGS)
+ .setPackage(info.packageName), 0) != null;
+ mInfo = info;
+ mPluginEnabler = pluginEnabler;
+ setTitle(info.applicationInfo.loadLabel(pm));
+ setChecked(isPluginEnabled());
+ setWidgetLayoutResource(R.layout.switch_preference_with_settings);
+ }
+
+ private boolean isEnabled(ComponentName cn) {
+ return mPluginEnabler.getBoolean(pluginEnabledKey(cn), true);
+
+ }
+
+ private boolean isPluginEnabled() {
+ for (int i = 0; i < mInfo.services.length; i++) {
+ ComponentName componentName = new ComponentName(mInfo.packageName,
+ mInfo.services[i].name);
+ if (!isEnabled(componentName)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean persistBoolean(boolean isEnabled) {
+ boolean shouldSendBroadcast = false;
+ for (int i = 0; i < mInfo.services.length; i++) {
+ ComponentName componentName = new ComponentName(mInfo.packageName,
+ mInfo.services[i].name);
+
+ if (isEnabled(componentName) != isEnabled) {
+ mPluginEnabler.putBoolean(pluginEnabledKey(componentName), isEnabled);
+ shouldSendBroadcast = true;
+ }
+ }
+ if (shouldSendBroadcast) {
+ final String pkg = mInfo.packageName;
+ final Intent intent = new Intent(PLUGIN_CHANGED,
+ pkg != null ? Uri.fromParts("package", pkg, null) : null);
+ getContext().sendBroadcast(intent);
+ }
+ setChecked(isEnabled);
+ return true;
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ holder.findViewById(R.id.settings).setVisibility(mHasSettings ? View.VISIBLE
+ : View.GONE);
+ holder.findViewById(R.id.divider).setVisibility(mHasSettings ? View.VISIBLE
+ : View.GONE);
+ holder.findViewById(R.id.settings).setOnClickListener(v -> {
+ ResolveInfo result = v.getContext().getPackageManager().resolveActivity(
+ new Intent(ACTION_PLUGIN_SETTINGS).setPackage(
+ mInfo.packageName), 0);
+ if (result != null) {
+ v.getContext().startActivity(new Intent().setComponent(
+ new ComponentName(result.activityInfo.packageName,
+ result.activityInfo.name)));
+ }
+ });
+ holder.itemView.setOnLongClickListener(v -> {
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.setData(Uri.fromParts("package", mInfo.packageName, null));
+ getContext().startActivity(intent);
+ return true;
+ });
+ }
+ }
+}
diff --git a/src/com/android/launcher3/settings/IconBadgingPreference.java b/src/com/android/launcher3/settings/IconBadgingPreference.java
new file mode 100644
index 0000000..7c97b38
--- /dev/null
+++ b/src/com/android/launcher3/settings/IconBadgingPreference.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2017 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.settings;
+
+import static com.android.launcher3.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
+import static com.android.launcher3.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGS;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.launcher3.notification.NotificationListener;
+import com.android.launcher3.util.SecureSettingsObserver;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+/**
+ * A {@link Preference} for indicating icon badging status.
+ * Also has utility methods for updating UI based on badging status changes.
+ */
+public class IconBadgingPreference extends Preference
+ implements SecureSettingsObserver.OnChangeListener {
+
+ private boolean mWidgetFrameVisible = false;
+
+ /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
+ private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
+
+ public IconBadgingPreference(
+ Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public IconBadgingPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public IconBadgingPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public IconBadgingPreference(Context context) {
+ super(context);
+ }
+
+ private void setWidgetFrameVisible(boolean isVisible) {
+ if (mWidgetFrameVisible != isVisible) {
+ mWidgetFrameVisible = isVisible;
+ notifyChanged();
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ View widgetFrame = holder.findViewById(android.R.id.widget_frame);
+ if (widgetFrame != null) {
+ widgetFrame.setVisibility(mWidgetFrameVisible ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ @Override
+ public void onSettingsChanged(boolean enabled) {
+ int summary = enabled ? R.string.icon_badging_desc_on : R.string.icon_badging_desc_off;
+
+ boolean serviceEnabled = true;
+ if (enabled) {
+ // Check if the listener is enabled or not.
+ String enabledListeners = Settings.Secure.getString(
+ getContext().getContentResolver(), NOTIFICATION_ENABLED_LISTENERS);
+ ComponentName myListener =
+ new ComponentName(getContext(), NotificationListener.class);
+ serviceEnabled = enabledListeners != null &&
+ (enabledListeners.contains(myListener.flattenToString()) ||
+ enabledListeners.contains(myListener.flattenToShortString()));
+ if (!serviceEnabled) {
+ summary = R.string.title_missing_notification_access;
+ }
+ }
+ setWidgetFrameVisible(!serviceEnabled);
+ setFragment(serviceEnabled ? null : NotificationAccessConfirmation.class.getName());
+ setSummary(summary);
+ }
+
+ public static class NotificationAccessConfirmation
+ extends DialogFragment implements DialogInterface.OnClickListener {
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Context context = getActivity();
+ String msg = context.getString(R.string.msg_missing_notification_access,
+ context.getString(R.string.derived_app_name));
+ return new AlertDialog.Builder(context)
+ .setTitle(R.string.title_missing_notification_access)
+ .setMessage(msg)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(R.string.title_change_settings, this)
+ .create();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ ComponentName cn = new ComponentName(getActivity(), NotificationListener.class);
+ Bundle showFragmentArgs = new Bundle();
+ showFragmentArgs.putString(EXTRA_FRAGMENT_ARG_KEY, cn.flattenToString());
+
+ Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .putExtra(EXTRA_FRAGMENT_ARG_KEY, cn.flattenToString())
+ .putExtra(EXTRA_SHOW_FRAGMENT_ARGS, showFragmentArgs);
+ getActivity().startActivity(intent);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/settings/PreferenceHighlighter.java b/src/com/android/launcher3/settings/PreferenceHighlighter.java
new file mode 100644
index 0000000..8ba8146
--- /dev/null
+++ b/src/com/android/launcher3/settings/PreferenceHighlighter.java
@@ -0,0 +1,127 @@
+/*
+ * 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.settings;
+
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.Property;
+import android.view.View;
+
+import com.android.launcher3.util.Themes;
+
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.ItemDecoration;
+import androidx.recyclerview.widget.RecyclerView.State;
+import androidx.recyclerview.widget.RecyclerView.ViewHolder;
+
+/**
+ * Utility class for highlighting a preference
+ */
+public class PreferenceHighlighter extends ItemDecoration implements Runnable {
+
+ private static final Property<PreferenceHighlighter, Integer> HIGHLIGHT_COLOR =
+ new Property<PreferenceHighlighter, Integer>(Integer.TYPE, "highlightColor") {
+
+ @Override
+ public Integer get(PreferenceHighlighter highlighter) {
+ return highlighter.mHighlightColor;
+ }
+
+ @Override
+ public void set(PreferenceHighlighter highlighter, Integer value) {
+ highlighter.mHighlightColor = value;
+ highlighter.mRv.invalidateItemDecorations();
+ }
+ };
+
+ private static final long HIGHLIGHT_DURATION = 15000L;
+ private static final long HIGHLIGHT_FADE_OUT_DURATION = 500L;
+ private static final long HIGHLIGHT_FADE_IN_DURATION = 200L;
+ private static final int END_COLOR = setColorAlphaBound(Color.WHITE, 0);
+
+ private final Paint mPaint = new Paint();
+ private final RecyclerView mRv;
+ private final int mIndex;
+
+ private boolean mHighLightStarted = false;
+ private int mHighlightColor = END_COLOR;
+
+
+ public PreferenceHighlighter(RecyclerView rv, int index) {
+ mRv = rv;
+ mIndex = index;
+ }
+
+ @Override
+ public void run() {
+ mRv.addItemDecoration(this);
+ mRv.smoothScrollToPosition(mIndex);
+ }
+
+ @Override
+ public void onDraw(Canvas c, RecyclerView parent, State state) {
+ ViewHolder holder = parent.findViewHolderForAdapterPosition(mIndex);
+ if (holder == null) {
+ return;
+ }
+ if (!mHighLightStarted && state.getRemainingScrollVertical() != 0) {
+ // Wait until scrolling stopped
+ return;
+ }
+
+ if (!mHighLightStarted) {
+ // Start highlight
+ int colorTo = setColorAlphaBound(Themes.getColorAccent(mRv.getContext()), 66);
+ ObjectAnimator anim = ObjectAnimator.ofArgb(this, HIGHLIGHT_COLOR, END_COLOR, colorTo);
+ anim.setDuration(HIGHLIGHT_FADE_IN_DURATION);
+ anim.setRepeatMode(ValueAnimator.REVERSE);
+ anim.setRepeatCount(4);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ removeHighlight();
+ }
+ });
+ anim.start();
+ mHighLightStarted = true;
+ }
+
+ View view = holder.itemView;
+ mPaint.setColor(mHighlightColor);
+ c.drawRect(0, view.getY(), parent.getWidth(), view.getY() + view.getHeight(), mPaint);
+ }
+
+ private void removeHighlight() {
+ ObjectAnimator anim = ObjectAnimator.ofArgb(
+ this, HIGHLIGHT_COLOR, mHighlightColor, END_COLOR);
+ anim.setDuration(HIGHLIGHT_FADE_OUT_DURATION);
+ anim.setStartDelay(HIGHLIGHT_DURATION);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mRv.removeItemDecoration(PreferenceHighlighter.this);
+ }
+ });
+ anim.start();
+ }
+}
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
new file mode 100644
index 0000000..7c158d9
--- /dev/null
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2015 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.settings;
+
+import static com.android.launcher3.SessionCommitReceiver.ADD_ICON_PREFERENCE_KEY;
+import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
+import static com.android.launcher3.states.RotationHelper.getAllowRotationDefaultValue;
+import static com.android.launcher3.util.SecureSettingsObserver.newNotificationSettingsObserver;
+
+import android.app.Activity;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import com.android.launcher3.LauncherFiles;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.graphics.IconShapeOverride;
+import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
+import com.android.launcher3.util.SecureSettingsObserver;
+
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragment;
+import androidx.preference.PreferenceFragment.OnPreferenceStartFragmentCallback;
+import androidx.preference.PreferenceFragment.OnPreferenceStartScreenCallback;
+import androidx.preference.PreferenceGroup.PreferencePositionCallback;
+import androidx.preference.PreferenceScreen;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * Settings activity for Launcher. Currently implements the following setting: Allow rotation
+ */
+public class SettingsActivity extends Activity
+ implements OnPreferenceStartFragmentCallback, OnPreferenceStartScreenCallback {
+
+ private static final String DEVELOPER_OPTIONS_KEY = "pref_developer_options";
+ private static final String FLAGS_PREFERENCE_KEY = "flag_toggler";
+
+ private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging";
+ /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
+ private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
+
+ public static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
+ public static final String EXTRA_SHOW_FRAGMENT_ARGS = ":settings:show_fragment_args";
+ private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600;
+ public static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState == null) {
+ Bundle args = new Bundle();
+ String prefKey = getIntent().getStringExtra(EXTRA_FRAGMENT_ARG_KEY);
+ if (!TextUtils.isEmpty(prefKey)) {
+ args.putString(EXTRA_FRAGMENT_ARG_KEY, prefKey);
+ }
+
+ Fragment f = Fragment.instantiate(
+ this, getString(R.string.settings_fragment_name), args);
+ // Display the fragment as the main content.
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, f)
+ .commit();
+ }
+ }
+
+ private boolean startFragment(String fragment, Bundle args, String key) {
+ if (Utilities.ATLEAST_P && getFragmentManager().isStateSaved()) {
+ // Sometimes onClick can come after onPause because of being posted on the handler.
+ // Skip starting new fragments in that case.
+ return false;
+ }
+ Fragment f = Fragment.instantiate(this, fragment, args);
+ if (f instanceof DialogFragment) {
+ ((DialogFragment) f).show(getFragmentManager(), key);
+ } else {
+ getFragmentManager()
+ .beginTransaction()
+ .replace(android.R.id.content, f)
+ .addToBackStack(key)
+ .commit();
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onPreferenceStartFragment(
+ PreferenceFragment preferenceFragment, Preference pref) {
+ return startFragment(pref.getFragment(), pref.getExtras(), pref.getKey());
+ }
+
+ @Override
+ public boolean onPreferenceStartScreen(PreferenceFragment caller, PreferenceScreen pref) {
+ Bundle args = new Bundle();
+ args.putString(PreferenceFragment.ARG_PREFERENCE_ROOT, pref.getKey());
+ return startFragment(getString(R.string.settings_fragment_name), args, pref.getKey());
+ }
+
+ /**
+ * This fragment shows the launcher preferences.
+ */
+ public static class LauncherSettingsFragment extends PreferenceFragment {
+
+ private SecureSettingsObserver mIconBadgingObserver;
+
+ private String mHighLightKey;
+ private boolean mPreferenceHighlighted = false;
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ final Bundle args = getArguments();
+ mHighLightKey = args == null ? null : args.getString(EXTRA_FRAGMENT_ARG_KEY);
+ if (rootKey == null && !TextUtils.isEmpty(mHighLightKey)) {
+ rootKey = getParentKeyForPref(mHighLightKey);
+ }
+
+ if (savedInstanceState != null) {
+ mPreferenceHighlighted = savedInstanceState.getBoolean(SAVE_HIGHLIGHTED_KEY);
+ }
+
+ getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY);
+ setPreferencesFromResource(R.xml.launcher_preferences, rootKey);
+
+ PreferenceScreen screen = getPreferenceScreen();
+ for (int i = screen.getPreferenceCount() - 1; i >= 0; i--) {
+ Preference preference = screen.getPreference(i);
+ if (!initPreference(preference)) {
+ screen.removePreference(preference);
+ }
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted);
+ }
+
+ protected String getParentKeyForPref(String key) {
+ return null;
+ }
+
+ /**
+ * Initializes a preference. This is called for every preference. Returning false here
+ * will remove that preference from the list.
+ */
+ protected boolean initPreference(Preference preference) {
+ switch (preference.getKey()) {
+ case ICON_BADGING_PREFERENCE_KEY:
+ if (!Utilities.ATLEAST_OREO ||
+ !getResources().getBoolean(R.bool.notification_badging_enabled)) {
+ return false;
+ }
+
+ // Listen to system notification badge settings while this UI is active.
+ mIconBadgingObserver = newNotificationSettingsObserver(
+ getActivity(), (IconBadgingPreference) preference);
+ mIconBadgingObserver.register();
+ // Also listen if notification permission changes
+ mIconBadgingObserver.getResolver().registerContentObserver(
+ Settings.Secure.getUriFor(NOTIFICATION_ENABLED_LISTENERS), false,
+ mIconBadgingObserver);
+ mIconBadgingObserver.dispatchOnChange();
+ return true;
+
+ case ADD_ICON_PREFERENCE_KEY:
+ return Utilities.ATLEAST_OREO;
+
+ case IconShapeOverride.KEY_PREFERENCE:
+ if (!IconShapeOverride.isSupported(getActivity())) {
+ return false;
+ }
+ IconShapeOverride.handlePreferenceUi((ListPreference) preference);
+ return true;
+
+ case ALLOW_ROTATION_PREFERENCE_KEY:
+ if (getResources().getBoolean(R.bool.allow_rotation)) {
+ // Launcher supports rotation by default. No need to show this setting.
+ return false;
+ }
+ // Initialize the UI once
+ preference.setDefaultValue(getAllowRotationDefaultValue());
+ return true;
+
+ case FLAGS_PREFERENCE_KEY:
+ // Only show flag toggler UI if this build variant implements that.
+ return FeatureFlags.showFlagTogglerUi(getContext());
+
+ case DEVELOPER_OPTIONS_KEY:
+ // Show if plugins are enabled or flag UI is enabled.
+ return FeatureFlags.showFlagTogglerUi(getContext()) ||
+ PluginManagerWrapper.hasPlugins(getContext());
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ if (isAdded() && !mPreferenceHighlighted) {
+ PreferenceHighlighter highlighter = createHighlighter();
+ if (highlighter != null) {
+ getView().postDelayed(highlighter, DELAY_HIGHLIGHT_DURATION_MILLIS);
+ mPreferenceHighlighted = true;
+ }
+ }
+ }
+
+ private PreferenceHighlighter createHighlighter() {
+ if (TextUtils.isEmpty(mHighLightKey)) {
+ return null;
+ }
+
+ PreferenceScreen screen = getPreferenceScreen();
+ if (screen == null) {
+ return null;
+ }
+
+ RecyclerView list = getListView();
+ PreferencePositionCallback callback = (PreferencePositionCallback) list.getAdapter();
+ int position = callback.getPreferenceAdapterPosition(mHighLightKey);
+ return position >= 0 ? new PreferenceHighlighter(list, position) : null;
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mIconBadgingObserver != null) {
+ mIconBadgingObserver.unregister();
+ mIconBadgingObserver = null;
+ }
+ super.onDestroy();
+ }
+ }
+}
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java b/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
index c809f27..2daa2fe 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
@@ -18,8 +18,10 @@
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Toast;
@@ -38,6 +40,10 @@
private Toast mInstructionToast;
+ private boolean mShowLoadingState;
+ private Drawable mLoadingStatePlaceholder;
+ private final Rect mLoadingStateBounds = new Rect();
+
public DeepShortcutTextView(Context context) {
this(context, null, 0);
}
@@ -53,6 +59,7 @@
mDragHandleWidth = resources.getDimensionPixelSize(R.dimen.popup_padding_end)
+ resources.getDimensionPixelSize(R.dimen.deep_shortcut_drag_handle_size)
+ resources.getDimensionPixelSize(R.dimen.deep_shortcut_drawable_padding) / 2;
+ showLoadingState(true);
}
@Override
@@ -63,6 +70,25 @@
if (!Utilities.isRtl(getResources())) {
mDragHandleBounds.offset(getMeasuredWidth() - mDragHandleBounds.width(), 0);
}
+
+ setLoadingBounds();
+ }
+
+ private void setLoadingBounds() {
+ if (mLoadingStatePlaceholder == null) {
+ return;
+ }
+ mLoadingStateBounds.set(
+ 0,
+ 0,
+ getMeasuredWidth() - mDragHandleWidth - getPaddingStart(),
+ mLoadingStatePlaceholder.getIntrinsicHeight());
+ mLoadingStateBounds.offset(
+ Utilities.isRtl(getResources()) ? mDragHandleWidth : getPaddingStart(),
+ (int) ((getMeasuredHeight() - mLoadingStatePlaceholder.getIntrinsicHeight())
+ / 2.0f)
+ );
+ mLoadingStatePlaceholder.setBounds(mLoadingStateBounds);
}
@Override
@@ -71,6 +97,15 @@
}
@Override
+ public void setText(CharSequence text, BufferType type) {
+ super.setText(text, type);
+
+ if (!TextUtils.isEmpty(text)) {
+ showLoadingState(false);
+ }
+ }
+
+ @Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
// Show toast if user touches the drag handle (long clicks still start the drag).
@@ -88,6 +123,34 @@
return super.performClick();
}
+ @Override
+ public void onDraw(Canvas canvas) {
+ if (!mShowLoadingState) {
+ super.onDraw(canvas);
+ return;
+ }
+
+ mLoadingStatePlaceholder.draw(canvas);
+ }
+
+ private void showLoadingState(boolean loading) {
+ if (loading == mShowLoadingState) {
+ return;
+ }
+
+ mShowLoadingState = loading;
+
+ if (loading) {
+ mLoadingStatePlaceholder = getContext().getDrawable(
+ R.drawable.deep_shortcuts_text_placeholder);
+ setLoadingBounds();
+ } else {
+ mLoadingStatePlaceholder = null;
+ }
+
+ invalidate();
+ }
+
private void showToast() {
if (mInstructionToast != null) {
mInstructionToast.cancel();
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
index 9ad266b..7b93ba2 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
@@ -40,8 +40,6 @@
private static final Point sTempPoint = new Point();
- private final Rect mPillRect;
-
private BubbleTextView mBubbleText;
private View mIconView;
private View mDivider;
@@ -59,8 +57,6 @@
public DeepShortcutView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
-
- mPillRect = new Rect();
}
@Override
@@ -98,12 +94,6 @@
return sTempPoint;
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- mPillRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
- }
-
/** package private **/
public void applyShortcutInfo(ShortcutInfo info, ShortcutInfoCompat detail,
PopupContainerWithArrow container) {
@@ -121,7 +111,7 @@
mBubbleText.setText(usingLongLabel ? longLabel : mDetail.getShortLabel());
// TODO: Add the click handler to this view directly and not the child view.
- mBubbleText.setOnClickListener(ItemClickHandler.INSTANCE);
+ mBubbleText.setOnClickListener(container.getItemClickListener());
mBubbleText.setOnLongClickListener(container);
mBubbleText.setOnTouchListener(container);
}
@@ -141,4 +131,8 @@
public View getIconView() {
return mIconView;
}
+
+ public ShortcutInfoCompat getDetail() {
+ return mDetail;
+ }
}
diff --git a/src/com/android/launcher3/states/InternalStateHandler.java b/src/com/android/launcher3/states/InternalStateHandler.java
index c6370c5..d326ff3 100644
--- a/src/com/android/launcher3/states/InternalStateHandler.java
+++ b/src/com/android/launcher3/states/InternalStateHandler.java
@@ -36,6 +36,7 @@
public abstract class InternalStateHandler extends Binder {
public static final String EXTRA_STATE_HANDLER = "launcher.state_handler";
+ public static final String EXTRA_FROM_HOME_KEY = "android.intent.extra.FROM_HOME_KEY";
private static final Scheduler sScheduler = new Scheduler();
@@ -76,6 +77,10 @@
Launcher launcher, Intent intent, boolean alreadyOnHome, boolean explicitIntent) {
boolean result = false;
if (intent != null && intent.getExtras() != null) {
+ // If we know that this the intent comes from pressing Home, defer to the default
+ // processing.
+ if (intent.hasExtra(EXTRA_FROM_HOME_KEY)) return false;
+
IBinder stateBinder = intent.getExtras().getBinder(EXTRA_STATE_HANDLER);
if (stateBinder instanceof InternalStateHandler) {
InternalStateHandler handler = (InternalStateHandler) stateBinder;
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index e866445..9c4a4ea 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -56,7 +56,7 @@
private final Activity mActivity;
private final SharedPreferences mPrefs;
- private final boolean mIgnoreAutoRotateSettings;
+ private boolean mIgnoreAutoRotateSettings;
private boolean mAutoRotateEnabled;
/**
@@ -110,6 +110,13 @@
}
}
+ // Used by tests only.
+ public void forceAllowRotationForTesting(boolean allowRotation) {
+ mIgnoreAutoRotateSettings =
+ allowRotation || mActivity.getResources().getBoolean(R.bool.allow_rotation);
+ notifyChange();
+ }
+
public void initialize() {
if (!mInitialized) {
mInitialized = true;
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 55f850c..ce1cc89 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -39,10 +39,12 @@
import com.android.launcher3.LauncherStateManager.AnimationComponents;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
+import com.android.launcher3.TestProtocol;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -254,7 +256,7 @@
}
@Override
- public boolean onDrag(float displacement, float velocity) {
+ public boolean onDrag(float displacement) {
float deltaProgress = mProgressMultiplier * (displacement - mDisplacementShift);
float progress = deltaProgress + mStartProgress;
updateProgress(progress);
@@ -515,6 +517,9 @@
logReachedState(logAction, targetState);
}
mLauncher.getStateManager().goToState(targetState, false /* animated */);
+
+ AccessibilityManagerCompat.sendEventToTest(
+ mLauncher, TestProtocol.SWITCHED_TO_STATE_MESSAGE);
}
}
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index f2f5592..52fef9f 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -162,7 +162,7 @@
*
* @param v The view that was clicked. Must be a tagged with a {@link ShortcutInfo}.
*/
- private static void onClickAppShortcut(View v, ShortcutInfo shortcut, Launcher launcher) {
+ public static void onClickAppShortcut(View v, ShortcutInfo shortcut, Launcher launcher) {
if (shortcut.isDisabled()) {
final int disabledFlags = shortcut.runtimeStatusFlags & ShortcutInfo.FLAG_DISABLED_MASK;
if ((disabledFlags &
@@ -218,7 +218,7 @@
if (item instanceof ShortcutInfo) {
ShortcutInfo si = (ShortcutInfo) item;
if (si.hasStatusFlag(ShortcutInfo.FLAG_SUPPORTS_WEB_UI)
- && intent.getAction() == Intent.ACTION_VIEW) {
+ && Intent.ACTION_VIEW.equals(intent.getAction())) {
// make a copy of the intent that has the package set to null
// we do this because the platform sometimes disables instant
// apps temporarily (triggered by the user) and fallbacks to the
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 6f012f6..babbcdd 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -17,7 +17,6 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
-
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -30,7 +29,6 @@
import com.android.launcher3.DropTarget;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.folder.Folder;
diff --git a/src/com/android/launcher3/touch/OverScroll.java b/src/com/android/launcher3/touch/OverScroll.java
index dc801ec..bf895ad 100644
--- a/src/com/android/launcher3/touch/OverScroll.java
+++ b/src/com/android/launcher3/touch/OverScroll.java
@@ -20,7 +20,7 @@
*/
public class OverScroll {
- private static final float OVERSCROLL_DAMP_FACTOR = 0.07f;
+ public static final float OVERSCROLL_DAMP_FACTOR = 0.07f;
/**
* This curve determines how the effect of scrolling over the limits of the page diminishes
diff --git a/src/com/android/launcher3/touch/SwipeDetector.java b/src/com/android/launcher3/touch/SwipeDetector.java
index 703e4fd..a0a410e 100644
--- a/src/com/android/launcher3/touch/SwipeDetector.java
+++ b/src/com/android/launcher3/touch/SwipeDetector.java
@@ -19,12 +19,14 @@
import android.content.Context;
import android.graphics.PointF;
-import android.support.annotation.NonNull;
-import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.VelocityTracker;
import android.view.ViewConfiguration;
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+
/**
* One dimensional scroll/drag/swipe gesture detector.
*
@@ -51,12 +53,6 @@
*/
public static final float RELEASE_VELOCITY_PX_MS = 1.0f;
- /**
- * The time constant used to calculate dampening in the low-pass filter of scroll velocity.
- * Cutoff frequency is set at 10 Hz.
- */
- public static final float SCROLL_VELOCITY_DAMPENING_RC = 1000f / (2f * (float) Math.PI * 10);
-
/* Scroll state, this is set to true during dragging and animation. */
private ScrollState mState = ScrollState.IDLE;
@@ -74,6 +70,8 @@
* Distance in pixels a touch can wander before we think the user is scrolling.
*/
abstract float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos);
+
+ abstract float getVelocity(VelocityTracker tracker);
}
public static final Direction VERTICAL = new Direction() {
@@ -87,6 +85,11 @@
float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos) {
return Math.abs(ev.getX(pointerIndex) - downPos.x);
}
+
+ @Override
+ float getVelocity(VelocityTracker tracker) {
+ return tracker.getYVelocity();
+ }
};
public static final Direction HORIZONTAL = new Direction() {
@@ -100,6 +103,11 @@
float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos) {
return Math.abs(ev.getY(pointerIndex) - downPos.y);
}
+
+ @Override
+ float getVelocity(VelocityTracker tracker) {
+ return tracker.getXVelocity();
+ }
};
//------------------- ScrollState transition diagram -----------------------------------
@@ -150,16 +158,16 @@
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
- private Direction mDir;
+ private final Direction mDir;
private final float mTouchSlop;
+ private final float mMaxVelocity;
/* Client of this gesture detector can register a callback. */
private final Listener mListener;
- private long mCurrentMillis;
+ private VelocityTracker mVelocityTracker;
- private float mVelocity;
private float mLastDisplacement;
private float mDisplacement;
@@ -169,24 +177,22 @@
public interface Listener {
void onDragStart(boolean start);
- boolean onDrag(float displacement, float velocity);
+ boolean onDrag(float displacement);
void onDragEnd(float velocity, boolean fling);
}
public SwipeDetector(@NonNull Context context, @NonNull Listener l, @NonNull Direction dir) {
- this(ViewConfiguration.get(context).getScaledTouchSlop(), l, dir);
+ this(ViewConfiguration.get(context), l, dir);
}
@VisibleForTesting
- protected SwipeDetector(float touchSlope, @NonNull Listener l, @NonNull Direction dir) {
- mTouchSlop = touchSlope;
+ protected SwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l,
+ @NonNull Direction dir) {
mListener = l;
mDir = dir;
- }
-
- public void updateDirection(Direction dir) {
- mDir = dir;
+ mTouchSlop = config.getScaledTouchSlop();
+ mMaxVelocity = config.getScaledMaximumFlingVelocity();
}
public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
@@ -214,14 +220,22 @@
}
public boolean onTouchEvent(MotionEvent ev) {
- switch (ev.getActionMasked()) {
+ int actionMasked = ev.getActionMasked();
+ if (actionMasked == MotionEvent.ACTION_DOWN && mVelocityTracker != null) {
+ mVelocityTracker.clear();
+ }
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ mVelocityTracker.addMovement(ev);
+
+ switch (actionMasked) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = ev.getPointerId(0);
mDownPos.set(ev.getX(), ev.getY());
mLastPos.set(mDownPos);
mLastDisplacement = 0;
mDisplacement = 0;
- mVelocity = 0;
if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
setState(ScrollState.DRAGGING);
@@ -246,8 +260,6 @@
break;
}
mDisplacement = mDir.getDisplacement(ev, pointerIndex, mDownPos);
- computeVelocity(mDir.getDisplacement(ev, pointerIndex, mLastPos),
- ev.getEventTime());
// handle state and listener calls.
if (mState != ScrollState.DRAGGING && shouldScrollStart(ev, pointerIndex)) {
@@ -264,6 +276,8 @@
if (mState == ScrollState.DRAGGING) {
setState(ScrollState.SETTLING);
}
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
break;
default:
break;
@@ -307,55 +321,24 @@
private boolean reportDragging() {
if (mDisplacement != mLastDisplacement) {
if (DBG) {
- Log.d(TAG, String.format("onDrag disp=%.1f, velocity=%.1f",
- mDisplacement, mVelocity));
+ Log.d(TAG, String.format("onDrag disp=%.1f", mDisplacement));
}
mLastDisplacement = mDisplacement;
- return mListener.onDrag(mDisplacement - mSubtractDisplacement, mVelocity);
+ return mListener.onDrag(mDisplacement - mSubtractDisplacement);
}
return true;
}
private void reportDragEnd() {
+ mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
+ float velocity = mDir.getVelocity(mVelocityTracker) / 1000;
if (DBG) {
Log.d(TAG, String.format("onScrollEnd disp=%.1f, velocity=%.1f",
- mDisplacement, mVelocity));
+ mDisplacement, velocity));
}
- mListener.onDragEnd(mVelocity, Math.abs(mVelocity) > RELEASE_VELOCITY_PX_MS);
- }
-
- /**
- * Computes the damped velocity.
- */
- public float computeVelocity(float delta, long currentMillis) {
- long previousMillis = mCurrentMillis;
- mCurrentMillis = currentMillis;
-
- float deltaTimeMillis = mCurrentMillis - previousMillis;
- float velocity = (deltaTimeMillis > 0) ? (delta / deltaTimeMillis) : 0;
- if (Math.abs(mVelocity) < 0.001f) {
- mVelocity = velocity;
- } else {
- float alpha = computeDampeningFactor(deltaTimeMillis);
- mVelocity = interpolate(mVelocity, velocity, alpha);
- }
- return mVelocity;
- }
-
- /**
- * Returns a time-dependent dampening factor using delta time.
- */
- private static float computeDampeningFactor(float deltaTime) {
- return deltaTime / (SCROLL_VELOCITY_DAMPENING_RC + deltaTime);
- }
-
- /**
- * Returns the linear interpolation between two values
- */
- public static float interpolate(float from, float to, float alpha) {
- return (1.0f - alpha) * from + alpha * to;
+ mListener.onDragEnd(velocity, Math.abs(velocity) > RELEASE_VELOCITY_PX_MS);
}
public static long calculateDuration(float velocity, float progressNeeded) {
diff --git a/src/com/android/launcher3/touch/TouchEventTranslator.java b/src/com/android/launcher3/touch/TouchEventTranslator.java
new file mode 100644
index 0000000..bf0c84c
--- /dev/null
+++ b/src/com/android/launcher3/touch/TouchEventTranslator.java
@@ -0,0 +1,283 @@
+/*
+ * 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.touch;
+
+import android.graphics.PointF;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+
+import com.android.launcher3.Utilities.Consumer;
+
+/**
+ * To minimize the size of the MotionEvent, historic events are not copied and passed via the
+ * listener.
+ */
+public class TouchEventTranslator {
+
+ private static final String TAG = "TouchEventTranslator";
+ private static final boolean DEBUG = false;
+
+ private class DownState {
+ long timeStamp;
+ float downX;
+ float downY;
+ public DownState(long timeStamp, float downX, float downY) {
+ this.timeStamp = timeStamp;
+ this.downX = downX;
+ this.downY = downY;
+ }
+ };
+ private final DownState ZERO = new DownState(0, 0f, 0f);
+
+ private final Consumer<MotionEvent> mListener;
+
+ private final SparseArray<DownState> mDownEvents;
+ private final SparseArray<PointF> mFingers;
+
+ private final SparseArray<Pair<PointerProperties[], PointerCoords[]>> mCache;
+
+ public TouchEventTranslator(Consumer<MotionEvent> listener) {
+ mDownEvents = new SparseArray<>();
+ mFingers = new SparseArray<>();
+ mCache = new SparseArray<>();
+
+ mListener = listener;
+ }
+
+ public void reset() {
+ mDownEvents.clear();
+ mFingers.clear();
+ }
+
+ public float getDownX() {
+ return mDownEvents.get(0).downX;
+ }
+
+ public float getDownY() {
+ return mDownEvents.get(0).downY;
+ }
+
+ public void setDownParameters(int idx, MotionEvent e) {
+ DownState ev = new DownState(e.getEventTime(), e.getX(idx), e.getY(idx));
+ mDownEvents.append(idx, ev);
+ }
+
+ public void dispatchDownEvents(MotionEvent ev) {
+ for(int i = 0; i < ev.getPointerCount() && i < mDownEvents.size(); i++) {
+ int pid = ev.getPointerId(i);
+ put(pid, i, ev.getX(i), 0, mDownEvents.get(i).timeStamp, ev);
+ }
+ }
+
+ public void processMotionEvent(MotionEvent ev) {
+ if (DEBUG) {
+ printSamples(TAG + " processMotionEvent", ev);
+ }
+ int index = ev.getActionIndex();
+ float x = ev.getX(index);
+ float y = ev.getY(index) - mDownEvents.get(index, ZERO).downY;
+ switch (ev.getActionMasked()) {
+ case MotionEvent.ACTION_POINTER_DOWN:
+ int pid = ev.getPointerId(index);
+ if(mFingers.get(pid, null) != null) {
+ for(int i=0; i < ev.getPointerCount(); i++) {
+ pid = ev.getPointerId(i);
+ position(pid, x, y);
+ }
+ generateEvent(ev.getAction(), ev);
+ } else {
+ put(pid, index, x, y, ev);
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ for(int i=0; i < ev.getPointerCount(); i++) {
+ pid = ev.getPointerId(i);
+ position(pid, x, y);
+ }
+ generateEvent(ev.getAction(), ev);
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ case MotionEvent.ACTION_UP:
+ pid = ev.getPointerId(index);
+ lift(pid, index, x, y, ev);
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ cancel(ev);
+ break;
+ default:
+ Log.v(TAG, "Didn't process ");
+ printSamples(TAG, ev);
+
+ }
+ }
+
+ private TouchEventTranslator put(int id, int index, float x, float y, MotionEvent ev) {
+ return put(id, index, x, y, ev.getEventTime(), ev);
+ }
+
+ private TouchEventTranslator put(int id, int index, float x, float y, long ms, MotionEvent ev) {
+ checkFingerExistence(id, false);
+ boolean isInitialDown = (mFingers.size() == 0);
+
+ mFingers.put(id, new PointF(x, y));
+ int n = mFingers.size();
+
+ if (mCache.get(n) == null) {
+ PointerProperties[] properties = new PointerProperties[n];
+ PointerCoords[] coords = new PointerCoords[n];
+ for (int i = 0; i < n; i++) {
+ properties[i] = new PointerProperties();
+ coords[i] = new PointerCoords();
+ }
+ mCache.put(n, new Pair(properties, coords));
+ }
+
+ int action;
+ if (isInitialDown) {
+ action = MotionEvent.ACTION_DOWN;
+ } else {
+ action = MotionEvent.ACTION_POINTER_DOWN;
+ // Set the id of the changed pointer.
+ action |= index << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ }
+ generateEvent(action, ms, ev);
+ return this;
+ }
+
+ public TouchEventTranslator position(int id, float x, float y) {
+ checkFingerExistence(id, true);
+ mFingers.get(id).set(x, y);
+ return this;
+ }
+
+ private TouchEventTranslator lift(int id, int index, MotionEvent ev) {
+ checkFingerExistence(id, true);
+ boolean isFinalUp = (mFingers.size() == 1);
+ int action;
+ if (isFinalUp) {
+ action = MotionEvent.ACTION_UP;
+ } else {
+ action = MotionEvent.ACTION_POINTER_UP;
+ // Set the id of the changed pointer.
+ action |= index << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ }
+ generateEvent(action, ev);
+ mFingers.remove(id);
+ return this;
+ }
+
+ private TouchEventTranslator lift(int id, int index, float x, float y, MotionEvent ev) {
+ checkFingerExistence(id, true);
+ mFingers.get(id).set(x, y);
+ return lift(id, index, ev);
+ }
+
+ public TouchEventTranslator cancel(MotionEvent ev) {
+ generateEvent(MotionEvent.ACTION_CANCEL, ev);
+ mFingers.clear();
+ return this;
+ }
+
+ private void checkFingerExistence(int id, boolean shouldExist) {
+ if (shouldExist != (mFingers.get(id, null) != null)) {
+ throw new IllegalArgumentException(
+ shouldExist ? "Finger does not exist" : "Finger already exists");
+ }
+ }
+
+
+ /**
+ * Used to debug MotionEvents being sent/received.
+ */
+ public void printSamples(String msg, MotionEvent ev) {
+ System.out.printf("%s %s", msg, MotionEvent.actionToString(ev.getActionMasked()));
+ final int pointerCount = ev.getPointerCount();
+ System.out.printf("#%d/%d", ev.getActionIndex(), pointerCount);
+ System.out.printf(" t=%d:", ev.getEventTime());
+ for (int p = 0; p < pointerCount; p++) {
+ System.out.printf(" id=%d: (%f,%f)",
+ ev.getPointerId(p), ev.getX(p), ev.getY(p));
+ }
+ System.out.println();
+ }
+
+ private void generateEvent(int action, MotionEvent ev) {
+ generateEvent(action, ev.getEventTime(), ev);
+ }
+
+ private void generateEvent(int action, long ms, MotionEvent ev) {
+ Pair<PointerProperties[], PointerCoords[]> state = getFingerState();
+ MotionEvent event = MotionEvent.obtain(
+ mDownEvents.get(0).timeStamp,
+ ms,
+ action,
+ state.first.length,
+ state.first,
+ state.second,
+ ev.getMetaState(),
+ ev.getButtonState() /* buttonState */,
+ ev.getXPrecision() /* xPrecision */,
+ ev.getYPrecision() /* yPrecision */,
+ ev.getDeviceId(),
+ ev.getEdgeFlags(),
+ ev.getSource(),
+ ev.getFlags() /* flags */);
+ if (DEBUG) {
+ printSamples(TAG + " generateEvent", event);
+ }
+ if (event.getPointerId(event.getActionIndex()) < 0) {
+ printSamples(TAG + "generateEvent", event);
+ throw new IllegalStateException(event.getActionIndex() + " not found in MotionEvent");
+ }
+ mListener.accept(event);
+ event.recycle();
+ }
+
+ /**
+ * Returns the description of the fingers' state expected by MotionEvent.
+ */
+ private Pair<PointerProperties[], PointerCoords[]> getFingerState() {
+ int nFingers = mFingers.size();
+
+ Pair<PointerProperties[], PointerCoords[]> result = mCache.get(nFingers);
+ PointerProperties[] properties = result.first;
+ PointerCoords[] coordinates = result.second;
+
+ int index = 0;
+ for (int i = 0; i < mFingers.size(); i++) {
+ int id = mFingers.keyAt(i);
+ PointF location = mFingers.get(id);
+
+ PointerProperties property = properties[i];
+ property.id = id;
+ property.toolType = MotionEvent.TOOL_TYPE_FINGER;
+ properties[index] = property;
+
+ PointerCoords coordinate = coordinates[i];
+ coordinate.x = location.x;
+ coordinate.y = location.y;
+ coordinate.pressure = 1.0f;
+ coordinates[index] = coordinate;
+
+ index++;
+ }
+ return mCache.get(nFingers);
+ }
+}
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index f59f14e..4de082e 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -17,6 +17,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_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.ViewConfiguration.getLongPressTimeout;
@@ -29,6 +30,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
+import android.view.ViewConfiguration;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.CellLayout;
@@ -60,12 +62,16 @@
private final Launcher mLauncher;
private final Workspace mWorkspace;
private final PointF mTouchDownPoint = new PointF();
+ private final float mTouchSlop;
private int mLongPressState = STATE_CANCELLED;
public WorkspaceTouchListener(Launcher launcher, Workspace workspace) {
mLauncher = launcher;
mWorkspace = workspace;
+ // Use twice the touch slop as we are looking for long press which is more
+ // likely to cause movement.
+ mTouchSlop = 2 * ViewConfiguration.get(launcher).getScaledTouchSlop();
}
@Override
@@ -116,6 +122,9 @@
mWorkspace.onTouchEvent(ev);
if (mWorkspace.isHandlingTouch()) {
cancelLongPress();
+ } else if (action == ACTION_MOVE && PointF.length(
+ mTouchDownPoint.x - ev.getX(), mTouchDownPoint.y - ev.getY()) > mTouchSlop) {
+ cancelLongPress();
}
result = true;
@@ -125,7 +134,7 @@
}
if (action == ACTION_UP || action == ACTION_POINTER_UP) {
- if (!mWorkspace.isTouchActive()) {
+ if (!mWorkspace.isHandlingTouch()) {
final CellLayout currentPage =
(CellLayout) mWorkspace.getChildAt(mWorkspace.getCurrentPage());
if (currentPage != null) {
diff --git a/src/com/android/launcher3/util/ConfigMonitor.java b/src/com/android/launcher3/util/ConfigMonitor.java
index 611931d..717acdc 100644
--- a/src/com/android/launcher3/util/ConfigMonitor.java
+++ b/src/com/android/launcher3/util/ConfigMonitor.java
@@ -29,9 +29,12 @@
import android.view.Display;
import android.view.WindowManager;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.Utilities.Consumer;
+
/**
* {@link BroadcastReceiver} which watches configuration changes and
- * restarts the process in case changes which affect the device profile occur.
+ * notifies the callback in case changes which affect the device profile occur.
*/
public class ConfigMonitor extends BroadcastReceiver implements DisplayListener {
@@ -48,7 +51,9 @@
private final Point mRealSize;
private final Point mSmallestSize, mLargestSize;
- public ConfigMonitor(Context context) {
+ private Consumer<Context> mCallback;
+
+ public ConfigMonitor(Context context, Consumer<Context> callback) {
mContext = context;
Configuration config = context.getResources().getConfiguration();
@@ -64,6 +69,12 @@
mSmallestSize = new Point();
mLargestSize = new Point();
display.getCurrentSizeRange(mSmallestSize, mLargestSize);
+
+ mCallback = callback;
+
+ mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
+ mContext.getSystemService(DisplayManager.class)
+ .registerDisplayListener(this, new Handler(UiThreadHelper.getBackgroundLooper()));
}
@Override
@@ -71,16 +82,10 @@
Configuration config = context.getResources().getConfiguration();
if (mFontScale != config.fontScale || mDensity != config.densityDpi) {
Log.d(TAG, "Configuration changed");
- killProcess();
+ notifyChange();
}
}
- public void register() {
- mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
- mContext.getSystemService(DisplayManager.class)
- .registerDisplayListener(this, new Handler(UiThreadHelper.getBackgroundLooper()));
- }
-
@Override
public void onDisplayAdded(int displayId) { }
@@ -97,7 +102,7 @@
if (!mRealSize.equals(mTmpPoint1) && !mRealSize.equals(mTmpPoint1.y, mTmpPoint1.x)) {
Log.d(TAG, String.format("Display size changed from %s to %s", mRealSize, mTmpPoint1));
- killProcess();
+ notifyChange();
return;
}
@@ -105,18 +110,28 @@
if (!mSmallestSize.equals(mTmpPoint1) || !mLargestSize.equals(mTmpPoint2)) {
Log.d(TAG, String.format("Available size changed from [%s, %s] to [%s, %s]",
mSmallestSize, mLargestSize, mTmpPoint1, mTmpPoint2));
- killProcess();
+ notifyChange();
}
}
- private void killProcess() {
- Log.d(TAG, "restarting launcher");
- mContext.unregisterReceiver(this);
- mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
- android.os.Process.killProcess(android.os.Process.myPid());
+ private synchronized void notifyChange() {
+ if (mCallback != null) {
+ Consumer<Context> callback = mCallback;
+ mCallback = null;
+ new MainThreadExecutor().execute(() -> callback.accept(mContext));
+ }
}
private Display getDefaultDisplay(Context context) {
return context.getSystemService(WindowManager.class).getDefaultDisplay();
}
+
+ public void unregister() {
+ try {
+ mContext.unregisterReceiver(this);
+ mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to unregister config monitor", e);
+ }
+ }
}
diff --git a/src/com/android/launcher3/util/ContentWriter.java b/src/com/android/launcher3/util/ContentWriter.java
index 4384328..00adf10 100644
--- a/src/com/android/launcher3/util/ContentWriter.java
+++ b/src/com/android/launcher3/util/ContentWriter.java
@@ -25,8 +25,8 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.Utilities;
import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.icons.GraphicsUtils;
/**
* A wrapper around {@link ContentValues} with some utility methods.
@@ -97,7 +97,7 @@
Preconditions.assertNonUiThread();
if (mIcon != null && !LauncherAppState.getInstance(context).getIconCache()
.isDefaultIcon(mIcon, mUser)) {
- mValues.put(LauncherSettings.Favorites.ICON, Utilities.flattenBitmap(mIcon));
+ mValues.put(LauncherSettings.Favorites.ICON, GraphicsUtils.flattenBitmap(mIcon));
mIcon = null;
}
return mValues;
diff --git a/src/com/android/launcher3/util/FlagOp.java b/src/com/android/launcher3/util/FlagOp.java
index 5e26ed1..a012c86 100644
--- a/src/com/android/launcher3/util/FlagOp.java
+++ b/src/com/android/launcher3/util/FlagOp.java
@@ -1,30 +1,16 @@
package com.android.launcher3.util;
-public abstract class FlagOp {
+public interface FlagOp {
- public static FlagOp NO_OP = new FlagOp() {};
+ FlagOp NO_OP = i -> i;
- private FlagOp() {}
+ int apply(int flags);
- public int apply(int flags) {
- return flags;
+ static FlagOp addFlag(int flag) {
+ return i -> i + flag;
}
- public static FlagOp addFlag(final int flag) {
- return new FlagOp() {
- @Override
- public int apply(int flags) {
- return flags | flag;
- }
- };
- }
-
- public static FlagOp removeFlag(final int flag) {
- return new FlagOp() {
- @Override
- public int apply(int flags) {
- return flags & ~flag;
- }
- };
+ static FlagOp removeFlag(int flag) {
+ return i -> i & ~flag;
}
}
diff --git a/src/com/android/launcher3/util/FlingAnimation.java b/src/com/android/launcher3/util/FlingAnimation.java
index fe0571b..9d0ad22 100644
--- a/src/com/android/launcher3/util/FlingAnimation.java
+++ b/src/com/android/launcher3/util/FlingAnimation.java
@@ -14,6 +14,7 @@
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.Launcher;
import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
public class FlingAnimation implements AnimatorUpdateListener, Runnable {
@@ -28,6 +29,7 @@
private final Launcher mLauncher;
protected final DragObject mDragObject;
+ protected final DragOptions mDragOptions;
protected final DragLayer mDragLayer;
protected final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
protected final float mUX, mUY;
@@ -39,13 +41,15 @@
protected float mAX, mAY;
- public FlingAnimation(DragObject d, PointF vel, ButtonDropTarget dropTarget, Launcher launcher) {
+ public FlingAnimation(DragObject d, PointF vel, ButtonDropTarget dropTarget, Launcher launcher,
+ DragOptions options) {
mDropTarget = dropTarget;
mLauncher = launcher;
mDragObject = d;
mUX = vel.x / 1000;
mUY = vel.y / 1000;
mDragLayer = mLauncher.getDragLayer();
+ mDragOptions = options;
}
@Override
@@ -102,6 +106,7 @@
}
};
+ mDropTarget.onDrop(mDragObject, mDragOptions);
mDragLayer.animateView(mDragObject.dragView, this, duration, tInterpolator,
onAnimationEndRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null);
}
diff --git a/src/com/android/launcher3/util/FloatRange.java b/src/com/android/launcher3/util/FloatRange.java
deleted file mode 100644
index 12772f3..0000000
--- a/src/com/android/launcher3/util/FloatRange.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.util;
-
-/**
- * A mutable class for describing the range of two int values.
- */
-public class FloatRange {
-
- public float start, end;
-
- public FloatRange() { }
-
- public FloatRange(float s, float e) {
- set(s, e);
- }
-
- public void set(float s, float e) {
- start = s;
- end = e;
- }
-
- public boolean contains(float value) {
- return value >= start && value <= end;
- }
-}
diff --git a/src/com/android/launcher3/util/FocusLogic.java b/src/com/android/launcher3/util/FocusLogic.java
index b793f54..4f4cccd 100644
--- a/src/com/android/launcher3/util/FocusLogic.java
+++ b/src/com/android/launcher3/util/FocusLogic.java
@@ -201,10 +201,6 @@
ViewGroup hotseatParent = hotseatLayout.getShortcutsAndWidgets();
boolean isHotseatHorizontal = !dp.isVerticalBarLayout();
- boolean moreIconsInHotseatThanWorkspace = !FeatureFlags.NO_ALL_APPS_ICON &&
- (isHotseatHorizontal
- ? hotseatLayout.getCountX() > iconLayout.getCountX()
- : hotseatLayout.getCountY() > iconLayout.getCountY());
int m, n;
if (isHotseatHorizontal) {
@@ -215,19 +211,7 @@
n = hotseatLayout.getCountY();
}
int[][] matrix = createFullMatrix(m, n);
- if (moreIconsInHotseatThanWorkspace) {
- int allappsiconRank = dp.inv.getAllAppsButtonRank();
- if (isHotseatHorizontal) {
- for (int j = 0; j < n; j++) {
- matrix[allappsiconRank][j] = ALL_APPS_COLUMN;
- }
- } else {
- for (int j = 0; j < m; j++) {
- matrix[j][allappsiconRank] = ALL_APPS_COLUMN;
- }
- }
- }
- // Iterate thru the children of the workspace.
+ // Iterate through the children of the workspace.
for (int i = 0; i < iconParent.getChildCount(); i++) {
View cell = iconParent.getChildAt(i);
if (!cell.isFocusable()) {
@@ -235,17 +219,6 @@
}
int cx = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellX;
int cy = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellY;
- if (moreIconsInHotseatThanWorkspace) {
- int allappsiconRank = dp.inv.getAllAppsButtonRank();
- if (isHotseatHorizontal && cx >= allappsiconRank) {
- // Add 1 to account for the All Apps button.
- cx++;
- }
- if (!isHotseatHorizontal && cy >= allappsiconRank) {
- // Add 1 to account for the All Apps button.
- cy++;
- }
- }
matrix[cx][cy] = i;
}
diff --git a/src/com/android/launcher3/util/InstantAppResolver.java b/src/com/android/launcher3/util/InstantAppResolver.java
index 4485427..5dc7af8 100644
--- a/src/com/android/launcher3/util/InstantAppResolver.java
+++ b/src/com/android/launcher3/util/InstantAppResolver.java
@@ -23,7 +23,6 @@
import com.android.launcher3.AppInfo;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import java.util.Collections;
import java.util.List;
@@ -31,10 +30,10 @@
/**
* A wrapper class to access instant app related APIs.
*/
-public class InstantAppResolver {
+public class InstantAppResolver implements ResourceBasedOverride {
public static InstantAppResolver newInstance(Context context) {
- return Utilities.getOverrideObject(
+ return Overrides.getObject(
InstantAppResolver.class, context, R.string.instant_app_resolver_class);
}
diff --git a/src/com/android/launcher3/util/IntArray.java b/src/com/android/launcher3/util/IntArray.java
new file mode 100644
index 0000000..b2fb32a
--- /dev/null
+++ b/src/com/android/launcher3/util/IntArray.java
@@ -0,0 +1,236 @@
+/*
+ * 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.util;
+
+import java.util.Arrays;
+
+/**
+ * Copy of the platform hidden implementation of android.util.IntArray.
+ * Implements a growing array of int primitives.
+ */
+public class IntArray implements Cloneable {
+ private static final int MIN_CAPACITY_INCREMENT = 12;
+
+ private static final int[] EMPTY_INT = new int[0];
+
+ /* package private */ int[] mValues;
+ /* package private */ int mSize;
+
+ private IntArray(int[] array, int size) {
+ mValues = array;
+ mSize = size;
+ }
+
+ /**
+ * Creates an empty IntArray with the default initial capacity.
+ */
+ public IntArray() {
+ this(10);
+ }
+
+ /**
+ * Creates an empty IntArray with the specified initial capacity.
+ */
+ public IntArray(int initialCapacity) {
+ if (initialCapacity == 0) {
+ mValues = EMPTY_INT;
+ } else {
+ mValues = new int[initialCapacity];
+ }
+ mSize = 0;
+ }
+
+ /**
+ * Creates an IntArray wrapping the given primitive int array.
+ */
+ public static IntArray wrap(int... array) {
+ return new IntArray(array, array.length);
+ }
+
+ /**
+ * Appends the specified value to the end of this array.
+ */
+ public void add(int value) {
+ add(mSize, value);
+ }
+
+ /**
+ * Inserts a value at the specified position in this array. If the specified index is equal to
+ * the length of the array, the value is added at the end.
+ *
+ * @throws IndexOutOfBoundsException when index < 0 || index > size()
+ */
+ public void add(int index, int value) {
+ ensureCapacity(1);
+ int rightSegment = mSize - index;
+ mSize++;
+ checkBounds(mSize, index);
+
+ if (rightSegment != 0) {
+ // Move by 1 all values from the right of 'index'
+ System.arraycopy(mValues, index, mValues, index + 1, rightSegment);
+ }
+
+ mValues[index] = value;
+ }
+
+ /**
+ * Adds the values in the specified array to this array.
+ */
+ public void addAll(IntArray values) {
+ final int count = values.mSize;
+ ensureCapacity(count);
+
+ System.arraycopy(values.mValues, 0, mValues, mSize, count);
+ mSize += count;
+ }
+
+ /**
+ * Ensures capacity to append at least <code>count</code> values.
+ */
+ private void ensureCapacity(int count) {
+ final int currentSize = mSize;
+ final int minCapacity = currentSize + count;
+ if (minCapacity >= mValues.length) {
+ final int targetCap = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2) ?
+ MIN_CAPACITY_INCREMENT : currentSize >> 1);
+ final int newCapacity = targetCap > minCapacity ? targetCap : minCapacity;
+ final int[] newValues = new int[newCapacity];
+ System.arraycopy(mValues, 0, newValues, 0, currentSize);
+ mValues = newValues;
+ }
+ }
+
+ /**
+ * Removes all values from this array.
+ */
+ public void clear() {
+ mSize = 0;
+ }
+
+ @Override
+ public IntArray clone() {
+ return wrap(toArray());
+ }
+
+ /**
+ * Returns the value at the specified position in this array.
+ */
+ public int get(int index) {
+ checkBounds(mSize, index);
+ return mValues[index];
+ }
+
+ /**
+ * Sets the value at the specified position in this array.
+ */
+ public void set(int index, int value) {
+ checkBounds(mSize, index);
+ mValues[index] = value;
+ }
+
+ /**
+ * Returns the index of the first occurrence of the specified value in this
+ * array, or -1 if this array does not contain the value.
+ */
+ public int indexOf(int value) {
+ final int n = mSize;
+ for (int i = 0; i < n; i++) {
+ if (mValues[i] == value) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public boolean contains(int value) {
+ return indexOf(value) >= 0;
+ }
+
+ public boolean isEmpty() {
+ return mSize == 0;
+ }
+
+ /**
+ * Removes the value at the specified index from this array.
+ */
+ public void removeIndex(int index) {
+ checkBounds(mSize, index);
+ System.arraycopy(mValues, index + 1, mValues, index, mSize - index - 1);
+ mSize--;
+ }
+
+ /**
+ * Removes the values if it exists
+ */
+ public void removeValue(int value) {
+ int index = indexOf(value);
+ if (index >= 0) {
+ removeIndex(index);
+ }
+ }
+
+ /**
+ * Removes the values if it exists
+ */
+ public void removeAllValues(IntArray values) {
+ for (int i = 0; i < values.mSize; i++) {
+ removeValue(values.mValues[i]);
+ }
+ }
+
+ /**
+ * Returns the number of values in this array.
+ */
+ public int size() {
+ return mSize;
+ }
+
+ /**
+ * Returns a new array with the contents of this IntArray.
+ */
+ public int[] toArray() {
+ return mSize == 0 ? EMPTY_INT : Arrays.copyOf(mValues, mSize);
+ }
+
+ /**
+ * Returns a comma separate list of all values.
+ */
+ public String toConcatString() {
+ StringBuilder b = new StringBuilder();
+ for (int i = 0; i < mSize ; i++) {
+ if (i > 0) {
+ b.append(", ");
+ }
+ b.append(mValues[i]);
+ }
+ return b.toString();
+ }
+
+ /**
+ * Throws {@link ArrayIndexOutOfBoundsException} if the index is out of bounds.
+ *
+ * @param len length of the array. Must be non-negative
+ * @param index the index to check
+ * @throws ArrayIndexOutOfBoundsException if the {@code index} is out of bounds of the array
+ */
+ private static void checkBounds(int len, int index) {
+ if (index < 0 || len <= index) {
+ throw new ArrayIndexOutOfBoundsException("length=" + len + "; index=" + index);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/util/IntSet.java b/src/com/android/launcher3/util/IntSet.java
new file mode 100644
index 0000000..63499b0
--- /dev/null
+++ b/src/com/android/launcher3/util/IntSet.java
@@ -0,0 +1,51 @@
+/*
+ * 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.util;
+
+import java.util.Arrays;
+
+/**
+ * A wrapper over IntArray implementing a growing set of int primitives.
+ */
+public class IntSet {
+
+ final IntArray mArray = new IntArray();
+
+ /**
+ * Appends the specified value to the set if it does not exist.
+ */
+ public void add(int value) {
+ int index = Arrays.binarySearch(mArray.mValues, 0, mArray.mSize, value);
+ if (index < 0) {
+ mArray.add(-index - 1, value);
+ }
+ }
+
+ public boolean contains(int value) {
+ return Arrays.binarySearch(mArray.mValues, 0, mArray.mSize, value) >= 0;
+ }
+
+ public boolean isEmpty() {
+ return mArray.isEmpty();
+ }
+
+ /**
+ * Returns the number of values in this set.
+ */
+ public int size() {
+ return mArray.size();
+ }
+}
diff --git a/src/com/android/launcher3/util/LongArrayMap.java b/src/com/android/launcher3/util/IntSparseArrayMap.java
similarity index 80%
rename from src/com/android/launcher3/util/LongArrayMap.java
rename to src/com/android/launcher3/util/IntSparseArrayMap.java
index a337e85..9d5391b 100644
--- a/src/com/android/launcher3/util/LongArrayMap.java
+++ b/src/com/android/launcher3/util/IntSparseArrayMap.java
@@ -16,16 +16,16 @@
package com.android.launcher3.util;
-import android.util.LongSparseArray;
+import android.util.SparseArray;
import java.util.Iterator;
/**
- * Extension of {@link LongSparseArray} with some utility methods.
+ * Extension of {@link SparseArray} with some utility methods.
*/
-public class LongArrayMap<E> extends LongSparseArray<E> implements Iterable<E> {
+public class IntSparseArrayMap<E> extends SparseArray<E> implements Iterable<E> {
- public boolean containsKey(long key) {
+ public boolean containsKey(int key) {
return indexOfKey(key) >= 0;
}
@@ -34,8 +34,8 @@
}
@Override
- public LongArrayMap<E> clone() {
- return (LongArrayMap<E>) super.clone();
+ public IntSparseArrayMap<E> clone() {
+ return (IntSparseArrayMap<E>) super.clone();
}
@Override
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index daedaef..c3570fe 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -18,7 +18,6 @@
import android.content.ComponentName;
import android.os.UserHandle;
-import android.util.SparseLongArray;
import com.android.launcher3.FolderInfo;
import com.android.launcher3.ItemInfo;
@@ -32,14 +31,14 @@
/**
* A utility class to check for {@link ItemInfo}
*/
-public abstract class ItemInfoMatcher {
+public interface ItemInfoMatcher {
- public abstract boolean matches(ItemInfo info, ComponentName cn);
+ boolean matches(ItemInfo info, ComponentName cn);
/**
* Filters {@param infos} to those satisfying the {@link #matches(ItemInfo, ComponentName)}.
*/
- public final HashSet<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos) {
+ default HashSet<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos) {
HashSet<ItemInfo> filtered = new HashSet<>();
for (ItemInfo i : infos) {
if (i instanceof ShortcutInfo) {
@@ -70,88 +69,43 @@
/**
* Returns a new matcher with returns true if either this or {@param matcher} returns true.
*/
- public ItemInfoMatcher or(final ItemInfoMatcher matcher) {
- final ItemInfoMatcher that = this;
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return that.matches(info, cn) || matcher.matches(info, cn);
- }
- };
+ default ItemInfoMatcher or(ItemInfoMatcher matcher) {
+ return (info, cn) -> matches(info, cn) || matcher.matches(info, cn);
}
/**
* Returns a new matcher with returns true if both this and {@param matcher} returns true.
*/
- public ItemInfoMatcher and(final ItemInfoMatcher matcher) {
- final ItemInfoMatcher that = this;
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return that.matches(info, cn) && matcher.matches(info, cn);
- }
- };
+ default ItemInfoMatcher and(ItemInfoMatcher matcher) {
+ return (info, cn) -> matches(info, cn) && matcher.matches(info, cn);
}
/**
* Returns a new matcher which returns the opposite boolean value of the provided
* {@param matcher}.
*/
- public static ItemInfoMatcher not(final ItemInfoMatcher matcher) {
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return !matcher.matches(info, cn);
- }
- };
+ static ItemInfoMatcher not(ItemInfoMatcher matcher) {
+ return (info, cn) -> !matcher.matches(info, cn);
}
- public static ItemInfoMatcher ofUser(final UserHandle user) {
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return info.user.equals(user);
- }
- };
+ static ItemInfoMatcher ofUser(UserHandle user) {
+ return (info, cn) -> info.user.equals(user);
}
- public static ItemInfoMatcher ofComponents(
- final HashSet<ComponentName> components, final UserHandle user) {
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return components.contains(cn) && info.user.equals(user);
- }
- };
+ static ItemInfoMatcher ofComponents(HashSet<ComponentName> components, UserHandle user) {
+ return (info, cn) -> components.contains(cn) && info.user.equals(user);
}
- public static ItemInfoMatcher ofPackages(
- final HashSet<String> packageNames, final UserHandle user) {
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return packageNames.contains(cn.getPackageName()) && info.user.equals(user);
- }
- };
+ static ItemInfoMatcher ofPackages(HashSet<String> packageNames, UserHandle user) {
+ return (info, cn) -> packageNames.contains(cn.getPackageName()) && info.user.equals(user);
}
- public static ItemInfoMatcher ofShortcutKeys(final HashSet<ShortcutKey> keys) {
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
+ static ItemInfoMatcher ofShortcutKeys(HashSet<ShortcutKey> keys) {
+ return (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
keys.contains(ShortcutKey.fromItemInfo(info));
- }
- };
}
- public static ItemInfoMatcher ofItemIds(
- final LongArrayMap<Boolean> ids, final Boolean matchDefault) {
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return ids.get(info.id, matchDefault);
- }
- };
+ static ItemInfoMatcher ofItemIds(IntSparseArrayMap<Boolean> ids, Boolean matchDefault) {
+ return (info, cn) -> ids.get(info.id, matchDefault);
}
}
diff --git a/src/com/android/launcher3/util/ListViewHighlighter.java b/src/com/android/launcher3/util/ListViewHighlighter.java
deleted file mode 100644
index ecad2af..0000000
--- a/src/com/android/launcher3/util/ListViewHighlighter.java
+++ /dev/null
@@ -1,141 +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.util;
-
-import android.animation.ArgbEvaluator;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.support.v4.graphics.ColorUtils;
-import android.view.View;
-import android.view.View.OnLayoutChangeListener;
-import android.widget.AbsListView;
-import android.widget.AbsListView.OnScrollListener;
-import android.widget.AbsListView.RecyclerListener;
-import android.widget.ListView;
-
-import com.android.launcher3.R;
-
-/**
- * Utility class to scroll and highlight a list view item
- */
-public class ListViewHighlighter implements OnScrollListener, RecyclerListener,
- OnLayoutChangeListener {
-
- private final ListView mListView;
- private int mPosHighlight;
-
- private boolean mColorAnimated = false;
-
- public ListViewHighlighter(ListView listView, int posHighlight) {
- mListView = listView;
- mPosHighlight = posHighlight;
- mListView.setOnScrollListener(this);
- mListView.setRecyclerListener(this);
- mListView.addOnLayoutChangeListener(this);
-
- mListView.post(this::tryHighlight);
- }
-
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- mListView.post(this::tryHighlight);
- }
-
- private void tryHighlight() {
- if (mPosHighlight < 0 || mListView.getChildCount() == 0) {
- return;
- }
- if (!highlightIfVisible(mListView.getFirstVisiblePosition(),
- mListView.getLastVisiblePosition())) {
- mListView.smoothScrollToPosition(mPosHighlight);
- }
- }
-
- @Override
- public void onScrollStateChanged(AbsListView absListView, int i) { }
-
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem,
- int visibleItemCount, int totalItemCount) {
- highlightIfVisible(firstVisibleItem, firstVisibleItem + visibleItemCount);
- }
-
- private boolean highlightIfVisible(int start, int end) {
- if (mPosHighlight < 0 || mListView.getChildCount() == 0) {
- return false;
- }
- if (start > mPosHighlight || mPosHighlight > end) {
- return false;
- }
- highlightView(mListView.getChildAt(mPosHighlight - start));
-
- // finish highlight
- mListView.setOnScrollListener(null);
- mListView.removeOnLayoutChangeListener(this);
-
- mPosHighlight = -1;
- return true;
- }
-
- @Override
- public void onMovedToScrapHeap(View view) {
- unhighlightView(view);
- }
-
- private void highlightView(View view) {
- if (Boolean.TRUE.equals(view.getTag(R.id.view_highlighted))) {
- // already highlighted
- } else {
- view.setTag(R.id.view_highlighted, true);
- view.setTag(R.id.view_unhighlight_background, view.getBackground());
- view.setBackground(getHighlightBackground());
- view.postDelayed(() -> {
- unhighlightView(view);
- }, 15000L);
- }
- }
-
- private void unhighlightView(View view) {
- if (Boolean.TRUE.equals(view.getTag(R.id.view_highlighted))) {
- Object background = view.getTag(R.id.view_unhighlight_background);
- if (background instanceof Drawable) {
- view.setBackground((Drawable) background);
- }
- view.setTag(R.id.view_unhighlight_background, null);
- view.setTag(R.id.view_highlighted, false);
- }
- }
-
- private ColorDrawable getHighlightBackground() {
- int color = ColorUtils.setAlphaComponent(Themes.getColorAccent(mListView.getContext()), 26);
- if (mColorAnimated) {
- return new ColorDrawable(color);
- }
- mColorAnimated = true;
- ColorDrawable bg = new ColorDrawable(Color.WHITE);
- ObjectAnimator anim = ObjectAnimator.ofInt(bg, "color", Color.WHITE, color);
- anim.setEvaluator(new ArgbEvaluator());
- anim.setDuration(200L);
- anim.setRepeatMode(ValueAnimator.REVERSE);
- anim.setRepeatCount(4);
- anim.start();
- return bg;
- }
-}
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
new file mode 100644
index 0000000..5747db1
--- /dev/null
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -0,0 +1,60 @@
+/*
+ * 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.util;
+
+import android.content.Context;
+import android.os.Looper;
+
+import com.android.launcher3.MainThreadExecutor;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Utility class for defining singletons which are initiated on main thread.
+ */
+public class MainThreadInitializedObject<T> {
+
+ private final ObjectProvider<T> mProvider;
+ private T mValue;
+
+ public MainThreadInitializedObject(ObjectProvider<T> provider) {
+ mProvider = provider;
+ }
+
+ public T get(Context context) {
+ if (mValue == null) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ mValue = mProvider.get(context.getApplicationContext());
+ } else {
+ try {
+ return new MainThreadExecutor().submit(() -> get(context)).get();
+ } catch (InterruptedException|ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ return mValue;
+ }
+
+ public T getNoCreate() {
+ return mValue;
+ }
+
+ public interface ObjectProvider<T> {
+
+ T get(Context context);
+ }
+}
diff --git a/src/com/android/launcher3/util/MultiValueAlpha.java b/src/com/android/launcher3/util/MultiValueAlpha.java
index f810f48..07f835d 100644
--- a/src/com/android/launcher3/util/MultiValueAlpha.java
+++ b/src/com/android/launcher3/util/MultiValueAlpha.java
@@ -19,6 +19,8 @@
import android.util.Property;
import android.view.View;
+import java.util.Arrays;
+
/**
* Utility class to handle separating a single value as a factor of multiple values
*/
@@ -55,6 +57,11 @@
}
}
+ @Override
+ public String toString() {
+ return Arrays.toString(mMyProperties);
+ }
+
public AlphaProperty getProperty(int index) {
return mMyProperties[index];
}
@@ -97,5 +104,10 @@
public float getValue() {
return mValue;
}
+
+ @Override
+ public String toString() {
+ return Float.toString(mValue);
+ }
}
}
diff --git a/src/com/android/launcher3/util/OverScroller.java b/src/com/android/launcher3/util/OverScroller.java
new file mode 100644
index 0000000..d697ece
--- /dev/null
+++ b/src/com/android/launcher3/util/OverScroller.java
@@ -0,0 +1,779 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import static com.android.launcher3.anim.Interpolators.SCROLL;
+
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.hardware.SensorManager;
+import android.util.Log;
+import android.view.ViewConfiguration;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+/**
+ * Based on {@link android.widget.OverScroller} supporting only 1-d scrolling and with more
+ * customization options.
+ */
+public class OverScroller {
+ private int mMode;
+
+ private final SplineOverScroller mScroller;
+
+ private TimeInterpolator mInterpolator;
+
+ private final boolean mFlywheel;
+
+ private static final int DEFAULT_DURATION = 250;
+ private static final int SCROLL_MODE = 0;
+ private static final int FLING_MODE = 1;
+
+ /**
+ * Creates an OverScroller with a viscous fluid scroll interpolator and flywheel.
+ * @param context
+ */
+ public OverScroller(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Creates an OverScroller with flywheel enabled.
+ * @param context The context of this application.
+ * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will
+ * be used.
+ */
+ public OverScroller(Context context, Interpolator interpolator) {
+ this(context, interpolator, true);
+ }
+
+ /**
+ * Creates an OverScroller.
+ * @param context The context of this application.
+ * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will
+ * be used.
+ * @param flywheel If true, successive fling motions will keep on increasing scroll speed.
+ */
+ public OverScroller(Context context, Interpolator interpolator, boolean flywheel) {
+ if (interpolator == null) {
+ mInterpolator = SCROLL;
+ } else {
+ mInterpolator = interpolator;
+ }
+ mFlywheel = flywheel;
+ mScroller = new SplineOverScroller(context);
+ }
+
+ public void setInterpolator(TimeInterpolator interpolator) {
+ if (interpolator == null) {
+ mInterpolator = SCROLL;
+ } else {
+ mInterpolator = interpolator;
+ }
+ }
+
+ /**
+ * The amount of friction applied to flings. The default value
+ * is {@link ViewConfiguration#getScrollFriction}.
+ *
+ * @param friction A scalar dimension-less value representing the coefficient of
+ * friction.
+ */
+ public final void setFriction(float friction) {
+ mScroller.setFriction(friction);
+ }
+
+ /**
+ *
+ * Returns whether the scroller has finished scrolling.
+ *
+ * @return True if the scroller has finished scrolling, false otherwise.
+ */
+ public final boolean isFinished() {
+ return mScroller.mFinished;
+ }
+
+ /**
+ * Force the finished field to a particular value. Contrary to
+ * {@link #abortAnimation()}, forcing the animation to finished
+ * does NOT cause the scroller to move to the final x and y
+ * position.
+ *
+ * @param finished The new finished value.
+ */
+ public final void forceFinished(boolean finished) {
+ mScroller.mFinished = finished;
+ }
+
+ /**
+ * Returns the current offset in the scroll.
+ *
+ * @return The new offset as an absolute distance from the origin.
+ */
+ public final int getCurrPos() {
+ return mScroller.mCurrentPosition;
+ }
+
+ /**
+ * Returns the absolute value of the current velocity.
+ *
+ * @return The original velocity less the deceleration, norm of the X and Y velocity vector.
+ */
+ public float getCurrVelocity() {
+ return mScroller.mCurrVelocity;
+ }
+
+ /**
+ * Returns the start offset in the scroll.
+ *
+ * @return The start offset as an absolute distance from the origin.
+ */
+ public final int getStartPos() {
+ return mScroller.mStart;
+ }
+
+ /**
+ * Returns where the scroll will end. Valid only for "fling" scrolls.
+ *
+ * @return The final offset as an absolute distance from the origin.
+ */
+ public final int getFinalPos() {
+ return mScroller.mFinal;
+ }
+
+ /**
+ * Returns how long the scroll event will take, in milliseconds.
+ *
+ * @return The duration of the scroll in milliseconds.
+ */
+ public final int getDuration() {
+ return mScroller.mDuration;
+ }
+
+ /**
+ * Extend the scroll animation. This allows a running animation to scroll
+ * further and longer, when used with {@link #setFinalPos(int)}.
+ *
+ * @param extend Additional time to scroll in milliseconds.
+ * @see #setFinalPos(int)
+ */
+ public void extendDuration(int extend) {
+ mScroller.extendDuration(extend);
+ }
+
+ /**
+ * Sets the final position for this scroller.
+ *
+ * @param newPos The new offset as an absolute distance from the origin.
+ * @see #extendDuration(int)
+ */
+ public void setFinalPos(int newPos) {
+ mScroller.setFinalPosition(newPos);
+ }
+
+ /**
+ * Call this when you want to know the new location. If it returns true, the
+ * animation is not yet finished.
+ */
+ public boolean computeScrollOffset() {
+ if (isFinished()) {
+ return false;
+ }
+
+ switch (mMode) {
+ case SCROLL_MODE:
+ long time = AnimationUtils.currentAnimationTimeMillis();
+ // Any scroller can be used for time, since they were started
+ // together in scroll mode. We use X here.
+ final long elapsedTime = time - mScroller.mStartTime;
+
+ final int duration = mScroller.mDuration;
+ if (elapsedTime < duration) {
+ final float q = mInterpolator.getInterpolation(elapsedTime / (float) duration);
+ mScroller.updateScroll(q);
+ } else {
+ abortAnimation();
+ }
+ break;
+
+ case FLING_MODE:
+ if (!mScroller.mFinished) {
+ if (!mScroller.update()) {
+ if (!mScroller.continueWhenFinished()) {
+ mScroller.finish();
+ }
+ }
+ }
+
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ * Start scrolling by providing a starting point and the distance to travel.
+ * The scroll will use the default value of 250 milliseconds for the
+ * duration.
+ *
+ * @param start Starting horizontal scroll offset in pixels. Positive
+ * numbers will scroll the content to the left.
+ * @param delta Distance to travel. Positive numbers will scroll the
+ * content to the left.
+ */
+ public void startScroll(int start, int delta) {
+ startScroll(start, delta, DEFAULT_DURATION);
+ }
+
+ /**
+ * Start scrolling by providing a starting point and the distance to travel.
+ *
+ * @param start Starting scroll offset in pixels. Positive
+ * numbers will scroll the content to the left.
+ * @param delta Distance to travel. Positive numbers will scroll the
+ * content to the left.
+ * @param duration Duration of the scroll in milliseconds.
+ */
+ public void startScroll(int start, int delta, int duration) {
+ mMode = SCROLL_MODE;
+ mScroller.startScroll(start, delta, duration);
+ }
+
+ /**
+ * Call this when you want to 'spring back' into a valid coordinate range.
+ *
+ * @param start Starting X coordinate
+ * @param min Minimum valid X value
+ * @param max Maximum valid X value
+ * @return true if a springback was initiated, false if startX and startY were
+ * already within the valid range.
+ */
+ public boolean springBack(int start, int min, int max) {
+ mMode = FLING_MODE;
+ return mScroller.springback(start, min, max);
+ }
+
+ public void fling(int start, int velocity, int min, int max) {
+ fling(start, velocity, min, max, 0);
+ }
+
+ /**
+ * Start scrolling based on a fling gesture. The distance traveled will
+ * depend on the initial velocity of the fling.
+ * @param start Starting point of the scroll (X)
+ * @param velocity Initial velocity of the fling (X) measured in pixels per
+ * second.
+ * @param min Minimum X value. The scroller will not scroll past this point
+ * unless overX > 0. If overfling is allowed, it will use minX as
+ * a springback boundary.
+ * @param max Maximum X value. The scroller will not scroll past this point
+* unless overX > 0. If overfling is allowed, it will use maxX as
+* a springback boundary.
+ * @param over Overfling range. If > 0, horizontal overfling in either
+* direction will be possible.
+ */
+ public void fling(int start, int velocity, int min, int max, int over) {
+ // Continue a scroll or fling in progress
+ if (mFlywheel && !isFinished()) {
+ float oldVelocityX = mScroller.mCurrVelocity;
+ if (Math.signum(velocity) == Math.signum(oldVelocityX)) {
+ velocity += oldVelocityX;
+ }
+ }
+
+ mMode = FLING_MODE;
+ mScroller.fling(start, velocity, min, max, over);
+ }
+
+ /**
+ * Notify the scroller that we've reached a horizontal boundary.
+ * Normally the information to handle this will already be known
+ * when the animation is started, such as in a call to one of the
+ * fling functions. However there are cases where this cannot be known
+ * in advance. This function will transition the current motion and
+ * animate from startX to finalX as appropriate.
+ * @param start Starting/current X position
+ * @param finalPos Desired final X position
+ * @param over Magnitude of overscroll allowed. This should be the maximum
+ */
+ public void notifyEdgeReached(int start, int finalPos, int over) {
+ mScroller.notifyEdgeReached(start, finalPos, over);
+ }
+
+ /**
+ * Returns whether the current Scroller is currently returning to a valid position.
+ * Valid bounds were provided by the
+ * {@link #fling(int, int, int, int, int)} method.
+ *
+ * One should check this value before calling
+ * {@link #startScroll(int, int)} as the interpolation currently in progress
+ * to restore a valid position will then be stopped. The caller has to take into account
+ * the fact that the started scroll will start from an overscrolled position.
+ *
+ * @return true when the current position is overscrolled and in the process of
+ * interpolating back to a valid value.
+ */
+ public boolean isOverScrolled() {
+ return (!mScroller.mFinished && mScroller.mState != SplineOverScroller.SPLINE);
+ }
+
+ /**
+ * Stops the animation. Contrary to {@link #forceFinished(boolean)},
+ * aborting the animating causes the scroller to move to the final x and y
+ * positions.
+ *
+ * @see #forceFinished(boolean)
+ */
+ public void abortAnimation() {
+ mScroller.finish();
+ }
+
+ /**
+ * Returns the time elapsed since the beginning of the scrolling.
+ *
+ * @return The elapsed time in milliseconds.
+ *
+ * @hide
+ */
+ public int timePassed() {
+ final long time = AnimationUtils.currentAnimationTimeMillis();
+ return (int) (time - mScroller.mStartTime);
+ }
+
+ static class SplineOverScroller {
+ // Initial position
+ private int mStart;
+
+ // Current position
+ private int mCurrentPosition;
+
+ // Final position
+ private int mFinal;
+
+ // Initial velocity
+ private int mVelocity;
+
+ // Current velocity
+ private float mCurrVelocity;
+
+ // Constant current deceleration
+ private float mDeceleration;
+
+ // Animation starting time, in system milliseconds
+ private long mStartTime;
+
+ // Animation duration, in milliseconds
+ private int mDuration;
+
+ // Duration to complete spline component of animation
+ private int mSplineDuration;
+
+ // Distance to travel along spline animation
+ private int mSplineDistance;
+
+ // Whether the animation is currently in progress
+ private boolean mFinished;
+
+ // The allowed overshot distance before boundary is reached.
+ private int mOver;
+
+ // Fling friction
+ private float mFlingFriction = ViewConfiguration.getScrollFriction();
+
+ // Current state of the animation.
+ private int mState = SPLINE;
+
+ // Constant gravity value, used in the deceleration phase.
+ private static final float GRAVITY = 2000.0f;
+
+ // A context-specific coefficient adjusted to physical values.
+ private float mPhysicalCoeff;
+
+ private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
+ private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)
+ private static final float START_TENSION = 0.5f;
+ private static final float END_TENSION = 1.0f;
+ private static final float P1 = START_TENSION * INFLEXION;
+ private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION);
+
+ private static final int NB_SAMPLES = 100;
+ private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1];
+ private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1];
+
+ private static final int SPLINE = 0;
+ private static final int CUBIC = 1;
+ private static final int BALLISTIC = 2;
+
+ static {
+ float x_min = 0.0f;
+ float y_min = 0.0f;
+ for (int i = 0; i < NB_SAMPLES; i++) {
+ final float alpha = (float) i / NB_SAMPLES;
+
+ float x_max = 1.0f;
+ float x, tx, coef;
+ while (true) {
+ x = x_min + (x_max - x_min) / 2.0f;
+ coef = 3.0f * x * (1.0f - x);
+ tx = coef * ((1.0f - x) * P1 + x * P2) + x * x * x;
+ if (Math.abs(tx - alpha) < 1E-5) break;
+ if (tx > alpha) x_max = x;
+ else x_min = x;
+ }
+ SPLINE_POSITION[i] = coef * ((1.0f - x) * START_TENSION + x) + x * x * x;
+
+ float y_max = 1.0f;
+ float y, dy;
+ while (true) {
+ y = y_min + (y_max - y_min) / 2.0f;
+ coef = 3.0f * y * (1.0f - y);
+ dy = coef * ((1.0f - y) * START_TENSION + y) + y * y * y;
+ if (Math.abs(dy - alpha) < 1E-5) break;
+ if (dy > alpha) y_max = y;
+ else y_min = y;
+ }
+ SPLINE_TIME[i] = coef * ((1.0f - y) * P1 + y * P2) + y * y * y;
+ }
+ SPLINE_POSITION[NB_SAMPLES] = SPLINE_TIME[NB_SAMPLES] = 1.0f;
+ }
+
+ void setFriction(float friction) {
+ mFlingFriction = friction;
+ }
+
+ SplineOverScroller(Context context) {
+ mFinished = true;
+ final float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
+ mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
+ * 39.37f // inch/meter
+ * ppi
+ * 0.84f; // look and feel tuning
+ }
+
+ void updateScroll(float q) {
+ mCurrentPosition = mStart + Math.round(q * (mFinal - mStart));
+ }
+
+ /*
+ * Get a signed deceleration that will reduce the velocity.
+ */
+ static private float getDeceleration(int velocity) {
+ return velocity > 0 ? -GRAVITY : GRAVITY;
+ }
+
+ /*
+ * Modifies mDuration to the duration it takes to get from start to newFinal using the
+ * spline interpolation. The previous duration was needed to get to oldFinal.
+ */
+ private void adjustDuration(int start, int oldFinal, int newFinal) {
+ final int oldDistance = oldFinal - start;
+ final int newDistance = newFinal - start;
+ final float x = Math.abs((float) newDistance / oldDistance);
+ final int index = (int) (NB_SAMPLES * x);
+ if (index < NB_SAMPLES) {
+ final float x_inf = (float) index / NB_SAMPLES;
+ final float x_sup = (float) (index + 1) / NB_SAMPLES;
+ final float t_inf = SPLINE_TIME[index];
+ final float t_sup = SPLINE_TIME[index + 1];
+ final float timeCoef = t_inf + (x - x_inf) / (x_sup - x_inf) * (t_sup - t_inf);
+ mDuration *= timeCoef;
+ }
+ }
+
+ void startScroll(int start, int distance, int duration) {
+ mFinished = false;
+
+ mCurrentPosition = mStart = start;
+ mFinal = start + distance;
+
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ mDuration = duration;
+
+ // Unused
+ mDeceleration = 0.0f;
+ mVelocity = 0;
+ }
+
+ void finish() {
+ mCurrentPosition = mFinal;
+ // Not reset since WebView relies on this value for fast fling.
+ // TODO: restore when WebView uses the fast fling implemented in this class.
+ // mCurrVelocity = 0.0f;
+ mFinished = true;
+ }
+
+ void setFinalPosition(int position) {
+ mFinal = position;
+ mSplineDistance = mFinal - mStart;
+ mFinished = false;
+ }
+
+ void extendDuration(int extend) {
+ final long time = AnimationUtils.currentAnimationTimeMillis();
+ final int elapsedTime = (int) (time - mStartTime);
+ mDuration = mSplineDuration = elapsedTime + extend;
+ mFinished = false;
+ }
+
+ boolean springback(int start, int min, int max) {
+ mFinished = true;
+
+ mCurrentPosition = mStart = mFinal = start;
+ mVelocity = 0;
+
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ mDuration = 0;
+
+ if (start < min) {
+ startSpringback(start, min, 0);
+ } else if (start > max) {
+ startSpringback(start, max, 0);
+ }
+
+ return !mFinished;
+ }
+
+ private void startSpringback(int start, int end, int velocity) {
+ // mStartTime has been set
+ mFinished = false;
+ mState = CUBIC;
+ mCurrentPosition = mStart = start;
+ mFinal = end;
+ final int delta = start - end;
+ mDeceleration = getDeceleration(delta);
+ // TODO take velocity into account
+ mVelocity = -delta; // only sign is used
+ mOver = Math.abs(delta);
+ mDuration = (int) (1000.0 * Math.sqrt(-2.0 * delta / mDeceleration));
+ }
+
+ void fling(int start, int velocity, int min, int max, int over) {
+ mOver = over;
+ mFinished = false;
+ mCurrVelocity = mVelocity = velocity;
+ mDuration = mSplineDuration = 0;
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ mCurrentPosition = mStart = start;
+
+ if (start > max || start < min) {
+ startAfterEdge(start, min, max, velocity);
+ return;
+ }
+
+ mState = SPLINE;
+ double totalDistance = 0.0;
+
+ if (velocity != 0) {
+ mDuration = mSplineDuration = getSplineFlingDuration(velocity);
+ totalDistance = getSplineFlingDistance(velocity);
+ }
+
+ mSplineDistance = (int) (totalDistance * Math.signum(velocity));
+ mFinal = start + mSplineDistance;
+
+ // Clamp to a valid final position
+ if (mFinal < min) {
+ adjustDuration(mStart, mFinal, min);
+ mFinal = min;
+ }
+
+ if (mFinal > max) {
+ adjustDuration(mStart, mFinal, max);
+ mFinal = max;
+ }
+ }
+
+ private double getSplineDeceleration(int velocity) {
+ return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff));
+ }
+
+ private double getSplineFlingDistance(int velocity) {
+ final double l = getSplineDeceleration(velocity);
+ final double decelMinusOne = DECELERATION_RATE - 1.0;
+ return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
+ }
+
+ /* Returns the duration, expressed in milliseconds */
+ private int getSplineFlingDuration(int velocity) {
+ final double l = getSplineDeceleration(velocity);
+ final double decelMinusOne = DECELERATION_RATE - 1.0;
+ return (int) (1000.0 * Math.exp(l / decelMinusOne));
+ }
+
+ private void fitOnBounceCurve(int start, int end, int velocity) {
+ // Simulate a bounce that started from edge
+ final float durationToApex = - velocity / mDeceleration;
+ // The float cast below is necessary to avoid integer overflow.
+ final float velocitySquared = (float) velocity * velocity;
+ final float distanceToApex = velocitySquared / 2.0f / Math.abs(mDeceleration);
+ final float distanceToEdge = Math.abs(end - start);
+ final float totalDuration = (float) Math.sqrt(
+ 2.0 * (distanceToApex + distanceToEdge) / Math.abs(mDeceleration));
+ mStartTime -= (int) (1000.0f * (totalDuration - durationToApex));
+ mCurrentPosition = mStart = end;
+ mVelocity = (int) (- mDeceleration * totalDuration);
+ }
+
+ private void startBounceAfterEdge(int start, int end, int velocity) {
+ mDeceleration = getDeceleration(velocity == 0 ? start - end : velocity);
+ fitOnBounceCurve(start, end, velocity);
+ onEdgeReached();
+ }
+
+ private void startAfterEdge(int start, int min, int max, int velocity) {
+ if (start > min && start < max) {
+ Log.e("OverScroller", "startAfterEdge called from a valid position");
+ mFinished = true;
+ return;
+ }
+ final boolean positive = start > max;
+ final int edge = positive ? max : min;
+ final int overDistance = start - edge;
+ boolean keepIncreasing = overDistance * velocity >= 0;
+ if (keepIncreasing) {
+ // Will result in a bounce or a to_boundary depending on velocity.
+ startBounceAfterEdge(start, edge, velocity);
+ } else {
+ final double totalDistance = getSplineFlingDistance(velocity);
+ if (totalDistance > Math.abs(overDistance)) {
+ fling(start, velocity, positive ? min : start, positive ? start : max, mOver);
+ } else {
+ startSpringback(start, edge, velocity);
+ }
+ }
+ }
+
+ void notifyEdgeReached(int start, int end, int over) {
+ // mState is used to detect successive notifications
+ if (mState == SPLINE) {
+ mOver = over;
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ // We were in fling/scroll mode before: current velocity is such that distance to
+ // edge is increasing. This ensures that startAfterEdge will not start a new fling.
+ startAfterEdge(start, end, end, (int) mCurrVelocity);
+ }
+ }
+
+ private void onEdgeReached() {
+ // mStart, mVelocity and mStartTime were adjusted to their values when edge was reached.
+ // The float cast below is necessary to avoid integer overflow.
+ final float velocitySquared = (float) mVelocity * mVelocity;
+ float distance = velocitySquared / (2.0f * Math.abs(mDeceleration));
+ final float sign = Math.signum(mVelocity);
+
+ if (distance > mOver) {
+ // Default deceleration is not sufficient to slow us down before boundary
+ mDeceleration = - sign * velocitySquared / (2.0f * mOver);
+ distance = mOver;
+ }
+
+ mOver = (int) distance;
+ mState = BALLISTIC;
+ mFinal = mStart + (int) (mVelocity > 0 ? distance : -distance);
+ mDuration = - (int) (1000.0f * mVelocity / mDeceleration);
+ }
+
+ boolean continueWhenFinished() {
+ switch (mState) {
+ case SPLINE:
+ // Duration from start to null velocity
+ if (mDuration < mSplineDuration) {
+ // If the animation was clamped, we reached the edge
+ mCurrentPosition = mStart = mFinal;
+ // TODO Better compute speed when edge was reached
+ mVelocity = (int) mCurrVelocity;
+ mDeceleration = getDeceleration(mVelocity);
+ mStartTime += mDuration;
+ onEdgeReached();
+ } else {
+ // Normal stop, no need to continue
+ return false;
+ }
+ break;
+ case BALLISTIC:
+ mStartTime += mDuration;
+ startSpringback(mFinal, mStart, 0);
+ break;
+ case CUBIC:
+ return false;
+ }
+
+ update();
+ return true;
+ }
+
+ /*
+ * Update the current position and velocity for current time. Returns
+ * true if update has been done and false if animation duration has been
+ * reached.
+ */
+ boolean update() {
+ final long time = AnimationUtils.currentAnimationTimeMillis();
+ final long currentTime = time - mStartTime;
+
+ if (currentTime == 0) {
+ // Skip work but report that we're still going if we have a nonzero duration.
+ return mDuration > 0;
+ }
+ if (currentTime > mDuration) {
+ return false;
+ }
+
+ double distance = 0.0;
+ switch (mState) {
+ case SPLINE: {
+ final float t = (float) currentTime / mSplineDuration;
+ final int index = (int) (NB_SAMPLES * t);
+ float distanceCoef = 1.f;
+ float velocityCoef = 0.f;
+ if (index < NB_SAMPLES) {
+ final float t_inf = (float) index / NB_SAMPLES;
+ final float t_sup = (float) (index + 1) / NB_SAMPLES;
+ final float d_inf = SPLINE_POSITION[index];
+ final float d_sup = SPLINE_POSITION[index + 1];
+ velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
+ distanceCoef = d_inf + (t - t_inf) * velocityCoef;
+ }
+
+ distance = distanceCoef * mSplineDistance;
+ mCurrVelocity = velocityCoef * mSplineDistance / mSplineDuration * 1000.0f;
+ break;
+ }
+
+ case BALLISTIC: {
+ final float t = currentTime / 1000.0f;
+ mCurrVelocity = mVelocity + mDeceleration * t;
+ distance = mVelocity * t + mDeceleration * t * t / 2.0f;
+ break;
+ }
+
+ case CUBIC: {
+ final float t = (float) (currentTime) / mDuration;
+ final float t2 = t * t;
+ final float sign = Math.signum(mVelocity);
+ distance = sign * mOver * (3.0f * t2 - 2.0f * t * t2);
+ mCurrVelocity = sign * mOver * 6.0f * (- t + t2);
+ break;
+ }
+ }
+
+ mCurrentPosition = mStart + (int) Math.round(distance);
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/util/ResourceBasedOverride.java b/src/com/android/launcher3/util/ResourceBasedOverride.java
new file mode 100644
index 0000000..e2c4992
--- /dev/null
+++ b/src/com/android/launcher3/util/ResourceBasedOverride.java
@@ -0,0 +1,54 @@
+/*
+ * 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.util;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * An interface to indicate that a class is dynamically loaded using resource overlay, hence its
+ * class name and constructor should be preserved by proguard
+ */
+public interface ResourceBasedOverride {
+
+ class Overrides {
+
+ private static final String TAG = "Overrides";
+
+ public static <T extends ResourceBasedOverride> T getObject(
+ Class<T> clazz, Context context, int resId) {
+ String className = context.getString(resId);
+ if (!TextUtils.isEmpty(className)) {
+ try {
+ Class<?> cls = Class.forName(className);
+ return (T) cls.getDeclaredConstructor(Context.class).newInstance(context);
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
+ | ClassCastException | NoSuchMethodException | InvocationTargetException e) {
+ Log.e(TAG, "Bad overriden class", e);
+ }
+ }
+
+ try {
+ return clazz.newInstance();
+ } catch (InstantiationException|IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/src/com/android/launcher3/util/SecureSettingsObserver.java b/src/com/android/launcher3/util/SecureSettingsObserver.java
new file mode 100644
index 0000000..48aa02b
--- /dev/null
+++ b/src/com/android/launcher3/util/SecureSettingsObserver.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings;
+
+/**
+ * Utility class to listen for secure settings changes
+ */
+public class SecureSettingsObserver extends ContentObserver {
+
+ /** Hidden field Settings.Secure.NOTIFICATION_BADGING */
+ public static final String NOTIFICATION_BADGING = "notification_badging";
+
+ private final ContentResolver mResolver;
+ private final String mKeySetting;
+ private final int mDefaultValue;
+ private final OnChangeListener mOnChangeListener;
+
+ public SecureSettingsObserver(ContentResolver resolver, OnChangeListener listener,
+ String keySetting, int defaultValue) {
+ super(new Handler());
+
+ mResolver = resolver;
+ mOnChangeListener = listener;
+ mKeySetting = keySetting;
+ mDefaultValue = defaultValue;
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mOnChangeListener.onSettingsChanged(getValue());
+ }
+
+ public boolean getValue() {
+ return Settings.Secure.getInt(mResolver, mKeySetting, mDefaultValue) == 1;
+ }
+
+ public void register() {
+ mResolver.registerContentObserver(Settings.Secure.getUriFor(mKeySetting), false, this);
+ }
+
+ public ContentResolver getResolver() {
+ return mResolver;
+ }
+
+ public void dispatchOnChange() {
+ onChange(true);
+ }
+
+ public void unregister() {
+ mResolver.unregisterContentObserver(this);
+ }
+
+ public interface OnChangeListener {
+ void onSettingsChanged(boolean isEnabled);
+ }
+
+ public static SecureSettingsObserver newNotificationSettingsObserver(Context context,
+ OnChangeListener listener) {
+ return new SecureSettingsObserver(
+ context.getContentResolver(), listener, NOTIFICATION_BADGING, 1);
+ }
+}
diff --git a/src/com/android/launcher3/util/SettingsObserver.java b/src/com/android/launcher3/util/SettingsObserver.java
deleted file mode 100644
index 6baa242..0000000
--- a/src/com/android/launcher3/util/SettingsObserver.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.util;
-
-import android.content.ContentResolver;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.provider.Settings;
-
-public interface SettingsObserver {
-
- /**
- * Registers the content observer to call {@link #onSettingChanged(boolean)} when any of the
- * passed settings change. The value passed to onSettingChanged() is based on the key setting.
- */
- void register(String keySetting, String ... dependentSettings);
- void unregister();
- void onSettingChanged(boolean keySettingEnabled);
-
-
- abstract class Secure extends ContentObserver implements SettingsObserver {
- private ContentResolver mResolver;
- private String mKeySetting;
-
- public Secure(ContentResolver resolver) {
- super(new Handler());
- mResolver = resolver;
- }
-
- @Override
- public void register(String keySetting, String ... dependentSettings) {
- mKeySetting = keySetting;
- mResolver.registerContentObserver(
- Settings.Secure.getUriFor(mKeySetting), false, this);
- for (String setting : dependentSettings) {
- mResolver.registerContentObserver(
- Settings.Secure.getUriFor(setting), false, this);
- }
- onChange(true);
- }
-
- @Override
- public void unregister() {
- mResolver.unregisterContentObserver(this);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
- onSettingChanged(Settings.Secure.getInt(mResolver, mKeySetting, 1) == 1);
- }
- }
-
- abstract class System extends ContentObserver implements SettingsObserver {
- private ContentResolver mResolver;
- private String mKeySetting;
-
- public System(ContentResolver resolver) {
- super(new Handler());
- mResolver = resolver;
- }
-
- @Override
- public void register(String keySetting, String ... dependentSettings) {
- mKeySetting = keySetting;
- mResolver.registerContentObserver(
- Settings.System.getUriFor(mKeySetting), false, this);
- for (String setting : dependentSettings) {
- mResolver.registerContentObserver(
- Settings.System.getUriFor(setting), false, this);
- }
- onChange(true);
- }
-
- @Override
- public void unregister() {
- mResolver.unregisterContentObserver(this);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
- onSettingChanged(Settings.System.getInt(mResolver, mKeySetting, 1) == 1);
- }
- }
-}
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index c8d1457..f948beb 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -30,7 +30,6 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.touch.SwipeDetector;
@@ -76,7 +75,7 @@
mScrollInterpolator = Interpolators.SCROLL_CUBIC;
mSwipeDetector = new SwipeDetector(context, this, SwipeDetector.VERTICAL);
- mOpenCloseAnimator = LauncherAnimUtils.ofPropertyValuesHolder(this);
+ mOpenCloseAnimator = ObjectAnimator.ofPropertyValuesHolder(this);
mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -103,28 +102,33 @@
directionsToDetectScroll, false);
mSwipeDetector.onTouchEvent(ev);
return mSwipeDetector.isDraggingOrSettling()
- || !mLauncher.getDragLayer().isEventOverView(mContent, ev);
+ || !getPopupContainer().isEventOverView(mContent, ev);
}
@Override
public boolean onControllerTouchEvent(MotionEvent ev) {
mSwipeDetector.onTouchEvent(ev);
- if (ev.getAction() == MotionEvent.ACTION_UP && mSwipeDetector.isIdleState()) {
+ if (ev.getAction() == MotionEvent.ACTION_UP && mSwipeDetector.isIdleState()
+ && !isOpeningAnimationRunning()) {
// If we got ACTION_UP without ever starting swipe, close the panel.
- if (!mLauncher.getDragLayer().isEventOverView(mContent, ev)) {
+ if (!getPopupContainer().isEventOverView(mContent, ev)) {
close(true);
}
}
return true;
}
+ private boolean isOpeningAnimationRunning() {
+ return mIsOpen && mOpenCloseAnimator.isRunning();
+ }
+
/* SwipeDetector.Listener */
@Override
public void onDragStart(boolean start) { }
@Override
- public boolean onDrag(float displacement, float velocity) {
+ public boolean onDrag(float displacement) {
float range = mContent.getHeight();
displacement = Utilities.boundToRange(displacement, 0, range);
setTranslationShift(displacement / range);
@@ -155,7 +159,7 @@
onCloseComplete();
return;
}
- if (!mIsOpen || mOpenCloseAnimator.isRunning()) {
+ if (!mIsOpen) {
return;
}
mOpenCloseAnimator.setValues(
@@ -178,6 +182,10 @@
protected void onCloseComplete() {
mIsOpen = false;
- mLauncher.getDragLayer().removeView(this);
+ getPopupContainer().removeView(this);
+ }
+
+ protected BaseDragLayer getPopupContainer() {
+ return mLauncher.getDragLayer();
}
}
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
new file mode 100644
index 0000000..04100af
--- /dev/null
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -0,0 +1,43 @@
+/*
+ * 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.views;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.view.ContextThemeWrapper;
+
+/**
+ * An interface to be used along with a context. This allows a generic class to depend on Context
+ * subclass instead of an Activity.
+ */
+public interface ActivityContext {
+
+ default boolean finishAutoCancelActionMode() {
+ return false;
+ }
+
+ BaseDragLayer getDragLayer();
+
+ static ActivityContext lookupContext(Context context) {
+ if (context instanceof ActivityContext) {
+ return (ActivityContext) context;
+ } else if (context instanceof ContextThemeWrapper) {
+ return lookupContext(((ContextWrapper) context).getBaseContext());
+ } else {
+ throw new IllegalArgumentException("Cannot find ActivityContext in parent tree");
+ }
+ }
+}
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 8457b2b..4545a1e 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -16,11 +16,16 @@
package com.android.launcher3.views;
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_UP;
+
import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Property;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -28,20 +33,46 @@
import android.widget.FrameLayout;
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.BaseActivity;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.TouchController;
+import java.io.PrintWriter;
import java.util.ArrayList;
/**
* A viewgroup with utility methods for drag-n-drop and touch interception
*/
-public abstract class BaseDragLayer<T extends BaseDraggingActivity> extends InsettableFrameLayout {
+public abstract class BaseDragLayer<T extends Context & ActivityContext>
+ extends InsettableFrameLayout {
+
+ public static final Property<LayoutParams, Integer> LAYOUT_X =
+ new Property<LayoutParams, Integer>(Integer.TYPE, "x") {
+ @Override
+ public Integer get(LayoutParams lp) {
+ return lp.x;
+ }
+
+ @Override
+ public void set(LayoutParams lp, Integer x) {
+ lp.x = x;
+ }
+ };
+
+ public static final Property<LayoutParams, Integer> LAYOUT_Y =
+ new Property<LayoutParams, Integer>(Integer.TYPE, "y") {
+ @Override
+ public Integer get(LayoutParams lp) {
+ return lp.y;
+ }
+
+ @Override
+ public void set(LayoutParams lp, Integer y) {
+ lp.y = y;
+ }
+ };
protected final int[] mTmpXY = new int[2];
protected final Rect mHitRect = new Rect();
@@ -53,9 +84,12 @@
protected TouchController mActiveController;
private TouchCompleteListener mTouchCompleteListener;
+ // Object controlling the current touch interaction
+ private Object mCurrentTouchOwner;
+
public BaseDragLayer(Context context, AttributeSet attrs, int alphaChannelCount) {
super(context, attrs);
- mActivity = (T) BaseActivity.fromContext(context);
+ mActivity = (T) ActivityContext.lookupContext(context);
mMultiValueAlpha = new MultiValueAlpha(this, alphaChannelCount);
}
@@ -68,7 +102,7 @@
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ if (action == ACTION_UP || action == ACTION_CANCEL) {
if (mTouchCompleteListener != null) {
mTouchCompleteListener.onTouchComplete();
}
@@ -151,7 +185,7 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ if (action == ACTION_UP || action == ACTION_CANCEL) {
if (mTouchCompleteListener != null) {
mTouchCompleteListener.onTouchComplete();
}
@@ -166,6 +200,37 @@
}
}
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ return verifyTouchDispatch(this, ev) && super.dispatchTouchEvent(ev);
+ }
+
+ /**
+ * Returns true if the {@param caller} is allowed to dispatch {@param ev} on this view,
+ * false otherwise.
+ */
+ public boolean verifyTouchDispatch(Object caller, MotionEvent ev) {
+ int action = ev.getAction();
+ if (action == ACTION_DOWN) {
+ if (mCurrentTouchOwner != null) {
+ // Another touch in progress.
+ ev.setAction(ACTION_CANCEL);
+ super.dispatchTouchEvent(ev);
+ ev.setAction(action);
+ }
+ mCurrentTouchOwner = caller;
+ return true;
+ }
+ if (mCurrentTouchOwner != caller) {
+ // Someone else is controlling the touch
+ return false;
+ }
+ if (action == ACTION_UP || action == ACTION_CANCEL) {
+ mCurrentTouchOwner = null;
+ }
+ return true;
+ }
+
/**
* Determine the rect of the descendant in this DragLayer's coordinates
*
@@ -293,6 +358,10 @@
return mMultiValueAlpha.getProperty(index);
}
+ public void dumpAlpha(PrintWriter writer) {
+ writer.println(" dragLayerAlpha : " + mMultiValueAlpha );
+ }
+
public static class LayoutParams extends InsettableFrameLayout.LayoutParams {
public int x, y;
public boolean customPosition = false;
@@ -308,38 +377,6 @@
public LayoutParams(ViewGroup.LayoutParams lp) {
super(lp);
}
-
- public void setWidth(int width) {
- this.width = width;
- }
-
- public int getWidth() {
- return width;
- }
-
- public void setHeight(int height) {
- this.height = height;
- }
-
- public int getHeight() {
- return height;
- }
-
- public void setX(int x) {
- this.x = x;
- }
-
- public int getX() {
- return x;
- }
-
- public void setY(int y) {
- this.y = y;
- }
-
- public int getY() {
- return y;
- }
}
protected void onLayout(boolean changed, int l, int t, int r, int b) {
diff --git a/src/com/android/launcher3/views/ButtonPreference.java b/src/com/android/launcher3/views/ButtonPreference.java
deleted file mode 100644
index fdcf2ca..0000000
--- a/src/com/android/launcher3/views/ButtonPreference.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2017 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.views;
-
-import android.content.Context;
-import android.preference.Preference;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * Extension of {@link Preference} which makes the widget layout clickable.
- *
- * @see #setWidgetLayoutResource(int)
- */
-public class ButtonPreference extends Preference {
-
- private boolean mWidgetFrameVisible = false;
-
- public ButtonPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- public ButtonPreference(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public ButtonPreference(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public ButtonPreference(Context context) {
- super(context);
- }
-
- public void setWidgetFrameVisible(boolean isVisible) {
- if (mWidgetFrameVisible != isVisible) {
- mWidgetFrameVisible = isVisible;
- notifyChanged();
- }
- }
-
- @Override
- protected void onBindView(View view) {
- super.onBindView(view);
-
- ViewGroup widgetFrame = view.findViewById(android.R.id.widget_frame);
- if (widgetFrame != null) {
- widgetFrame.setVisibility(mWidgetFrameVisible ? View.VISIBLE : View.GONE);
- }
- }
-}
diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
index a11a8c5..323eecb 100644
--- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -16,11 +16,12 @@
package com.android.launcher3.views;
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.support.v4.graphics.ColorUtils;
import android.util.AttributeSet;
import android.widget.TextView;
@@ -59,7 +60,7 @@
// We enhance the shadow by drawing the shadow twice
getPaint().setShadowLayer(mShadowInfo.ambientShadowBlur, 0, 0,
- ColorUtils.setAlphaComponent(mShadowInfo.ambientShadowColor, alpha));
+ setColorAlphaBound(mShadowInfo.ambientShadowColor, alpha));
drawWithoutBadge(canvas);
canvas.save();
@@ -68,7 +69,7 @@
getScrollY() + getHeight());
getPaint().setShadowLayer(mShadowInfo.keyShadowBlur, 0.0f, mShadowInfo.keyShadowOffset,
- ColorUtils.setAlphaComponent(mShadowInfo.keyShadowColor, alpha));
+ setColorAlphaBound(mShadowInfo.keyShadowColor, alpha));
drawWithoutBadge(canvas);
canvas.restore();
@@ -106,11 +107,11 @@
return true;
} else if (ambientShadowAlpha > 0) {
textView.getPaint().setShadowLayer(ambientShadowBlur, 0, 0,
- ColorUtils.setAlphaComponent(ambientShadowColor, textAlpha));
+ setColorAlphaBound(ambientShadowColor, textAlpha));
return true;
} else if (keyShadowAlpha > 0) {
textView.getPaint().setShadowLayer(keyShadowBlur, 0.0f, keyShadowOffset,
- ColorUtils.setAlphaComponent(keyShadowColor, textAlpha));
+ setColorAlphaBound(keyShadowColor, textAlpha));
return true;
} else {
return false;
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index db4c492..6ba2f40 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -34,6 +34,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.popup.ArrowPopup;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
@@ -43,6 +44,8 @@
import java.util.ArrayList;
import java.util.List;
+import androidx.annotation.VisibleForTesting;
+
/**
* Popup shown on long pressing an empty space in launcher
*/
@@ -94,7 +97,7 @@
if (ev.getAction() != MotionEvent.ACTION_DOWN) {
return false;
}
- if (mLauncher.getDragLayer().isEventOverView(this, ev)) {
+ if (getPopupContainer().isEventOverView(this, ev)) {
return false;
}
close(true);
@@ -133,6 +136,11 @@
popup.reorderAndShow(popup.getChildCount());
}
+ @VisibleForTesting
+ public static ArrowPopup getOptionsPopup(Launcher launcher) {
+ return launcher.findViewById(R.id.deep_shortcuts_container);
+ }
+
public static void showDefaultOptions(Launcher launcher, float x, float y) {
float halfSize = launcher.getResources().getDimension(R.dimen.options_menu_thumb_size) / 2;
if (x < 0 || y < 0) {
@@ -144,8 +152,10 @@
ArrayList<OptionItem> options = new ArrayList<>();
options.add(new OptionItem(R.string.wallpaper_button_text, R.drawable.ic_wallpaper,
ControlType.WALLPAPER_BUTTON, OptionsPopupView::startWallpaperPicker));
- options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget,
- ControlType.WIDGETS_BUTTON, OptionsPopupView::onWidgetsClicked));
+ if (!FeatureFlags.GO_DISABLE_WIDGETS) {
+ options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget,
+ ControlType.WIDGETS_BUTTON, OptionsPopupView::onWidgetsClicked));
+ }
options.add(new OptionItem(R.string.settings_button_text, R.drawable.ic_setting,
ControlType.SETTINGS_BUTTON, OptionsPopupView::startSettings));
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 05bab8b..883cbee 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -24,7 +24,6 @@
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
-import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Property;
import android.view.MotionEvent;
@@ -35,10 +34,11 @@
import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.FastScrollThumbDrawable;
import com.android.launcher3.util.Themes;
+import androidx.recyclerview.widget.RecyclerView;
+
/**
* The track and scrollbar that shows when you scroll the list.
*/
@@ -175,6 +175,7 @@
if (mThumbOffsetY == y) {
return;
}
+ updatePopupY((int) y);
mThumbOffsetY = y;
invalidate();
}
@@ -224,8 +225,7 @@
}
if (isNearThumb(x, y)) {
mTouchOffsetY = mDownY - mThumbOffsetY;
- } else if (FeatureFlags.LAUNCHER3_DIRECT_SCROLL
- && mRv.supportsFastScrolling()
+ } else if (mRv.supportsFastScrolling()
&& isNearScrollBar(mDownX)) {
calcTouchOffsetAndPrepToFastScroll(mDownY, mLastY);
updateFastScrollSectionNameAndThumbOffset(mLastY, y);
@@ -282,7 +282,6 @@
mPopupView.setText(sectionName);
}
animatePopupVisibility(!sectionName.isEmpty());
- updatePopupY(lastY);
mLastTouchY = boundedY;
setThumbOffsetY((int) mLastTouchY);
}
@@ -300,11 +299,14 @@
canvas.translate(0, mThumbOffsetY);
halfW += mThumbPadding;
- float r = mWidth + mThumbPadding + mThumbPadding;
+ float r = getScrollThumbRadius();
canvas.drawRoundRect(-halfW, 0, halfW, mThumbHeight, r, r, mThumbPaint);
canvas.restoreToCount(saveCount);
}
+ private float getScrollThumbRadius() {
+ return mWidth + mThumbPadding + mThumbPadding;
+ }
/**
* Animates the width of the scrollbar.
@@ -353,11 +355,15 @@
}
private void updatePopupY(int lastTouchY) {
+ if (!mPopupVisible) {
+ return;
+ }
int height = mPopupView.getHeight();
- float top = lastTouchY - (FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR * height)
- + mRv.getScrollBarTop();
- top = Utilities.boundToRange(top,
- mMaxWidth, mRv.getScrollbarTrackHeight() - mMaxWidth - height);
+ // Aligns the rounded corner of the pop up with the top of the thumb.
+ float top = mRv.getScrollBarTop() + lastTouchY + (getScrollThumbRadius() / 2f)
+ - (height / 2f);
+ top = Utilities.boundToRange(top, 0,
+ getTop() + mRv.getScrollBarTop() + mRv.getScrollbarTrackHeight() - height);
mPopupView.setTranslationY(top);
}
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 7066980..deb0965 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -16,14 +16,15 @@
package com.android.launcher3.views;
import static android.content.Context.ACCESSIBILITY_SERVICE;
-import static android.support.v4.graphics.ColorUtils.compositeColors;
-import static android.support.v4.graphics.ColorUtils.setAlphaComponent;
import static android.view.MotionEvent.ACTION_DOWN;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
+
+import static androidx.core.graphics.ColorUtils.compositeColors;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -38,12 +39,6 @@
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
-import android.support.v4.widget.ExploreByTouchHelper;
import android.util.AttributeSet;
import android.util.Property;
import android.view.KeyEvent;
@@ -68,6 +63,13 @@
import java.util.List;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
+import androidx.customview.widget.ExploreByTouchHelper;
+
/**
* Simple scrim which draws a flat color
*/
@@ -180,7 +182,7 @@
@Override
public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) {
mScrimColor = wallpaperColorInfo.getMainColor();
- mEndFlatColor = compositeColors(mEndScrim, setAlphaComponent(
+ mEndFlatColor = compositeColors(mEndScrim, setColorAlphaBound(
mScrimColor, Math.round(mMaxScrimAlpha * 255)));
mEndFlatColorAlpha = Color.alpha(mEndFlatColor);
updateColors();
@@ -199,7 +201,7 @@
public void reInitUi() { }
protected void updateColors() {
- mCurrentFlatColor = mProgress >= 1 ? 0 : setAlphaComponent(
+ mCurrentFlatColor = mProgress >= 1 ? 0 : setColorAlphaBound(
mEndFlatColor, Math.round((1 - mProgress) * mEndFlatColorAlpha));
}
diff --git a/src/com/android/launcher3/views/Snackbar.java b/src/com/android/launcher3/views/Snackbar.java
new file mode 100644
index 0000000..04b637b
--- /dev/null
+++ b/src/com/android/launcher3/views/Snackbar.java
@@ -0,0 +1,183 @@
+/*
+ * 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.views;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.widget.TextView;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.dragndrop.DragLayer;
+
+/**
+ * A toast-like UI at the bottom of the screen with a label, button action, and dismiss action.
+ */
+public class Snackbar extends AbstractFloatingView {
+
+ private static final long SHOW_DURATION_MS = 180;
+ private static final long HIDE_DURATION_MS = 180;
+ private static final long TIMEOUT_DURATION_MS = 4000;
+
+ private final Launcher mLauncher;
+ private Runnable mOnDismissed;
+
+ public Snackbar(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public Snackbar(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mLauncher = Launcher.getLauncher(context);
+ inflate(context, R.layout.snackbar, this);
+ }
+
+ public static void show(Launcher launcher, int labelStringResId, int actionStringResId,
+ Runnable onDismissed, Runnable onActionClicked) {
+ closeOpenViews(launcher, true, TYPE_SNACKBAR);
+ Snackbar snackbar = new Snackbar(launcher, null);
+ // Set some properties here since inflated xml only contains the children.
+ snackbar.setOrientation(HORIZONTAL);
+ snackbar.setGravity(Gravity.CENTER_VERTICAL);
+ Resources res = launcher.getResources();
+ snackbar.setElevation(res.getDimension(R.dimen.snackbar_elevation));
+ int padding = res.getDimensionPixelSize(R.dimen.snackbar_padding);
+ snackbar.setPadding(padding, padding, padding, padding);
+ snackbar.setBackgroundResource(R.drawable.round_rect_primary);
+
+ snackbar.mIsOpen = true;
+ DragLayer dragLayer = launcher.getDragLayer();
+ dragLayer.addView(snackbar);
+
+ DragLayer.LayoutParams params = (DragLayer.LayoutParams) snackbar.getLayoutParams();
+ params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ params.height = res.getDimensionPixelSize(R.dimen.snackbar_height);
+ int maxMarginLeftRight = res.getDimensionPixelSize(R.dimen.snackbar_max_margin_left_right);
+ int minMarginLeftRight = res.getDimensionPixelSize(R.dimen.snackbar_min_margin_left_right);
+ int marginBottom = res.getDimensionPixelSize(R.dimen.snackbar_margin_bottom);
+ Rect insets = launcher.getDeviceProfile().getInsets();
+ int maxWidth = dragLayer.getWidth() - minMarginLeftRight * 2 - insets.left - insets.right;
+ int minWidth = dragLayer.getWidth() - maxMarginLeftRight * 2 - insets.left - insets.right;
+ params.width = minWidth;
+ params.setMargins(0, 0, 0, marginBottom + insets.bottom);
+
+ TextView labelView = snackbar.findViewById(R.id.label);
+ TextView actionView = snackbar.findViewById(R.id.action);
+ String labelText = res.getString(labelStringResId);
+ String actionText = res.getString(actionStringResId);
+ int totalContentWidth = (int) (labelView.getPaint().measureText(labelText)
+ + actionView.getPaint().measureText(actionText))
+ + labelView.getPaddingRight() + labelView.getPaddingLeft()
+ + actionView.getPaddingRight() + actionView.getPaddingLeft()
+ + padding * 2;
+ if (totalContentWidth > params.width) {
+ // The text doesn't fit in our standard width so update width to accommodate.
+ if (totalContentWidth <= maxWidth) {
+ params.width = totalContentWidth;
+ } else {
+ // One line will be cut off, fallback to 2 lines and smaller font. (This should only
+ // happen in some languages if system display and font size are set to largest.)
+ int textHeight = res.getDimensionPixelSize(R.dimen.snackbar_content_height);
+ float textSizePx = res.getDimension(R.dimen.snackbar_min_text_size);
+ labelView.setLines(2);
+ labelView.getLayoutParams().height = textHeight * 2;
+ actionView.getLayoutParams().height = textHeight * 2;
+ labelView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx);
+ actionView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx);
+ params.height += textHeight;
+ params.width = maxWidth;
+ }
+ }
+ labelView.setText(labelText);
+ actionView.setText(actionText);
+ actionView.setOnClickListener(v -> {
+ if (onActionClicked != null) {
+ onActionClicked.run();
+ }
+ snackbar.mOnDismissed = null;
+ snackbar.close(true);
+ });
+ snackbar.mOnDismissed = onDismissed;
+
+ snackbar.setAlpha(0);
+ snackbar.setScaleX(0.8f);
+ snackbar.setScaleY(0.8f);
+ snackbar.animate()
+ .alpha(1f)
+ .withLayer()
+ .scaleX(1)
+ .scaleY(1)
+ .setDuration(SHOW_DURATION_MS)
+ .setInterpolator(Interpolators.ACCEL_DEACCEL)
+ .start();
+ snackbar.postDelayed(() -> snackbar.close(true), TIMEOUT_DURATION_MS);
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ if (mIsOpen) {
+ if (animate) {
+ animate().alpha(0f)
+ .withLayer()
+ .setStartDelay(0)
+ .setDuration(HIDE_DURATION_MS)
+ .setInterpolator(Interpolators.ACCEL)
+ .withEndAction(this::onClosed)
+ .start();
+ } else {
+ animate().cancel();
+ onClosed();
+ }
+ mIsOpen = false;
+ }
+ }
+
+ private void onClosed() {
+ mLauncher.getDragLayer().removeView(this);
+ if (mOnDismissed != null) {
+ mOnDismissed.run();
+ }
+ }
+
+ @Override
+ public void logActionCommand(int command) {
+ // TODO
+ }
+
+ @Override
+ protected boolean isOfType(int type) {
+ return (type & TYPE_SNACKBAR) != 0;
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ DragLayer dl = mLauncher.getDragLayer();
+ if (!dl.isEventOverView(this, ev)) {
+ close(true);
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/com/android/launcher3/views/SpringRelativeLayout.java b/src/com/android/launcher3/views/SpringRelativeLayout.java
index b0313ce..d0ec9d7 100644
--- a/src/com/android/launcher3/views/SpringRelativeLayout.java
+++ b/src/com/android/launcher3/views/SpringRelativeLayout.java
@@ -15,24 +15,25 @@
*/
package com.android.launcher3.views;
+import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY;
+import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW;
+import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_MEDIUM;
+
import android.content.Context;
import android.graphics.Canvas;
-import android.support.animation.DynamicAnimation;
-import android.support.animation.FloatPropertyCompat;
-import android.support.animation.SpringAnimation;
-import android.support.animation.SpringForce;
-import android.support.annotation.NonNull;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.EdgeEffectFactory;
import android.util.AttributeSet;
import android.util.SparseBooleanArray;
import android.view.View;
import android.widget.EdgeEffect;
import android.widget.RelativeLayout;
-import static android.support.animation.SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY;
-import static android.support.animation.SpringForce.STIFFNESS_LOW;
-import static android.support.animation.SpringForce.STIFFNESS_MEDIUM;
+import androidx.annotation.NonNull;
+import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory;
public class SpringRelativeLayout extends RelativeLayout {
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 10708d6..673b3cc 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.widget;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
+import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import android.content.Context;
@@ -31,13 +34,14 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.graphics.ColorScrim;
import com.android.launcher3.touch.ItemLongClickListener;
+import com.android.launcher3.uioverrides.WallpaperColorInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.AbstractSlideInView;
+import com.android.launcher3.views.BaseDragLayer;
/**
* Base class for various widgets popup
@@ -49,11 +53,11 @@
/* Touch handling related member variables. */
private Toast mWidgetInstructionToast;
- protected final ColorScrim mColorScrim;
+ protected final View mColorScrim;
public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mColorScrim = ColorScrim.createExtractedColorScrim(this);
+ mColorScrim = createColorScrim(context);
}
@Override
@@ -71,7 +75,7 @@
}
@Override
- public final boolean onLongClick(View v) {
+ public boolean onLongClick(View v) {
if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
if (v instanceof WidgetCell) {
@@ -80,9 +84,14 @@
return true;
}
+ protected void attachToContainer() {
+ getPopupContainer().addView(mColorScrim);
+ getPopupContainer().addView(this);
+ }
+
protected void setTranslationShift(float translationShift) {
super.setTranslationShift(translationShift);
- mColorScrim.setProgress(1 - mTranslationShift);
+ mColorScrim.setAlpha(1 - mTranslationShift);
}
private boolean beginDraggingWidget(WidgetCell v) {
@@ -96,7 +105,7 @@
}
int[] loc = new int[2];
- mLauncher.getDragLayer().getLocationInDragLayer(image, loc);
+ getPopupContainer().getLocationInDragLayer(image, loc);
new PendingItemDragHelper(v).startDrag(
image.getBitmapBounds(), image.getBitmap().getWidth(), image.getWidth(),
@@ -115,17 +124,18 @@
protected void onCloseComplete() {
super.onCloseComplete();
+ getPopupContainer().removeView(mColorScrim);
clearNavBarColor();
}
protected void clearNavBarColor() {
- mLauncher.getSystemUiController().updateUiState(
+ getSystemUiController().updateUiState(
SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
}
protected void setupNavBarColor() {
- boolean isSheetDark = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
- mLauncher.getSystemUiController().updateUiState(
+ boolean isSheetDark = Themes.getAttrBoolean(getContext(), R.attr.isMainColorDark);
+ getSystemUiController().updateUiState(
SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET,
isSheetDark ? SystemUiController.FLAG_DARK_NAV : SystemUiController.FLAG_LIGHT_NAV);
}
@@ -145,4 +155,22 @@
protected abstract int getElementsRowCount();
+ protected SystemUiController getSystemUiController() {
+ return mLauncher.getSystemUiController();
+ }
+
+ private static View createColorScrim(Context context) {
+ View view = new View(context);
+ if (Utilities.ATLEAST_NOUGAT) view.forceHasOverlappingRendering(false);
+
+ WallpaperColorInfo colors = WallpaperColorInfo.getInstance(context);
+ int alpha = context.getResources().getInteger(R.integer.extracted_color_gradient_alpha);
+ view.setBackgroundColor(setColorAlphaBound(colors.getSecondaryColor(), alpha));
+
+ BaseDragLayer.LayoutParams lp = new BaseDragLayer.LayoutParams(MATCH_PARENT, MATCH_PARENT);
+ lp.ignoreInsets = true;
+ view.setLayoutParams(lp);
+
+ return view;
+ }
}
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 12859c7..95f8daa 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -16,16 +16,13 @@
package com.android.launcher3.widget;
-import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PointF;
-import android.graphics.Rect;
import android.os.Handler;
import android.os.SystemClock;
import android.util.SparseBooleanArray;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -49,12 +46,10 @@
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.views.BaseDragLayer.TouchCompleteListener;
-import java.util.ArrayList;
-
/**
* {@inheritDoc}
*/
-public class LauncherAppWidgetHostView extends AppWidgetHostView
+public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
implements TouchCompleteListener, View.OnLongClickListener {
// Related to the auto-advancing of widgets
@@ -75,9 +70,6 @@
private float mSlop;
- @ViewDebug.ExportedProperty(category = "launcher")
- private boolean mChildrenFocused;
-
private boolean mIsScrollable;
private boolean mIsAttachedToWindow;
private boolean mIsAutoAdvanceRegistered;
@@ -267,98 +259,6 @@
}
}
- @Override
- public int getDescendantFocusability() {
- return mChildrenFocused ? ViewGroup.FOCUS_BEFORE_DESCENDANTS
- : ViewGroup.FOCUS_BLOCK_DESCENDANTS;
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (mChildrenFocused && event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE
- && event.getAction() == KeyEvent.ACTION_UP) {
- mChildrenFocused = false;
- requestFocus();
- return true;
- }
- return super.dispatchKeyEvent(event);
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (!mChildrenFocused && keyCode == KeyEvent.KEYCODE_ENTER) {
- event.startTracking();
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (event.isTracking()) {
- if (!mChildrenFocused && keyCode == KeyEvent.KEYCODE_ENTER) {
- mChildrenFocused = true;
- ArrayList<View> focusableChildren = getFocusables(FOCUS_FORWARD);
- focusableChildren.remove(this);
- int childrenCount = focusableChildren.size();
- switch (childrenCount) {
- case 0:
- mChildrenFocused = false;
- break;
- case 1: {
- if (getTag() instanceof ItemInfo) {
- ItemInfo item = (ItemInfo) getTag();
- if (item.spanX == 1 && item.spanY == 1) {
- focusableChildren.get(0).performClick();
- mChildrenFocused = false;
- return true;
- }
- }
- // continue;
- }
- default:
- focusableChildren.get(0).requestFocus();
- return true;
- }
- }
- }
- return super.onKeyUp(keyCode, event);
- }
-
- @Override
- protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
- if (gainFocus) {
- mChildrenFocused = false;
- dispatchChildFocus(false);
- }
- super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
- }
-
- @Override
- public void requestChildFocus(View child, View focused) {
- super.requestChildFocus(child, focused);
- dispatchChildFocus(mChildrenFocused && focused != null);
- if (focused != null) {
- focused.setFocusableInTouchMode(false);
- }
- }
-
- @Override
- public void clearChildFocus(View child) {
- super.clearChildFocus(child);
- dispatchChildFocus(false);
- }
-
- @Override
- public boolean dispatchUnhandledMove(View focused, int direction) {
- return mChildrenFocused;
- }
-
- private void dispatchChildFocus(boolean childIsFocused) {
- // The host view's background changes when selected, to indicate the focus is inside.
- setSelected(childIsFocused);
- }
-
public void switchToErrorView() {
// Update the widget with 0 Layout id, to reset the view to error view.
updateAppWidget(new RemoteViews(getAppWidgetInfo().provider.getPackageName(), 0));
@@ -502,4 +402,13 @@
mLauncher.removeItem(this, info, false /* deleteFromDb */);
mLauncher.bindAppWidget(info);
}
+
+ @Override
+ protected boolean shouldAllowDirectClick() {
+ if (getTag() instanceof ItemInfo) {
+ ItemInfo item = (ItemInfo) getTag();
+ return item.spanX == 1 && item.spanY == 1;
+ }
+ return false;
+ }
}
diff --git a/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
new file mode 100644
index 0000000..68b1595
--- /dev/null
+++ b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
@@ -0,0 +1,136 @@
+/*
+ * 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.widget;
+
+import android.appwidget.AppWidgetHostView;
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewDebug;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+
+/**
+ * Extension of AppWidgetHostView with support for controlled keyboard navigation.
+ */
+public abstract class NavigableAppWidgetHostView extends AppWidgetHostView {
+
+ @ViewDebug.ExportedProperty(category = "launcher")
+ private boolean mChildrenFocused;
+
+ public NavigableAppWidgetHostView(Context context) {
+ super(context);
+ }
+
+ @Override
+ public int getDescendantFocusability() {
+ return mChildrenFocused ? ViewGroup.FOCUS_BEFORE_DESCENDANTS
+ : ViewGroup.FOCUS_BLOCK_DESCENDANTS;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (mChildrenFocused && event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE
+ && event.getAction() == KeyEvent.ACTION_UP) {
+ mChildrenFocused = false;
+ requestFocus();
+ return true;
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (!mChildrenFocused && keyCode == KeyEvent.KEYCODE_ENTER) {
+ event.startTracking();
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (event.isTracking()) {
+ if (!mChildrenFocused && keyCode == KeyEvent.KEYCODE_ENTER) {
+ mChildrenFocused = true;
+ ArrayList<View> focusableChildren = getFocusables(FOCUS_FORWARD);
+ focusableChildren.remove(this);
+ int childrenCount = focusableChildren.size();
+ switch (childrenCount) {
+ case 0:
+ mChildrenFocused = false;
+ break;
+ case 1: {
+ if (shouldAllowDirectClick()) {
+ focusableChildren.get(0).performClick();
+ mChildrenFocused = false;
+ return true;
+ }
+ // continue;
+ }
+ default:
+ focusableChildren.get(0).requestFocus();
+ return true;
+ }
+ }
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ /**
+ * For a widget with only a single interactive element, return true if whole widget should act
+ * as a single interactive element, and clicking 'enter' should activate the child element
+ * directly. Otherwise clicking 'enter' will only move the focus inside the widget.
+ */
+ protected abstract boolean shouldAllowDirectClick();
+
+ @Override
+ protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+ if (gainFocus) {
+ mChildrenFocused = false;
+ dispatchChildFocus(false);
+ }
+ super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+ }
+
+ @Override
+ public void requestChildFocus(View child, View focused) {
+ super.requestChildFocus(child, focused);
+ dispatchChildFocus(mChildrenFocused && focused != null);
+ if (focused != null) {
+ focused.setFocusableInTouchMode(false);
+ }
+ }
+
+ @Override
+ public void clearChildFocus(View child) {
+ super.clearChildFocus(child);
+ dispatchChildFocus(false);
+ }
+
+ @Override
+ public boolean dispatchUnhandledMove(View focused, int direction) {
+ return mChildrenFocused;
+ }
+
+ private void dispatchChildFocus(boolean childIsFocused) {
+ // The host view's background changes when selected, to indicate the focus is inside.
+ setSelected(childIsFocused);
+ }
+}
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 961799d..50db40f 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -17,7 +17,6 @@
package com.android.launcher3.widget;
import android.content.Context;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;
@@ -34,18 +33,15 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.FastBitmapDrawable;
-import com.android.launcher3.IconCache;
-import com.android.launcher3.IconCache.ItemInfoUpdateReceiver;
+import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.ItemInfoWithIcon;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.Themes;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
public class PendingAppWidgetHostView extends LauncherAppWidgetHostView
implements OnClickListener, ItemInfoUpdateReceiver {
@@ -137,19 +133,19 @@
// 1) App icon in the center
// 2) Preload icon in the center
// 3) Setup icon in the center and app icon in the top right corner.
- DrawableFactory drawableFactory = DrawableFactory.get(getContext());
+ DrawableFactory drawableFactory = DrawableFactory.INSTANCE.get(getContext());
if (mDisabledForSafeMode) {
- FastBitmapDrawable disabledIcon = drawableFactory.newIcon(info);
+ FastBitmapDrawable disabledIcon = drawableFactory.newIcon(getContext(), info);
disabledIcon.setIsDisabled(true);
mCenterDrawable = disabledIcon;
mSettingIconDrawable = null;
} else if (isReadyForClickSetup()) {
- mCenterDrawable = drawableFactory.newIcon(info);
+ mCenterDrawable = drawableFactory.newIcon(getContext(), info);
mSettingIconDrawable = getResources().getDrawable(R.drawable.ic_setting).mutate();
updateSettingColor(info.iconColor);
} else {
- mCenterDrawable = DrawableFactory.get(getContext())
- .newPendingIcon(info, getContext());
+ mCenterDrawable = DrawableFactory.INSTANCE.get(getContext())
+ .newPendingIcon(getContext(), info);
mSettingIconDrawable = null;
applyState();
}
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index 74ab14f..8ea9bd4 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -34,7 +34,7 @@
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.LivePreviewWidgetCell;
import com.android.launcher3.graphics.DragPreviewProvider;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.icons.LauncherIcons;
/**
* Extension of {@link DragPreviewProvider} with logic specific to pending widgets/shortcuts
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 2ba55ab..66af43a 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -179,8 +179,8 @@
return;
}
if (bitmap != null) {
- mWidgetImage.setBitmap(bitmap,
- DrawableFactory.get(getContext()).getBadgeForUser(mItem.user, getContext()));
+ mWidgetImage.setBitmap(bitmap, DrawableFactory.INSTANCE.get(getContext())
+ .getBadgeForUser(mItem.user, getContext()));
if (mAnimatePreview) {
mWidgetImage.setAlpha(0f);
ViewPropertyAnimator anim = mWidgetImage.animate();
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 5ce7e04..4bd6234 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -70,8 +70,7 @@
R.string.widgets_bottom_sheet_title, mOriginalItemInfo.title));
onWidgetsBound();
-
- mLauncher.getDragLayer().addView(this);
+ attachToContainer();
mIsOpen = false;
animateOpen();
}
@@ -118,7 +117,7 @@
LayoutInflater.from(getContext()).inflate(R.layout.widget_list_divider, parent, true);
}
- private WidgetCell addItemCell(ViewGroup parent) {
+ protected WidgetCell addItemCell(ViewGroup parent) {
WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext()).inflate(
R.layout.widget_cell, parent, false);
diff --git a/src/com/android/launcher3/widget/WidgetsDiffReporter.java b/src/com/android/launcher3/widget/WidgetsDiffReporter.java
index d67f403..435125b 100644
--- a/src/com/android/launcher3/widget/WidgetsDiffReporter.java
+++ b/src/com/android/launcher3/widget/WidgetsDiffReporter.java
@@ -16,16 +16,17 @@
package com.android.launcher3.widget;
-import android.support.v7.widget.RecyclerView;
import android.util.Log;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.widget.WidgetsListAdapter.WidgetListRowEntryComparator;
import java.util.ArrayList;
import java.util.Iterator;
+import androidx.recyclerview.widget.RecyclerView;
+
/**
* Do diff on widget's tray list items and call the {@link RecyclerView.Adapter}
* methods accordingly.
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index e94d81d..1112686 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -35,6 +35,8 @@
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.TopRoundedCornerView;
+import androidx.annotation.VisibleForTesting;
+
/**
* Popup for showing the full list of available widgets
*/
@@ -159,7 +161,7 @@
private void open(boolean animate) {
if (animate) {
- if (mLauncher.getDragLayer().getInsets().bottom > 0) {
+ if (getPopupContainer().getInsets().bottom > 0) {
mContent.setAlpha(0);
setTranslationShift(VERTICAL_START_POSITION);
}
@@ -206,10 +208,10 @@
mNoIntercept = false;
RecyclerViewFastScroller scroller = mRecyclerView.getScrollbar();
if (scroller.getThumbOffsetY() >= 0 &&
- mLauncher.getDragLayer().isEventOverView(scroller, ev)) {
+ getPopupContainer().isEventOverView(scroller, ev)) {
mNoIntercept = true;
- } else if (mLauncher.getDragLayer().isEventOverView(mContent, ev)) {
- mNoIntercept = !mRecyclerView.shouldContainerScroll(ev, mLauncher.getDragLayer());
+ } else if (getPopupContainer().isEventOverView(mContent, ev)) {
+ mNoIntercept = !mRecyclerView.shouldContainerScroll(ev, getPopupContainer());
}
}
return super.onControllerInterceptTouchEvent(ev);
@@ -218,12 +220,17 @@
public static WidgetsFullSheet show(Launcher launcher, boolean animate) {
WidgetsFullSheet sheet = (WidgetsFullSheet) launcher.getLayoutInflater()
.inflate(R.layout.widgets_full_sheet, launcher.getDragLayer(), false);
+ sheet.attachToContainer();
sheet.mIsOpen = true;
- launcher.getDragLayer().addView(sheet);
sheet.open(animate);
return sheet;
}
+ @VisibleForTesting
+ public static WidgetsRecyclerView getWidgetsView(Launcher launcher) {
+ return launcher.findViewById(R.id.widgets_list_view);
+ }
+
@Override
protected int getElementsRowCount() {
return mAdapter.getItemCount();
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index 0147ea4..a45521d 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -16,8 +16,6 @@
package com.android.launcher3.widget;
import android.content.Context;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.Adapter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -25,19 +23,20 @@
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.R;
import com.android.launcher3.WidgetPreviewLoader;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.util.LabelComparator;
-import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Iterator;
import java.util.List;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.Adapter;
+
/**
* List view adapter for the widget tray.
*
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
index 124058e..641183a 100644
--- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -18,9 +18,6 @@
import android.content.Context;
import android.graphics.Point;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.OnItemTouchListener;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -28,6 +25,10 @@
import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.R;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
+
/**
* The widgets recycler view.
*/
diff --git a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
index 8f269a6..d26edb6 100644
--- a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
+++ b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
@@ -15,12 +15,13 @@
*/
package com.android.launcher3.widget;
-import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.ViewGroup;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
+import androidx.recyclerview.widget.RecyclerView.ViewHolder;
+
public class WidgetsRowViewHolder extends ViewHolder {
public final ViewGroup cellContainer;
diff --git a/src_flags/com/android/launcher3/config/FeatureFlags.java b/src_flags/com/android/launcher3/config/FeatureFlags.java
index 3ffb6c9..73c6996 100644
--- a/src_flags/com/android/launcher3/config/FeatureFlags.java
+++ b/src_flags/com/android/launcher3/config/FeatureFlags.java
@@ -16,10 +16,13 @@
package com.android.launcher3.config;
+import android.content.Context;
+
/**
* Defines a set of flags used to control various launcher behaviors
*/
public final class FeatureFlags extends BaseFlags {
-
- private FeatureFlags() {}
+ private FeatureFlags() {
+ // Prevent instantiation
+ }
}
diff --git a/src_plugins/README.md b/src_plugins/README.md
new file mode 100644
index 0000000..c7ce1da
--- /dev/null
+++ b/src_plugins/README.md
@@ -0,0 +1,3 @@
+This directory contains plugin interfaces that launcher listens for and plugins implement. In other words, these are the hooks that specify what plugins launcher currently supports.
+
+Details about how to create a new plugin interface, or to use existing interfaces to write a plugin can be found at go/gnl/plugins.
diff --git a/src_plugins/com/android/systemui/plugins/AllAppsRow.java b/src_plugins/com/android/systemui/plugins/AllAppsRow.java
new file mode 100644
index 0000000..c003fc1
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/AllAppsRow.java
@@ -0,0 +1,51 @@
+/*
+ * 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.systemui.plugins;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Implement this plugin interface to add a row of views to the top of the all apps drawer.
+ */
+@ProvidesInterface(action = AllAppsRow.ACTION, version = AllAppsRow.VERSION)
+public interface AllAppsRow extends Plugin {
+ String ACTION = "com.android.systemui.action.PLUGIN_ALL_APPS_ACTIONS";
+ int VERSION = 1;
+
+ /**
+ * Setup the row and return the parent view.
+ * @param parent The ViewGroup to which launcher will add this row.
+ */
+ View setup(ViewGroup parent);
+
+ /**
+ * @return The height to reserve in all apps for your views.
+ */
+ int getExpectedHeight();
+
+ /**
+ * Update launcher whenever {@link #getExpectedHeight()} changes.
+ */
+ void setOnHeightUpdatedListener(OnHeightUpdatedListener onHeightUpdatedListener);
+
+ interface OnHeightUpdatedListener {
+ void onHeightUpdated();
+ }
+}
diff --git a/src_plugins/com/android/systemui/plugins/FirstScreenWidget.java b/src_plugins/com/android/systemui/plugins/FirstScreenWidget.java
new file mode 100644
index 0000000..8d7dd4b
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/FirstScreenWidget.java
@@ -0,0 +1,15 @@
+package com.android.systemui.plugins;
+
+import android.view.ViewGroup;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Implement this interface to wrap the widget on the first home screen, e.g. to add new content.
+ */
+@ProvidesInterface(action = FirstScreenWidget.ACTION, version = FirstScreenWidget.VERSION)
+public interface FirstScreenWidget extends Plugin {
+ String ACTION = "com.android.systemui.action.PLUGIN_FIRST_SCREEN_WIDGET";
+ int VERSION = 1;
+
+ void onWidgetUpdated(ViewGroup widgetView);
+}
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/LoaderResults.java b/src_shortcuts_overrides/com/android/launcher3/model/LoaderResults.java
new file mode 100644
index 0000000..9785887
--- /dev/null
+++ b/src_shortcuts_overrides/com/android/launcher3/model/LoaderResults.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 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 com.android.launcher3.AllAppsList;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.Callbacks;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.widget.WidgetListRowEntry;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Helper class to handle results of {@link com.android.launcher3.model.LoaderTask}.
+ */
+public class LoaderResults extends BaseLoaderResults {
+
+ public LoaderResults(LauncherAppState app, BgDataModel dataModel,
+ AllAppsList allAppsList, int pageToBindFirst, WeakReference<Callbacks> callbacks) {
+ super(app, dataModel, allAppsList, pageToBindFirst, callbacks);
+ }
+
+ @Override
+ public void bindDeepShortcuts() {
+ final HashMap<ComponentKey, Integer> shortcutMapCopy;
+ synchronized (mBgDataModel) {
+ shortcutMapCopy = new HashMap<>(mBgDataModel.deepShortcutMap);
+ }
+ mUiExecutor.execute(() -> {
+ Callbacks callbacks = mCallbacks.get();
+ if (callbacks != null) {
+ callbacks.bindDeepShortcutMap(shortcutMapCopy);
+ }
+ });
+ }
+
+ @Override
+ public void bindWidgets() {
+ final ArrayList<WidgetListRowEntry> widgets =
+ mBgDataModel.widgetsModel.getWidgetsList(mApp.getContext());
+ Runnable r = new Runnable() {
+ public void run() {
+ Callbacks callbacks = mCallbacks.get();
+ if (callbacks != null) {
+ callbacks.bindAllWidgets(widgets);
+ }
+ }
+ };
+ mUiExecutor.execute(r);
+ }
+}
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
similarity index 80%
rename from src/com/android/launcher3/model/WidgetsModel.java
rename to src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index 9f8f263..9a17ec6 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -8,11 +8,11 @@
import android.content.pm.PackageManager;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import android.util.Log;
import com.android.launcher3.AppFilter;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.icons.ComponentWithLabel;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
@@ -32,7 +32,12 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import androidx.annotation.Nullable;
/**
* Widgets data model that is used by the adapters of the widget views and controllers.
@@ -75,26 +80,32 @@
* @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise
* only widgets and shortcuts associated with the package/user are.
*/
- public void update(LauncherAppState app, @Nullable PackageUserKey packageUser) {
+ public List<ComponentWithLabel> update(LauncherAppState app, @Nullable PackageUserKey packageUser) {
Preconditions.assertWorkerThread();
Context context = app.getContext();
final ArrayList<WidgetItem> widgetsAndShortcuts = new ArrayList<>();
+ List<ComponentWithLabel> updatedItems = new ArrayList<>();
try {
- PackageManager pm = context.getPackageManager();
InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
+ PackageManager pm = app.getContext().getPackageManager();
// Widgets
AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(context);
for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders(packageUser)) {
- widgetsAndShortcuts.add(new WidgetItem(LauncherAppWidgetProviderInfo
- .fromProviderInfo(context, widgetInfo), pm, idp));
+ LauncherAppWidgetProviderInfo launcherWidgetInfo =
+ LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo);
+
+ widgetsAndShortcuts.add(new WidgetItem(
+ launcherWidgetInfo, idp, app.getIconCache()));
+ updatedItems.add(launcherWidgetInfo);
}
// Shortcuts
for (ShortcutConfigActivityInfo info : LauncherAppsCompat.getInstance(context)
.getCustomShortcutActivityList(packageUser)) {
- widgetsAndShortcuts.add(new WidgetItem(info));
+ widgetsAndShortcuts.add(new WidgetItem(info, app.getIconCache(), pm));
+ updatedItems.add(info);
}
setWidgetsAndShortcuts(widgetsAndShortcuts, app, packageUser);
} catch (Exception e) {
@@ -109,6 +120,7 @@
}
app.getWidgetCache().removeObsoletePreviews(widgetsAndShortcuts, packageUser);
+ return updatedItems;
}
private synchronized void setWidgetsAndShortcuts(ArrayList<WidgetItem> rawWidgetsShortcuts,
@@ -203,4 +215,26 @@
iconCache.getTitleAndIconForApp(p, true /* userLowResIcon */);
}
}
+
+ public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user,
+ LauncherAppState app) {
+ for (Entry<PackageItemInfo, ArrayList<WidgetItem>> entry : mWidgetsList.entrySet()) {
+ if (packageNames.contains(entry.getKey().packageName)) {
+ ArrayList<WidgetItem> items = entry.getValue();
+ int count = items.size();
+ for (int i = 0; i < count; i++) {
+ WidgetItem item = items.get(i);
+ if (item.user.equals(user)) {
+ if (item.activityInfo != null) {
+ items.set(i, new WidgetItem(item.activityInfo, app.getIconCache(),
+ app.getContext().getPackageManager()));
+ } else {
+ items.set(i, new WidgetItem(item.widgetInfo,
+ app.getInvariantDeviceProfile(), app.getIconCache()));
+ }
+ }
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java
similarity index 98%
rename from src/com/android/launcher3/shortcuts/DeepShortcutManager.java
rename to src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java
index 24e2e2f..e70aac6 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
+++ b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java
@@ -94,10 +94,11 @@
* Gets all the manifest and dynamic shortcuts associated with the given package and user,
* to be displayed in the shortcuts container on long press.
*/
+ @TargetApi(25)
public List<ShortcutInfoCompat> queryForShortcutsContainer(ComponentName activity,
- List<String> ids, UserHandle user) {
+ UserHandle user) {
return query(ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_DYNAMIC,
- activity.getPackageName(), activity, ids, user);
+ activity.getPackageName(), activity, null, user);
}
/**
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/BackgroundAppState.java b/src_ui_overrides/com/android/launcher3/uioverrides/BackgroundAppState.java
new file mode 100644
index 0000000..9133b07
--- /dev/null
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/BackgroundAppState.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+/**
+ * A dummy background app state
+ */
+public class BackgroundAppState extends OverviewState {
+
+ public BackgroundAppState(int id) {
+ super(id);
+ }
+}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java b/src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java
index 2107094..56e3260 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java
@@ -56,7 +56,7 @@
private WallpaperColorInfo(Context context) {
mWallpaperManager = WallpaperManagerCompat.getInstance(context);
mWallpaperManager.addOnColorsChangedListener(this);
- mExtractionType = ColorExtractionAlgorithm.newInstance(context);
+ mExtractionType = new ColorExtractionAlgorithm();
update(mWallpaperManager.getWallpaperColors(FLAG_SYSTEM));
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
index 0444212..5a1f9ca 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
@@ -16,32 +16,26 @@
package com.android.launcher3.uioverrides.dynamicui;
-import android.content.Context;
import android.graphics.Color;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.graphics.ColorUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Range;
-import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.graphics.ColorUtils;
+
/**
* Implementation of tonal color extraction
**/
public class ColorExtractionAlgorithm {
- public static ColorExtractionAlgorithm newInstance(Context context) {
- return Utilities.getOverrideObject(ColorExtractionAlgorithm.class,
- context.getApplicationContext(), R.string.color_extraction_impl_class);
- }
-
private static final String TAG = "Tonal";
// Used for tonal palette fitting
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java
index 5c533ff..0fd0a35 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java
@@ -17,10 +17,11 @@
package com.android.launcher3.uioverrides.dynamicui;
import android.content.Context;
-import android.support.annotation.Nullable;
import com.android.launcher3.Utilities;
+import androidx.annotation.Nullable;
+
public abstract class WallpaperManagerCompat {
private static final Object sInstanceLock = new Object();
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java
index 4a8bbbd..6808859 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java
@@ -18,7 +18,6 @@
import static android.app.WallpaperManager.FLAG_SYSTEM;
import static com.android.launcher3.Utilities.getDevicePrefs;
-import static com.android.launcher3.graphics.ColorExtractor.findDominantColorByHue;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
@@ -42,15 +41,17 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
-import android.support.annotation.Nullable;
import android.util.Log;
import android.util.Pair;
import com.android.launcher3.Utilities;
+import com.android.launcher3.icons.ColorExtractor;
import java.io.IOException;
import java.util.ArrayList;
+import androidx.annotation.Nullable;
+
public class WallpaperManagerCompatVL extends WallpaperManagerCompat {
private static final String TAG = "WMCompatVL";
@@ -169,6 +170,7 @@
private HandlerThread mWorkerThread;
private Handler mWorkerHandler;
+ private ColorExtractor mColorExtractor;
@Override
public void onCreate() {
@@ -176,6 +178,7 @@
mWorkerThread = new HandlerThread("ColorExtractionService");
mWorkerThread.start();
mWorkerHandler = new Handler(mWorkerThread.getLooper());
+ mColorExtractor = new ColorExtractor();
}
@Override
@@ -258,7 +261,8 @@
String value = VERSION_PREFIX + wallpaperId;
if (bitmap != null) {
- int color = findDominantColorByHue(bitmap, MAX_WALLPAPER_EXTRACTION_AREA);
+ int color = mColorExtractor.findDominantColorByHue(bitmap,
+ MAX_WALLPAPER_EXTRACTION_AREA);
value += "," + color;
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java
index 4509e05..f34497d 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java
@@ -21,11 +21,12 @@
import android.app.WallpaperManager.OnColorsChangedListener;
import android.content.Context;
import android.graphics.Color;
-import android.support.annotation.Nullable;
import android.util.Log;
import java.lang.reflect.Method;
+import androidx.annotation.Nullable;
+
@TargetApi(27)
public class WallpaperManagerCompatVOMR1 extends WallpaperManagerCompat {
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
new file mode 100644
index 0000000..e1a35c9
--- /dev/null
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
@@ -0,0 +1,64 @@
+/*
+ * 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 android.content.ComponentName;
+import android.content.Context;
+
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.PluginListener;
+
+import java.util.Collections;
+import java.util.Set;
+
+import androidx.preference.PreferenceDataStore;
+
+public class PluginManagerWrapper {
+
+ public static final MainThreadInitializedObject<PluginManagerWrapper> INSTANCE =
+ new MainThreadInitializedObject<>(PluginManagerWrapper::new);
+
+ private static final String PREFIX_PLUGIN_ENABLED = "PLUGIN_ENABLED_";
+ public static final String PLUGIN_CHANGED = "com.android.systemui.action.PLUGIN_CHANGED";
+
+ private PluginManagerWrapper(Context c) {
+ }
+
+ public void addPluginListener(PluginListener<? extends Plugin> listener, Class<?> pluginClass) {
+ }
+
+ public void addPluginListener(PluginListener<? extends Plugin> listener, Class<?> pluginClass,
+ boolean allowMultiple) {
+ }
+
+ public void removePluginListener(PluginListener<? extends Plugin> listener) { }
+
+ public Set<String> getPluginActions() {
+ return Collections.emptySet();
+ }
+
+ public PreferenceDataStore getPluginEnabler() {
+ return new PreferenceDataStore() { };
+ }
+
+ public static String pluginEnabledKey(ComponentName cn) {
+ return PREFIX_PLUGIN_ENABLED + cn.flattenToString();
+ }
+
+ public static boolean hasPlugins(Context context) {
+ return false;
+ }
+}
diff --git a/tests/Android.mk b/tests/Android.mk
index f6f02fe..a787537 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -14,17 +14,52 @@
#
LOCAL_PATH := $(call my-dir)
+
+#
+# Build rule for Tapl library.
+#
+include $(CLEAR_VARS)
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ androidx.annotation_annotation \
+ androidx.test.runner \
+ androidx.test.rules \
+ androidx.test.uiautomator_uiautomator \
+ libSharedSystemUI
+
+LOCAL_SRC_FILES := $(call all-java-files-under, tapl) \
+ ../quickstep/src/com/android/quickstep/SwipeUpSetting.java \
+ ../src/com/android/launcher3/util/SecureSettingsObserver.java \
+ ../src/com/android/launcher3/TestProtocol.java \
+
+LOCAL_SDK_VERSION := current
+LOCAL_MODULE := ub-launcher-aosp-tapl
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+#
+# Build rule for Launcher3Tests
+#
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ androidx.test.runner \
+ androidx.test.rules \
+ androidx.test.uiautomator_uiautomator \
+ mockito-target-minus-junit4
+
+ifneq (,$(wildcard frameworks/base))
+ LOCAL_PRIVATE_PLATFORM_APIS := true
+ LOCAL_STATIC_JAVA_LIBRARIES += launcher-aosp-tapl
+else
+ LOCAL_SDK_VERSION := 28
+ LOCAL_MIN_SDK_VERSION := 21
+ LOCAL_STATIC_JAVA_LIBRARIES += ub-launcher-aosp-tapl
+endif
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest-common.xml
-LOCAL_SDK_VERSION := 28
-LOCAL_MIN_SDK_VERSION := 21
-
LOCAL_PACKAGE_NAME := Launcher3Tests
LOCAL_INSTRUMENTATION_FOR := Launcher3
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index af8b15c..46b463b 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -18,6 +18,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.launcher3.tests">
+ <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
+
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
@@ -31,7 +33,6 @@
android:resource="@xml/appwidget_no_config" />
</receiver>
-
<receiver
android:name="com.android.launcher3.testcomponent.AppWdigetHidden"
android:label="Hidden widget">
@@ -68,5 +69,33 @@
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
+
+ <provider
+ android:name="com.android.launcher3.testcomponent.TestCommandReceiver"
+ android:authorities="${packageName}.commands"
+ android:exported="true" />
+
+ <activity
+ android:name="com.android.launcher3.testcomponent.TestLauncherActivity"
+ android:launchMode="singleTask"
+ android:clearTaskOnLaunch="true"
+ android:label="Test launcher"
+ android:stateNotNeeded="true"
+ android:theme="@android:style/Theme.DeviceDefault.Light"
+ android:windowSoftInputMode="adjustPan"
+ android:screenOrientation="unspecified"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
+ android:resizeableActivity="true"
+ android:taskAffinity=""
+ android:process=":testLauncherProcess"
+ android:enabled="false">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.HOME" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.MONKEY"/>
+ <category android:name="android.intent.category.LAUNCHER_APP" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 43030ae..0be5f11 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -18,8 +18,8 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.android.launcher3.tests">
- <uses-sdk android:targetSdkVersion="25" android:minSdkVersion="21"/>
- <uses-sdk tools:overrideLibrary="android.support.test.uiautomator.v18"/>
+ <uses-sdk android:targetSdkVersion="25" android:minSdkVersion="21"
+ tools:overrideLibrary="android.support.test.uiautomator.v18"/>
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
@@ -28,7 +28,7 @@
<instrumentation
android:functionalTest="false"
android:handleProfiling="false"
- android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.launcher3" >
</instrumentation>
</manifest>
diff --git a/tests/dummy_app/Android.mk b/tests/dummy_app/Android.mk
new file mode 100644
index 0000000..f4ab582
--- /dev/null
+++ b/tests/dummy_app/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := samples
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := Aardwolf
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/dummy_app/AndroidManifest.xml b/tests/dummy_app/AndroidManifest.xml
new file mode 100644
index 0000000..0546015
--- /dev/null
+++ b/tests/dummy_app/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<!-- Declare the contents of this Android application. The namespace
+ attribute brings in the Android platform namespace, and the package
+ supplies a unique name for the application. When writing your
+ own application, the package name must be changed from "com.example.*"
+ to come from a domain that you own or have control over. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.aardwolf">
+ <uses-sdk android:targetSdkVersion="25" android:minSdkVersion="21"/>
+ <application android:label="Aardwolf">
+ <activity
+ android:name="Activity1"
+ android:icon="@mipmap/ic_launcher1"
+ android:label="Aardwolf">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/dummy_app/res/layout/empty_activity.xml b/tests/dummy_app/res/layout/empty_activity.xml
new file mode 100644
index 0000000..377c56b
--- /dev/null
+++ b/tests/dummy_app/res/layout/empty_activity.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<EditText xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:textSize="18sp"
+ android:autoText="true"
+ android:capitalize="sentences"
+ android:text="Did you enjoy the adaptive icon?" />
+
diff --git a/res/drawable-v26/adaptive_icon_drawable_wrapper.xml b/tests/dummy_app/res/mipmap-anydpi/ic_launcher1.xml
similarity index 73%
copy from res/drawable-v26/adaptive_icon_drawable_wrapper.xml
copy to tests/dummy_app/res/mipmap-anydpi/ic_launcher1.xml
index 2d78b69..37c8c73 100644
--- a/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
+++ b/tests/dummy_app/res/mipmap-anydpi/ic_launcher1.xml
@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2017 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
+ 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,
@@ -15,8 +14,8 @@
limitations under the License.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
- <background android:drawable="@color/legacy_icon_background"/>
+ <background android:drawable="@mipmap/icon_back_1"/>
<foreground>
- <com.android.launcher3.graphics.FixedScaleDrawable />
+ <bitmap android:src="@mipmap/icon_fore_1"/>
</foreground>
</adaptive-icon>
diff --git a/res/drawable-v26/adaptive_icon_drawable_wrapper.xml b/tests/dummy_app/res/mipmap-anydpi/ic_launcher2.xml
similarity index 69%
copy from res/drawable-v26/adaptive_icon_drawable_wrapper.xml
copy to tests/dummy_app/res/mipmap-anydpi/ic_launcher2.xml
index 2d78b69..20b2986 100644
--- a/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
+++ b/tests/dummy_app/res/mipmap-anydpi/ic_launcher2.xml
@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2017 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
+ 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,
@@ -15,8 +14,6 @@
limitations under the License.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
- <background android:drawable="@color/legacy_icon_background"/>
- <foreground>
- <com.android.launcher3.graphics.FixedScaleDrawable />
- </foreground>
+ <background android:drawable="@color/background" />
+ <foreground android:drawable="@mipmap/icon_fore_1"/>
</adaptive-icon>
diff --git a/tests/dummy_app/res/mipmap-xxhdpi/ic_launcher1.png b/tests/dummy_app/res/mipmap-xxhdpi/ic_launcher1.png
new file mode 100644
index 0000000..73bc8e6
--- /dev/null
+++ b/tests/dummy_app/res/mipmap-xxhdpi/ic_launcher1.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxhdpi/ic_launcher2.png b/tests/dummy_app/res/mipmap-xxhdpi/ic_launcher2.png
new file mode 100644
index 0000000..cd40b63
--- /dev/null
+++ b/tests/dummy_app/res/mipmap-xxhdpi/ic_launcher2.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxhdpi/icon_back_1.png b/tests/dummy_app/res/mipmap-xxhdpi/icon_back_1.png
new file mode 100644
index 0000000..8debef3
--- /dev/null
+++ b/tests/dummy_app/res/mipmap-xxhdpi/icon_back_1.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxhdpi/icon_fore_1.png b/tests/dummy_app/res/mipmap-xxhdpi/icon_fore_1.png
new file mode 100644
index 0000000..de4079b
--- /dev/null
+++ b/tests/dummy_app/res/mipmap-xxhdpi/icon_fore_1.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxxhdpi/ic_launcher1.png b/tests/dummy_app/res/mipmap-xxxhdpi/ic_launcher1.png
new file mode 100644
index 0000000..889a99c
--- /dev/null
+++ b/tests/dummy_app/res/mipmap-xxxhdpi/ic_launcher1.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxxhdpi/ic_launcher2.png b/tests/dummy_app/res/mipmap-xxxhdpi/ic_launcher2.png
new file mode 100644
index 0000000..973bb79
--- /dev/null
+++ b/tests/dummy_app/res/mipmap-xxxhdpi/ic_launcher2.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxxhdpi/icon_back_1.png b/tests/dummy_app/res/mipmap-xxxhdpi/icon_back_1.png
new file mode 100644
index 0000000..70c0ebd
--- /dev/null
+++ b/tests/dummy_app/res/mipmap-xxxhdpi/icon_back_1.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxxhdpi/icon_fore_1.png b/tests/dummy_app/res/mipmap-xxxhdpi/icon_fore_1.png
new file mode 100644
index 0000000..9d91632
--- /dev/null
+++ b/tests/dummy_app/res/mipmap-xxxhdpi/icon_fore_1.png
Binary files differ
diff --git a/tests/dummy_app/res/values/colors.xml b/tests/dummy_app/res/values/colors.xml
new file mode 100644
index 0000000..b5ce66e
--- /dev/null
+++ b/tests/dummy_app/res/values/colors.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="background">#455A64</color>
+</resources>
\ No newline at end of file
diff --git a/go/src_flags/com/android/launcher3/config/FeatureFlags.java b/tests/dummy_app/src/com/example/android/aardwolf/Activity1.java
similarity index 61%
copy from go/src_flags/com/android/launcher3/config/FeatureFlags.java
copy to tests/dummy_app/src/com/example/android/aardwolf/Activity1.java
index b11bb7c..d4eab15 100644
--- a/go/src_flags/com/android/launcher3/config/FeatureFlags.java
+++ b/tests/dummy_app/src/com/example/android/aardwolf/Activity1.java
@@ -14,16 +14,18 @@
* limitations under the License.
*/
-package com.android.launcher3.config;
+package com.example.android.aardwolf;
-/**
- * Defines a set of flags used to control various launcher behaviors
- */
-public final class FeatureFlags extends BaseFlags {
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
- private FeatureFlags() {}
-
- // Features to control Launcher3Go behavior
- public static final boolean GO_DISABLE_WIDGETS = true;
- public static final boolean LAUNCHER3_SPRING_ICONS = false;
+public class Activity1 extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ View view = getLayoutInflater().inflate(R.layout.empty_activity, null);
+ setContentView(view);
+ }
}
+
diff --git a/tests/res/raw/aardwolf_dummy_app.apk b/tests/res/raw/aardwolf_dummy_app.apk
new file mode 100644
index 0000000..39fb368
--- /dev/null
+++ b/tests/res/raw/aardwolf_dummy_app.apk
Binary files differ
diff --git a/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java b/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
index 846a163..afbedba 100644
--- a/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
+++ b/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
@@ -15,8 +15,13 @@
*/
package com.android.launcher3.allapps.search;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
import android.content.ComponentName;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.AppInfo;
import com.android.launcher3.Utilities;
@@ -24,12 +29,10 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
/**
* Unit tests for {@link DefaultAppSearchAlgorithm}
*/
+@SmallTest
@RunWith(AndroidJUnit4.class)
public class DefaultAppSearchAlgorithmTest {
private static final DefaultAppSearchAlgorithm.StringMatcher MATCHER =
diff --git a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java b/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
index 1d9148b..0903ddc 100644
--- a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
+++ b/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
@@ -25,9 +25,9 @@
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.LauncherProvider;
import com.android.launcher3.LauncherProvider.DatabaseHelper;
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
index dfefa31..ac1be17 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -6,18 +6,19 @@
import android.database.MatrixCursor;
import android.graphics.Bitmap;
import android.os.Process;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.graphics.BitmapInfo;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.util.IntArray;
import org.junit.Before;
import org.junit.Test;
@@ -149,83 +150,83 @@
@Test
public void checkItemPlacement_wrongWorkspaceScreen() {
- ArrayList<Long> workspaceScreens = new ArrayList<>(Arrays.asList(1L, 3L));
+ IntArray workspaceScreens = IntArray.wrap(1, 3);
mIDP.numRows = 4;
mIDP.numColumns = 4;
mIDP.numHotseatIcons = 3;
// Item on unknown screen are not placed
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 4L), workspaceScreens));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 4), workspaceScreens));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 5L), workspaceScreens));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 5), workspaceScreens));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2L), workspaceScreens));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2), workspaceScreens));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1), workspaceScreens));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 3L), workspaceScreens));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 3), workspaceScreens));
}
@Test
public void checkItemPlacement_outsideBounds() {
- ArrayList<Long> workspaceScreens = new ArrayList<>(Arrays.asList(1L, 2L));
+ IntArray workspaceScreens = IntArray.wrap(1, 2);
mIDP.numRows = 4;
mIDP.numColumns = 4;
mIDP.numHotseatIcons = 3;
// Item outside screen bounds are not placed
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(4, 4, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens));
+ newItemInfo(4, 4, 1, 1, CONTAINER_DESKTOP, 1), workspaceScreens));
}
@Test
public void checkItemPlacement_overlappingItems() {
- ArrayList<Long> workspaceScreens = new ArrayList<>(Arrays.asList(1L, 2L));
+ IntArray workspaceScreens = IntArray.wrap(1, 2);
mIDP.numRows = 4;
mIDP.numColumns = 4;
mIDP.numHotseatIcons = 3;
// Overlapping items are not placed
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1), workspaceScreens));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1), workspaceScreens));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2L), workspaceScreens));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2), workspaceScreens));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2L), workspaceScreens));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2), workspaceScreens));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(1, 1, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens));
+ newItemInfo(1, 1, 1, 1, CONTAINER_DESKTOP, 1), workspaceScreens));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(2, 2, 2, 2, CONTAINER_DESKTOP, 1L), workspaceScreens));
+ newItemInfo(2, 2, 2, 2, CONTAINER_DESKTOP, 1), workspaceScreens));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(3, 2, 1, 2, CONTAINER_DESKTOP, 1L), workspaceScreens));
+ newItemInfo(3, 2, 1, 2, CONTAINER_DESKTOP, 1), workspaceScreens));
}
@Test
public void checkItemPlacement_hotseat() {
- ArrayList<Long> workspaceScreens = new ArrayList<>();
+ IntArray workspaceScreens = new IntArray();
mIDP.numRows = 4;
mIDP.numColumns = 4;
mIDP.numHotseatIcons = 3;
// Hotseat items are only placed based on screenId
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 1L), workspaceScreens));
+ newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 1), workspaceScreens));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 2L), workspaceScreens));
+ newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 2), workspaceScreens));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 3L), workspaceScreens));
+ newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 3), workspaceScreens));
}
private ItemInfo newItemInfo(int cellX, int cellY, int spanX, int spanY,
- long container, long screenId) {
+ int container, int screenId) {
ItemInfo info = new ItemInfo();
info.cellX = cellX;
info.cellY = cellY;
diff --git a/tests/src/com/android/launcher3/popup/PopupPopulatorTest.java b/tests/src/com/android/launcher3/popup/PopupPopulatorTest.java
index 9a89b1b..d224c89 100644
--- a/tests/src/com/android/launcher3/popup/PopupPopulatorTest.java
+++ b/tests/src/com/android/launcher3/popup/PopupPopulatorTest.java
@@ -16,8 +16,17 @@
package com.android.launcher3.popup;
+import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
+import static com.android.launcher3.popup.PopupPopulator.NUM_DYNAMIC;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
import android.content.pm.ShortcutInfo;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
@@ -28,15 +37,10 @@
import java.util.Collections;
import java.util.List;
-import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
-import static com.android.launcher3.popup.PopupPopulator.NUM_DYNAMIC;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
/**
* Tests the sorting and filtering of shortcuts in {@link PopupPopulator}.
*/
+@SmallTest
@RunWith(AndroidJUnit4.class)
public class PopupPopulatorTest {
diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index 5d417b5..babb731 100644
--- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -3,9 +3,9 @@
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.LauncherProvider.DatabaseHelper;
import com.android.launcher3.LauncherSettings.Favorites;
diff --git a/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java b/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java
new file mode 100644
index 0000000..0edb3d6
--- /dev/null
+++ b/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java
@@ -0,0 +1,107 @@
+/*
+ * 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.testcomponent;
+
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.DONT_KILL_APP;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+
+import androidx.test.InstrumentationRegistry;
+
+/**
+ * Content provider to receive commands from tests
+ */
+public class TestCommandReceiver extends ContentProvider {
+
+ public static final String ENABLE_TEST_LAUNCHER = "enable-test-launcher";
+ public static final String DISABLE_TEST_LAUNCHER = "disable-test-launcher";
+ public static final String KILL_PROCESS = "kill-process";
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
+ @Override
+ public Bundle call(String method, String arg, Bundle extras) {
+ switch (method) {
+ case ENABLE_TEST_LAUNCHER: {
+ getContext().getPackageManager().setComponentEnabledSetting(
+ new ComponentName(getContext(), TestLauncherActivity.class),
+ COMPONENT_ENABLED_STATE_ENABLED, DONT_KILL_APP);
+ return null;
+ }
+ case DISABLE_TEST_LAUNCHER: {
+ getContext().getPackageManager().setComponentEnabledSetting(
+ new ComponentName(getContext(), TestLauncherActivity.class),
+ COMPONENT_ENABLED_STATE_DISABLED, DONT_KILL_APP);
+ return null;
+ }
+ case KILL_PROCESS: {
+ ((ActivityManager) getContext().getSystemService(Activity.ACTIVITY_SERVICE)).
+ killBackgroundProcesses(arg);
+ return null;
+ }
+ }
+ return super.call(method, arg, extras);
+ }
+
+ public static Bundle callCommand(String command) {
+ return callCommand(command, null);
+ }
+
+ public static Bundle callCommand(String command, String arg) {
+ Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+ Uri uri = Uri.parse("content://" + inst.getContext().getPackageName() + ".commands");
+ return inst.getTargetContext().getContentResolver().call(uri, command, arg, null);
+ }
+}
diff --git a/tests/src/com/android/launcher3/testcomponent/TestLauncherActivity.java b/tests/src/com/android/launcher3/testcomponent/TestLauncherActivity.java
new file mode 100644
index 0000000..357a232
--- /dev/null
+++ b/tests/src/com/android/launcher3/testcomponent/TestLauncherActivity.java
@@ -0,0 +1,34 @@
+/*
+ * 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.testcomponent;
+
+import static android.content.Intent.ACTION_MAIN;
+import static android.content.Intent.CATEGORY_LAUNCHER;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
+
+import android.app.LauncherActivity;
+import android.content.Intent;
+
+public class TestLauncherActivity extends LauncherActivity {
+
+ @Override
+ protected Intent getTargetIntent() {
+ return new Intent(ACTION_MAIN, null)
+ .addCategory(CATEGORY_LAUNCHER)
+ .addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ }
+}
diff --git a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
index ff83131..b600473 100644
--- a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
+++ b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
@@ -15,11 +15,10 @@
*/
package com.android.launcher3.touch;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import android.util.Log;
-import android.view.MotionEvent;
import android.view.ViewConfiguration;
import com.android.launcher3.testcomponent.TouchEventGenerator;
@@ -32,6 +31,7 @@
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -51,25 +51,28 @@
@Mock
private SwipeDetector.Listener mMockListener;
+ @Mock
+ private ViewConfiguration mMockConfig;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mGenerator = new TouchEventGenerator(new TouchEventGenerator.Listener() {
- @Override
- public void onTouchEvent(MotionEvent event) {
- mDetector.onTouchEvent(event);
- }
- });
+ mGenerator = new TouchEventGenerator((ev) -> mDetector.onTouchEvent(ev));
+ ViewConfiguration orgConfig = ViewConfiguration
+ .get(InstrumentationRegistry.getTargetContext());
+ doReturn(orgConfig.getScaledMaximumFlingVelocity()).when(mMockConfig)
+ .getScaledMaximumFlingVelocity();
- mDetector = new SwipeDetector(mTouchSlop, mMockListener, SwipeDetector.VERTICAL);
+ mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.VERTICAL);
mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false);
- mTouchSlop = ViewConfiguration.get(InstrumentationRegistry.getTargetContext())
- .getScaledTouchSlop();
+ mTouchSlop = orgConfig.getScaledTouchSlop();
+ doReturn(mTouchSlop).when(mMockConfig).getScaledTouchSlop();
+
L("mTouchSlop=", mTouchSlop);
}
@Test
- public void testDragStart_vertical() throws Exception {
+ public void testDragStart_vertical() {
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100, 100 + mTouchSlop);
// TODO: actually calculate the following parameters and do exact value checks.
@@ -77,7 +80,7 @@
}
@Test
- public void testDragStart_failed() throws Exception {
+ public void testDragStart_failed() {
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100 + mTouchSlop, 100);
// TODO: actually calculate the following parameters and do exact value checks.
@@ -85,8 +88,8 @@
}
@Test
- public void testDragStart_horizontal() throws Exception {
- mDetector = new SwipeDetector(mTouchSlop, mMockListener, SwipeDetector.HORIZONTAL);
+ public void testDragStart_horizontal() {
+ mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL);
mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false);
mGenerator.put(0, 100, 100);
@@ -96,15 +99,15 @@
}
@Test
- public void testDrag() throws Exception {
+ public void testDrag() {
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100, 100 + mTouchSlop);
// TODO: actually calculate the following parameters and do exact value checks.
- verify(mMockListener).onDrag(anyFloat(), anyFloat());
+ verify(mMockListener).onDrag(anyFloat());
}
@Test
- public void testDragEnd() throws Exception {
+ public void testDragEnd() {
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100, 100 + mTouchSlop);
mGenerator.move(0, 100, 100 + mTouchSlop * 2);
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index f16f514..bc5aaee 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -15,47 +15,57 @@
*/
package com.android.launcher3.ui;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.fail;
+
import android.app.Instrumentation;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.LauncherActivityInfo;
-import android.graphics.Point;
import android.os.Process;
import android.os.RemoteException;
-import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.Direction;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.util.Log;
-import android.view.MotionEvent;
+import android.view.Surface;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.Direction;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.LauncherState;
import com.android.launcher3.MainThreadExecutor;
-import com.android.launcher3.R;
-import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.Utilities;
import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.testcomponent.AppWidgetNoConfig;
-import com.android.launcher3.testcomponent.AppWidgetWithConfig;
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.tapl.TestHelpers;
+import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.LauncherActivityRule;
+import com.android.launcher3.util.rule.ShellCommandRule;
+import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.Statement;
-import java.util.Locale;
+import java.io.IOException;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import java.util.function.Consumer;
+import java.util.function.Function;
/**
* Base class for all instrumentation tests providing various utility methods.
@@ -66,24 +76,91 @@
public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 5;
public static final long SHORT_UI_TIMEOUT= 300;
- public static final long DEFAULT_UI_TIMEOUT = 3000;
- public static final long LARGE_UI_TIMEOUT = 10000;
- public static final long DEFAULT_WORKER_TIMEOUT_SECS = 5;
+ public static final long DEFAULT_UI_TIMEOUT = 10000;
protected MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
- protected UiDevice mDevice;
+ protected final UiDevice mDevice;
+ protected final LauncherInstrumentation mLauncher;
protected Context mTargetContext;
protected String mTargetPackage;
- private static final String TAG = "AbstractLauncherUiTest";
+ protected AbstractLauncherUiTest() {
+ final Instrumentation instrumentation = getInstrumentation();
+ mDevice = UiDevice.getInstance(instrumentation);
+ try {
+ mDevice.setOrientationNatural();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ if (TestHelpers.isInLauncherProcess()) Utilities.enableRunningInTestHarnessForTests();
+ mLauncher = new LauncherInstrumentation(instrumentation);
+ }
+
+ @Rule
+ public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
+
+ @Rule public ShellCommandRule mDefaultLauncherRule =
+ TestHelpers.isInLauncherProcess() ? ShellCommandRule.setDefaultLauncher() : null;
+
+ @Rule public ShellCommandRule mDisableHeadsUpNotification =
+ ShellCommandRule.disableHeadsUpNotification();
+
+ // Annotation for tests that need to be run in portrait and landscape modes.
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ protected @interface PortraitLandscape {
+ }
+
+ @Rule
+ public TestRule mPortraitLandscapeExecutor =
+ (base, description) -> false && description.getAnnotation(PortraitLandscape.class)
+ != null ? new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ // Create launcher activity if necessary and bring it to the front.
+ mDevice.pressHome();
+ waitForLauncherCondition("Launcher activity wasn't created",
+ launcher -> launcher != null);
+
+ executeOnLauncher(launcher ->
+ launcher.getRotationHelper().forceAllowRotationForTesting(true));
+
+ evaluateInPortrait();
+ evaluateInLandscape();
+ } finally {
+ mDevice.setOrientationNatural();
+ executeOnLauncher(launcher ->
+ launcher.getRotationHelper().forceAllowRotationForTesting(false));
+ mLauncher.setExpectedRotation(Surface.ROTATION_0);
+ }
+ }
+
+ private void evaluateInPortrait() throws Throwable {
+ mDevice.setOrientationNatural();
+ mLauncher.setExpectedRotation(Surface.ROTATION_0);
+ base.evaluate();
+ }
+
+ private void evaluateInLandscape() throws Throwable {
+ mDevice.setOrientationLeft();
+ mLauncher.setExpectedRotation(Surface.ROTATION_90);
+ base.evaluate();
+ }
+ } : base;
@Before
public void setUp() throws Exception {
- mDevice = UiDevice.getInstance(getInstrumentation());
mTargetContext = InstrumentationRegistry.getTargetContext();
mTargetPackage = mTargetContext.getPackageName();
}
+ @After
+ public void tearDown() throws Exception {
+ // Limits UI tests affecting tests running after them.
+ waitForModelLoaded();
+ }
+
protected void lockRotation(boolean naturalOrientation) throws RemoteException {
if (naturalOrientation) {
mDevice.setOrientationNatural();
@@ -92,39 +169,14 @@
}
}
- protected Instrumentation getInstrumentation() {
- return InstrumentationRegistry.getInstrumentation();
- }
-
- /**
- * Opens all apps and returns the recycler view
- */
- protected UiObject2 openAllApps() {
- mDevice.waitForIdle();
- if (FeatureFlags.NO_ALL_APPS_ICON) {
- UiObject2 hotseat = mDevice.wait(
- Until.findObject(getSelectorForId(R.id.hotseat)), 2500);
- Point start = hotseat.getVisibleCenter();
- int endY = (int) (mDevice.getDisplayHeight() * 0.1f);
- // 100 px/step
- mDevice.swipe(start.x, start.y, start.x, endY, (start.y - endY) / 100);
-
+ protected void clearLauncherData() throws IOException {
+ if (TestHelpers.isInLauncherProcess()) {
+ LauncherSettings.Settings.call(mTargetContext.getContentResolver(),
+ LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
+ resetLoaderState();
} else {
- mDevice.wait(Until.findObject(
- By.desc(mTargetContext.getString(R.string.all_apps_button_label))),
- DEFAULT_UI_TIMEOUT).click();
+ mDevice.executeShellCommand("pm clear " + mDevice.getLauncherPackageName());
}
- return findViewById(R.id.apps_list_view);
- }
-
- /**
- * Opens widget tray and returns the recycler view.
- */
- protected UiObject2 openWidgetsTray() {
- mDevice.pressMenu(); // Enter overview mode.
- mDevice.wait(Until.findObject(
- By.text(mTargetContext.getString(R.string.widget_button_text))), DEFAULT_UI_TIMEOUT).click();
- return findViewById(R.id.widgets_list_view);
}
/**
@@ -132,82 +184,20 @@
* @return the matching object.
*/
protected UiObject2 scrollAndFind(UiObject2 container, BySelector condition) {
- do {
+ container.setGestureMargins(0, 0, 0, 200);
+
+ int i = 0;
+ for (; ; ) {
// findObject can only execute after spring settles.
mDevice.wait(Until.findObject(condition), SHORT_UI_TIMEOUT);
UiObject2 widget = container.findObject(condition);
- if (widget != null) {
+ if (widget != null && widget.getVisibleBounds().intersects(
+ 0, 0, mDevice.getDisplayWidth(), mDevice.getDisplayHeight() - 200)) {
return widget;
}
- } while (container.scroll(Direction.DOWN, 1f));
- return container.findObject(condition);
- }
-
- /**
- * Drags an icon to the center of homescreen.
- * @param icon object that is either app icon or shortcut icon
- */
- protected void dragToWorkspace(UiObject2 icon, boolean expectedToShowShortcuts) {
- Point center = icon.getVisibleCenter();
-
- // Action Down
- sendPointer(MotionEvent.ACTION_DOWN, center);
-
- UiObject2 dragLayer = findViewById(R.id.drag_layer);
-
- if (expectedToShowShortcuts) {
- // Make sure shortcuts show up, and then move a bit to hide them.
- assertNotNull(findViewById(R.id.deep_shortcuts_container));
-
- Point moveLocation = new Point(center);
- int distanceToMove = mTargetContext.getResources().getDimensionPixelSize(
- R.dimen.deep_shortcuts_start_drag_threshold) + 50;
- if (moveLocation.y - distanceToMove >= dragLayer.getVisibleBounds().top) {
- moveLocation.y -= distanceToMove;
- } else {
- moveLocation.y += distanceToMove;
- }
- movePointer(center, moveLocation);
-
- assertNull(findViewById(R.id.deep_shortcuts_container));
+ if (++i > 40) fail("Too many attempts");
+ container.scroll(Direction.DOWN, 1f);
}
-
- // Wait until Remove/Delete target is visible
- assertNotNull(findViewById(R.id.delete_target_text));
-
- Point moveLocation = dragLayer.getVisibleCenter();
-
- // Move to center
- movePointer(center, moveLocation);
- sendPointer(MotionEvent.ACTION_UP, center);
-
- // Wait until remove target is gone.
- mDevice.wait(Until.gone(getSelectorForId(R.id.delete_target_text)), DEFAULT_UI_TIMEOUT);
- }
-
- private void movePointer(Point from, Point to) {
- while(!from.equals(to)) {
- from.x = getNextMoveValue(to.x, from.x);
- from.y = getNextMoveValue(to.y, from.y);
- sendPointer(MotionEvent.ACTION_MOVE, from);
- }
- }
-
- private int getNextMoveValue(int targetValue, int oldValue) {
- if (targetValue - oldValue > 10) {
- return oldValue + 10;
- } else if (targetValue - oldValue < -10) {
- return oldValue - 10;
- } else {
- return targetValue;
- }
- }
-
- protected void sendPointer(int action, Point point) {
- MotionEvent event = MotionEvent.obtain(SystemClock.uptimeMillis(),
- SystemClock.uptimeMillis(), action, point.x, point.y, 0);
- getInstrumentation().sendPointerSync(event);
- event.recycle();
}
/**
@@ -222,6 +212,11 @@
}
protected void resetLoaderState() {
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ "START " + android.util.Log.getStackTraceString(new Throwable()));
+ }
try {
mMainThreadExecutor.execute(new Runnable() {
@Override
@@ -232,6 +227,19 @@
} catch (Throwable t) {
throw new IllegalArgumentException(t);
}
+ waitForModelLoaded();
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ "FINISH " + android.util.Log.getStackTraceString(new Throwable()));
+ }
+ }
+
+ protected void waitForModelLoaded() {
+ waitForLauncherCondition("Launcher model didn't load", launcher -> {
+ final LauncherModel model = LauncherAppState.getInstance(mTargetContext).getModel();
+ return model.getCallback() == null || model.isModelLoaded();
+ });
}
/**
@@ -245,35 +253,41 @@
}
}
- /**
- * Finds a widget provider which can fit on the home screen.
- * @param hasConfigureScreen if true, a provider with a config screen is returned.
- */
- protected LauncherAppWidgetProviderInfo findWidgetProvider(final boolean hasConfigureScreen) {
- LauncherAppWidgetProviderInfo info =
- getOnUiThread(new Callable<LauncherAppWidgetProviderInfo>() {
- @Override
- public LauncherAppWidgetProviderInfo call() throws Exception {
- ComponentName cn = new ComponentName(getInstrumentation().getContext(),
- hasConfigureScreen ? AppWidgetWithConfig.class : AppWidgetNoConfig.class);
- Log.d(TAG, "findWidgetProvider componentName=" + cn.flattenToString());
- return AppWidgetManagerCompat.getInstance(mTargetContext)
- .findProvider(cn, Process.myUserHandle());
- }
+ protected <T> T getFromLauncher(Function<Launcher, T> f) {
+ if (!TestHelpers.isInLauncherProcess()) return null;
+ return getOnUiThread(() -> f.apply(mActivityMonitor.getActivity()));
+ }
+
+ protected void executeOnLauncher(Consumer<Launcher> f) {
+ getFromLauncher(launcher -> {
+ f.accept(launcher);
+ return null;
});
- if (info == null) {
- throw new IllegalArgumentException("No valid widget provider");
- }
- return info;
}
- protected UiObject2 findViewById(int id) {
- return mDevice.wait(Until.findObject(getSelectorForId(id)), DEFAULT_UI_TIMEOUT);
+ // Cannot be used in TaplTests between a Tapl call injecting a gesture and a tapl call expecting
+ // the results of that gesture because the wait can hide flakeness.
+ protected void waitForState(String message, LauncherState state) {
+ waitForLauncherCondition(message,
+ launcher -> launcher.getStateManager().getState() == state);
}
- protected BySelector getSelectorForId(int id) {
- String name = mTargetContext.getResources().getResourceEntryName(id);
- return By.res(mTargetPackage, name);
+ protected void waitForResumed(String message) {
+ waitForLauncherCondition(message, launcher -> launcher.hasBeenResumed());
+ }
+
+ // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
+ // flakiness.
+ protected void waitForLauncherCondition(String message, Function<Launcher, Boolean> condition) {
+ waitForLauncherCondition(message, condition, DEFAULT_ACTIVITY_TIMEOUT);
+ }
+
+ // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
+ // flakiness.
+ protected void waitForLauncherCondition(
+ String message, Function<Launcher, Boolean> condition, long timeout) {
+ if (!TestHelpers.isInLauncherProcess()) return;
+ Wait.atMost(message, () -> getFromLauncher(condition), timeout);
}
protected LauncherActivityInfo getSettingsApp() {
@@ -282,11 +296,6 @@
Process.myUserHandle()).get(0);
}
- protected LauncherActivityInfo getChromeApp() {
- return LauncherAppsCompat.getInstance(mTargetContext)
- .getActivityList("com.android.chrome", Process.myUserHandle()).get(0);
- }
-
/**
* Broadcast receiver which blocks until the result is received.
*/
diff --git a/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java b/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
deleted file mode 100644
index b95a850..0000000
--- a/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.android.launcher3.ui;
-
-import android.content.pm.LauncherActivityInfo;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-
-import com.android.launcher3.util.Condition;
-import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.assertTrue;
-
-/**
- * Test for verifying apps is launched from all-apps
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class AllAppsAppLaunchTest extends AbstractLauncherUiTest {
-
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
-
- @Test
- public void testAppLauncher_portrait() throws Exception {
- lockRotation(true);
- performTest();
- }
-
- @Test
- public void testAppLauncher_landscape() throws Exception {
- lockRotation(false);
- performTest();
- }
-
- private void performTest() throws Exception {
- mActivityMonitor.startLauncher();
-
- LauncherActivityInfo testApp = getChromeApp();
-
- // Open all apps and wait for load complete
- final UiObject2 appsContainer = openAllApps();
- assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
-
- // Open app and verify app launched
- scrollAndFind(appsContainer, By.text(testApp.getLabel().toString())).click();
- assertTrue(mDevice.wait(Until.hasObject(By.pkg(
- testApp.getComponentName().getPackageName()).depth(0)), DEFAULT_UI_TIMEOUT));
- }
-}
diff --git a/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
index 00f30ad..9354862 100644
--- a/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
+++ b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
@@ -1,23 +1,13 @@
package com.android.launcher3.ui;
import android.content.pm.LauncherActivityInfo;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import com.android.launcher3.util.Condition;
-import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
-import com.android.launcher3.util.rule.ShellCommandRule;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertTrue;
-
/**
* Test for dragging an icon from all-apps to homescreen.
*/
@@ -25,38 +15,24 @@
@RunWith(AndroidJUnit4.class)
public class AllAppsIconToHomeTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
- @Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
-
@Test
- public void testDragIcon_portrait() throws Throwable {
- lockRotation(true);
- performTest();
- }
-
- @Test
- public void testDragIcon_landscape() throws Throwable {
- lockRotation(false);
- performTest();
- }
-
- private void performTest() throws Throwable {
+ @PortraitLandscape
+ public void testDragIcon() throws Throwable {
LauncherActivityInfo settingsApp = getSettingsApp();
clearHomescreen();
- mActivityMonitor.startLauncher();
+ mDevice.pressHome();
+ mDevice.waitForIdle();
- // Open all apps and wait for load complete.
- final UiObject2 appsContainer = openAllApps();
- assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
-
- // Drag icon to homescreen.
- UiObject2 icon = scrollAndFind(appsContainer, By.text(settingsApp.getLabel().toString()));
- dragToWorkspace(icon, true);
-
- // Verify that the icon works on homescreen.
- mDevice.findObject(By.text(settingsApp.getLabel().toString())).click();
- assertTrue(mDevice.wait(Until.hasObject(By.pkg(
- settingsApp.getComponentName().getPackageName()).depth(0)), DEFAULT_UI_TIMEOUT));
+ final String appName = settingsApp.getLabel().toString();
+ // 1. Open all apps and wait for load complete.
+ // 2. Drag icon to homescreen.
+ // 3. Verify that the icon works on homescreen.
+ mLauncher.getWorkspace().
+ switchToAllApps().
+ getAppIcon(appName).
+ dragToWorkspace().
+ getWorkspaceAppIcon(appName).
+ launch(settingsApp.getComponentName().getPackageName());
}
}
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
index 69f6c87..1fea4d5 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
@@ -1,27 +1,21 @@
package com.android.launcher3.ui;
+import static org.junit.Assert.assertTrue;
+
import android.content.pm.LauncherActivityInfo;
-import android.graphics.Point;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.view.MotionEvent;
-import com.android.launcher3.R;
-import com.android.launcher3.util.Condition;
-import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
-import com.android.launcher3.util.rule.ShellCommandRule;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
-import org.junit.Rule;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.popup.ArrowPopup;
+import com.android.launcher3.tapl.AppIconMenu;
+import com.android.launcher3.tapl.AppIconMenuItem;
+import com.android.launcher3.views.OptionsPopupView;
+
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
/**
* Test for verifying that shortcuts are shown and can be launched after long pressing an app
*/
@@ -29,48 +23,30 @@
@RunWith(AndroidJUnit4.class)
public class ShortcutsLaunchTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
- @Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
-
- @Test
- public void testAppLauncher_portrait() throws Exception {
- lockRotation(true);
- performTest();
+ private boolean isOptionsPopupVisible(Launcher launcher) {
+ final ArrowPopup popup = OptionsPopupView.getOptionsPopup(launcher);
+ return popup != null && popup.isShown();
}
@Test
- public void testAppLauncher_landscape() throws Exception {
- lockRotation(false);
- performTest();
- }
-
- private void performTest() throws Exception {
+ @PortraitLandscape
+ public void testAppLauncher() throws Exception {
mActivityMonitor.startLauncher();
- LauncherActivityInfo testApp = getSettingsApp();
+ final LauncherActivityInfo testApp = getSettingsApp();
- // Open all apps and wait for load complete
- final UiObject2 appsContainer = openAllApps();
- assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2),
- DEFAULT_UI_TIMEOUT));
+ final AppIconMenu menu = mLauncher.
+ pressHome().
+ switchToAllApps().
+ getAppIcon(testApp.getLabel().toString()).
+ openMenu();
- // Find settings app and verify shortcuts appear when long pressed
- UiObject2 icon = scrollAndFind(appsContainer, By.text(testApp.getLabel().toString()));
- // Press icon center until shortcuts appear
- Point iconCenter = icon.getVisibleCenter();
- sendPointer(MotionEvent.ACTION_DOWN, iconCenter);
- UiObject2 deepShortcutsContainer = findViewById(R.id.deep_shortcuts_container);
- assertNotNull(deepShortcutsContainer);
- sendPointer(MotionEvent.ACTION_UP, iconCenter);
+ executeOnLauncher(
+ launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu",
+ isOptionsPopupVisible(launcher)));
- // Verify that launching a shortcut opens a page with the same text
- assertTrue(deepShortcutsContainer.getChildCount() > 0);
+ final AppIconMenuItem menuItem = menu.getMenuItem(1);
+ final String itemName = menuItem.getText();
- // Pick second children as it starts showing shortcuts.
- UiObject2 shortcut = deepShortcutsContainer.getChildren().get(1)
- .findObject(getSelectorForId(R.id.bubble_text));
- shortcut.click();
- assertTrue(mDevice.wait(Until.hasObject(By.pkg(
- testApp.getComponentName().getPackageName())
- .text(shortcut.getText())), DEFAULT_UI_TIMEOUT));
+ menuItem.launch(testApp.getComponentName().getPackageName(), itemName);
}
}
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
index fad06a6..4c2c959 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
@@ -1,27 +1,15 @@
package com.android.launcher3.ui;
import android.content.pm.LauncherActivityInfo;
-import android.graphics.Point;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.view.MotionEvent;
-import com.android.launcher3.R;
-import com.android.launcher3.util.Condition;
-import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
-import com.android.launcher3.util.rule.ShellCommandRule;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
-import org.junit.Rule;
+import com.android.launcher3.tapl.AppIconMenuItem;
+
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
/**
* Test for dragging a deep shortcut to the home screen.
*/
@@ -29,53 +17,31 @@
@RunWith(AndroidJUnit4.class)
public class ShortcutsToHomeTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
- @Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
-
@Test
- public void testDragIcon_portrait() throws Throwable {
- lockRotation(true);
- performTest();
- }
-
- @Test
- public void testDragIcon_landscape() throws Throwable {
- lockRotation(false);
- performTest();
- }
-
- private void performTest() throws Throwable {
+ @PortraitLandscape
+ public void testDragIcon() throws Throwable {
clearHomescreen();
mActivityMonitor.startLauncher();
- LauncherActivityInfo testApp = getSettingsApp();
+ LauncherActivityInfo testApp = getSettingsApp();
- // Open all apps and wait for load complete.
- final UiObject2 appsContainer = openAllApps();
- assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2),
- DEFAULT_UI_TIMEOUT));
+ // 1. Open all apps and wait for load complete.
+ // 2. Find the app and long press it to show shortcuts.
+ // 3. Press icon center until shortcuts appear
+ final AppIconMenuItem menuItem = mLauncher.
+ getWorkspace().
+ switchToAllApps().
+ getAppIcon(testApp.getLabel().toString()).
+ openMenu().
+ getMenuItem(0);
+ final String shortcutName = menuItem.getText();
- // Find the app and long press it to show shortcuts.
- UiObject2 icon = scrollAndFind(appsContainer, By.text(testApp.getLabel().toString()));
- // Press icon center until shortcuts appear
- Point iconCenter = icon.getVisibleCenter();
- sendPointer(MotionEvent.ACTION_DOWN, iconCenter);
- UiObject2 deepShortcutsContainer = findViewById(R.id.deep_shortcuts_container);
- assertNotNull(deepShortcutsContainer);
- sendPointer(MotionEvent.ACTION_UP, iconCenter);
-
- // Drag the first shortcut to the home screen.
- assertTrue(deepShortcutsContainer.getChildCount() > 0);
- UiObject2 shortcut = deepShortcutsContainer.getChildren().get(1)
- .findObject(getSelectorForId(R.id.bubble_text));
- String shortcutName = shortcut.getText();
- dragToWorkspace(shortcut, false);
-
- // Verify that the shortcut works on home screen
- // (the app opens and has the same text as the shortcut).
- mDevice.findObject(By.text(shortcutName)).click();
- assertTrue(mDevice.wait(Until.hasObject(By.pkg(
- testApp.getComponentName().getPackageName())
- .text(shortcutName)), DEFAULT_UI_TIMEOUT));
+ // 4. Drag the first shortcut to the home screen.
+ // 5. Verify that the shortcut works on home screen
+ // (the app opens and has the same text as the shortcut).
+ menuItem.
+ dragToWorkspace().
+ getWorkspaceAppIcon(shortcutName).
+ launch(testApp.getComponentName().getPackageName(), shortcutName);
}
}
diff --git a/tests/src/com/android/launcher3/ui/TestViewHelpers.java b/tests/src/com/android/launcher3/ui/TestViewHelpers.java
new file mode 100644
index 0000000..6fa28f1
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/TestViewHelpers.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.android.launcher3.ui;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static androidx.test.InstrumentationRegistry.getTargetContext;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.Point;
+import android.os.Process;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.testcomponent.AppWidgetNoConfig;
+import com.android.launcher3.testcomponent.AppWidgetWithConfig;
+
+import java.util.concurrent.Callable;
+import java.util.function.Function;
+
+public class TestViewHelpers {
+ private static final String TAG = "TestViewHelpers";
+
+ private static UiDevice getDevice() {
+ return UiDevice.getInstance(getInstrumentation());
+ }
+
+ /**
+ * Opens all apps and returns the recycler view
+ */
+ public static UiObject2 openAllApps() {
+ final UiDevice device = getDevice();
+ device.waitForIdle();
+ UiObject2 hotseat = device.wait(
+ Until.findObject(getSelectorForId(R.id.hotseat)), 2500);
+ Point start = hotseat.getVisibleCenter();
+ int endY = (int) (device.getDisplayHeight() * 0.1f);
+ // 100 px/step
+ device.swipe(start.x, start.y, start.x, endY, (start.y - endY) / 100);
+ return findViewById(R.id.apps_list_view);
+ }
+
+ public static UiObject2 findViewById(int id) {
+ return getDevice().wait(Until.findObject(getSelectorForId(id)),
+ AbstractLauncherUiTest.DEFAULT_UI_TIMEOUT);
+ }
+
+ public static BySelector getSelectorForId(int id) {
+ final Context targetContext = getTargetContext();
+ String name = targetContext.getResources().getResourceEntryName(id);
+ return By.res(targetContext.getPackageName(), name);
+ }
+
+ /**
+ * Finds a widget provider which can fit on the home screen.
+ *
+ * @param test test suite.
+ * @param hasConfigureScreen if true, a provider with a config screen is returned.
+ */
+ public static LauncherAppWidgetProviderInfo findWidgetProvider(AbstractLauncherUiTest test,
+ final boolean hasConfigureScreen) {
+ LauncherAppWidgetProviderInfo info =
+ test.getOnUiThread(new Callable<LauncherAppWidgetProviderInfo>() {
+ @Override
+ public LauncherAppWidgetProviderInfo call() throws Exception {
+ ComponentName cn = new ComponentName(getInstrumentation().getContext(),
+ hasConfigureScreen ? AppWidgetWithConfig.class
+ : AppWidgetNoConfig.class);
+ Log.d(TAG, "findWidgetProvider componentName=" + cn.flattenToString());
+ return AppWidgetManagerCompat.getInstance(getTargetContext())
+ .findProvider(cn, Process.myUserHandle());
+ }
+ });
+ if (info == null) {
+ throw new IllegalArgumentException("No valid widget provider");
+ }
+ return info;
+ }
+
+ /**
+ * Drags an icon to the center of homescreen.
+ *
+ * @param icon object that is either app icon or shortcut icon
+ */
+ public static void dragToWorkspace(UiObject2 icon, boolean expectedToShowShortcuts) {
+ Point center = icon.getVisibleCenter();
+
+ // Action Down
+ sendPointer(MotionEvent.ACTION_DOWN, center);
+
+ UiObject2 dragLayer = findViewById(R.id.drag_layer);
+
+ if (expectedToShowShortcuts) {
+ // Make sure shortcuts show up, and then move a bit to hide them.
+ assertNotNull(findViewById(R.id.deep_shortcuts_container));
+
+ Point moveLocation = new Point(center);
+ int distanceToMove =
+ getTargetContext().getResources().getDimensionPixelSize(
+ R.dimen.deep_shortcuts_start_drag_threshold) + 50;
+ if (moveLocation.y - distanceToMove >= dragLayer.getVisibleBounds().top) {
+ moveLocation.y -= distanceToMove;
+ } else {
+ moveLocation.y += distanceToMove;
+ }
+ movePointer(center, moveLocation);
+
+ assertNull(findViewById(R.id.deep_shortcuts_container));
+ }
+
+ // Wait until Remove/Delete target is visible
+ assertNotNull(findViewById(R.id.delete_target_text));
+
+ Point moveLocation = dragLayer.getVisibleCenter();
+
+ // Move to center
+ movePointer(center, moveLocation);
+ sendPointer(MotionEvent.ACTION_UP, center);
+
+ // Wait until remove target is gone.
+ getDevice().wait(Until.gone(getSelectorForId(R.id.delete_target_text)),
+ AbstractLauncherUiTest.DEFAULT_UI_TIMEOUT);
+ }
+
+ private static void movePointer(Point from, Point to) {
+ while (!from.equals(to)) {
+ from.x = getNextMoveValue(to.x, from.x);
+ from.y = getNextMoveValue(to.y, from.y);
+ sendPointer(MotionEvent.ACTION_MOVE, from);
+ }
+ }
+
+ private static int getNextMoveValue(int targetValue, int oldValue) {
+ if (targetValue - oldValue > 10) {
+ return oldValue + 10;
+ } else if (targetValue - oldValue < -10) {
+ return oldValue - 10;
+ } else {
+ return targetValue;
+ }
+ }
+
+ public static void sendPointer(int action, Point point) {
+ MotionEvent event = MotionEvent.obtain(SystemClock.uptimeMillis(),
+ SystemClock.uptimeMillis(), action, point.x, point.y, 0);
+ getInstrumentation().sendPointerSync(event);
+ event.recycle();
+ }
+
+ /**
+ * Opens widget tray and returns the recycler view.
+ */
+ public static UiObject2 openWidgetsTray() {
+ final UiDevice device = getDevice();
+ device.pressMenu(); // Enter overview mode.
+ device.wait(Until.findObject(
+ By.text(getTargetContext().getString(R.string.widget_button_text))),
+ AbstractLauncherUiTest.DEFAULT_UI_TIMEOUT).click();
+ return findViewById(R.id.widgets_list_view);
+ }
+
+ public static View findChildView(ViewGroup parent, Function<View, Boolean> condition) {
+ for (int i = 0; i < parent.getChildCount(); ++i) {
+ final View child = parent.getChildAt(i);
+ if (condition.apply(child)) return child;
+ }
+ return null;
+ }
+}
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
index 6244434..c93c20a 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -15,32 +15,21 @@
*/
package com.android.launcher3.ui;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
+import static com.android.launcher3.LauncherState.ALL_APPS;
-import com.android.launcher3.R;
-import com.android.launcher3.util.Condition;
-import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
-import com.android.launcher3.util.rule.ShellCommandRule;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertTrue;
-
@LargeTest
@RunWith(AndroidJUnit4.class)
public class WorkTabTest extends AbstractLauncherUiTest {
- @Rule
- public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
- @Rule
- public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
private int mProfileUserId;
@@ -66,17 +55,13 @@
public void workTabExists() {
mActivityMonitor.startLauncher();
- // Open all apps and wait for load complete
- final UiObject2 appsContainer = openAllApps();
- assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2),
- LARGE_UI_TIMEOUT));
+ executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
/*
- assertTrue("Personal tab is missing",
- mDevice.wait(Until.hasObject(getSelectorForId(R.id.tab_personal)),
- LARGE_UI_TIMEOUT));
- assertTrue("Work tab is missing",
- mDevice.wait(Until.hasObject(getSelectorForId(R.id.tab_work)), LARGE_UI_TIMEOUT));
+ assertTrue("Personal tab is missing", waitForLauncherCondition(
+ launcher -> launcher.getAppsView().isPersonalTabVisible()));
+ assertTrue("Work tab is missing", waitForLauncherCondition(
+ launcher -> launcher.getAppsView().isWorkTabVisible()));
*/
}
}
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index a5c2e69..80561fc 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -15,36 +15,39 @@
*/
package com.android.launcher3.ui.widget;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+
import android.appwidget.AppWidgetManager;
import android.content.Intent;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiObject2;
import android.view.View;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiObject2;
+
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Workspace;
import com.android.launcher3.testcomponent.WidgetConfigActivity;
import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.WidgetCell;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
-
/**
* Test to verify widget configuration is properly shown.
*/
@@ -52,8 +55,7 @@
@RunWith(AndroidJUnit4.class)
public class AddConfigWidgetTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
- @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
+ @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
private LauncherAppWidgetProviderInfo mWidgetInfo;
private AppWidgetManager mAppWidgetManager;
@@ -64,26 +66,30 @@
@Before
public void setUp() throws Exception {
super.setUp();
- mWidgetInfo = findWidgetProvider(true /* hasConfigureScreen */);
+ mWidgetInfo = TestViewHelpers.findWidgetProvider(this, true /* hasConfigureScreen */);
mAppWidgetManager = AppWidgetManager.getInstance(mTargetContext);
}
@Test
+ @Ignore
public void testWidgetConfig() throws Throwable {
runTest(false, true);
}
@Test
+ @Ignore
public void testWidgetConfig_rotate() throws Throwable {
runTest(true, true);
}
@Test
+ @Ignore
public void testConfigCancelled() throws Throwable {
runTest(false, false);
}
@Test
+ @Ignore
public void testConfigCancelled_rotate() throws Throwable {
runTest(true, false);
}
@@ -99,14 +105,14 @@
mActivityMonitor.startLauncher();
// Open widget tray and wait for load complete.
- final UiObject2 widgetContainer = openWidgetsTray();
- assertTrue(Wait.atMost(Condition.minChildCount(widgetContainer, 2), DEFAULT_UI_TIMEOUT));
+ final UiObject2 widgetContainer = TestViewHelpers.openWidgetsTray();
+ Wait.atMost(null, Condition.minChildCount(widgetContainer, 2), DEFAULT_UI_TIMEOUT);
// Drag widget to homescreen
WidgetConfigStartupMonitor monitor = new WidgetConfigStartupMonitor();
UiObject2 widget = scrollAndFind(widgetContainer, By.clazz(WidgetCell.class)
.hasDescendant(By.text(mWidgetInfo.getLabel(mTargetContext.getPackageManager()))));
- dragToWorkspace(widget, false);
+ TestViewHelpers.dragToWorkspace(widget, false);
// Widget id for which the config activity was opened
mWidgetId = monitor.getWidgetId();
@@ -122,21 +128,16 @@
setResult(acceptConfig);
if (acceptConfig) {
- assertTrue(Wait.atMost(new WidgetSearchCondition(), DEFAULT_ACTIVITY_TIMEOUT));
+ Wait.atMost(null, new WidgetSearchCondition(), DEFAULT_ACTIVITY_TIMEOUT);
assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
} else {
// Verify that the widget id is deleted.
- assertTrue(Wait.atMost(new Condition() {
- @Override
- public boolean isTrue() throws Throwable {
- return mAppWidgetManager.getAppWidgetInfo(mWidgetId) == null;
- }
- }, DEFAULT_ACTIVITY_TIMEOUT));
+ Wait.atMost(null, () -> mAppWidgetManager.getAppWidgetInfo(mWidgetId) == null,
+ DEFAULT_ACTIVITY_TIMEOUT);
}
}
private void setResult(boolean success) {
-
getInstrumentation().getTargetContext().sendBroadcast(
WidgetConfigActivity.getCommandIntent(WidgetConfigActivity.class,
success ? "clickOK" : "clickCancel"));
@@ -145,8 +146,7 @@
/**
* Condition for searching widget id
*/
- private class WidgetSearchCondition extends Condition
- implements Workspace.ItemOperator {
+ private class WidgetSearchCondition implements Condition, Workspace.ItemOperator {
@Override
public boolean isTrue() throws Throwable {
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index 19f7db7..7d3cf2b 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -15,10 +15,12 @@
*/
package com.android.launcher3.ui.widget;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiObject2;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiObject2;
import android.view.View;
import com.android.launcher3.ItemInfo;
@@ -26,18 +28,17 @@
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.WidgetCell;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertTrue;
-
/**
* Test to add widget from widget tray
*/
@@ -45,16 +46,17 @@
@RunWith(AndroidJUnit4.class)
public class AddWidgetTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
- @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
+ @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
@Test
+ @Ignore
public void testDragIcon_portrait() throws Throwable {
lockRotation(true);
performTest();
}
@Test
+ @Ignore
public void testDragIcon_landscape() throws Throwable {
lockRotation(false);
performTest();
@@ -65,16 +67,16 @@
mActivityMonitor.startLauncher();
final LauncherAppWidgetProviderInfo widgetInfo =
- findWidgetProvider(false /* hasConfigureScreen */);
+ TestViewHelpers.findWidgetProvider(this, false /* hasConfigureScreen */);
// Open widget tray and wait for load complete.
- final UiObject2 widgetContainer = openWidgetsTray();
- assertTrue(Wait.atMost(Condition.minChildCount(widgetContainer, 2), DEFAULT_UI_TIMEOUT));
+ final UiObject2 widgetContainer = TestViewHelpers.openWidgetsTray();
+ Wait.atMost(null, Condition.minChildCount(widgetContainer, 2), DEFAULT_UI_TIMEOUT);
// Drag widget to homescreen
UiObject2 widget = scrollAndFind(widgetContainer, By.clazz(WidgetCell.class)
.hasDescendant(By.text(widgetInfo.getLabel(mTargetContext.getPackageManager()))));
- dragToWorkspace(widget, false);
+ TestViewHelpers.dragToWorkspace(widget, false);
assertTrue(mActivityMonitor.itemExists(new ItemOperator() {
@Override
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index b557119..22bc05c 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -15,6 +15,11 @@
*/
package com.android.launcher3.ui.widget;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
@@ -25,26 +30,21 @@
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.UiSelector;
import com.android.launcher3.LauncherAppWidgetHost;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.Workspace;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.ContentWriter;
-import com.android.launcher3.util.LooperExecutor;
-import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.widget.WidgetHostViewLoader;
import org.junit.After;
@@ -55,13 +55,11 @@
import org.junit.runner.RunWith;
import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.UiSelector;
+import java.util.concurrent.Callable;
/**
* Tests for bind widget flow.
@@ -72,8 +70,8 @@
@RunWith(AndroidJUnit4.class)
public class BindWidgetTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
- @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
+ @Rule
+ public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
private ContentResolver mResolver;
private AppWidgetManagerCompat mWidgetManager;
@@ -86,6 +84,11 @@
@Override
@Before
public void setUp() throws Exception {
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ android.util.Log.getStackTraceString(new Throwable()));
+ }
super.setUp();
mResolver = mTargetContext.getContentResolver();
@@ -105,34 +108,44 @@
if (mSessionId > -1) {
mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId);
}
+
+ super.tearDown();
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ android.util.Log.getStackTraceString(new Throwable()));
+ }
}
@Test
public void testBindNormalWidget_withConfig() {
- LauncherAppWidgetProviderInfo info = findWidgetProvider(true);
+ LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, true);
LauncherAppWidgetInfo item = createWidgetInfo(info, true);
- setupAndVerifyContents(item, LauncherAppWidgetHostView.class, info.label);
+ setupContents(item);
+ verifyWidgetPresent(info);
}
@Test
public void testBindNormalWidget_withoutConfig() {
- LauncherAppWidgetProviderInfo info = findWidgetProvider(false);
+ LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
LauncherAppWidgetInfo item = createWidgetInfo(info, true);
- setupAndVerifyContents(item, LauncherAppWidgetHostView.class, info.label);
+ setupContents(item);
+ verifyWidgetPresent(info);
}
@Test @Ignore
- public void testUnboundWidget_removed() throws Exception {
- LauncherAppWidgetProviderInfo info = findWidgetProvider(false);
+ public void testUnboundWidget_removed() {
+ LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
LauncherAppWidgetInfo item = createWidgetInfo(info, false);
item.appWidgetId = -33;
- // Since there is no widget to verify, just wait until the workspace is ready.
- setupAndVerifyContents(item, Workspace.class, null);
+ setupContents(item);
- waitUntilLoaderIdle();
+ // Since there is no widget to verify, just wait until the workspace is ready.
+ // TODO: fix LauncherInstrumentation#LAUNCHER_PKG
+ mLauncher.getWorkspace();
// Item deleted from db
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
null, null, null, null, null);
@@ -144,27 +157,44 @@
@Test
public void testPendingWidget_autoRestored() {
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ "Test Started @ " + android.util.Log.getStackTraceString(new Throwable()));
+ }
// A non-restored widget with no config screen gets restored automatically.
- LauncherAppWidgetProviderInfo info = findWidgetProvider(false);
+ LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
// Do not bind the widget
LauncherAppWidgetInfo item = createWidgetInfo(info, false);
item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID;
- setupAndVerifyContents(item, LauncherAppWidgetHostView.class, info.label);
+ setupContents(item);
+ verifyWidgetPresent(info);
+
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ "Test Ended @ " + android.util.Log.getStackTraceString(new Throwable()));
+ }
}
@Test
- public void testPendingWidget_withConfigScreen() throws Exception {
+ public void testPendingWidget_withConfigScreen() {
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ "Test Started @ " + android.util.Log.getStackTraceString(new Throwable()));
+ }
// A non-restored widget with config screen get bound and shows a 'Click to setup' UI.
- LauncherAppWidgetProviderInfo info = findWidgetProvider(true);
+ LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, true);
// Do not bind the widget
LauncherAppWidgetInfo item = createWidgetInfo(info, false);
item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID;
- setupAndVerifyContents(item, PendingAppWidgetHostView.class, null);
- waitUntilLoaderIdle();
+ setupContents(item);
+ verifyPendingWidgetPresent();
+
// Item deleted from db
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
null, null, null, null, null);
@@ -176,19 +206,27 @@
assertNotNull(AppWidgetManager.getInstance(mTargetContext)
.getAppWidgetInfo(mCursor.getInt(mCursor.getColumnIndex(
LauncherSettings.Favorites.APPWIDGET_ID))));
+ if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+ && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+ android.util.Log.d("b/117332845",
+ "Test Ended @ " + android.util.Log.getStackTraceString(new Throwable()));
+ }
}
@Test @Ignore
- public void testPendingWidget_notRestored_removed() throws Exception {
+ public void testPendingWidget_notRestored_removed() {
LauncherAppWidgetInfo item = getInvalidWidgetInfo();
item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID
| LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
- setupAndVerifyContents(item, Workspace.class, null);
+ setupContents(item);
+
+ // Since there is no widget to verify, just wait until the workspace is ready.
+ // TODO: fix LauncherInstrumentation#LAUNCHER_PKG
+ mLauncher.getWorkspace();
// The view does not exist
assertFalse(mDevice.findObject(
new UiSelector().className(PendingAppWidgetHostView.class)).exists());
- waitUntilLoaderIdle();
// Item deleted from db
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
null, null, null, null, null);
@@ -196,7 +234,7 @@
}
@Test
- public void testPendingWidget_notRestored_brokenInstall() throws Exception {
+ public void testPendingWidget_notRestored_brokenInstall() {
// A widget which is was being installed once, even if its not being
// installed at the moment is not removed.
LauncherAppWidgetInfo item = getInvalidWidgetInfo();
@@ -204,9 +242,10 @@
| LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
| LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
- setupAndVerifyContents(item, PendingAppWidgetHostView.class, null);
+ setupContents(item);
+ verifyPendingWidgetPresent();
+
// Verify item still exists in db
- waitUntilLoaderIdle();
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
null, null, null, null, null);
assertEquals(1, mCursor.getCount());
@@ -231,9 +270,10 @@
PackageInstaller installer = mTargetContext.getPackageManager().getPackageInstaller();
mSessionId = installer.createSession(params);
- setupAndVerifyContents(item, PendingAppWidgetHostView.class, null);
+ setupContents(item);
+ verifyPendingWidgetPresent();
+
// Verify item still exists in db
- waitUntilLoaderIdle();
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
null, null, null, null, null);
assertEquals(1, mCursor.getCount());
@@ -248,12 +288,9 @@
/**
* Adds {@param item} on the homescreen on the 0th screen at 0,0, and verifies that the
* widget class is displayed on the homescreen.
- * @param widgetClass the View class which is displayed on the homescreen
- * @param desc the content description of the view or null.
*/
- private void setupAndVerifyContents(
- LauncherAppWidgetInfo item, Class<?> widgetClass, String desc) {
- long screenId = Workspace.FIRST_SCREEN_ID;
+ private void setupContents(LauncherAppWidgetInfo item) {
+ int screenId = Workspace.FIRST_SCREEN_ID;
// Update the screen id counter for the provider.
LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_NEW_SCREEN_ID);
@@ -269,7 +306,7 @@
ContentWriter writer = new ContentWriter(mTargetContext);
item.id = LauncherSettings.Settings.call(
mResolver, LauncherSettings.Settings.METHOD_NEW_ITEM_ID)
- .getLong(LauncherSettings.Settings.EXTRA_VALUE);
+ .getInt(LauncherSettings.Settings.EXTRA_VALUE);
item.screenId = screenId;
item.onAddToDatabase(writer);
writer.put(LauncherSettings.Favorites._ID, item.id);
@@ -278,12 +315,18 @@
// Launch the home activity
mActivityMonitor.startLauncher();
- // Verify UI
+ waitForModelLoaded();
+ }
+
+ private void verifyWidgetPresent(LauncherAppWidgetProviderInfo info) {
UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
- .className(widgetClass);
- if (desc != null) {
- selector = selector.description(desc);
- }
+ .className(LauncherAppWidgetHostView.class).description(info.label);
+ assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
+ }
+
+ private void verifyPendingWidgetPresent() {
+ UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
+ .className(PendingAppWidgetHostView.class);
assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
}
@@ -332,13 +375,9 @@
int count = 0;
String pkg = invalidPackage;
- Set<String> activePackage = getOnUiThread(new Callable<Set<String>>() {
- @Override
- public Set<String> call() throws Exception {
- return PackageInstallerCompat.getInstance(mTargetContext)
- .updateAndGetActiveSessionCache().keySet();
- }
- });
+ Set<String> activePackage = getOnUiThread(() ->
+ PackageInstallerCompat.getInstance(mTargetContext)
+ .updateAndGetActiveSessionCache().keySet());
while(true) {
try {
mTargetContext.getPackageManager().getPackageInfo(
@@ -362,15 +401,4 @@
item.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
return item;
}
-
- /**
- * Blocks the current thread until all the jobs in the main worker thread are complete.
- */
- private void waitUntilLoaderIdle() throws Exception {
- new LooperExecutor(LauncherModel.getWorkerLooper())
- .submit(new Runnable() {
- @Override
- public void run() { }
- }).get(DEFAULT_WORKER_TIMEOUT_SECS, TimeUnit.SECONDS);
- }
}
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index dcb564a..95a1289 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -15,15 +15,19 @@
*/
package com.android.launcher3.ui.widget;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.graphics.Color;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
import android.view.View;
import com.android.launcher3.ItemInfo;
@@ -38,9 +42,9 @@
import com.android.launcher3.testcomponent.AppWidgetWithConfig;
import com.android.launcher3.testcomponent.RequestPinItemActivity;
import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.WidgetCell;
@@ -52,20 +56,14 @@
import java.util.UUID;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
-
/**
* Test to verify pin item request flow.
*/
@LargeTest
@RunWith(AndroidJUnit4.class)
-public class RequestPinItemTest extends AbstractLauncherUiTest {
+public class RequestPinItemTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
- @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
- @Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
+ @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
private String mCallbackAction;
private String mShortcutId;
@@ -154,8 +152,8 @@
mActivityMonitor.startLauncher();
// Open all apps and wait for load complete
- final UiObject2 appsContainer = openAllApps();
- assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
+ final UiObject2 appsContainer = TestViewHelpers.openAllApps();
+ Wait.atMost(null, Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT);
// Open Pin item activity
BlockingBroadcastReceiver openMonitor = new BlockingBroadcastReceiver(
@@ -194,13 +192,13 @@
// Go back to home
mActivityMonitor.returnToHome();
- assertTrue(Wait.atMost(new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT));
+ Wait.atMost(null, new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT);
}
/**
* Condition for for an item
*/
- private class ItemSearchCondition extends Condition {
+ private class ItemSearchCondition implements Condition {
private final ItemOperator mOp;
diff --git a/tests/src/com/android/launcher3/util/Condition.java b/tests/src/com/android/launcher3/util/Condition.java
index e9ee67c..b564a1a 100644
--- a/tests/src/com/android/launcher3/util/Condition.java
+++ b/tests/src/com/android/launcher3/util/Condition.java
@@ -1,6 +1,6 @@
package com.android.launcher3.util;
-import android.support.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.UiObject2;
import com.android.launcher3.MainThreadExecutor;
@@ -8,47 +8,36 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
-public abstract class Condition {
+public interface Condition {
- public abstract boolean isTrue() throws Throwable;
+ boolean isTrue() throws Throwable;
/**
* Converts the condition to be run on UI thread.
*/
- public static Condition runOnUiThread(final Condition condition) {
+ static Condition runOnUiThread(final Condition condition) {
final MainThreadExecutor executor = new MainThreadExecutor();
- return new Condition() {
- @Override
- public boolean isTrue() throws Throwable {
- final AtomicBoolean value = new AtomicBoolean(false);
- final Throwable[] exceptions = new Throwable[1];
- final CountDownLatch latch = new CountDownLatch(1);
- executor.execute(new Runnable() {
- @Override
- public void run() {
- try {
- value.set(condition.isTrue());
- } catch (Throwable e) {
- exceptions[0] = e;
- }
-
- }
- });
- latch.await(1, TimeUnit.SECONDS);
- if (exceptions[0] != null) {
- throw exceptions[0];
+ return () -> {
+ final AtomicBoolean value = new AtomicBoolean(false);
+ final Throwable[] exceptions = new Throwable[1];
+ final CountDownLatch latch = new CountDownLatch(1);
+ executor.execute(() -> {
+ try {
+ value.set(condition.isTrue());
+ } catch (Throwable e) {
+ exceptions[0] = e;
}
- return value.get();
+
+ });
+ latch.await(1, TimeUnit.SECONDS);
+ if (exceptions[0] != null) {
+ throw exceptions[0];
}
+ return value.get();
};
}
- public static Condition minChildCount(final UiObject2 obj, final int childCount) {
- return new Condition() {
- @Override
- public boolean isTrue() {
- return obj.getChildCount() >= childCount;
- }
- };
+ static Condition minChildCount(final UiObject2 obj, final int childCount) {
+ return () -> obj.getChildCount() >= childCount;
}
}
diff --git a/tests/src/com/android/launcher3/util/TestUtil.java b/tests/src/com/android/launcher3/util/TestUtil.java
new file mode 100644
index 0000000..1338dcb
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/TestUtil.java
@@ -0,0 +1,51 @@
+/*
+ * 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.util;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import android.content.res.Resources;
+
+import androidx.test.uiautomator.UiDevice;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class TestUtil {
+ public static void installDummyApp() throws IOException {
+ // Copy apk from resources to a local file and install from there.
+ final Resources resources = getContext().getResources();
+ final InputStream in = resources.openRawResource(
+ resources.getIdentifier("aardwolf_dummy_app",
+ "raw", getContext().getPackageName()));
+ final String apkFilename = getInstrumentation().getTargetContext().
+ getFilesDir().getPath() + "/dummy_app.apk";
+
+ final FileOutputStream out = new FileOutputStream(apkFilename);
+ byte[] buff = new byte[1024];
+ int read;
+
+ while ((read = in.read(buff)) > 0) {
+ out.write(buff, 0, read);
+ }
+ in.close();
+ out.close();
+
+ UiDevice.getInstance(getInstrumentation()).executeShellCommand("pm install " + apkFilename);
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/Wait.java b/tests/src/com/android/launcher3/util/Wait.java
index f9e53ba..0e41c02 100644
--- a/tests/src/com/android/launcher3/util/Wait.java
+++ b/tests/src/com/android/launcher3/util/Wait.java
@@ -2,6 +2,8 @@
import android.os.SystemClock;
+import org.junit.Assert;
+
/**
* A utility class for waiting for a condition to be true.
*/
@@ -9,16 +11,16 @@
private static final long DEFAULT_SLEEP_MS = 200;
- public static boolean atMost(Condition condition, long timeout) {
- return atMost(condition, timeout, DEFAULT_SLEEP_MS);
+ public static void atMost(String message, Condition condition, long timeout) {
+ atMost(message, condition, timeout, DEFAULT_SLEEP_MS);
}
- public static boolean atMost(Condition condition, long timeout, long sleepMillis) {
+ public static void atMost(String message, Condition condition, long timeout, long sleepMillis) {
long endTime = SystemClock.uptimeMillis() + timeout;
while (SystemClock.uptimeMillis() < endTime) {
try {
if (condition.isTrue()) {
- return true;
+ return;
}
} catch (Throwable t) {
// Ignore
@@ -29,11 +31,11 @@
// Check once more before returning false.
try {
if (condition.isTrue()) {
- return true;
+ return;
}
} catch (Throwable t) {
// Ignore
}
- return false;
+ Assert.fail(message);
}
}
diff --git a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java
index edd152a..145c3c8 100644
--- a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java
+++ b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java
@@ -15,12 +15,16 @@
*/
package com.android.launcher3.util.rule;
+import static com.android.launcher3.tapl.TestHelpers.getHomeIntentInPackage;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static androidx.test.InstrumentationRegistry.getTargetContext;
+
import android.app.Activity;
import android.app.Application;
import android.app.Application.ActivityLifecycleCallbacks;
-import android.content.Intent;
import android.os.Bundle;
-import android.support.test.InstrumentationRegistry;
+import androidx.test.InstrumentationRegistry;
import com.android.launcher3.Launcher;
import com.android.launcher3.Workspace.ItemOperator;
@@ -65,19 +69,12 @@
* Starts the launcher activity in the target package.
*/
public void startLauncher() {
- InstrumentationRegistry.getInstrumentation().startActivitySync(getHomeIntent());
+ getInstrumentation().startActivitySync(getHomeIntentInPackage(getTargetContext()));
}
public void returnToHome() {
- InstrumentationRegistry.getTargetContext().startActivity(getHomeIntent());
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
- }
-
- public static Intent getHomeIntent() {
- return new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME)
- .setPackage(InstrumentationRegistry.getTargetContext().getPackageName())
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ getTargetContext().startActivity(getHomeIntentInPackage(getTargetContext()));
+ getInstrumentation().waitForIdleSync();
}
private class MyStatement extends Statement implements ActivityLifecycleCallbacks {
diff --git a/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
index dba2d71..0ec0f02 100644
--- a/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
+++ b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
@@ -15,17 +15,20 @@
*/
package com.android.launcher3.util.rule;
+import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
-import android.os.ParcelFileDescriptor;
-import android.support.test.InstrumentationRegistry;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
-import java.io.FileInputStream;
-import java.io.IOException;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.uiautomator.UiDevice;
/**
* Test rule which executes a shell command at the start of the test.
@@ -33,58 +36,55 @@
public class ShellCommandRule implements TestRule {
private final String mCmd;
+ private final String mRevertCommand;
- public ShellCommandRule(String cmd) {
+ public ShellCommandRule(String cmd, @Nullable String revertCommand) {
mCmd = cmd;
+ mRevertCommand = revertCommand;
}
@Override
public Statement apply(Statement base, Description description) {
- return new MyStatement(base, mCmd);
- }
-
- public static void runShellCommand(String command) throws IOException {
- ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
- .executeShellCommand(command);
-
- // Read the input stream fully.
- FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
- while (fis.read() != -1);
- fis.close();
- }
-
- private static class MyStatement extends Statement {
- private final Statement mBase;
- private final String mCmd;
-
- public MyStatement(Statement base, String cmd) {
- mBase = base;
- mCmd = cmd;
- }
-
- @Override
- public void evaluate() throws Throwable {
- runShellCommand(mCmd);
- mBase.evaluate();
- }
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ UiDevice.getInstance(getInstrumentation()).executeShellCommand(mCmd);
+ try {
+ base.evaluate();
+ } finally {
+ if (mRevertCommand != null) {
+ UiDevice.getInstance(getInstrumentation()).executeShellCommand(mRevertCommand);
+ }
+ }
+ }
+ };
}
/**
* Grants the launcher permission to bind widgets.
*/
- public static ShellCommandRule grandWidgetBind() {
+ public static ShellCommandRule grantWidgetBind() {
return new ShellCommandRule("appwidget grantbind --package "
- + InstrumentationRegistry.getTargetContext().getPackageName());
+ + InstrumentationRegistry.getTargetContext().getPackageName(), null);
}
/**
* Sets the target launcher as default launcher.
*/
public static ShellCommandRule setDefaultLauncher() {
- ActivityInfo launcher = InstrumentationRegistry.getTargetContext().getPackageManager()
- .queryIntentActivities(LauncherActivityRule.getHomeIntent(), 0).get(0)
- .activityInfo;
- return new ShellCommandRule("cmd package set-home-activity " +
- new ComponentName(launcher.packageName, launcher.name).flattenToString());
+ return new ShellCommandRule(getLauncherCommand(getLauncherInMyProcess()), null);
+ }
+
+ public static String getLauncherCommand(ActivityInfo launcher) {
+ return "cmd package set-home-activity " +
+ new ComponentName(launcher.packageName, launcher.name).flattenToString();
+ }
+
+ /**
+ * Disables heads up notification for the duration of the test
+ */
+ public static ShellCommandRule disableHeadsUpNotification() {
+ return new ShellCommandRule("settings put global heads_up_notifications_enabled 0",
+ "settings put global heads_up_notifications_enabled 1");
}
}
diff --git a/tests/src/com/android/launcher3/widget/WidgetsListAdapterTest.java b/tests/src/com/android/launcher3/widget/WidgetsListAdapterTest.java
index 0185f13..a31d8a6 100644
--- a/tests/src/com/android/launcher3/widget/WidgetsListAdapterTest.java
+++ b/tests/src/com/android/launcher3/widget/WidgetsListAdapterTest.java
@@ -15,17 +15,20 @@
*/
package com.android.launcher3.widget;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.graphics.Bitmap;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v7.widget.RecyclerView;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import android.view.LayoutInflater;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.icons.IconCache;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.WidgetPreviewLoader;
@@ -43,10 +46,7 @@
import java.util.ArrayList;
import java.util.Map;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isNull;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
+import androidx.recyclerview.widget.RecyclerView;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -128,11 +128,10 @@
if (num <= 0) return result;
MultiHashMap<PackageItemInfo, WidgetItem> newMap = new MultiHashMap();
- PackageManager pm = mContext.getPackageManager();
AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(mContext);
for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders(null)) {
WidgetItem wi = new WidgetItem(LauncherAppWidgetProviderInfo
- .fromProviderInfo(mContext, widgetInfo), pm, mTestProfile);
+ .fromProviderInfo(mContext, widgetInfo), mTestProfile, mIconCache);
PackageItemInfo pInfo = new PackageItemInfo(wi.componentName.getPackageName());
pInfo.title = pInfo.packageName;
diff --git a/tests/tapl/README b/tests/tapl/README
new file mode 100644
index 0000000..a35d792
--- /dev/null
+++ b/tests/tapl/README
@@ -0,0 +1 @@
+http://go/tapl
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromHome.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
similarity index 60%
rename from tests/tapl/com/android/launcher3/tapl/AllAppsFromHome.java
rename to tests/tapl/com/android/launcher3/tapl/AllApps.java
index 02f8183..84fd908 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromHome.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -16,36 +16,32 @@
package com.android.launcher3.tapl;
-import android.support.annotation.NonNull;
-import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.Direction;
-import android.support.test.uiautomator.UiObject2;
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.Direction;
+import androidx.test.uiautomator.UiObject2;
+
+import com.android.launcher3.TestProtocol;
/**
- * Operations on AllApps opened from Home.
+ * Operations on AllApps opened from Home. Also a parent for All Apps opened from Overview.
*/
-public final class AllAppsFromHome {
+public class AllApps extends LauncherInstrumentation.VisibleContainer {
private static final int MAX_SCROLL_ATTEMPTS = 40;
private static final int MIN_INTERACT_SIZE = 100;
private static final int FLING_SPEED = 12000;
- private final Launcher mLauncher;
private final int mHeight;
- AllAppsFromHome(Launcher launcher) {
- mLauncher = launcher;
- final UiObject2 allAppsContainer = assertState();
+ AllApps(LauncherInstrumentation launcher) {
+ super(launcher);
+ final UiObject2 allAppsContainer = verifyActiveContainer();
mHeight = allAppsContainer.getVisibleBounds().height();
}
- /**
- * Asserts that we are in all apps.
- *
- * @return All apps container.
- */
- @NonNull
- private UiObject2 assertState() {
- return mLauncher.assertState(Launcher.State.ALL_APPS);
+ @Override
+ protected LauncherInstrumentation.ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.ALL_APPS;
}
/**
@@ -57,19 +53,20 @@
*/
@NonNull
public AppIcon getAppIcon(String appName) {
- final UiObject2 allAppsContainer = assertState();
+ final UiObject2 allAppsContainer = verifyActiveContainer();
final BySelector appIconSelector = AppIcon.getAppIconSelector(appName);
if (!allAppsContainer.hasObject(appIconSelector)) {
scrollBackToBeginning();
int attempts = 0;
while (!allAppsContainer.hasObject(appIconSelector) &&
allAppsContainer.scroll(Direction.DOWN, 0.8f)) {
- mLauncher.assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
+ LauncherInstrumentation.assertTrue(
+ "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
++attempts <= MAX_SCROLL_ATTEMPTS);
- assertState();
+ verifyActiveContainer();
}
}
- assertState();
+ verifyActiveContainer();
final UiObject2 appIcon = mLauncher.getObjectInContainer(allAppsContainer, appIconSelector);
ensureIconVisible(appIcon, allAppsContainer);
@@ -77,21 +74,31 @@
}
private void scrollBackToBeginning() {
- final UiObject2 allAppsContainer = assertState();
+ final UiObject2 allAppsContainer = verifyActiveContainer();
+ final UiObject2 searchBox =
+ mLauncher.waitForObjectInContainer(allAppsContainer, "search_container_all_apps");
int attempts = 0;
- allAppsContainer.setGestureMargins(5, 500, 5, 5);
+ allAppsContainer.setGestureMargins(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
- while (allAppsContainer.scroll(Direction.UP, 0.5f)) {
- mLauncher.waitForIdle();
- assertState();
+ for (int scroll = getScroll(allAppsContainer);
+ scroll != 0;
+ scroll = getScroll(allAppsContainer)) {
+ LauncherInstrumentation.assertTrue("Negative scroll position", scroll > 0);
- mLauncher.assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
+ LauncherInstrumentation.assertTrue(
+ "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
++attempts <= MAX_SCROLL_ATTEMPTS);
+
+ allAppsContainer.scroll(Direction.UP, 1);
}
- mLauncher.waitForIdle();
- assertState();
+ verifyActiveContainer();
+ }
+
+ private int getScroll(UiObject2 allAppsContainer) {
+ return mLauncher.getAnswerFromLauncher(allAppsContainer, TestProtocol.GET_SCROLL_MESSAGE).
+ getInt(TestProtocol.SCROLL_Y_FIELD, -1);
}
private void ensureIconVisible(UiObject2 appIcon, UiObject2 allAppsContainer) {
@@ -102,7 +109,7 @@
final float pct = Math.max(((float) (MIN_INTERACT_SIZE - appHeight)) / mHeight, 0.2f);
allAppsContainer.scroll(Direction.DOWN, pct);
mLauncher.waitForIdle();
- assertState();
+ verifyActiveContainer();
}
}
@@ -110,33 +117,21 @@
* Flings forward (down) and waits the fling's end.
*/
public void flingForward() {
- final UiObject2 allAppsContainer = assertState();
+ final UiObject2 allAppsContainer = verifyActiveContainer();
// Start the gesture in the center to avoid starting at elements near the top.
allAppsContainer.setGestureMargins(0, 0, 0, mHeight / 2);
allAppsContainer.fling(Direction.DOWN, FLING_SPEED);
- assertState();
+ verifyActiveContainer();
}
/**
* Flings backward (up) and waits the fling's end.
*/
public void flingBackward() {
- final UiObject2 allAppsContainer = assertState();
+ final UiObject2 allAppsContainer = verifyActiveContainer();
// Start the gesture in the center, for symmetry with forward.
allAppsContainer.setGestureMargins(0, mHeight / 2, 0, 0);
allAppsContainer.fling(Direction.UP, FLING_SPEED);
- assertState();
- }
-
- /**
- * Gets the UI object for AllApps.
- * Used by NexusLauncherStrategy.openAllApps(). No one else should use it.
- *
- * @return container object.
- */
- @Deprecated
- @NonNull
- public UiObject2 getObjectDeprecated() {
- return assertState();
+ verifyActiveContainer();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
index cba7086..42817c1 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
@@ -17,29 +17,18 @@
package com.android.launcher3.tapl;
import android.graphics.Point;
-import android.support.annotation.NonNull;
-import android.support.test.uiautomator.UiObject2;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.UiObject2;
/**
* Operations on AllApps opened from Overview.
- * Scroll gestures that are OK for {@link AllAppsFromHome} may close it, so they are not supported.
*/
-public final class AllAppsFromOverview {
- private final Launcher mLauncher;
+public final class AllAppsFromOverview extends AllApps {
- AllAppsFromOverview(Launcher launcher) {
- mLauncher = launcher;
- assertState();
- }
-
- /**
- * Asserts that we are in all apps.
- *
- * @return All apps container.
- */
- @NonNull
- private UiObject2 assertState() {
- return mLauncher.assertState(Launcher.State.ALL_APPS);
+ AllAppsFromOverview(LauncherInstrumentation launcher) {
+ super(launcher);
+ verifyActiveContainer();
}
/**
@@ -49,13 +38,14 @@
*/
@NonNull
public Overview switchBackToOverview() {
- final UiObject2 allAppsContainer = assertState();
+ final UiObject2 allAppsContainer = verifyActiveContainer();
// Swipe from the search box to the bottom.
final UiObject2 qsb = mLauncher.waitForObjectInContainer(
allAppsContainer, "search_container_all_apps");
final Point start = qsb.getVisibleCenter();
final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.6);
- mLauncher.swipe(start.x, start.y, start.x, endY, (endY - start.y) / 100); // 100 px/step
+ LauncherInstrumentation.log("AllAppsFromOverview.switchBackToOverview before swipe");
+ mLauncher.swipe(start.x, start.y, start.x, endY);
return new Overview(mLauncher);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index 73a74f2..efefc0d 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -16,38 +16,33 @@
package com.android.launcher3.tapl;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
+import android.graphics.Point;
import android.widget.TextView;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiObject2;
+
/**
* App icon, whether in all apps or in workspace/
*/
-public final class AppIcon {
- private final Launcher mLauncher;
- private final UiObject2 mIcon;
-
- AppIcon(Launcher launcher, UiObject2 icon) {
- mLauncher = launcher;
- mIcon = icon;
+public final class AppIcon extends Launchable {
+ AppIcon(LauncherInstrumentation launcher, UiObject2 icon) {
+ super(launcher, icon);
}
static BySelector getAppIconSelector(String appName) {
- return By.clazz(TextView.class).text(appName).pkg(Launcher.LAUNCHER_PKG);
+ return By.clazz(TextView.class).text(appName).pkg(LauncherInstrumentation.LAUNCHER_PKG);
}
/**
- * Clicks the icon to launch its app.
+ * Long-clicks the icon to open its menu.
*/
- public void launch() {
- mLauncher.assertTrue("Launching an app didn't open a new window: " + mIcon.getText(),
- mIcon.clickAndWait(Until.newWindow(), Launcher.APP_LAUNCH_TIMEOUT_MS));
- mLauncher.assertState(Launcher.State.BACKGROUND);
- }
-
- UiObject2 getIcon() {
- return mIcon;
+ public AppIconMenu openMenu() {
+ final Point iconCenter = mObject.getVisibleCenter();
+ mLauncher.longTap(iconCenter.x, iconCenter.y);
+ final UiObject2 deepShortcutsContainer = mLauncher.waitForLauncherObject(
+ "deep_shortcuts_container");
+ return new AppIconMenu(mLauncher, deepShortcutsContainer);
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIconMenu.java b/tests/tapl/com/android/launcher3/tapl/AppIconMenu.java
new file mode 100644
index 0000000..2a03f9a
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/AppIconMenu.java
@@ -0,0 +1,46 @@
+/*
+ * 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.tapl;
+
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * Context menu of an app icon.
+ */
+public class AppIconMenu {
+ private final LauncherInstrumentation mLauncher;
+ private final UiObject2 mDeepShortcutsContainer;
+
+ AppIconMenu(LauncherInstrumentation launcher,
+ UiObject2 deepShortcutsContainer) {
+ mLauncher = launcher;
+ mDeepShortcutsContainer = deepShortcutsContainer;
+ }
+
+ /**
+ * Returns a menu item with a given number. Fails if it doesn't exist.
+ */
+ public AppIconMenuItem getMenuItem(int itemNumber) {
+ assertTrue(mDeepShortcutsContainer.getChildCount() > itemNumber);
+
+ final UiObject2 shortcut = mLauncher.waitForObjectInContainer(
+ mDeepShortcutsContainer.getChildren().get(itemNumber), "bubble_text");
+ return new AppIconMenuItem(mLauncher, shortcut);
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
new file mode 100644
index 0000000..c39f8d1
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
@@ -0,0 +1,35 @@
+/*
+ * 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.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * Menu item in an app icon menu.
+ */
+public class AppIconMenuItem extends Launchable {
+ AppIconMenuItem(LauncherInstrumentation launcher, UiObject2 shortcut) {
+ super(launcher, shortcut);
+ }
+
+ /**
+ * Returns the visible text of the menu item.
+ */
+ public String getText() {
+ return mObject.getText();
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
new file mode 100644
index 0000000..27e0954
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -0,0 +1,72 @@
+/*
+ * 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.tapl;
+
+import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
+import static com.android.launcher3.tapl.TestHelpers.getOverviewPackageName;
+
+import static org.junit.Assert.assertTrue;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+/**
+ * Indicates the base state with a UI other than Overview running as foreground. It can also
+ * indicate Launcher as long as Launcher is not in Overview state.
+ */
+public class Background extends LauncherInstrumentation.VisibleContainer {
+
+ Background(LauncherInstrumentation launcher) {
+ super(launcher);
+ }
+
+ @Override
+ protected LauncherInstrumentation.ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.BACKGROUND;
+ }
+
+ /**
+ * Swipes up or presses the square button to switch to Overview.
+ * Returns the base overview, which can be either in Launcher or the fallback recents.
+ *
+ * @return the Overview panel object.
+ */
+ @NonNull
+ public BaseOverview switchToOverview() {
+ verifyActiveContainer();
+ goToOverviewUnchecked();
+ assertTrue("Overview not visible", mLauncher.getDevice().wait(
+ Until.hasObject(By.pkg(getOverviewPackageName())), WAIT_TIME_MS));
+ return new BaseOverview(mLauncher);
+ }
+
+
+ protected void goToOverviewUnchecked() {
+ if (mLauncher.isSwipeUpEnabled()) {
+ final int height = mLauncher.getDevice().getDisplayHeight();
+ final UiObject2 navBar = mLauncher.getSystemUiObject("navigation_bar_frame");
+
+ mLauncher.swipe(
+ navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
+ navBar.getVisibleBounds().centerX(), height - 300);
+ } else {
+ mLauncher.getSystemUiObject("recent_apps").click();
+ }
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
new file mode 100644
index 0000000..4fce211
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -0,0 +1,84 @@
+/*
+ * 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.tapl;
+
+import java.util.Collections;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.Direction;
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * Common overview pane for both Launcher and fallback recents
+ */
+public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
+ private static final int DEFAULT_FLING_SPEED = 15000;
+
+ BaseOverview(LauncherInstrumentation launcher) {
+ super(launcher);
+ }
+
+ @Override
+ protected LauncherInstrumentation.ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.BASE_OVERVIEW;
+ }
+
+ /**
+ * Flings forward (left) and waits the fling's end.
+ */
+ public void flingForward() {
+ final UiObject2 overview = verifyActiveContainer();
+ LauncherInstrumentation.log("Overview.flingForward before fling");
+ overview.fling(Direction.LEFT, DEFAULT_FLING_SPEED);
+ mLauncher.waitForIdle();
+ verifyActiveContainer();
+ }
+
+ /**
+ * Flings backward (right) and waits the fling's end.
+ */
+ public void flingBackward() {
+ final UiObject2 overview = verifyActiveContainer();
+ LauncherInstrumentation.log("Overview.flingBackward before fling");
+ overview.fling(Direction.RIGHT, DEFAULT_FLING_SPEED);
+ mLauncher.waitForIdle();
+ verifyActiveContainer();
+ }
+
+ /**
+ * Gets the current task in the carousel, or fails if the carousel is empty.
+ *
+ * @return the task in the middle of the visible tasks list.
+ */
+ @NonNull
+ public OverviewTask getCurrentTask() {
+ verifyActiveContainer();
+ final List<UiObject2> taskViews = mLauncher.getDevice().findObjects(
+ LauncherInstrumentation.getLauncherObjectSelector("snapshot"));
+ LauncherInstrumentation.assertNotEquals("Unable to find a task", 0, taskViews.size());
+
+ // taskViews contains up to 3 task views: the 'main' (having the widest visible
+ // part) one in the center, and parts of its right and left siblings. Find the
+ // main task view by its width.
+ final UiObject2 widestTask = Collections.max(taskViews,
+ (t1, t2) -> Integer.compare(t1.getVisibleBounds().width(),
+ t2.getVisibleBounds().width()));
+
+ return new OverviewTask(mLauncher, widestTask, this);
+ }
+}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Home.java b/tests/tapl/com/android/launcher3/tapl/Home.java
index 0ec1a64..522ce14 100644
--- a/tests/tapl/com/android/launcher3/tapl/Home.java
+++ b/tests/tapl/com/android/launcher3/tapl/Home.java
@@ -16,38 +16,26 @@
package com.android.launcher3.tapl;
-import static junit.framework.TestCase.assertTrue;
-
-import android.graphics.Point;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.test.uiautomator.Direction;
-import android.support.test.uiautomator.UiObject2;
-import android.view.KeyEvent;
+import androidx.annotation.NonNull;
/**
* Operations on the home screen.
+ *
+ * Launcher can be invoked both when its activity is in the foreground and when it is in the
+ * background. This class is a parent of the two classes {@link Background} and {@link Workspace}
+ * that essentially represents these two activity states. Any gestures (e.g., switchToOverview) that
+ * can be performed in both of these states can be defined here.
*/
-public final class Home {
+public abstract class Home extends Background {
- private final Launcher mLauncher;
- private final UiObject2 mHotseat;
- private final int ICON_DRAG_SPEED = 2000;
-
- Home(Launcher launcher) {
- mLauncher = launcher;
- assertState();
- mHotseat = launcher.waitForLauncherObject("hotseat");
+ protected Home(LauncherInstrumentation launcher) {
+ super(launcher);
+ verifyActiveContainer();
}
- /**
- * Asserts that we are in home.
- *
- * @return Workspace.
- */
- @NonNull
- private UiObject2 assertState() {
- return mLauncher.assertState(Launcher.State.HOME);
+ @Override
+ protected LauncherInstrumentation.ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.WORKSPACE;
}
/**
@@ -56,132 +44,10 @@
* @return the Overview panel object.
*/
@NonNull
+ @Override
public Overview switchToOverview() {
- assertState();
- if (mLauncher.isSwipeUpEnabled()) {
- final int height = mLauncher.getDevice().getDisplayHeight();
- final UiObject2 navBar = mLauncher.getSystemUiObject("navigation_bar_frame");
-
- // Swipe from nav bar to 2/3rd down the screen.
- mLauncher.swipe(
- navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
- navBar.getVisibleBounds().centerX(), height * 2 / 3,
- (navBar.getVisibleBounds().centerY() - height * 2 / 3) / 100); // 100 px/step
- } else {
- mLauncher.getSystemUiObject("recent_apps").click();
- }
-
+ verifyActiveContainer();
+ goToOverviewUnchecked();
return new Overview(mLauncher);
}
-
- /**
- * Swipes up to All Apps.
- *
- * @return the App Apps object.
- */
- @NonNull
- public AllAppsFromHome switchToAllApps() {
- assertState();
- if (mLauncher.isSwipeUpEnabled()) {
- int midX = mLauncher.getDevice().getDisplayWidth() / 2;
- int height = mLauncher.getDevice().getDisplayHeight();
- // Swipe from 6/7ths down the screen to 1/7th down the screen.
- mLauncher.swipe(
- midX,
- height * 6 / 7,
- midX,
- height / 7,
- (height * 2 / 3) / 100); // 100 px/step
- } else {
- // Swipe from the hotseat to near the top, e.g. 10% of the screen.
- final UiObject2 hotseat = mHotseat;
- final Point start = hotseat.getVisibleCenter();
- final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f);
- mLauncher.swipe(
- start.x,
- start.y,
- start.x,
- endY,
- (start.y - endY) / 100); // 100 px/step
- }
-
- return new AllAppsFromHome(mLauncher);
- }
-
- /**
- * Returns an icon for the app, if currently visible.
- *
- * @param appName name of the app
- * @return app icon, if found, null otherwise.
- */
- @Nullable
- public AppIcon tryGetWorkspaceAppIcon(String appName) {
- final UiObject2 workspace = assertState();
- final UiObject2 icon = workspace.findObject(AppIcon.getAppIconSelector(appName));
- return icon != null ? new AppIcon(mLauncher, icon) : null;
- }
-
- /**
- * Ensures that workspace is scrollable. If it's not, drags an icon icons from hotseat to the
- * second screen.
- */
- public void ensureWorkspaceIsScrollable() {
- final UiObject2 workspace = assertState();
- if (!isWorkspaceScrollable(workspace)) {
- dragIconToNextScreen(getHotseatAppIcon("Messages"), workspace);
- }
- assertTrue("Home screen workspace didn't become scrollable",
- isWorkspaceScrollable(workspace));
- }
-
- private boolean isWorkspaceScrollable(UiObject2 workspace) {
- return workspace.isScrollable();
- }
-
- @NonNull
- private AppIcon getHotseatAppIcon(String appName) {
- return new AppIcon(mLauncher, mLauncher.getObjectInContainer(
- mHotseat, AppIcon.getAppIconSelector(appName)));
- }
-
- private void dragIconToNextScreen(AppIcon app, UiObject2 workspace) {
- final Point dest = new Point(
- mLauncher.getDevice().getDisplayWidth(), workspace.getVisibleBounds().centerY());
- app.getIcon().drag(dest, ICON_DRAG_SPEED);
- assertState();
- }
-
- /**
- * Flings to get to screens on the right. Waits for scrolling and a possible overscroll
- * recoil to complete.
- */
- public void flingForward() {
- final UiObject2 workspace = assertState();
- workspace.fling(Direction.RIGHT);
- mLauncher.waitForIdle();
- assertState();
- }
-
- /**
- * Flings to get to screens on the left. Waits for scrolling and a possible overscroll
- * recoil to complete.
- */
- public void flingBackward() {
- final UiObject2 workspace = assertState();
- workspace.fling(Direction.LEFT);
- mLauncher.waitForIdle();
- assertState();
- }
-
- /**
- * Opens widgets container by pressing Ctrl+W.
- *
- * @return the widgets container.
- */
- @NonNull
- public Widgets openAllWidgets() {
- assertState();
- mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
- return new Widgets(mLauncher);
- }
}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
new file mode 100644
index 0000000..7e2c966
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -0,0 +1,81 @@
+/*
+ * 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.tapl;
+
+import android.graphics.Point;
+
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+/**
+ * Ancestor for AppIcon and AppMenuItem.
+ */
+class Launchable {
+ private static final int DRAG_SPEED = 500;
+ protected final LauncherInstrumentation mLauncher;
+
+ protected final UiObject2 mObject;
+
+ Launchable(LauncherInstrumentation launcher, UiObject2 object) {
+ mObject = object;
+ mLauncher = launcher;
+ }
+
+ UiObject2 getObject() {
+ return mObject;
+ }
+
+ /**
+ * Clicks the object to launch its app.
+ */
+ public Background launch(String expectedPackageName) {
+ return launch(expectedPackageName, By.pkg(expectedPackageName).depth(0));
+ }
+
+ /**
+ * Clicks the object to launch its app.
+ */
+ public Background launch(String expectedPackageName, String expectedAppText) {
+ return launch(expectedPackageName, By.pkg(expectedPackageName).text(expectedAppText));
+ }
+
+ private Background launch(String errorMessage, BySelector selector) {
+ LauncherInstrumentation.log("Launchable.launch before click " +
+ mObject.getVisibleCenter());
+ LauncherInstrumentation.assertTrue(
+ "Launching an app didn't open a new window: " + mObject.getText(),
+ mObject.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS));
+ LauncherInstrumentation.assertTrue(
+ "App didn't start: " + errorMessage,
+ mLauncher.getDevice().wait(Until.hasObject(selector),
+ LauncherInstrumentation.WAIT_TIME_MS));
+ return new Background(mLauncher);
+ }
+
+ /**
+ * Drags an object to the center of homescreen.
+ */
+ public Workspace dragToWorkspace() {
+ final UiDevice device = mLauncher.getDevice();
+ mObject.drag(new Point(
+ device.getDisplayWidth() / 2, device.getDisplayHeight() / 2), DRAG_SPEED);
+ return new Workspace(mLauncher);
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Launcher.java b/tests/tapl/com/android/launcher3/tapl/Launcher.java
deleted file mode 100644
index 5201dc8..0000000
--- a/tests/tapl/com/android/launcher3/tapl/Launcher.java
+++ /dev/null
@@ -1,303 +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.tapl;
-
-import static com.android.systemui.shared.system.SettingsCompat.SWIPE_UP_SETTING_NAME;
-
-import android.content.res.Resources;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.util.Log;
-
-import org.junit.Assert;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-/**
- * The main tapl object. The only object that can be explicitly constructed by the using code. It
- * produces all other objects.
- */
-public final class Launcher {
-
- private static final String WORKSPACE_RES_ID = "workspace";
- private static final String APPS_RES_ID = "apps_view";
- private static final String OVERVIEW_RES_ID = "overview_panel";
- private static final String WIDGETS_RES_ID = "widgets_list_view";
-
- enum State {HOME, ALL_APPS, OVERVIEW, WIDGETS, BACKGROUND}
-
- static final String LAUNCHER_PKG = "com.google.android.apps.nexuslauncher";
- static final int APP_LAUNCH_TIMEOUT_MS = 10000;
- private static final int UI_OBJECT_WAIT_TIMEOUT_MS = 10000;
- private static final String SWIPE_UP_SETTING_AVAILABLE_RES_NAME =
- "config_swipe_up_gesture_setting_available";
- private static final String SWIPE_UP_ENABLED_DEFAULT_RES_NAME =
- "config_swipe_up_gesture_default";
- private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
- private static final String TAG = "tapl.Launcher";
- private final UiDevice mDevice;
- private final boolean mSwipeUpEnabled;
-
- /**
- * Constructs the root of TAPL hierarchy. You get all other object from it.
- */
- public Launcher(UiDevice device) {
- mDevice = device;
- final boolean swipeUpEnabledDefault =
- !getSystemBooleanRes(SWIPE_UP_SETTING_AVAILABLE_RES_NAME) ||
- getSystemBooleanRes(SWIPE_UP_ENABLED_DEFAULT_RES_NAME);
- mSwipeUpEnabled = Settings.Secure.getInt(
- InstrumentationRegistry.getTargetContext().getContentResolver(),
- SWIPE_UP_SETTING_NAME,
- swipeUpEnabledDefault ? 1 : 0) == 1;
- }
-
- private boolean getSystemBooleanRes(String resName) {
- final Resources res = Resources.getSystem();
- final int resId = res.getIdentifier(resName, "bool", "android");
- assertTrue("Resource not found: " + resName, resId != 0);
- return res.getBoolean(resId);
- }
-
- private void dumpViewHierarchy() {
- final ByteArrayOutputStream stream = new ByteArrayOutputStream();
- try {
- mDevice.dumpWindowHierarchy(stream);
- stream.flush();
- stream.close();
- for (String line : stream.toString().split("\\r?\\n")) {
- Log.e(TAG, line.trim());
- }
- } catch (IOException e) {
- Log.e(TAG, "error dumping XML to logcat", e);
- }
- }
-
- void fail(String message) {
- dumpViewHierarchy();
- Assert.fail(message);
- }
-
- void assertTrue(String message, boolean condition) {
- if (!condition) {
- fail(message);
- }
- }
-
- void assertNotNull(String message, Object object) {
- assertTrue(message, object != null);
- }
-
- private void failEquals(String message, Object actual) {
- String formatted = "Values should be different. ";
- if (message != null) {
- formatted = message + ". ";
- }
-
- formatted += "Actual: " + actual;
- fail(formatted);
- }
-
- void assertNotEquals(String message, int unexpected, int actual) {
- if (unexpected == actual) {
- failEquals(message, actual);
- }
- }
-
- boolean isSwipeUpEnabled() {
- return mSwipeUpEnabled;
- }
-
- UiObject2 assertState(State state) {
- switch (state) {
- case HOME: {
- //waitUntilGone(APPS_RES_ID);
- waitUntilGone(OVERVIEW_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
- return waitForLauncherObject(WORKSPACE_RES_ID);
- }
- case WIDGETS: {
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(APPS_RES_ID);
- waitUntilGone(OVERVIEW_RES_ID);
- return waitForLauncherObject(WIDGETS_RES_ID);
- }
- case ALL_APPS: {
- waitUntilGone(OVERVIEW_RES_ID);
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
- return waitForLauncherObject(APPS_RES_ID);
- }
- case OVERVIEW: {
- //waitForLauncherObject(APPS_RES_ID);
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
- return waitForLauncherObject(OVERVIEW_RES_ID);
- }
- case BACKGROUND: {
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(APPS_RES_ID);
- waitUntilGone(OVERVIEW_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
- return null;
- }
- default:
- fail("Invalid state: " + state);
- return null;
- }
- }
-
- /**
- * Presses nav bar home button.
- *
- * @return the Home object.
- */
- public Home pressHome() {
- getSystemUiObject("home").click();
- return getHome();
- }
-
- /**
- * Gets the Home object if the current state is "active home", i.e. workspace. Fails if the
- * launcher is not in that state.
- *
- * @return Home object.
- */
- @NonNull
- public Home getHome() {
- return new Home(this);
- }
-
- /**
- * Gets the Widgets object if the current state is showing all widgets. Fails if the launcher is
- * not in that state.
- *
- * @return Widgets object.
- */
- @NonNull
- public Widgets getAllWidgets() {
- return new Widgets(this);
- }
-
- /**
- * Gets the Overview object if the current state is showing the overview panel. Fails if the
- * launcher is not in that state.
- *
- * @return Overview object.
- */
- @NonNull
- public Overview getOverview() {
- return new Overview(this);
- }
-
- /**
- * Gets the All Apps object if the current state is showing the all apps panel. Fails if the
- * launcher is not in that state.
- *
- * @return All Aps object.
- */
- @NonNull
- public AllAppsFromHome getAllApps() {
- return new AllAppsFromHome(this);
- }
-
- /**
- * Gets the All Apps object if the current state is showing the all apps panel. Returns null if
- * the launcher is not in that state.
- *
- * @return All Aps object or null.
- */
- @Nullable
- public AllAppsFromHome tryGetAllApps() {
- return tryGetLauncherObject(APPS_RES_ID) != null ? getAllApps() : null;
- }
-
- private void waitUntilGone(String resId) {
-// assertTrue("Unexpected launcher object visible: " + resId,
-// mDevice.wait(Until.gone(getLauncherObjectSelector(resId)),
-// UI_OBJECT_WAIT_TIMEOUT_MS));
- }
-
- @NonNull
- UiObject2 getSystemUiObject(String resId) {
- try {
- mDevice.wakeUp();
- } catch (RemoteException e) {
- fail("Failed to wake up the device: " + e);
- }
- final UiObject2 object = mDevice.findObject(By.res(SYSTEMUI_PACKAGE, resId));
- assertNotNull("Can't find a systemui object with id: " + resId, object);
- return object;
- }
-
- @NonNull
- UiObject2 getObjectInContainer(UiObject2 container, BySelector selector) {
- final UiObject2 object = container.findObject(selector);
- assertNotNull("Can't find an object with selector: " + selector, object);
- return object;
- }
-
- @Nullable
- private UiObject2 tryGetLauncherObject(String resName) {
- return mDevice.findObject(getLauncherObjectSelector(resName));
- }
-
- @NonNull
- UiObject2 waitForObjectInContainer(UiObject2 container, String resName) {
- final UiObject2 object = container.wait(
- Until.findObject(getLauncherObjectSelector(resName)),
- UI_OBJECT_WAIT_TIMEOUT_MS);
- assertNotNull("Can find a launcher object id: " + resName + " in container: " +
- container.getResourceName(), object);
- return object;
- }
-
- @NonNull
- UiObject2 waitForLauncherObject(String resName) {
- final UiObject2 object = mDevice.wait(Until.findObject(getLauncherObjectSelector(resName)),
- UI_OBJECT_WAIT_TIMEOUT_MS);
- assertNotNull("Can find a launcher object; id: " + resName, object);
- return object;
- }
-
- static BySelector getLauncherObjectSelector(String resName) {
- return By.res(LAUNCHER_PKG, resName);
- }
-
- @NonNull
- UiDevice getDevice() {
- return mDevice;
- }
-
- void swipe(int startX, int startY, int endX, int endY, int steps) {
- mDevice.swipe(startX, startY, endX, endY, steps);
- waitForIdle();
- }
-
- void waitForIdle() {
- mDevice.waitForIdle();
- }
-}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
new file mode 100644
index 0000000..bd1c657
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -0,0 +1,413 @@
+/*
+ * 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.tapl;
+
+import static com.android.systemui.shared.system.SettingsCompat.SWIPE_UP_SETTING_NAME;
+
+import android.app.ActivityManager;
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.Surface;
+import android.view.accessibility.AccessibilityEvent;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import com.android.launcher3.TestProtocol;
+import com.android.quickstep.SwipeUpSetting;
+
+import org.junit.Assert;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * The main tapl object. The only object that can be explicitly constructed by the using code. It
+ * produces all other objects.
+ */
+public final class LauncherInstrumentation {
+
+ private static final String TAG = "Tapl";
+
+ // Types for launcher containers that the user is interacting with. "Background" is a
+ // pseudo-container corresponding to inactive launcher covered by another app.
+ enum ContainerType {
+ WORKSPACE, ALL_APPS, OVERVIEW, WIDGETS, BACKGROUND, BASE_OVERVIEW
+ }
+
+ // Base class for launcher containers.
+ static abstract class VisibleContainer {
+ protected final LauncherInstrumentation mLauncher;
+
+ protected VisibleContainer(LauncherInstrumentation launcher) {
+ mLauncher = launcher;
+ launcher.setActiveContainer(this);
+ }
+
+ protected abstract ContainerType getContainerType();
+
+ /**
+ * Asserts that the launcher is in the mode matching 'this' object.
+ *
+ * @return UI object for the container.
+ */
+ final UiObject2 verifyActiveContainer() {
+ assertTrue("Attempt to use a stale container", this == sActiveContainer.get());
+ return mLauncher.verifyContainerType(getContainerType());
+ }
+ }
+
+ private static final String WORKSPACE_RES_ID = "workspace";
+ private static final String APPS_RES_ID = "apps_view";
+ private static final String OVERVIEW_RES_ID = "overview_panel";
+ private static final String WIDGETS_RES_ID = "widgets_list_view";
+ static final String LAUNCHER_PKG = "com.google.android.apps.nexuslauncher";
+ public static final int WAIT_TIME_MS = 60000;
+ private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
+
+ private static WeakReference<VisibleContainer> sActiveContainer = new WeakReference<>(null);
+
+ private final UiDevice mDevice;
+ private final boolean mSwipeUpEnabled;
+ private Boolean mSwipeUpEnabledOverride = null;
+ private final Instrumentation mInstrumentation;
+ private int mExpectedRotation = Surface.ROTATION_0;
+
+ /**
+ * Constructs the root of TAPL hierarchy. You get all other objects from it.
+ */
+ public LauncherInstrumentation(Instrumentation instrumentation) {
+ mInstrumentation = instrumentation;
+ mDevice = UiDevice.getInstance(instrumentation);
+ final boolean swipeUpEnabledDefault =
+ !SwipeUpSetting.isSwipeUpSettingAvailable() ||
+ SwipeUpSetting.isSwipeUpEnabledDefaultValue();
+ mSwipeUpEnabled = Settings.Secure.getInt(
+ instrumentation.getTargetContext().getContentResolver(),
+ SWIPE_UP_SETTING_NAME,
+ swipeUpEnabledDefault ? 1 : 0) == 1;
+
+ // Launcher should run in test harness so that custom accessibility protocol between
+ // Launcher and TAPL is enabled. In-process tests enable this protocol with a direct call
+ // into Launcher.
+ assertTrue("Device must run in a test harness",
+ TestHelpers.isInLauncherProcess() || ActivityManager.isRunningInTestHarness());
+ }
+
+ // Used only by TaplTests.
+ public void overrideSwipeUpEnabled(Boolean swipeUpEnabledOverride) {
+ mSwipeUpEnabledOverride = swipeUpEnabledOverride;
+ }
+
+ void setActiveContainer(VisibleContainer container) {
+ sActiveContainer = new WeakReference<>(container);
+ }
+
+ public boolean isSwipeUpEnabled() {
+ return mSwipeUpEnabledOverride != null ? mSwipeUpEnabledOverride : mSwipeUpEnabled;
+ }
+
+ static void log(String message) {
+ Log.d(TAG, message);
+ }
+
+ private static void fail(String message) {
+ Assert.fail("http://go/tapl : " + message);
+ }
+
+ static void assertTrue(String message, boolean condition) {
+ if (!condition) {
+ fail(message);
+ }
+ }
+
+ static void assertNotNull(String message, Object object) {
+ assertTrue(message, object != null);
+ }
+
+ static private void failEquals(String message, Object actual) {
+ fail(message + ". " + "Actual: " + actual);
+ }
+
+ static public void assertEquals(String message, int expected, int actual) {
+ if (expected != actual) {
+ fail(message + " expected: " + expected + " but was: " + actual);
+ }
+ }
+
+ static void assertNotEquals(String message, int unexpected, int actual) {
+ if (unexpected == actual) {
+ failEquals(message, actual);
+ }
+ }
+
+ public void setExpectedRotation(int expectedRotation) {
+ mExpectedRotation = expectedRotation;
+ }
+
+ private UiObject2 verifyContainerType(ContainerType containerType) {
+ assertEquals("Unexpected display rotation",
+ mExpectedRotation, mDevice.getDisplayRotation());
+ assertTrue("Presence of recents button doesn't match isSwipeUpEnabled()",
+ isSwipeUpEnabled() ==
+ (mDevice.findObject(By.res(SYSTEMUI_PACKAGE, "recent_apps")) == null));
+ log("verifyContainerType: " + containerType);
+
+ switch (containerType) {
+ case WORKSPACE: {
+ waitForLauncherObject(APPS_RES_ID);
+ waitUntilGone(OVERVIEW_RES_ID);
+ waitUntilGone(WIDGETS_RES_ID);
+ return waitForLauncherObject(WORKSPACE_RES_ID);
+ }
+ case WIDGETS: {
+ waitUntilGone(WORKSPACE_RES_ID);
+ waitUntilGone(APPS_RES_ID);
+ waitUntilGone(OVERVIEW_RES_ID);
+ return waitForLauncherObject(WIDGETS_RES_ID);
+ }
+ case ALL_APPS: {
+ waitUntilGone(WORKSPACE_RES_ID);
+ waitUntilGone(OVERVIEW_RES_ID);
+ waitUntilGone(WIDGETS_RES_ID);
+ return waitForLauncherObject(APPS_RES_ID);
+ }
+ case OVERVIEW: {
+ if (mDevice.isNaturalOrientation()) {
+ waitForLauncherObject(APPS_RES_ID);
+ } else {
+ waitUntilGone(APPS_RES_ID);
+ }
+ // Fall through
+ }
+ case BASE_OVERVIEW: {
+ waitUntilGone(WORKSPACE_RES_ID);
+ waitUntilGone(WIDGETS_RES_ID);
+
+ return waitForLauncherObject(OVERVIEW_RES_ID);
+ }
+ case BACKGROUND: {
+ waitUntilGone(WORKSPACE_RES_ID);
+ waitUntilGone(APPS_RES_ID);
+ waitUntilGone(OVERVIEW_RES_ID);
+ waitUntilGone(WIDGETS_RES_ID);
+ return null;
+ }
+ default:
+ fail("Invalid state: " + containerType);
+ return null;
+ }
+ }
+
+ private Parcelable executeAndWaitForEvent(Runnable command,
+ UiAutomation.AccessibilityEventFilter eventFilter, String message) {
+ try {
+ final AccessibilityEvent event =
+ mInstrumentation.getUiAutomation().executeAndWaitForEvent(
+ command, eventFilter, WAIT_TIME_MS);
+ assertNotNull("executeAndWaitForEvent returned null (this can't happen)", event);
+ return event.getParcelableData();
+ } catch (TimeoutException e) {
+ fail(message);
+ return null;
+ }
+ }
+
+ Bundle getAnswerFromLauncher(UiObject2 view, String requestTag) {
+ // Send a fake set-text request to Launcher to initiate a response with requested data.
+ final String responseTag = requestTag + TestProtocol.RESPONSE_MESSAGE_POSTFIX;
+ return (Bundle) executeAndWaitForEvent(
+ () -> view.setText(requestTag),
+ event -> responseTag.equals(event.getClassName()),
+ "Launcher didn't respond to request: " + requestTag);
+ }
+
+ /**
+ * Presses nav bar home button.
+ *
+ * @return the Workspace object.
+ */
+ public Workspace pressHome() {
+ // Click home, then wait for any accessibility event, then wait until accessibility events
+ // stop.
+ // We need waiting for any accessibility event generated after pressing Home because
+ // otherwise waitForIdle may return immediately in case when there was a big enough pause in
+ // accessibility events prior to pressing Home.
+ executeAndWaitForEvent(
+ () -> {
+ log("LauncherInstrumentation.pressHome before clicking");
+ getSystemUiObject("home").click();
+ },
+ event -> true,
+ "Pressing Home didn't produce any events");
+ mDevice.waitForIdle();
+ return getWorkspace();
+ }
+
+ /**
+ * Gets the Workspace object if the current state is "active home", i.e. workspace. Fails if the
+ * launcher is not in that state.
+ *
+ * @return Workspace object.
+ */
+ @NonNull
+ public Workspace getWorkspace() {
+ return new Workspace(this);
+ }
+
+ /**
+ * Gets the Workspace object if the current state is "background home", i.e. some other app is
+ * active. Fails if the launcher is not in that state.
+ *
+ * @return Background object.
+ */
+ @NonNull
+ public Background getBackground() {
+ return new Background(this);
+ }
+
+ /**
+ * Gets the Widgets object if the current state is showing all widgets. Fails if the launcher is
+ * not in that state.
+ *
+ * @return Widgets object.
+ */
+ @NonNull
+ public Widgets getAllWidgets() {
+ return new Widgets(this);
+ }
+
+ /**
+ * Gets the Overview object if the current state is showing the overview panel. Fails if the
+ * launcher is not in that state.
+ *
+ * @return Overview object.
+ */
+ @NonNull
+ public Overview getOverview() {
+ return new Overview(this);
+ }
+
+ /**
+ * Gets the Base overview object if either Launcher is in overview state or the fallback
+ * overview activity is showing. Fails otherwise.
+ *
+ * @return BaseOverview object.
+ */
+ @NonNull
+ public BaseOverview getBaseOverview() {
+ return new BaseOverview(this);
+ }
+
+ /**
+ * Gets the All Apps object if the current state is showing the all apps panel opened by swiping
+ * from workspace. Fails if the launcher is not in that state. Please don't call this method if
+ * App Apps was opened by swiping up from Overview, as it won't fail and will return an
+ * incorrect object.
+ *
+ * @return All Aps object.
+ */
+ @NonNull
+ public AllApps getAllApps() {
+ return new AllApps(this);
+ }
+
+ /**
+ * Gets the All Apps object if the current state is showing the all apps panel opened by swiping
+ * from overview. Fails if the launcher is not in that state. Please don't call this method if
+ * App Apps was opened by swiping up from home, as it won't fail and will return an
+ * incorrect object.
+ *
+ * @return All Aps object.
+ */
+ @NonNull
+ public AllAppsFromOverview getAllAppsFromOverview() {
+ return new AllAppsFromOverview(this);
+ }
+
+ private void waitUntilGone(String resId) {
+ assertTrue("Unexpected launcher object visible: " + resId,
+ mDevice.wait(Until.gone(getLauncherObjectSelector(resId)),
+ WAIT_TIME_MS));
+ }
+
+ @NonNull
+ UiObject2 getSystemUiObject(String resId) {
+ final UiObject2 object = mDevice.findObject(By.res(SYSTEMUI_PACKAGE, resId));
+ assertNotNull("Can't find a systemui object with id: " + resId, object);
+ return object;
+ }
+
+ @NonNull
+ UiObject2 getObjectInContainer(UiObject2 container, BySelector selector) {
+ final UiObject2 object = container.findObject(selector);
+ assertNotNull("Can't find an object with selector: " + selector, object);
+ return object;
+ }
+
+ @NonNull
+ UiObject2 waitForObjectInContainer(UiObject2 container, String resName) {
+ final UiObject2 object = container.wait(
+ Until.findObject(getLauncherObjectSelector(resName)),
+ WAIT_TIME_MS);
+ assertNotNull("Can't find a launcher object id: " + resName + " in container: " +
+ container.getResourceName(), object);
+ return object;
+ }
+
+ @NonNull
+ UiObject2 waitForLauncherObject(String resName) {
+ final UiObject2 object = mDevice.wait(Until.findObject(getLauncherObjectSelector(resName)),
+ WAIT_TIME_MS);
+ assertNotNull("Can't find a launcher object; id: " + resName, object);
+ return object;
+ }
+
+ static BySelector getLauncherObjectSelector(String resName) {
+ return By.res(LAUNCHER_PKG, resName);
+ }
+
+ @NonNull
+ UiDevice getDevice() {
+ return mDevice;
+ }
+
+ void longTap(int x, int y) {
+ mDevice.drag(x, y, x, y, 0);
+ }
+
+
+ void swipe(int startX, int startY, int endX, int endY) {
+ executeAndWaitForEvent(
+ () -> mDevice.swipe(startX, startY, endX, endY, 60),
+ event -> TestProtocol.SWITCHED_TO_STATE_MESSAGE.equals(event.getClassName()),
+ "Swipe failed to receive an event for the swipe end: " + startX + ", " + startY
+ + ", " + endX + ", " + endY);
+ }
+
+ void waitForIdle() {
+ mDevice.waitForIdle();
+ }
+}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
index 2251655..9e0c07f 100644
--- a/tests/tapl/com/android/launcher3/tapl/Overview.java
+++ b/tests/tapl/com/android/launcher3/tapl/Overview.java
@@ -17,76 +17,25 @@
package com.android.launcher3.tapl;
import android.graphics.Point;
-import android.support.annotation.NonNull;
-import android.support.test.uiautomator.Direction;
-import android.support.test.uiautomator.UiObject2;
-import java.util.Collections;
-import java.util.List;
+import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.UiObject2;
/**
* Overview pane.
*/
-public final class Overview {
- private static final int DEFAULT_FLING_SPEED = 15000;
+public final class Overview extends BaseOverview {
- private final Launcher mLauncher;
-
- Overview(Launcher launcher) {
- mLauncher = launcher;
- assertState();
+ Overview(LauncherInstrumentation launcher) {
+ super(launcher);
+ verifyActiveContainer();
}
- /**
- * Asserts that we are in overview.
- *
- * @return Overview panel.
- */
- @NonNull
- private UiObject2 assertState() {
- return mLauncher.assertState(Launcher.State.OVERVIEW);
- }
-
- /**
- * Flings forward (left) and waits the fling's end.
- */
- public void flingForward() {
- final UiObject2 overview = assertState();
- overview.fling(Direction.LEFT, DEFAULT_FLING_SPEED);
- mLauncher.waitForIdle();
- assertState();
- }
-
- /**
- * Flings backward (right) and waits the fling's end.
- */
- public void flingBackward() {
- final UiObject2 overview = assertState();
- overview.fling(Direction.RIGHT, DEFAULT_FLING_SPEED);
- mLauncher.waitForIdle();
- assertState();
- }
-
- /**
- * Gets the current task in the carousel, or fails if the carousel is empty.
- *
- * @return the task in the middle of the visible tasks list.
- */
- @NonNull
- public OverviewTask getCurrentTask() {
- assertState();
- final List<UiObject2> taskViews = mLauncher.getDevice().findObjects(
- Launcher.getLauncherObjectSelector("snapshot"));
- mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
-
- // taskViews contains up to 3 task views: the 'main' (having the widest visible
- // part) one in the center, and parts of its right and left siblings. Find the
- // main task view by its width.
- final UiObject2 widestTask = Collections.max(taskViews,
- (t1, t2) -> Integer.compare(t1.getVisibleBounds().width(),
- t2.getVisibleBounds().width()));
-
- return new OverviewTask(mLauncher, widestTask);
+ @Override
+ protected ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.OVERVIEW;
}
/**
@@ -96,15 +45,13 @@
*/
@NonNull
public AllAppsFromOverview switchToAllApps() {
- assertState();
+ verifyActiveContainer();
- // Swipe from the hotseat to near the top, e.g. 10% of the screen.
- final UiObject2 predictionRow = mLauncher.waitForLauncherObject(
- "prediction_row");
- final Point start = predictionRow.getVisibleCenter();
- final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f);
- mLauncher.swipe(
- start.x, start.y, start.x, endY, (start.y - endY) / 100); // 100 px/step
+ // Swipe from navbar to the top.
+ final UiObject2 navBar = mLauncher.getSystemUiObject("navigation_bar_frame");
+ final Point start = navBar.getVisibleCenter();
+ LauncherInstrumentation.log("Overview.switchToAllApps before swipe");
+ mLauncher.swipe(start.x, start.y, start.x, 0);
return new AllAppsFromOverview(mLauncher);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 68d3082..48686c4 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -16,37 +16,34 @@
package com.android.launcher3.tapl;
-import android.support.test.uiautomator.Direction;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
+import androidx.test.uiautomator.Direction;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
/**
* A recent task in the overview panel carousel.
*/
public final class OverviewTask {
- private final Launcher mLauncher;
+ private final LauncherInstrumentation mLauncher;
private final UiObject2 mTask;
+ private final BaseOverview mOverview;
- OverviewTask(Launcher launcher, UiObject2 task) {
+ OverviewTask(LauncherInstrumentation launcher, UiObject2 task, BaseOverview overview) {
mLauncher = launcher;
- assertState();
mTask = task;
+ mOverview = overview;
+ verifyActiveContainer();
}
- /**
- * Asserts that we are in overview.
- *
- * @return Overview panel.
- */
- private void assertState() {
- mLauncher.assertState(Launcher.State.OVERVIEW);
+ private void verifyActiveContainer() {
+ mOverview.verifyActiveContainer();
}
/**
* Swipes the task up.
*/
public void dismiss() {
- assertState();
+ verifyActiveContainer();
// Dismiss the task via flinging it up.
mTask.fling(Direction.DOWN);
mLauncher.waitForIdle();
@@ -55,11 +52,11 @@
/**
* Clicks at the task.
*/
- public void open() {
- assertState();
- mLauncher.assertTrue("Launching task didn't open a new window: " +
+ public Background open() {
+ verifyActiveContainer();
+ LauncherInstrumentation.assertTrue("Launching task didn't open a new window: " +
mTask.getParent().getContentDescription(),
- mTask.clickAndWait(Until.newWindow(), Launcher.APP_LAUNCH_TIMEOUT_MS));
- mLauncher.assertState(Launcher.State.BACKGROUND);
+ mTask.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS));
+ return new Background(mLauncher);
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java
new file mode 100644
index 0000000..93554d2
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java
@@ -0,0 +1,84 @@
+/*
+ * 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.tapl;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static androidx.test.InstrumentationRegistry.getTargetContext;
+
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+
+import java.util.List;
+
+public class TestHelpers {
+
+ private static Boolean sIsInLauncherProcess;
+
+ public static boolean isInLauncherProcess() {
+ if (sIsInLauncherProcess == null) {
+ sIsInLauncherProcess = initIsInLauncherProcess();
+ }
+ return sIsInLauncherProcess;
+ }
+
+ private static boolean initIsInLauncherProcess() {
+ ActivityInfo info = getLauncherInMyProcess();
+
+ // If we are in the same process, we can instantiate the class name.
+ try {
+ Class launcherClazz = Class.forName("com.android.launcher3.Launcher");
+ return launcherClazz.isAssignableFrom(Class.forName(info.name));
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ public static Intent getHomeIntentInPackage(Context context) {
+ return new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setPackage(context.getPackageName())
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+
+ public static ActivityInfo getLauncherInMyProcess() {
+ Instrumentation instrumentation = getInstrumentation();
+ if (instrumentation.getTargetContext() == null) {
+ return null;
+ }
+
+ List<ResolveInfo> launchers = getTargetContext().getPackageManager()
+ .queryIntentActivities(getHomeIntentInPackage(getTargetContext()), 0);
+ if (launchers.size() != 1) {
+ return null;
+ }
+ return launchers.get(0).activityInfo;
+ }
+
+ public static String getOverviewPackageName() {
+ Resources res = Resources.getSystem();
+ int id = res.getIdentifier("config_recentsComponentName", "string", "android");
+ if (id != 0) {
+ return ComponentName.unflattenFromString(res.getString(id)).getPackageName();
+ }
+ return "com.android.systemui";
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 7a5198a..facf1c6 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -16,50 +16,43 @@
package com.android.launcher3.tapl;
-import android.support.annotation.NonNull;
-import android.support.test.uiautomator.Direction;
-import android.support.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Direction;
+import androidx.test.uiautomator.UiObject2;
/**
* All widgets container.
*/
-public final class Widgets {
+public final class Widgets extends LauncherInstrumentation.VisibleContainer {
private static final int FLING_SPEED = 12000;
- private final Launcher mLauncher;
-
- Widgets(Launcher launcher) {
- mLauncher = launcher;
- assertState();
+ Widgets(LauncherInstrumentation launcher) {
+ super(launcher);
+ verifyActiveContainer();
}
/**
* Flings forward (down) and waits the fling's end.
*/
public void flingForward() {
- final UiObject2 widgetsContainer = assertState();
+ final UiObject2 widgetsContainer = verifyActiveContainer();
+ widgetsContainer.setGestureMargin(100);
widgetsContainer.fling(Direction.DOWN, FLING_SPEED);
- mLauncher.waitForIdle();
- assertState();
+ verifyActiveContainer();
}
/**
* Flings backward (up) and waits the fling's end.
*/
public void flingBackward() {
- final UiObject2 widgetsContainer = assertState();
+ final UiObject2 widgetsContainer = verifyActiveContainer();
+ widgetsContainer.setGestureMargin(100);
widgetsContainer.fling(Direction.UP, FLING_SPEED);
mLauncher.waitForIdle();
- assertState();
+ verifyActiveContainer();
}
- /**
- * Asserts that we are in widgets.
- *
- * @return Widgets container.
- */
- @NonNull
- private UiObject2 assertState() {
- return mLauncher.assertState(Launcher.State.WIDGETS);
+ @Override
+ protected LauncherInstrumentation.ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.WIDGETS;
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
new file mode 100644
index 0000000..c63822e
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -0,0 +1,166 @@
+/*
+ * 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.tapl;
+
+import static junit.framework.TestCase.assertTrue;
+
+import android.graphics.Point;
+import android.view.KeyEvent;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.uiautomator.Direction;
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * Operations on the workspace screen.
+ */
+public final class Workspace extends Home {
+ private final UiObject2 mHotseat;
+ private final int ICON_DRAG_SPEED = 2000;
+
+ Workspace(LauncherInstrumentation launcher) {
+ super(launcher);
+ mHotseat = launcher.waitForLauncherObject("hotseat");
+ }
+
+ /**
+ * Swipes up to All Apps.
+ *
+ * @return the App Apps object.
+ */
+ @NonNull
+ public AllApps switchToAllApps() {
+ verifyActiveContainer();
+ if (mLauncher.isSwipeUpEnabled()) {
+ int midX = mLauncher.getDevice().getDisplayWidth() / 2;
+ int height = mLauncher.getDevice().getDisplayHeight();
+ // Swipe from 6/7ths down the screen to 1/7th down the screen.
+ mLauncher.swipe(
+ midX,
+ height * 6 / 7,
+ midX,
+ height / 7
+ );
+ } else {
+ // Swipe from the hotseat to near the top, e.g. 10% of the screen.
+ final UiObject2 hotseat = mHotseat;
+ final Point start = hotseat.getVisibleCenter();
+ final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f);
+ mLauncher.swipe(
+ start.x,
+ start.y,
+ start.x,
+ endY
+ );
+ }
+
+ return new AllApps(mLauncher);
+ }
+
+ /**
+ * Returns an icon for the app, if currently visible.
+ *
+ * @param appName name of the app
+ * @return app icon, if found, null otherwise.
+ */
+ @Nullable
+ public AppIcon tryGetWorkspaceAppIcon(String appName) {
+ final UiObject2 workspace = verifyActiveContainer();
+ final UiObject2 icon = workspace.findObject(AppIcon.getAppIconSelector(appName));
+ return icon != null ? new AppIcon(mLauncher, icon) : null;
+ }
+
+
+ /**
+ * Returns an icon for the app; fails if the icon doesn't exist.
+ *
+ * @param appName name of the app
+ * @return app icon.
+ */
+ @NonNull
+ public AppIcon getWorkspaceAppIcon(String appName) {
+ return new AppIcon(mLauncher,
+ mLauncher.getObjectInContainer(
+ verifyActiveContainer(),
+ AppIcon.getAppIconSelector(appName)));
+ }
+
+ /**
+ * Ensures that workspace is scrollable. If it's not, drags an icon icons from hotseat to the
+ * second screen.
+ */
+ public void ensureWorkspaceIsScrollable() {
+ final UiObject2 workspace = verifyActiveContainer();
+ if (!isWorkspaceScrollable(workspace)) {
+ dragIconToNextScreen(getHotseatAppIcon("Messages"), workspace);
+ }
+ assertTrue("Home screen workspace didn't become scrollable",
+ isWorkspaceScrollable(workspace));
+ }
+
+ private boolean isWorkspaceScrollable(UiObject2 workspace) {
+ return workspace.isScrollable();
+ }
+
+ @NonNull
+ private AppIcon getHotseatAppIcon(String appName) {
+ return new AppIcon(mLauncher, mLauncher.getObjectInContainer(
+ mHotseat, AppIcon.getAppIconSelector(appName)));
+ }
+
+ private void dragIconToNextScreen(AppIcon app, UiObject2 workspace) {
+ final Point dest = new Point(
+ mLauncher.getDevice().getDisplayWidth(), workspace.getVisibleBounds().centerY());
+ app.getObject().drag(dest, ICON_DRAG_SPEED);
+ verifyActiveContainer();
+ }
+
+ /**
+ * Flings to get to screens on the right. Waits for scrolling and a possible overscroll
+ * recoil to complete.
+ */
+ public void flingForward() {
+ final UiObject2 workspace = verifyActiveContainer();
+ workspace.fling(Direction.RIGHT);
+ mLauncher.waitForIdle();
+ verifyActiveContainer();
+ }
+
+ /**
+ * Flings to get to screens on the left. Waits for scrolling and a possible overscroll
+ * recoil to complete.
+ */
+ public void flingBackward() {
+ final UiObject2 workspace = verifyActiveContainer();
+ workspace.fling(Direction.LEFT);
+ mLauncher.waitForIdle();
+ verifyActiveContainer();
+ }
+
+ /**
+ * Opens widgets container by pressing Ctrl+W.
+ *
+ * @return the widgets container.
+ */
+ @NonNull
+ public Widgets openAllWidgets() {
+ verifyActiveContainer();
+ mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
+ return new Widgets(mLauncher);
+ }
+}
\ No newline at end of file