summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk62
-rw-r--r--build.gradle32
-rw-r--r--go/AndroidManifest.xml53
-rw-r--r--go/res/layout/widget_cell_content.xml66
-rw-r--r--go/res/values-af/strings.xml26
-rw-r--r--go/res/values-am/strings.xml26
-rw-r--r--go/res/values-ar/strings.xml26
-rw-r--r--go/res/values-az-rAZ/strings.xml26
-rw-r--r--go/res/values-b+sr+Latn/strings.xml26
-rw-r--r--go/res/values-bs-rBA/strings.xml26
-rw-r--r--go/res/values-da/strings.xml26
-rw-r--r--go/res/values-en-rAU/strings.xml26
-rw-r--r--go/res/values-en-rGB/strings.xml26
-rw-r--r--go/res/values-en-rIN/strings.xml26
-rw-r--r--go/res/values-fa/strings.xml26
-rw-r--r--go/res/values-hr/strings.xml26
-rw-r--r--go/res/values-in/strings.xml26
-rw-r--r--go/res/values-it/strings.xml26
-rw-r--r--go/res/values-ja/strings.xml26
-rw-r--r--go/res/values-ka-rGE/strings.xml26
-rw-r--r--go/res/values-ky-rKG/strings.xml26
-rw-r--r--go/res/values-lo-rLA/strings.xml26
-rw-r--r--go/res/values-lt/strings.xml26
-rw-r--r--go/res/values-nl/strings.xml26
-rw-r--r--go/res/values-pl/strings.xml26
-rw-r--r--go/res/values-pt-rPT/strings.xml26
-rw-r--r--go/res/values-pt/strings.xml26
-rw-r--r--go/res/values-si-rLK/strings.xml26
-rw-r--r--go/res/values-sk/strings.xml26
-rw-r--r--go/res/values-sl/strings.xml26
-rw-r--r--go/res/values-sr/strings.xml26
-rw-r--r--go/res/values-sv/strings.xml26
-rw-r--r--go/res/values-sw/strings.xml26
-rw-r--r--go/res/values-tr/strings.xml26
-rw-r--r--go/res/values-uk/strings.xml26
-rw-r--r--go/res/values-uz-rUZ/strings.xml26
-rw-r--r--go/res/values-zu/strings.xml26
-rw-r--r--go/res/values/strings.xml33
-rw-r--r--go/src_flags/com/android/launcher3/config/FeatureFlags.java28
-rw-r--r--proto_overrides/launcher_log_extension.proto30
-rw-r--r--protos/launcher_log.proto6
-rw-r--r--res/drawable/all_apps_alpha_mask.pngbin16512 -> 0 bytes
-rw-r--r--res/drawable/gutter_horizontal.xml9
-rw-r--r--res/drawable/ic_warning.xml27
-rw-r--r--res/interpolator/large_folder_preview_item_close_interpolator.xml24
-rw-r--r--res/interpolator/large_folder_preview_item_open_interpolator.xml (renamed from res/interpolator/large_folder_preview_item_interpolator.xml)2
-rw-r--r--res/layout-land/launcher.xml21
-rw-r--r--res/layout-port/launcher.xml7
-rw-r--r--res/layout-sw720dp/launcher.xml7
-rw-r--r--res/layout/all_apps.xml4
-rw-r--r--res/layout/gradient_scrim.xml31
-rw-r--r--res/layout/horizontal_divider.xml5
-rw-r--r--res/layout/notification.xml24
-rw-r--r--res/layout/notification_main.xml2
-rw-r--r--res/layout/notification_pref_warning.xml24
-rw-r--r--res/layout/page_indicator.xml4
-rw-r--r--res/layout/popup_container.xml4
-rw-r--r--res/layout/search_container_all_apps.xml (renamed from res/layout/all_apps_search_container.xml)2
-rw-r--r--res/layout/search_container_workspace.xml (renamed from res/layout/qsb_container.xml)2
-rw-r--r--res/layout/user_folder.xml2
-rw-r--r--res/layout/user_folder_icon_normalized.xml2
-rw-r--r--res/values-af/strings.xml15
-rw-r--r--res/values-am/strings.xml15
-rw-r--r--res/values-ar/strings.xml15
-rw-r--r--res/values-b+sr+Latn/strings.xml15
-rw-r--r--res/values-be/strings.xml21
-rw-r--r--res/values-bg/strings.xml15
-rw-r--r--res/values-ca/strings.xml19
-rw-r--r--res/values-cs/strings.xml15
-rw-r--r--res/values-da/strings.xml15
-rw-r--r--res/values-de/strings.xml15
-rw-r--r--res/values-el/strings.xml15
-rw-r--r--res/values-en-rAU/strings.xml15
-rw-r--r--res/values-en-rGB/strings.xml15
-rw-r--r--res/values-en-rIN/strings.xml15
-rw-r--r--res/values-es-rUS/strings.xml15
-rw-r--r--res/values-es/strings.xml15
-rw-r--r--res/values-et/strings.xml19
-rw-r--r--res/values-fa/strings.xml15
-rw-r--r--res/values-fi/strings.xml15
-rw-r--r--res/values-fr-rCA/strings.xml15
-rw-r--r--res/values-fr/strings.xml17
-rw-r--r--res/values-hi/strings.xml15
-rw-r--r--res/values-hr/strings.xml15
-rw-r--r--res/values-hu/strings.xml15
-rw-r--r--res/values-in/strings.xml15
-rw-r--r--res/values-it/strings.xml15
-rw-r--r--res/values-iw/strings.xml15
-rw-r--r--res/values-ja/strings.xml15
-rw-r--r--res/values-ko/strings.xml15
-rw-r--r--res/values-land/dimens.xml9
-rw-r--r--res/values-lt/strings.xml15
-rw-r--r--res/values-lv/strings.xml15
-rw-r--r--res/values-ms/strings.xml19
-rw-r--r--res/values-nb/strings.xml15
-rw-r--r--res/values-nl/strings.xml15
-rw-r--r--res/values-pl/strings.xml15
-rw-r--r--res/values-pt-rPT/strings.xml15
-rw-r--r--res/values-pt/strings.xml15
-rw-r--r--res/values-ro/strings.xml15
-rw-r--r--res/values-ru/strings.xml15
-rw-r--r--res/values-sk/strings.xml15
-rw-r--r--res/values-sl/strings.xml15
-rw-r--r--res/values-sr/strings.xml15
-rw-r--r--res/values-sv/strings.xml15
-rw-r--r--res/values-sw/strings.xml15
-rw-r--r--res/values-sw720dp/dimens.xml1
-rw-r--r--res/values-sw720dp/styles.xml2
-rw-r--r--res/values-th/strings.xml17
-rw-r--r--res/values-tl/strings.xml15
-rw-r--r--res/values-tr/strings.xml15
-rw-r--r--res/values-uk/strings.xml15
-rw-r--r--res/values-vi/strings.xml15
-rw-r--r--res/values-zh-rCN/strings.xml15
-rw-r--r--res/values-zh-rHK/strings.xml15
-rw-r--r--res/values-zh-rTW/strings.xml15
-rw-r--r--res/values-zu/strings.xml15
-rw-r--r--res/values/config.xml8
-rw-r--r--res/values/dimens.xml7
-rw-r--r--res/values/strings.xml12
-rw-r--r--res/values/styles.xml9
-rw-r--r--res/xml/launcher_preferences.xml7
-rw-r--r--src/com/android/launcher3/AppWidgetsRestoredReceiver.java34
-rw-r--r--src/com/android/launcher3/BaseActivity.java6
-rw-r--r--src/com/android/launcher3/BubbleTextView.java11
-rw-r--r--src/com/android/launcher3/CellLayout.java10
-rw-r--r--src/com/android/launcher3/DeviceProfile.java85
-rw-r--r--src/com/android/launcher3/FirstFrameAnimatorHelper.java8
-rw-r--r--src/com/android/launcher3/IconCache.java20
-rw-r--r--src/com/android/launcher3/ItemInfo.java13
-rw-r--r--src/com/android/launcher3/Launcher.java58
-rw-r--r--src/com/android/launcher3/LauncherAppWidgetHost.java109
-rw-r--r--src/com/android/launcher3/LauncherModel.java3
-rw-r--r--src/com/android/launcher3/LauncherProvider.java2
-rw-r--r--src/com/android/launcher3/LauncherStateTransitionAnimation.java4
-rw-r--r--src/com/android/launcher3/PagedView.java110
-rw-r--r--src/com/android/launcher3/SettingsActivity.java94
-rw-r--r--src/com/android/launcher3/Utilities.java24
-rw-r--r--src/com/android/launcher3/WidgetPreviewLoader.java2
-rw-r--r--src/com/android/launcher3/Workspace.java107
-rw-r--r--src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java6
-rw-r--r--src/com/android/launcher3/allapps/AllAppsCaretController.java3
-rw-r--r--src/com/android/launcher3/allapps/AllAppsContainerView.java39
-rw-r--r--src/com/android/launcher3/allapps/AllAppsGridAdapter.java20
-rw-r--r--src/com/android/launcher3/allapps/AllAppsRecyclerView.java167
-rw-r--r--src/com/android/launcher3/allapps/AllAppsTransitionController.java36
-rw-r--r--src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java3
-rw-r--r--src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java54
-rw-r--r--src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java2
-rw-r--r--src/com/android/launcher3/anim/SpringAnimationHandler.java58
-rw-r--r--src/com/android/launcher3/compat/AppWidgetManagerCompat.java6
-rw-r--r--src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java33
-rw-r--r--src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java5
-rw-r--r--src/com/android/launcher3/compat/WallpaperColorsCompat.java1
-rw-r--r--src/com/android/launcher3/config/BaseFlags.java73
-rw-r--r--src/com/android/launcher3/dragndrop/AddItemActivity.java28
-rw-r--r--src/com/android/launcher3/dragndrop/DragView.java323
-rw-r--r--src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java175
-rw-r--r--src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java59
-rw-r--r--src/com/android/launcher3/dynamicui/WallpaperColorInfo.java6
-rw-r--r--src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java69
-rw-r--r--src/com/android/launcher3/folder/Folder.java34
-rw-r--r--src/com/android/launcher3/folder/FolderAnimationManager.java84
-rw-r--r--src/com/android/launcher3/folder/FolderIcon.java296
-rw-r--r--src/com/android/launcher3/folder/FolderIconPreviewVerifier.java27
-rw-r--r--src/com/android/launcher3/folder/FolderPagedView.java10
-rw-r--r--src/com/android/launcher3/folder/FolderPreviewItemAnim.java30
-rw-r--r--src/com/android/launcher3/folder/PreviewBackground.java26
-rw-r--r--src/com/android/launcher3/folder/PreviewItemManager.java359
-rw-r--r--src/com/android/launcher3/folder/StackFolderIconLayoutRule.java15
-rw-r--r--src/com/android/launcher3/graphics/GradientView.java87
-rw-r--r--src/com/android/launcher3/graphics/LauncherIcons.java35
-rw-r--r--src/com/android/launcher3/graphics/ScrimView.java115
-rw-r--r--src/com/android/launcher3/graphics/ShadowGenerator.java19
-rw-r--r--src/com/android/launcher3/logging/LoggerUtils.java16
-rw-r--r--src/com/android/launcher3/logging/UserEventDispatcher.java79
-rw-r--r--src/com/android/launcher3/model/LoaderCursor.java4
-rw-r--r--src/com/android/launcher3/model/LoaderTask.java20
-rw-r--r--src/com/android/launcher3/model/ShortcutsChangedTask.java6
-rw-r--r--src/com/android/launcher3/model/UserLockStateChangedTask.java3
-rw-r--r--src/com/android/launcher3/notification/FlingAnimationUtils.java356
-rw-r--r--src/com/android/launcher3/notification/NotificationFooterLayout.java5
-rw-r--r--src/com/android/launcher3/notification/NotificationItemView.java43
-rw-r--r--src/com/android/launcher3/notification/NotificationListener.java24
-rw-r--r--src/com/android/launcher3/notification/NotificationMainView.java85
-rw-r--r--src/com/android/launcher3/notification/SwipeHelper.java687
-rw-r--r--src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java2
-rw-r--r--src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java9
-rw-r--r--src/com/android/launcher3/popup/PopupContainerWithArrow.java95
-rw-r--r--src/com/android/launcher3/provider/RestoreDbTask.java2
-rw-r--r--src/com/android/launcher3/qsb/QsbContainerView.java9
-rw-r--r--src/com/android/launcher3/shortcuts/ShortcutsItemView.java17
-rw-r--r--src/com/android/launcher3/touch/OverScroll.java55
-rw-r--r--src/com/android/launcher3/touch/SwipeDetector.java (renamed from src/com/android/launcher3/allapps/VerticalPullDetector.java)188
-rw-r--r--src/com/android/launcher3/util/LauncherEdgeEffect.java365
-rw-r--r--src/com/android/launcher3/views/ButtonPreference.java70
-rw-r--r--src/com/android/launcher3/views/DoubleShadowBubbleTextView.java28
-rw-r--r--src/com/android/launcher3/widget/PendingAddShortcutInfo.java1
-rw-r--r--src/com/android/launcher3/widget/WidgetAddFlowHandler.java18
-rw-r--r--src/com/android/launcher3/widget/WidgetsBottomSheet.java54
-rw-r--r--src_flags/com/android/launcher3/config/FeatureFlags.java43
-rw-r--r--tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java20
-rw-r--r--tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java7
-rw-r--r--tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java275
-rw-r--r--tests/src/com/android/launcher3/touch/SwipeDetectorTest.java115
-rw-r--r--tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java3
206 files changed, 4819 insertions, 3131 deletions
diff --git a/Android.mk b/Android.mk
index c8a53d23d..d41e184f0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,7 +17,7 @@
LOCAL_PATH := $(call my-dir)
#
-# Build app code.
+# Build rule for Launcher3 app.
#
include $(CLEAR_VARS)
@@ -33,7 +33,8 @@ LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
$(call all-java-files-under, src_config) \
$(call all-java-files-under, src_flags) \
- $(call all-proto-files-under, protos)
+ $(call all-proto-files-under, protos) \
+ $(call all-proto-files-under, proto_overrides)
LOCAL_RESOURCE_DIR := \
$(LOCAL_PATH)/res \
@@ -42,7 +43,7 @@ LOCAL_RESOURCE_DIR := \
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ --proto_path=$(LOCAL_PATH)/proto_overrides/
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := enum_style=java
LOCAL_AAPT_FLAGS := \
@@ -62,14 +63,65 @@ LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.launcher3.*
include $(BUILD_PACKAGE)
#
+# Build rule for Launcher3 Go app for Android Go devices.
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-v4 \
+ android-support-v7-recyclerview \
+ android-support-v7-palette \
+ android-support-dynamic-animation
+
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src) \
+ $(call all-java-files-under, src_config) \
+ $(call all-java-files-under, go/src_flags) \
+ $(call all-proto-files-under, protos) \
+ $(call all-proto-files-under, proto_overrides)
+
+LOCAL_RESOURCE_DIR := \
+ $(LOCAL_PATH)/go/res \
+ $(LOCAL_PATH)/res \
+ prebuilts/sdk/current/support/v7/recyclerview/res \
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ --proto_path=$(LOCAL_PATH)/proto_overrides/
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := enum_style=java
+
+LOCAL_AAPT_FLAGS := \
+ --auto-add-overlay \
+ --extra-packages android.support.v7.recyclerview \
+
+LOCAL_SDK_VERSION := current
+LOCAL_MIN_SDK_VERSION := 21
+LOCAL_PACKAGE_NAME := Launcher3Go
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3
+
+LOCAL_FULL_LIBS_MANIFEST_FILES := \
+ $(LOCAL_PATH)/AndroidManifest.xml \
+ $(LOCAL_PATH)/AndroidManifest-common.xml
+
+LOCAL_MANIFEST_FILE := go/AndroidManifest.xml
+
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.launcher3.*
+
+include $(BUILD_PACKAGE)
+
+#
# Launcher proto buffer jar used for development
#
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-proto-files-under, protos)
+LOCAL_SRC_FILES := $(call all-proto-files-under, protos) $(call all-proto-files-under, proto_overrides)
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ --proto_path=$(LOCAL_PATH)/proto_overrides/
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := enum_style=java
LOCAL_MODULE_TAGS := optional
diff --git a/build.gradle b/build.gradle
index c23a29920..886ccace6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -35,28 +35,49 @@ android {
applicationId 'com.android.launcher3'
testApplicationId 'com.android.launcher3.tests'
}
+
+ l3go {
+ applicationId 'com.android.launcher3'
+ testApplicationId 'com.android.launcher3.tests'
+ }
}
sourceSets {
main {
res.srcDirs = ['res']
- java.srcDirs = ['src', 'src_flags']
+ java.srcDirs = ['src']
manifest.srcFile 'AndroidManifest-common.xml'
- proto.srcDirs 'protos/'
+ proto {
+ srcDir 'protos/'
+ srcDir 'proto_overrides/'
+ }
}
androidTest {
- java.srcDirs = ['tests/src']
res.srcDirs = ['tests/res']
+ java.srcDirs = ['tests/src']
manifest.srcFile "tests/AndroidManifest-common.xml"
}
aosp {
+ java.srcDirs = ['src_flags']
manifest.srcFile "AndroidManifest.xml"
}
aospAndroidTest {
manifest.srcFile "tests/AndroidManifest.xml"
}
+
+ l3go {
+ res.srcDirs = ['go/res']
+ java.srcDirs = ['go/src_flags']
+ // Note: we are using the Launcher3 manifest here because the gradle manifest-merger uses
+ // different attributes than the build system.
+ manifest.srcFile "AndroidManifest.xml"
+ }
+
+ l3goAndroidTest {
+ manifest.srcFile "tests/AndroidManifest.xml"
+ }
}
}
@@ -71,10 +92,10 @@ dependencies {
compile "com.android.support:support-dynamic-animation:${SUPPORT_LIBS_VERSION}"
compile "com.android.support:recyclerview-v7:${SUPPORT_LIBS_VERSION}"
compile "com.android.support:palette-v7:${SUPPORT_LIBS_VERSION}"
- compile 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-2'
+ compile 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7'
testCompile 'junit:junit:4.12'
- androidTestCompile "org.mockito:mockito-core:1.+"
+ androidTestCompile "org.mockito:mockito-core:1.9.5"
androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
androidTestCompile 'com.android.support.test:runner:0.5'
@@ -92,6 +113,7 @@ protobuf {
task.builtins {
remove java
javanano {
+ option "java_package=launcher_log_extension.proto|com.android.launcher3.userevent.nano"
option "java_package=launcher_log.proto|com.android.launcher3.userevent.nano"
option "java_package=launcher_dump.proto|com.android.launcher3.model.nano"
option "enum_style=java"
diff --git a/go/AndroidManifest.xml b/go/AndroidManifest.xml
new file mode 100644
index 000000000..ed8e0ad3b
--- /dev/null
+++ b/go/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.launcher3" >
+
+ <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
+
+ <application
+ android:backupAgent="com.android.launcher3.LauncherBackupAgent"
+ android:fullBackupOnly="true"
+ android:fullBackupContent="@xml/backupscheme"
+ android:hardwareAccelerated="true"
+ android:icon="@drawable/ic_launcher_home"
+ android:label="@string/derived_app_name"
+ android:theme="@style/LauncherTheme"
+ android:largeHeap="@bool/config_largeHeap"
+ android:restoreAnyVersion="true"
+ android:supportsRtl="true" >
+
+ <!-- Activity for handling PinItemRequest. Only supports shortcuts -->
+ <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"
+ tools:merge="override" >
+ <intent-filter>
+ <action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
+ </intent-filter>
+ </activity>
+
+ </application>
+
+</manifest>
diff --git a/go/res/layout/widget_cell_content.xml b/go/res/layout/widget_cell_content.xml
new file mode 100644
index 000000000..49506d9be
--- /dev/null
+++ b/go/res/layout/widget_cell_content.xml
@@ -0,0 +1,66 @@
+<?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
new file mode 100644
index 000000000..10ac473c1
--- /dev/null
+++ b/go/res/values-af/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..b3b253f42
--- /dev/null
+++ b/go/res/values-am/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..2b3b80746
--- /dev/null
+++ b/go/res/values-ar/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..c4b8cb780
--- /dev/null
+++ b/go/res/values-az-rAZ/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..0da569941
--- /dev/null
+++ b/go/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,26 @@
+<?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-bs-rBA/strings.xml b/go/res/values-bs-rBA/strings.xml
new file mode 100644
index 000000000..7042468b4
--- /dev/null
+++ b/go/res/values-bs-rBA/strings.xml
@@ -0,0 +1,26 @@
+<?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">"Dvaput dodirnite 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-da/strings.xml b/go/res/values-da/strings.xml
new file mode 100644
index 000000000..821d36a7d
--- /dev/null
+++ b/go/res/values-da/strings.xml
@@ -0,0 +1,26 @@
+<?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-en-rAU/strings.xml b/go/res/values-en-rAU/strings.xml
new file mode 100644
index 000000000..2ee2c2645
--- /dev/null
+++ b/go/res/values-en-rAU/strings.xml
@@ -0,0 +1,26 @@
+<?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 &amp; hold to pick up a shortcut."</string>
+ <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap &amp; 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
new file mode 100644
index 000000000..2ee2c2645
--- /dev/null
+++ b/go/res/values-en-rGB/strings.xml
@@ -0,0 +1,26 @@
+<?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 &amp; hold to pick up a shortcut."</string>
+ <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap &amp; 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
new file mode 100644
index 000000000..2ee2c2645
--- /dev/null
+++ b/go/res/values-en-rIN/strings.xml
@@ -0,0 +1,26 @@
+<?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 &amp; hold to pick up a shortcut."</string>
+ <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap &amp; 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-fa/strings.xml b/go/res/values-fa/strings.xml
new file mode 100644
index 000000000..8bc5256d1
--- /dev/null
+++ b/go/res/values-fa/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..fccdeb59d
--- /dev/null
+++ b/go/res/values-hr/strings.xml
@@ -0,0 +1,26 @@
+<?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-in/strings.xml b/go/res/values-in/strings.xml
new file mode 100644
index 000000000..c8b9da306
--- /dev/null
+++ b/go/res/values-in/strings.xml
@@ -0,0 +1,26 @@
+<?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 &amp; 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-it/strings.xml b/go/res/values-it/strings.xml
new file mode 100644
index 000000000..bc5d99863
--- /dev/null
+++ b/go/res/values-it/strings.xml
@@ -0,0 +1,26 @@
+<?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-ja/strings.xml b/go/res/values-ja/strings.xml
new file mode 100644
index 000000000..8f02d7f4e
--- /dev/null
+++ b/go/res/values-ja/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..1b4653478
--- /dev/null
+++ b/go/res/values-ka-rGE/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..4c7e973ce
--- /dev/null
+++ b/go/res/values-ky-rKG/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..7864884ac
--- /dev/null
+++ b/go/res/values-lo-rLA/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..8f49032cf
--- /dev/null
+++ b/go/res/values-lt/strings.xml
@@ -0,0 +1,26 @@
+<?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-nl/strings.xml b/go/res/values-nl/strings.xml
new file mode 100644
index 000000000..5bcd016b4
--- /dev/null
+++ b/go/res/values-nl/strings.xml
@@ -0,0 +1,26 @@
+<?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-pl/strings.xml b/go/res/values-pl/strings.xml
new file mode 100644
index 000000000..45a1dc2ca
--- /dev/null
+++ b/go/res/values-pl/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..7a75a0545
--- /dev/null
+++ b/go/res/values-pt-rPT/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..53bbfc41a
--- /dev/null
+++ b/go/res/values-pt/strings.xml
@@ -0,0 +1,26 @@
+<?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-si-rLK/strings.xml b/go/res/values-si-rLK/strings.xml
new file mode 100644
index 000000000..4b25c90b0
--- /dev/null
+++ b/go/res/values-si-rLK/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..fc0293373
--- /dev/null
+++ b/go/res/values-sk/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..6ecedfb16
--- /dev/null
+++ b/go/res/values-sl/strings.xml
@@ -0,0 +1,26 @@
+<?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-sr/strings.xml b/go/res/values-sr/strings.xml
new file mode 100644
index 000000000..0b9aea2f9
--- /dev/null
+++ b/go/res/values-sr/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..c3f434c27
--- /dev/null
+++ b/go/res/values-sv/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..0379ed012
--- /dev/null
+++ b/go/res/values-sw/strings.xml
@@ -0,0 +1,26 @@
+<?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">"Gonga 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-tr/strings.xml b/go/res/values-tr/strings.xml
new file mode 100644
index 000000000..f0f3cce6d
--- /dev/null
+++ b/go/res/values-tr/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..8d1f58395
--- /dev/null
+++ b/go/res/values-uk/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..318bc1572
--- /dev/null
+++ b/go/res/values-uz-rUZ/strings.xml
@@ -0,0 +1,26 @@
+<?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-zu/strings.xml b/go/res/values-zu/strings.xml
new file mode 100644
index 000000000..e5051df1f
--- /dev/null
+++ b/go/res/values-zu/strings.xml
@@ -0,0 +1,26 @@
+<?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
new file mode 100644
index 000000000..8ef2e6243
--- /dev/null
+++ b/go/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?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 &amp; 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 &amp; 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_flags/com/android/launcher3/config/FeatureFlags.java
new file mode 100644
index 000000000..5bb2ac9a2
--- /dev/null
+++ b/go/src_flags/com/android/launcher3/config/FeatureFlags.java
@@ -0,0 +1,28 @@
+/*
+ * 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.config;
+
+/**
+ * Defines a set of flags used to control various launcher behaviors
+ */
+public final class FeatureFlags extends BaseFlags {
+
+ private FeatureFlags() {}
+
+ // Features to control Launcher3Go behavior
+ public static final boolean GO_DISABLE_WIDGETS = true;
+}
diff --git a/proto_overrides/launcher_log_extension.proto b/proto_overrides/launcher_log_extension.proto
new file mode 100644
index 000000000..2995aa283
--- /dev/null
+++ b/proto_overrides/launcher_log_extension.proto
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+syntax = "proto2";
+
+option java_package = "com.android.launcher3.userevent";
+option java_outer_classname = "LauncherLogExtensions";
+
+package userevent;
+
+//
+// Use this to add any app specific extensions to the proto.
+//
+message LauncherEventExtension {
+}
+
+message TargetExtension {
+}
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index 93e09aea8..0bbec188d 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -15,6 +15,8 @@
*/
syntax = "proto2";
+import "launcher_log_extension.proto";
+
option java_package = "com.android.launcher3.userevent";
option java_outer_classname = "LauncherLogProto";
@@ -52,6 +54,7 @@ message Target {
optional int32 span_x = 13 [default = 1];// Used for ItemType.WIDGET
optional int32 span_y = 14 [default = 1];// Used for ItemType.WIDGET
optional int32 predictedRank = 15;
+ optional TargetExtension extension = 16;
}
// Used to define what type of item a Target would represent.
@@ -144,7 +147,6 @@ message Action {
// Action (Touch) + Target + Target
//
message LauncherEvent {
-
required Action action = 1;
// List of targets that touch actions can be operated on.
@@ -157,4 +159,6 @@ message LauncherEvent {
optional bool is_in_multi_window_mode = 7;
optional bool is_in_landscape_mode = 8;
+
+ optional LauncherEventExtension extension = 9;
}
diff --git a/res/drawable/all_apps_alpha_mask.png b/res/drawable/all_apps_alpha_mask.png
deleted file mode 100644
index ed53ff924..000000000
--- a/res/drawable/all_apps_alpha_mask.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/gutter_horizontal.xml b/res/drawable/gutter_horizontal.xml
new file mode 100644
index 000000000..95b03df27
--- /dev/null
+++ b/res/drawable/gutter_horizontal.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This "gutter" has a shadow at the top and a subtler shadow on the bottom. -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <gradient android:type="linear"
+ android:angle="-90"
+ android:startColor="#ffE0E0E0"
+ android:centerColor="#ffffffff"
+ android:endColor="#ffF5F5F5" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/ic_warning.xml b/res/drawable/ic_warning.xml
new file mode 100644
index 000000000..332563dc2
--- /dev/null
+++ b/res/drawable/ic_warning.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/textColorPrimary" >
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M22.85,19.39L12.93,2.25c-0.41-0.71-1.44-0.71-1.85,0L1.15,19.39C0.73,20.11,1.25,21,2.07,21h19.85
+ C22.75,21,23.27,20.11,22.85,19.39z M11,10c0-0.55,0.45-1,1-1s1,0.45,1,1v3c0,0.55-0.45,1-1,1s-1-0.45-1-1V10z M12,18.2
+ c-0.61,0-1.1-0.49-1.1-1.1S11.39,16,12,16s1.1,0.49,1.1,1.1C13.1,17.71,12.61,18.2,12,18.2z"/>
+</vector>
diff --git a/res/interpolator/large_folder_preview_item_close_interpolator.xml b/res/interpolator/large_folder_preview_item_close_interpolator.xml
new file mode 100644
index 000000000..d28af63f8
--- /dev/null
+++ b/res/interpolator/large_folder_preview_item_close_interpolator.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.3"
+ android:controlY1="0"
+ android:controlX2="1"
+ android:controlY2="1"/>
diff --git a/res/interpolator/large_folder_preview_item_interpolator.xml b/res/interpolator/large_folder_preview_item_open_interpolator.xml
index dcf01579b..b5661abab 100644
--- a/res/interpolator/large_folder_preview_item_interpolator.xml
+++ b/res/interpolator/large_folder_preview_item_open_interpolator.xml
@@ -20,5 +20,5 @@
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:controlX1="0"
android:controlY1="1"
- android:controlX2="0"
+ android:controlX2="0.5"
android:controlY2="1"/>
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 2bbd76d52..dab074391 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -42,7 +42,12 @@
android:layout_gravity="center"
launcher:pageIndicator="@id/page_indicator" />
- <include layout="@layout/gradient_scrim" />
+ <com.android.launcher3.graphics.GradientView
+ android:id="@+id/gradient_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ launcher:layout_ignoreInsets="true"/>
<!-- DO NOT CHANGE THE ID -->
<include layout="@layout/hotseat"
@@ -60,13 +65,6 @@
android:id="@+id/overview_panel"
android:visibility="gone" />
- <com.android.launcher3.pageindicators.PageIndicatorCaretLandscape
- android:id="@+id/page_indicator"
- android:theme="@style/HomeScreenElementTheme"
- android:layout_width="@dimen/dynamic_grid_page_indicator_size"
- android:layout_height="@dimen/dynamic_grid_page_indicator_size"
- android:layout_gravity="bottom|left"/>
-
<include layout="@layout/widgets_view"
android:id="@+id/widgets_view"
android:layout_width="match_parent"
@@ -79,6 +77,13 @@
android:layout_height="match_parent"
android:visibility="invisible" />
+ <com.android.launcher3.pageindicators.PageIndicatorCaretLandscape
+ android:id="@+id/page_indicator"
+ android:theme="@style/HomeScreenElementTheme"
+ android:layout_width="@dimen/dynamic_grid_min_page_indicator_size"
+ android:layout_height="@dimen/dynamic_grid_min_page_indicator_size"
+ android:layout_gravity="bottom|left"/>
+
</com.android.launcher3.dragndrop.DragLayer>
</com.android.launcher3.LauncherRootView>
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 93c90780b..bace51aac 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -44,7 +44,12 @@
launcher:pageIndicator="@+id/page_indicator">
</com.android.launcher3.Workspace>
- <include layout="@layout/gradient_scrim" />
+ <com.android.launcher3.graphics.GradientView
+ android:id="@+id/gradient_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ launcher:layout_ignoreInsets="true"/>
<!-- DO NOT CHANGE THE ID -->
<include layout="@layout/hotseat"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index ca4d846f1..18d235c1d 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -43,7 +43,12 @@
launcher:pageIndicator="@id/page_indicator">
</com.android.launcher3.Workspace>
- <include layout="@layout/gradient_scrim" />
+ <com.android.launcher3.graphics.GradientView
+ android:id="@+id/gradient_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ launcher:layout_ignoreInsets="true"/>
<!-- DO NOT CHANGE THE ID -->
<include layout="@layout/hotseat"
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 93662fc08..6340619ab 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -49,7 +49,7 @@
<!-- DO NOT CHANGE THE ID -->
<com.android.launcher3.allapps.AllAppsRecyclerView
android:id="@+id/apps_list_view"
- android:layout_below="@+id/search_container"
+ android:layout_below="@id/search_container_all_apps"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal|top"
@@ -62,7 +62,7 @@
platform bug, which prevents using custom attributes in <include> tag -->
<include
layout="?android:attr/keyboardLayout"
- android:id="@+id/search_container" />
+ android:id="@id/search_container_all_apps" />
<include layout="@layout/all_apps_fast_scroller" />
diff --git a/res/layout/gradient_scrim.xml b/res/layout/gradient_scrim.xml
deleted file mode 100644
index c40c5fc0c..000000000
--- a/res/layout/gradient_scrim.xml
+++ /dev/null
@@ -1,31 +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"
- xmlns:app="http://schemas.android.com/apk/res-auto">
- <com.android.launcher3.graphics.GradientView
- android:id="@+id/gradient_bg"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone"
- app:layout_ignoreInsets="true"/>
-
- <com.android.launcher3.graphics.ScrimView
- android:id="@+id/scrim_bg"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone"
- app:layout_ignoreInsets="true"/>
-</merge> \ No newline at end of file
diff --git a/res/layout/horizontal_divider.xml b/res/layout/horizontal_divider.xml
deleted file mode 100644
index 167f8f5d8..000000000
--- a/res/layout/horizontal_divider.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<View xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="@dimen/popup_item_divider_height"
- android:background="?attr/popupColorTertiary" /> \ No newline at end of file
diff --git a/res/layout/notification.xml b/res/layout/notification.xml
index 085dfa93c..4a02aa169 100644
--- a/res/layout/notification.xml
+++ b/res/layout/notification.xml
@@ -28,6 +28,13 @@
android:orientation="vertical"
android:clipChildren="false">
+ <View
+ android:id="@+id/gutter_top"
+ android:layout_width="match_parent"
+ android:layout_height="4dp"
+ android:theme="@style/PopupGutter"
+ android:visibility="gone" />
+
<FrameLayout
android:id="@+id/header"
android:layout_width="match_parent"
@@ -35,22 +42,23 @@
android:paddingStart="@dimen/notification_padding_start"
android:paddingEnd="@dimen/notification_padding_end"
android:background="?attr/popupColorPrimary"
- android:elevation="@dimen/notification_elevation">
+ android:elevation="@dimen/notification_elevation"
+ android:layout_below="@id/gutter_top" >
<TextView
android:id="@+id/notification_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
- android:gravity="center_vertical"
+ android:gravity="bottom"
android:text="@string/notifications_header"
android:textSize="@dimen/notification_header_text_size"
- android:textColor="?android:attr/textColorSecondary" />
+ android:textColor="?android:attr/textColorPrimary" />
<TextView
android:id="@+id/notification_count"
android:layout_width="@dimen/notification_icon_size"
android:layout_height="match_parent"
android:layout_gravity="end"
- android:gravity="center"
+ android:gravity="bottom|center_horizontal"
android:textSize="@dimen/notification_header_count_text_size"
android:fontFamily="sans-serif-medium"
android:textColor="?android:attr/textColorPrimary" />
@@ -76,6 +84,14 @@
android:layout_height="@dimen/notification_footer_height"
android:layout_below="@id/divider" />
+ <View
+ android:id="@+id/gutter_bottom"
+ android:layout_width="match_parent"
+ android:layout_height="4dp"
+ android:theme="@style/PopupGutter"
+ android:visibility="gone"
+ android:layout_below="@id/footer" />
+
</RelativeLayout>
</com.android.launcher3.notification.NotificationItemView>
diff --git a/res/layout/notification_main.xml b/res/layout/notification_main.xml
index 7a8cf6d5c..f681e8b06 100644
--- a/res/layout/notification_main.xml
+++ b/res/layout/notification_main.xml
@@ -38,7 +38,7 @@
android:layout_height="wrap_content"
android:textAlignment="viewStart"
android:fontFamily="sans-serif"
- android:textSize="@dimen/notification_main_text_size"
+ android:textSize="@dimen/notification_main_title_size"
android:textColor="?android:attr/textColorPrimary"
android:lines="1"
android:ellipsize="end" />
diff --git a/res/layout/notification_pref_warning.xml b/res/layout/notification_pref_warning.xml
new file mode 100644
index 000000000..795699e99
--- /dev/null
+++ b/res/layout/notification_pref_warning.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.
+-->
+<ImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/title_missing_notification_access"
+ android:scaleType="center"
+ android:src="@drawable/ic_warning"
+ android:tint="?android:attr/textColorSecondary" />
diff --git a/res/layout/page_indicator.xml b/res/layout/page_indicator.xml
index 14ff2bd28..92f52d672 100644
--- a/res/layout/page_indicator.xml
+++ b/res/layout/page_indicator.xml
@@ -18,11 +18,11 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="@style/HomeScreenElementTheme"
android:layout_width="match_parent"
- android:layout_height="@dimen/dynamic_grid_page_indicator_size">
+ android:layout_height="@dimen/dynamic_grid_min_page_indicator_size">
<ImageView
android:id="@+id/all_apps_handle"
android:layout_width="48dp"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/dynamic_grid_min_page_indicator_size"
android:layout_gravity="top|center"
android:scaleType="centerInside"/>
</com.android.launcher3.pageindicators.PageIndicatorLineCaret>
diff --git a/res/layout/popup_container.xml b/res/layout/popup_container.xml
index e9cfe24ee..67db4a561 100644
--- a/res/layout/popup_container.xml
+++ b/res/layout/popup_container.xml
@@ -19,8 +19,8 @@
android:id="@+id/deep_shortcuts_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
android:clipToPadding="false"
android:clipChildren="false"
android:elevation="@dimen/deep_shortcuts_elevation"
diff --git a/res/layout/all_apps_search_container.xml b/res/layout/search_container_all_apps.xml
index 2528034eb..c4305214d 100644
--- a/res/layout/all_apps_search_container.xml
+++ b/res/layout/search_container_all_apps.xml
@@ -15,7 +15,7 @@
-->
<com.android.launcher3.allapps.search.AppsSearchContainerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/search_container"
+ android:id="@id/search_container_all_apps"
android:layout_width="match_parent"
android:layout_height="@dimen/all_apps_search_bar_height"
android:layout_gravity="center|top"
diff --git a/res/layout/qsb_container.xml b/res/layout/search_container_workspace.xml
index 6fa843d63..1c617b174 100644
--- a/res/layout/qsb_container.xml
+++ b/res/layout/search_container_workspace.xml
@@ -19,7 +19,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:id="@+id/qsb_container"
+ android:id="@id/search_container_workspace"
android:padding="0dp" >
<fragment
diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml
index 4d80aac29..afa19b897 100644
--- a/res/layout/user_folder.xml
+++ b/res/layout/user_folder.xml
@@ -29,7 +29,7 @@
android:layout_height="match_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp"
- android:paddingTop="6dp"
+ android:paddingTop="16dp"
launcher:pageIndicator="@+id/folder_page_indicator" />
<LinearLayout
diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml
index e91f96659..2e6ce946f 100644
--- a/res/layout/user_folder_icon_normalized.xml
+++ b/res/layout/user_folder_icon_normalized.xml
@@ -29,7 +29,7 @@
android:layout_height="match_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp"
- android:paddingTop="6dp"
+ android:paddingTop="16dp"
launcher:pageIndicator="@+id/folder_page_indicator" />
<LinearLayout
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index fe00d7af8..d71b4c78b 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breed by %2$d hoog"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Raak en hou om self te plaas"</string>
<string name="place_automatically" msgid="8064208734425456485">"Voeg outomaties by"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Deursoek programme"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Laai tans programme …"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Geen programme gevind wat met \"<xliff:g id="QUERY">%1$s</xliff:g>\" ooreenstem nie"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Deursoek programme"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Laai tans programme …"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Kon geen programme kry wat by \"<xliff:g id="QUERY">%1$s</xliff:g>\" pas nie"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Soek meer programme"</string>
<string name="notifications_header" msgid="1404149926117359025">"Kennisgewings"</string>
<string name="out_of_space" msgid="4691004494942118364">"Niks meer spasie op die tuisskerm nie."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Kennisgewingkolle"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Aan"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Af"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Kennisgewingtoegang word benodig"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Skakel programkennisgewings vir <xliff:g id="NAME">%1$s</xliff:g> aan om kennisgewingkolle te sien"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Verander instellings"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Voeg ikoon by tuisskerm"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Vir nuwe programme"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Verander ikoon se vorm"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Gebruik stelselverstek"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Vierkant"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Sirkelvierkant"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Sirkel"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Traandruppel"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Pas ikoonvormveranderings toe"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Onbekend"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Verwyder"</string>
<string name="abandoned_search" msgid="891119232568284442">"Soek"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index aebb428fb..293b452f6 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"መተግበሪያዎችን ይፈልጉ"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"መተግበሪያዎችን በመጫን ላይ..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"ከ«<xliff:g id="QUERY">%1$s</xliff:g>» ጋር የሚዛመዱ ምንም መተግበሪያዎች አልተገኙም"</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="out_of_space" msgid="4691004494942118364">"በዚህ መነሻ ማያ ገጽ ላይ ምንም ቦታ የለም።"</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"አዶ ወደ የመነሻ ማያ ገጽ አክል"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ለአዲስ መተግበሪያዎች"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"የአዶ ቅርፅ ለውጥ"</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">"Squircle"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"ክብ"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"የእንባ ጠብታ"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index a45e40ed7..6447bf015 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"البحث في التطبيقات"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"جارٍ تحميل التطبيقات…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"لم يتم العثور على أية تطبيقات تتطابق مع \"<xliff:g id="QUERY">%1$s</xliff:g>\""</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="out_of_space" msgid="4691004494942118364">"ليس هناك مساحة أخرى في هذه الشاشة الرئيسية."</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"إضافة رمز إلى الشاشة الرئيسية"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"للتطبيقات الجديدة"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"تغيير شكل الرمز"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index cb296f422..777512a96 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"širina od %1$d i visina od %2$d"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Dodirnite i zadržite da biste postavili ručno"</string>
<string name="place_automatically" msgid="8064208734425456485">"Automatski dodaj"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pretražite aplikacije"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Aplikacije se učitavaju..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nije pronađena nijedna aplikacija za „<xliff:g id="QUERY">%1$s</xliff:g>“"</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 „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Pretraži još aplikacija"</string>
<string name="notifications_header" msgid="1404149926117359025">"Obaveštenja"</string>
<string name="out_of_space" msgid="4691004494942118364">"Nema više prostora na ovom početnom ekranu."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Tačke za obaveš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 za obaveštenja"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Da biste prikazali tačke za obaveštenja, uključite obaveštenja za aplikaciju <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Promenite podešavanja"</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>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Promenite oblik ikona"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Koristi podrazumevano sistemsko podešavanje"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Primenjuju se promene 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>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index f5dba2dae..615fd5704 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -41,7 +41,7 @@
<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="app_info_drop_target_label" msgid="692894985365717661">"Звесткі пра праграмы"</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>
@@ -65,12 +65,26 @@
<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="8119458837558863227">"Налады"</string>
+ <string name="settings_button_text" msgid="8873672322605444408">"Налады галоўнага экрана"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Адключаная адміністратарам"</string>
<string name="accessibility_action_overview" msgid="6257665857640347026">"Агляд"</string>
<string name="allow_rotation_title" msgid="7728578836261442095">"Дазволіць паварот галоўнага экрана"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Пры павароце тэлефона"</string>
<string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Бягучая налада дысплэя не прадугледжвае паварот"</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="auto_add_shortcuts_label" msgid="8222286205987725611">"Дадаць значок на Галоўны экран"</string>
+ <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Для новых праграм"</string>
+ <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
+ <skip />
+ <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>
+ <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
+ <skip />
<string name="package_state_unknown" msgid="7592128424511031410">"Невядома"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Выдаліць"</string>
<string name="abandoned_search" msgid="891119232568284442">"Шукаць"</string>
@@ -104,4 +118,7 @@
<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>
</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index d5df3f231..3e05e0be5 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"Търсене в приложенията"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Приложенията се зареждат…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Няма намерени приложения, съответстващи на „<xliff:g id="QUERY">%1$s</xliff:g>“"</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="out_of_space" msgid="4691004494942118364">"На този начален екран няма повече място."</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"Добавяне на икона към началния екран"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"За нови приложения"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Промяна на формата на иконите"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 88b02bb1b..b1a1f85e0 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d d\'amplada per %2$d d\'alçada"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Toca i mantén premut l\'element per col·locar-lo manualment"</string>
<string name="place_automatically" msgid="8064208734425456485">"Afegeix automàticament"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Cerca a les aplicacions"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"S\'estan carregant les aplicacions..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"No s\'ha trobat cap aplicació que coincideixi amb <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cerca aplicacions"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"S\'estan carregant les aplicacions…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"No s\'ha trobat cap aplicació que coincideixi amb \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Cerca més aplicacions"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notificacions"</string>
<string name="out_of_space" msgid="4691004494942118364">"Ja no queda espai en aquesta pantalla d\'inici."</string>
@@ -77,19 +77,20 @@
<string name="allow_rotation_desc" msgid="8662546029078692509">"En girar el telèfon"</string>
<string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"La configuració actual de la pantalla no permet la rotació"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Punts de notificació"</string>
- <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activada"</string>
- <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivada"</string>
+ <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activat"</string>
+ <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivat"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Cal que tingui accés a les notificacions"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Per veure els punts de notificació, activa les notificacions de l\'aplicació <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Canvia la configuració"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Afegeix la icona a la pantalla d\'inici"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Per a les aplicacions noves"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Canvia la forma de les icones"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Utilitza l\'opció predeterminada del sistema"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Quadrat"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Quadrat arrodonit"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Cercle"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Llàgrima"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"S\'estan aplicant els canvis de forma de les icones"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Desconegut"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Suprimeix"</string>
<string name="abandoned_search" msgid="891119232568284442">"Cerca"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 1a80e396c..abc44c714 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"šířka %1$d, výška %2$d"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Chcete-li položku umístit ručně, klepněte na ni a podržte ji"</string>
<string name="place_automatically" msgid="8064208734425456485">"Přidat automaticky"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Hledat aplikace"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Načítání aplikací…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Dotazu „<xliff:g id="QUERY">%1$s</xliff:g>“ neodpovídají žádné aplikace"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hledat v aplikacích"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Načítání aplikací…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Dotazu „<xliff:g id="QUERY">%1$s</xliff:g>“ neodpovídají žádné aplikace"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Vyhledat další aplikace"</string>
<string name="notifications_header" msgid="1404149926117359025">"Oznámení"</string>
<string name="out_of_space" msgid="4691004494942118364">"Na této ploše již není místo."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Puntíky s oznámeními"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Zapnuto"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Vypnuto"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Je třeba udělit přístup k oznámením"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Chcete-li zobrazovat puntíky s oznámeními, zapněte oznámení z aplikace <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Změnit nastavení"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Přidat ikonu na plochu"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pro nové aplikace"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Změnit tvar ikony"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Použít výchozí nastavení systému"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Čtverec"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Kruh/čtverec"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Kruh"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Slza"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Tvar ikony se mění"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Neznámé"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Odstranit"</string>
<string name="abandoned_search" msgid="891119232568284442">"Hledat"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 17316b3b5..653105e05 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d i bredden og %2$d i højden"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Tryk, og hold fingeren nede for at placere manuelt"</string>
<string name="place_automatically" msgid="8064208734425456485">"Tilføj automatisk"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Søg i Apps"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Indlæser apps…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Der blev ikke fundet nogen apps, som matcher \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Søg efter apps"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Indlæser apps…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Der blev ikke fundet nogen apps, som matcher \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Søg efter flere apps"</string>
<string name="notifications_header" msgid="1404149926117359025">"Underretninger"</string>
<string name="out_of_space" msgid="4691004494942118364">"Der er ikke mere plads på denne startskærm."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Underretningscirkler"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Til"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Fra"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Kræver adgang til underretninger"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Hvis du vil se underretningscirkler, skal du aktivere appunderretninger for <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Skift indstillinger"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Føj ikon til startskærmen"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For nye apps"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Skift ikonform"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Brug systemstandarden"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Kvadrat med runde hjørner"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Cirkel"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Dråbeform"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Anvender ændringer af ikonform"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Ukendt"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Fjern"</string>
<string name="abandoned_search" msgid="891119232568284442">"Søg"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 72f7399dc..1c4cd7a7c 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breit und %2$d hoch"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Zum manuellen Hinzufügen gedrückt halten"</string>
<string name="place_automatically" msgid="8064208734425456485">"Automatisch hinzufügen"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"In Apps suchen"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Apps werden geladen..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Keine Apps für \"<xliff:g id="QUERY">%1$s</xliff:g>\" gefunden"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Apps finden"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Apps werden geladen…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Keine Apps für \"<xliff:g id="QUERY">%1$s</xliff:g>\" gefunden"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Weitere Apps suchen"</string>
<string name="notifications_header" msgid="1404149926117359025">"Benachrichtigungen"</string>
<string name="out_of_space" msgid="4691004494942118364">"Auf diesem Startbildschirm ist kein Platz mehr vorhanden."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"App-Benachrichtigungspunkte"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Aktiviert"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Deaktiviert"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Benachrichtigungszugriff erforderlich"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Um dir Benachrichtigungspunkte anzeigen zu lassen, aktiviere die Benachrichtigungen für die App \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Einstellungen ändern"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Symbol zu Startbildschirm hinzufügen"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Für neue Apps"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Form des Symbols ändern"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Systemstandardeinstellung verwenden"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Quadrat"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Superkreis"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Kreis"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Träne"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Änderungen an der Form des Symbols werden übernommen"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Unbekannt"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Entfernen"</string>
<string name="abandoned_search" msgid="891119232568284442">"Suchen"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 406101c73..25c8866b8 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"Αναζήτηση εφαρμογών"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Φόρτωση εφαρμογών…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Δεν βρέθηκαν εφαρμογές για το ερώτημα \"<xliff:g id="QUERY">%1$s</xliff:g>\""</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="out_of_space" msgid="4691004494942118364">"Δεν υπάρχει χώρος σε αυτήν την αρχική οθόνη."</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"Προσθήκη εικονιδίου στην Αρχική οθόνη"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Για νέες εφαρμογές"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Αλλαγή σχήματος εικονιδίου"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 4e0ba03cd..f3f10cc82 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Touch &amp; hold to place manually"</string>
<string name="place_automatically" msgid="8064208734425456485">"Add automatically"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Search Apps"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"No apps found matching \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Search for more apps"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
<string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Notification dots"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"On"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Off"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Notification access needed"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"To show Notification Dots, turn on app notifications for <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Change settings"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Add icon to Home screen"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For new apps"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Change icon shape"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Use system default"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Square"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Circle"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Teardrop"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Applying icon shape changes"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Unknown"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Remove"</string>
<string name="abandoned_search" msgid="891119232568284442">"Search"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 4e0ba03cd..f3f10cc82 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Touch &amp; hold to place manually"</string>
<string name="place_automatically" msgid="8064208734425456485">"Add automatically"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Search Apps"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"No apps found matching \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Search for more apps"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
<string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Notification dots"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"On"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Off"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Notification access needed"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"To show Notification Dots, turn on app notifications for <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Change settings"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Add icon to Home screen"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For new apps"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Change icon shape"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Use system default"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Square"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Circle"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Teardrop"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Applying icon shape changes"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Unknown"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Remove"</string>
<string name="abandoned_search" msgid="891119232568284442">"Search"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 4e0ba03cd..f3f10cc82 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Touch &amp; hold to place manually"</string>
<string name="place_automatically" msgid="8064208734425456485">"Add automatically"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Search Apps"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"No apps found matching \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Search for more apps"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
<string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Notification dots"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"On"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Off"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Notification access needed"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"To show Notification Dots, turn on app notifications for <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Change settings"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Add icon to Home screen"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For new apps"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Change icon shape"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Use system default"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Square"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Circle"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Teardrop"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Applying icon shape changes"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Unknown"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Remove"</string>
<string name="abandoned_search" msgid="891119232568284442">"Search"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index bef475787..f60e1862a 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de ancho por %2$d de alto"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Mantén presionado para ubicarlo manualmente"</string>
<string name="place_automatically" msgid="8064208734425456485">"Agregar automáticamente"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Buscar aplicaciones"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Cargando aplicaciones…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"No hay aplicaciones que coincidan con <xliff:g id="QUERY">%1$s</xliff:g>."</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar apps"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Cargando apps…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"No hay apps que coincidan con \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Buscar más apps"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notificaciones"</string>
<string name="out_of_space" msgid="4691004494942118364">"No hay más espacio en esta pantalla principal."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Puntos de notificación"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Activada"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivada"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Se necesita acceso a las notificaciones"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar los puntos de notificación, activa las notificaciones de la app para <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Cambiar la configuración"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Agregar ícono a la pantalla principal"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para nuevas apps"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Cambiar forma de los íconos"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Usar el sistema predeterminado"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Cuadrado"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Cuadrado con esquinas redondeadas"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Círculo"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Gota"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Aplicando cambio en la forma de los íconos"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Desconocido"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminar"</string>
<string name="abandoned_search" msgid="891119232568284442">"Buscar"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index e49ac3f77..3ab41caf6 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de ancho por %2$d de alto"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Mantenlo pulsado para añadirlo manualmente"</string>
<string name="place_automatically" msgid="8064208734425456485">"Añadir automáticamente"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Busca aplicaciones"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Cargando aplicaciones…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"No se han encontrado aplicaciones que contengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Buscar aplicaciones"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Cargando aplicaciones…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"No se han encontrado aplicaciones que contengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Buscar más aplicaciones"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notificaciones"</string>
<string name="out_of_space" msgid="4691004494942118364">"No queda espacio en la pantalla de inicio."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Puntos de notificación"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Activada"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivada"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Se necesita acceso a las notificaciones"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar burbujas de notificación, activa las notificaciones de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Cambiar ajustes"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Añadir icono a la pantalla de inicio"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para nuevas aplicaciones"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Cambiar forma de los iconos"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Usar opción predeterminada del sistema"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Cuadrado"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Cuadrado con esquinas redondeadas"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Círculo"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Lágrima"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Aplicando cambios en la forma de los iconos"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Desconocido"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Quitar"</string>
<string name="abandoned_search" msgid="891119232568284442">"Buscar"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index feb63ca31..6eca89e5c 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -65,12 +65,26 @@
<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="8119458837558863227">"Seaded"</string>
+ <string name="settings_button_text" msgid="8873672322605444408">"Avalehe seaded"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Keelas administraator"</string>
<string name="accessibility_action_overview" msgid="6257665857640347026">"Ülevaade"</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="allow_rotation_blocked_desc" msgid="3212602545192996253">"Praegune kuvaseade ei luba pööramist"</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="auto_add_shortcuts_label" msgid="8222286205987725611">"Lisa ikoon avaekraanile"</string>
+ <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Uute rakenduste puhul"</string>
+ <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
+ <skip />
+ <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>
+ <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
+ <skip />
<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>
@@ -104,4 +118,7 @@
<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>
</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 4edc4e7b3..8fe874b32 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"جستجوی برنامه‌ها"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"در حال بارگیری برنامه‌ها..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"هیچ برنامه‌ای مطابق با «<xliff:g id="QUERY">%1$s</xliff:g>» پیدا نشد"</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="out_of_space" msgid="4691004494942118364">"فضای بیشتری در این صفحه اصلی موجود نیست."</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"افزودن نماد به صفحه اصلی"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"برای برنامه‌های جدید"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"تغییر شکل نماد"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index f24cbae1e..016dbbce3 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Leveys: %1$d, korkeus: %2$d"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Sijoita manuaalisesti koskettamalla pitkään."</string>
<string name="place_automatically" msgid="8064208734425456485">"Lisää automaattisesti"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Sovellushaku"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Ladataan sovelluksia…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"”<xliff:g id="QUERY">%1$s</xliff:g>” ei palauttanut sovelluksia."</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hae sovelluksia"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Ladataan sovelluksia…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"<xliff:g id="QUERY">%1$s</xliff:g> ei palauttanut sovelluksia."</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Hae lisää sovelluksia"</string>
<string name="notifications_header" msgid="1404149926117359025">"Ilmoitukset"</string>
<string name="out_of_space" msgid="4691004494942118364">"Tässä aloitusruudussa ei ole enää tilaa."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Pistemerkit"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Käytössä"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Pois käytöstä"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Ilmoituksien käyttöoikeus tarvitaan"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"<xliff:g id="NAME">%1$s</xliff:g> tarvitsee ilmoitusten käyttöoikeuden, jotta pistemerkkejä voidaan näyttää."</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Muuta asetuksia"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Lisää kuvake aloitusruutuun"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Uusille sovelluksille"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Muuta kuvakkeen muotoa"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Käytä järjestelmän oletusarvoa"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Neliö"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Ympyräneliö"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Ympyrä"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Pisara"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Sovelletaan kuvakkeiden muotojen muutoksia"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Tuntematon"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Poista"</string>
<string name="abandoned_search" msgid="891119232568284442">"Haku"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 5a3bd542c..e57433d0c 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largeur sur %2$d de hauteur"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Maintenez le doigt sur l\'élément pour le placer manuellement"</string>
<string name="place_automatically" msgid="8064208734425456485">"Ajouter automatiquement"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Rechercher des applications"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Chargement des applications en cours..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Aucune application trouvée correspondant à « <xliff:g id="QUERY">%1$s</xliff:g> »"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Rechercher dans les applications"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Chargement des applications en cours…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Aucune application trouvée correspondant à « <xliff:g id="QUERY">%1$s</xliff:g> »"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Rechercher plus d\'applications"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
<string name="out_of_space" msgid="4691004494942118364">"Pas d\'espace libre sur l\'écran d\'accueil."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Points de notification"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Activé"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Désactivé"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"L\'accès aux notifications est requis"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Pour afficher les points de notification, activez les notifications d\'application pour <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Modifier les paramètres"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ajouter l\'icône à l\'écran d\'accueil"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pour les nouvelles applications"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Modifier la forme de l\'icône"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Utiliser les valeurs système par défaut"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Carré"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Carré aux coins ronds"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Cercle"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Goutte"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Application des changements à la forme de l\'icône en cours…"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Inconnu"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Supprimer"</string>
<string name="abandoned_search" msgid="891119232568284442">"Rechercher"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 2897af022..dde439288 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largeur et %2$d de hauteur"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Appuyez de manière prolongée pour placer l\'élément manuellement"</string>
<string name="place_automatically" msgid="8064208734425456485">"Ajouter automatiquement"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Rechercher dans les applications"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Chargement des applications en cours…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Aucune application ne correspond à la requête \"<xliff:g id="QUERY">%1$s</xliff:g>\"."</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Rechercher dans les applications"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Chargement des applications…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Aucune application ne correspond à la requête \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Rechercher plus d\'applications"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
<string name="out_of_space" msgid="4691004494942118364">"Pas d\'espace libre sur cet écran d\'accueil."</string>
@@ -70,7 +70,7 @@
<string name="folder_name_format" msgid="6629239338071103179">"Dossier \"<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">"Fonds d\'écran"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Paramètres du domicile"</string>
+ <string name="settings_button_text" msgid="8873672322605444408">"Paramètres de l\'écran d\'accueil"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Désactivé par votre administrateur"</string>
<string name="accessibility_action_overview" msgid="6257665857640347026">"Vue d\'ensemble"</string>
<string name="allow_rotation_title" msgid="7728578836261442095">"Autoriser la rotation de l\'écran d\'accueil"</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Pastilles de notification"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Activé"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Désactivé"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Accès aux notifications requis"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Pour afficher les pastilles de notification, activez les notifications de l\'application <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Modifier les paramètres"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ajouter l\'icône à l\'écran d\'accueil"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pour les nouvelles applications"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Modifier la forme des icônes"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Utiliser la valeur système par défaut"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Carré"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Cercle"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Goutte"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Application des modifications de forme des icônes…"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Inconnu"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Supprimer"</string>
<string name="abandoned_search" msgid="891119232568284442">"Rechercher"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 371f6b789..02c470ba0 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"ऐप्‍स खोजें"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"ऐप्स लोड हो रहे हैं..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" से मिलान करने वाला कोई ऐप नहीं मिला"</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="out_of_space" msgid="4691004494942118364">"इस होम स्‍क्रीन पर स्थान शेष नहीं है."</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"होम स्क्रीन में आइकन जोड़ें"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"नए ऐप्लिकेशन के लिए"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"आइकन का आकार बदलें"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 09126778f..aaae258b8 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d širine i %2$d visine"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Dodirnite i zadržite stavku da biste je postavili ručno"</string>
<string name="place_automatically" msgid="8064208734425456485">"Dodaj automatski"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pretraži aplikacije"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Učitavanje aplikacija…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nema aplikacija podudarnih s upitom \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretraži aplikacije"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Učitavanje aplikacija…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nema aplikacija podudarnih s upitom \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Traži više aplikacija"</string>
<string name="notifications_header" msgid="1404149926117359025">"Obavijesti"</string>
<string name="out_of_space" msgid="4691004494942118364">"Na ovom početnom zaslonu više nema mjesta."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Točke obavijesti"</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 obavijestima"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Za prikaz točaka obavijesti uključite obavijesti aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Promjena postavki"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikonu na početni zaslon"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Za nove aplikacije"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Promijeni oblik ikona"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Upotrijebi zadane postavke sustava"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Primjena 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">"Traži"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 3ffd5088c..2da64b06b 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d széles és %2$d magas"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Tartsa lenyomva a manuális hozzáadáshoz"</string>
<string name="place_automatically" msgid="8064208734425456485">"Automatikus hozzáadás"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Alkalmazások keresése"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Alkalmazások betöltése…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Egy alkalmazás sem található a(z) „<xliff:g id="QUERY">%1$s</xliff:g>” lekérdezésre."</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Alkalmazások keresése"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Alkalmazások betöltése…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nem található alkalmazás a(z) „<xliff:g id="QUERY">%1$s</xliff:g>” lekérdezésre"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"További alkalmazások keresése"</string>
<string name="notifications_header" msgid="1404149926117359025">"Értesítések"</string>
<string name="out_of_space" msgid="4691004494942118364">"Nincs több hely ezen a kezdőképernyőn."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Értesítési pöttyök"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Bekapcsolva"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Kikapcsolva"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Értesítésekhez való hozzáférésre van szükség"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Az értesítési pöttyök megjelenítéséhez kapcsolja be a(z) <xliff:g id="NAME">%1$s</xliff:g> alkalmazás értesítéseit"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Beállítások módosítása"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ikon hozzáadása a kezdőképernyőhöz"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Új alkalmazásoknál"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Ikon formájának módosítása"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Alapértelmezett érték használata"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Négyzet"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Kör"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Könnycsepp"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Ikonforma módosításainak alkalmazása…"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Ismeretlen"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Eltávolítás"</string>
<string name="abandoned_search" msgid="891119232568284442">"Keresés"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 5634963e5..379a960d0 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"lebar %1$d x tinggi %2$d"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Sentuh &amp; tahan untuk menempatkan secara manual"</string>
<string name="place_automatically" msgid="8064208734425456485">"Tambahkan otomatis"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Telusuri Apps"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Memuat Aplikasi..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Tidak ditemukan Aplikasi yang cocok dengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Telusuri aplikasi"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Memuat aplikasi…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Tidak ditemukan aplikasi yang cocok dengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Telusuri aplikasi lainnya"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notifikasi"</string>
<string name="out_of_space" msgid="4691004494942118364">"Tidak ada ruang lagi pada layar Utama ini."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Titik notifikasi"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Aktif"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Nonaktif"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Perlu akses notifikasi"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Guna menampilkan Titik Notifikasi, aktifkan notifikasi aplikasi untuk <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Ubah setelan"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Tambahkan ikon ke layar Utama"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Untuk aplikasi baru"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Ubah bentuk ikon"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Gunakan default sistem"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Persegi"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Persegi bundar"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Lingkaran"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Butiran Air"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Menerapkan perubahan bentuk ikon"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Tidak dikenal"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Buang"</string>
<string name="abandoned_search" msgid="891119232568284442">"Telusuri"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 8af098db5..a52aee429 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d di larghezza per %2$d di altezza"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Tieni premuto per posizionare l\'elemento manualmente"</string>
<string name="place_automatically" msgid="8064208734425456485">"Aggiungi automaticamente"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Cerca app"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Caricamento di app…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nessuna app trovata corrispondente a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cerca nelle app"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Caricamento delle app…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nessuna app trovata corrispondente a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Cerca altre app"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notifiche"</string>
<string name="out_of_space" msgid="4691004494942118364">"Spazio nella schermata Home esaurito."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Indicatori notifica"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Attiva"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Non attiva"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Accesso alle notifiche necessario"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Per mostrare gli indicatori di notifica, attiva le notifiche per l\'app <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Modifica impostazioni"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Aggiungi icone alla schermata Home"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Per le nuove app"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Cambia la forma delle icone"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Usa impostazione predefinita di sistema"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Quadrato"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Supercerchio"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Cerchio"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Goccia"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Applicazione delle modifiche alla forma delle icone"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Sconosciuto"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Rimuovi"</string>
<string name="abandoned_search" msgid="891119232568284442">"Cerca"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 2425254fe..650a90db8 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"חפש אפליקציות"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"טוען אפליקציות…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"לא נמצאו אפליקציות התואמות ל-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</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="out_of_space" msgid="4691004494942118364">"אין עוד מקום במסך דף הבית הזה."</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"הוספת סמל במסך דף הבית"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"לאפליקציות חדשות"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"שינוי הצורה של הסמלים"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index cb5fa15a2..4071a6cc9 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"アプリを検索"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"アプリを読み込んでいます…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"「<xliff:g id="QUERY">%1$s</xliff:g>」に一致するアプリは見つかりませんでした"</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="out_of_space" msgid="4691004494942118364">"このホーム画面に空きスペースがありません。"</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"通知ドット"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"ON"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"OFF"</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>」のアプリ通知を ON にしてください"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"設定を変更"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ホーム画面にアイコンを追加"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"新しいアプリをダウンロードしたときに"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"アイコンの形の変更"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 26535f0d4..e3511d441 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"앱 검색"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"앱 로드 중..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"\'<xliff:g id="QUERY">%1$s</xliff:g>\'와(과) 일치하는 앱이 없습니다."</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="out_of_space" msgid="4691004494942118364">"홈 화면에 더 이상 공간이 없습니다."</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"홈 화면에 아이콘 추가"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"새로 설치한 앱에 적용"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"아이콘 모양 변경"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 08073ce0d..1b58e1775 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -26,9 +26,12 @@
<!-- Dynamic grid -->
<dimen name="dynamic_grid_overview_bar_item_width">120dp</dimen>
- <dimen name="dynamic_grid_page_indicator_size">24dp</dimen>
- <dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
- <dimen name="dynamic_grid_cell_padding_x">8dp</dimen>
+ <dimen name="dynamic_grid_min_page_indicator_size">48dp</dimen>
+ <dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
+
+ <dimen name="dynamic_grid_cell_layout_padding">0dp</dimen>
+
+ <dimen name="folder_preview_padding">2dp</dimen>
<!-- Hotseat -->
<dimen name="dynamic_grid_hotseat_land_left_nav_bar_right_padding">18dp</dimen>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 945cbf6ea..d415e4df1 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d plotis ir %2$d aukštis"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Palieskite ir palaikykite, kad padėtumėte patys"</string>
<string name="place_automatically" msgid="8064208734425456485">"Pridėti automatiškai"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Ieškoti programų"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Įkeliamos programos..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nerasta jokių užklausą „<xliff:g id="QUERY">%1$s</xliff:g>“ atitinkančių programų"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Paieškos programos"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Įkeliamos programos…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nerasta jokių užklausą „<xliff:g id="QUERY">%1$s</xliff:g>“ atitinkančių programų"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Ieškoti daugiau programų"</string>
<string name="notifications_header" msgid="1404149926117359025">"Pranešimai"</string>
<string name="out_of_space" msgid="4691004494942118364">"Šiame pagrindiniame ekrane vietos nebėra."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Pranešimų taškai"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Įjungta"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Išjungta"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Reikalinga prieiga prie pranešimų"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Kad būtų rodomi pranešimų taškai, įjunkite programos „<xliff:g id="NAME">%1$s</xliff:g>“ pranešimus."</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Keisti nustatymus"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Pridėti piktogr. prie pagrindinio ekrano"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Skirta naujoms programoms"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Pakeisti piktogramos formą"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Naudoti numatytuosius sistemos nustatymus"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Kvadratas"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Kvadratais suapvalintais kampais"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Apskritimas"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Ašara"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Taikomi piktogramos formos pakeitimai"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Nežinoma"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Pašalinti"</string>
<string name="abandoned_search" msgid="891119232568284442">"Ieškoti"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index e3c3482a7..2d8bfd83a 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d plats un %2$d augsts"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Pieskarieties un turiet, lai manuāli pievienotu"</string>
<string name="place_automatically" msgid="8064208734425456485">"Pievienot automātiski"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Meklēt lietotnes"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Notiek lietotņu ielāde…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Vaicājumam “<xliff:g id="QUERY">%1$s</xliff:g>” neatbilda neviena lietotne."</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Meklēt lietotnes"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Notiek lietotņu ielāde…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Vaicājumam “<xliff:g id="QUERY">%1$s</xliff:g>” neatbilda neviena lietotne"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Meklēt citas lietotnes"</string>
<string name="notifications_header" msgid="1404149926117359025">"Paziņojumi"</string>
<string name="out_of_space" msgid="4691004494942118364">"Šajā sākuma ekrānā vairs nav vietas."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Paziņojumu punkti"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Ieslēgts"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Izslēgts"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Nepieciešama piekļuve paziņojumiem"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Lai tiktu rādīti paziņojumu punkti, ieslēdziet paziņojumus lietotnei <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Mainīt iestatījumus"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Pievienot ikonu sākuma ekrānā"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Jaunām lietotnēm"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Mainīt ikonu formu"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Izmantot sistēmas noklusējumu"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Kvadrāts"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Kvadrāts ar noapaļotiem stūriem"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Aplis"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Lāse"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Tiek piemērotas ikonu formas izmaiņas"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Nezināma"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Noņemt"</string>
<string name="abandoned_search" msgid="891119232568284442">"Meklēt"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 215315ad1..f7237a01d 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -65,12 +65,26 @@
<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="8119458837558863227">"Tetapan"</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="accessibility_action_overview" msgid="6257665857640347026">"Ikhtisar"</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="allow_rotation_blocked_desc" msgid="3212602545192996253">"Tetapan Paparan semasa tidak membenarkan putaran"</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="auto_add_shortcuts_label" msgid="8222286205987725611">"Tambahkan ikon pada Skrin Utama"</string>
+ <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Untuk apl baharu"</string>
+ <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
+ <skip />
+ <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>
+ <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
+ <skip />
<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>
@@ -104,4 +118,7 @@
<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>
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 2b776d64a..bd348b0aa 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d bredde x %2$d høyde"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Trykk og hold for å plassere manuelt"</string>
<string name="place_automatically" msgid="8064208734425456485">"Legg til automatisk"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Søk i apper"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Laster inn apper …"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Fant ingen apper som samsvarer med «<xliff:g id="QUERY">%1$s</xliff:g>»"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Søk etter apper"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Laster inn appene …"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Fant ingen apper som samsvarer med «<xliff:g id="QUERY">%1$s</xliff:g>»"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Søk etter flere apper"</string>
<string name="notifications_header" msgid="1404149926117359025">"Varsler"</string>
<string name="out_of_space" msgid="4691004494942118364">"Denne startsiden er full."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Varselsprikker"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"På"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Av"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Tilgang til varsler er nødvendig"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Slå på appvarsler for <xliff:g id="NAME">%1$s</xliff:g> for å vise varselsprikker"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Endre innstillingene"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Legg til ikon på startsiden"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For nye apper"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Endre ikonets form"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Bruk systemstandard"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Superellipse"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Sirkel"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Dråpe"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Aktiverer endringer av ikonets form"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Ukjent"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Fjern"</string>
<string name="abandoned_search" msgid="891119232568284442">"Søk"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 0180bb4c2..7e8def4ca 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breed en %2$d hoog"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Tik op een item en houd dit vast om het handmatig te plaatsen"</string>
<string name="place_automatically" msgid="8064208734425456485">"Automatisch toevoegen"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Apps zoeken"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Apps laden…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Er zijn geen apps gevonden die overeenkomen met \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Apps zoeken"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Apps laden…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Er zijn geen apps gevonden die overeenkomen met \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Zoeken naar meer apps"</string>
<string name="notifications_header" msgid="1404149926117359025">"Meldingen"</string>
<string name="out_of_space" msgid="4691004494942118364">"Er is geen ruimte meer op dit startscherm."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Meldingsstipjes"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Aan"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Uit"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Toegang tot meldingen vereist"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Als je meldingsstipjes wilt weergeven, schakel je app-meldingen in voor <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Instellingen wijzigen"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Pictogram toevoegen aan startscherm"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Voor nieuwe apps"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Vorm van pictogram wijzigen"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Systeemstandaard gebruiken"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Vierkant"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Cirkel"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Traan"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Wijzigingen in vorm van pictogram toepassen"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Onbekend"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Verwijderen"</string>
<string name="abandoned_search" msgid="891119232568284442">"Zoeken"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index f8a7f66e9..c07f7defb 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Szerokość %1$d, wysokość %2$d"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Kliknij i przytrzymaj, by umieścić ręcznie"</string>
<string name="place_automatically" msgid="8064208734425456485">"Dodaj automatycznie"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Szukaj w aplikacjach"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Wczytuję aplikacje…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nie znaleziono aplikacji pasujących do zapytania „<xliff:g id="QUERY">%1$s</xliff:g>”"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Wyszukaj aplikacje"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Ładuję aplikacje…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nie znaleziono aplikacji pasujących do zapytania „<xliff:g id="QUERY">%1$s</xliff:g>”"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Wyszukaj więcej aplikacji"</string>
<string name="notifications_header" msgid="1404149926117359025">"Powiadomienia"</string>
<string name="out_of_space" msgid="4691004494942118364">"Brak miejsca na tym ekranie głównym."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Plakietki z powiadomieniami"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Włączono"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Wyłączono"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Wymagany jest dostęp do powiadomień"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Aby pokazać plakietki z powiadomieniami, włącz powiadomienia aplikacji <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Zmień ustawienia"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikonę do ekranu głównego"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"W przypadku nowych aplikacji"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Zmień kształt ikon"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Użyj ustawienia domyślnego"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Kwadrat"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Zaokrąglony kwadrat"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Okrąg"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Łza"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Zmieniam kształt ikon"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Brak informacji"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Usuń"</string>
<string name="abandoned_search" msgid="891119232568284442">"Szukaj"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 5c37eb83a..100f07b66 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largura por %2$d de altura"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Toque sem soltar para colocar manualmente"</string>
<string name="place_automatically" msgid="8064208734425456485">"Adicionar automaticamente"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pesquisar aplicações"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"A carregar aplicações..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Não foram encontradas aplic. que correspondam a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pesquisar aplicações"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"A carregar aplicações…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nenhuma aplicação correspondente a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Pesquisar mais aplicações"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notificações"</string>
<string name="out_of_space" msgid="4691004494942118364">"Sem espaço suficiente neste Ecrã principal."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Pontos de notificação"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Ativada"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Desativada"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Acesso a notificações necessário"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar os Pontos de notificação, ative as notificações de aplicações para o <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Alterar definições"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Adicionar ícone ao ecrã principal"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para novas aplicações"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Alterar forma do ícone"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Utilizar a predefinição do sistema"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Quadrado"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Quadrado e círculo"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Círculo"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Lágrima"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"A aplicar alterações à forma do ícone..."</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Desconhecido"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Remover"</string>
<string name="abandoned_search" msgid="891119232568284442">"Pesquisar"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index fd2406658..d75159f94 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largura por %2$d de altura"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Toque e mantenha pressionado para posicionar manualmente"</string>
<string name="place_automatically" msgid="8064208734425456485">"Adicionar automaticamente"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pesquisar apps"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Carregando apps…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nenhum app encontrado que corresponda a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Apps de pesquisa"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Carregando apps…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nenhum app encontrado que corresponda a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Pesquisar mais apps"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notificações"</string>
<string name="out_of_space" msgid="4691004494942118364">"Não há mais espaço na tela inicial."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Pontos de notificação"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Ativado"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Desativado"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Acesso a notificações necessário"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar pontos de notificação, ative as notificações de app para <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Alterar configurações"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Adicionar ícone à tela inicial"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para novos apps"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Alterar forma de ícones"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Usar padrão do sistema"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Quadrado"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Quadrado arredondado"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Círculo"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Lágrima"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Aplicando alterações na forma dos ícones"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Desconhecido"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Remover"</string>
<string name="abandoned_search" msgid="891119232568284442">"Pesquisar"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index e7b814425..512d96d6b 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d lățime și %2$d înălțime"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Atingeți lung pentru a plasa manual"</string>
<string name="place_automatically" msgid="8064208734425456485">"Adăugați automat"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Căutați aplicații"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Se încarcă aplicațiile..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nu s-a găsit nicio aplicație pentru „<xliff:g id="QUERY">%1$s</xliff:g>”"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Căutați aplicații"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Se încarcă aplicații…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nu s-a găsit nicio aplicație pentru „<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Căutați mai multe aplicații"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notificări"</string>
<string name="out_of_space" msgid="4691004494942118364">"Nu mai este loc pe acest Ecran de pornire."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Puncte de notificare"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Activat"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Dezactivat"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Este necesar accesul la notificări"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Pentru a afișa punctele de notificare, activați notificările din aplicație pentru <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Modificați setările"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Adaugă pictograme în ecranul de pornire"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pentru aplicații noi"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Schimbați forma pictogramei"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Folosiți setarea prestabilită a sistemului"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Pătrat"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Pătrat cu colțuri rotunjite"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Cerc"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Lacrimă"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Se aplică modificările aduse formei pictogramei"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Necunoscut"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminați"</string>
<string name="abandoned_search" msgid="891119232568284442">"Căutați"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 07ff76157..aed8f18e0 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"Поиск приложений"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Загрузка…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"По запросу \"<xliff:g id="QUERY">%1$s</xliff:g>\" ничего не найдено"</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="out_of_space" msgid="4691004494942118364">"На этом экране все занято"</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"Добавлять значки"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Добавлять значки установленных приложений на главный экран."</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Изменить форму значков"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index b7999f431..490f823fe 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"šírka %1$d, výška %2$d"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Položku umiestnite ručne klepnutím a podržaním"</string>
<string name="place_automatically" msgid="8064208734425456485">"Pridať automaticky"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Hľadať aplikácie"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Načítavajú sa aplikácie..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nenašli sa žiadne aplikácie zodpovedajúce dopytu <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Hľadať aplikácie"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Načítavajú sa aplikácie…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nenašli sa žiadne aplikácie zodpovedajúce dopytu <xliff:g id="QUERY">%1$s</xliff:g>"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Hľadať ďalšie aplikácie"</string>
<string name="notifications_header" msgid="1404149926117359025">"Upozornenia"</string>
<string name="out_of_space" msgid="4691004494942118364">"Na tejto ploche už nie je miesto"</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Bodky upozornení"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Zapnuté"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Vypnuté"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Vyžaduje sa prístup k upozorneniam"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Ak chcete, aby sa zobrazovali bodky upozornení, zapnite upozornenia aplikácie <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Zmeniť nastavenia"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Pridať ikonu na plochu"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pri inštalácii novej aplikácie"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Zmeniť tvar ikony"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Použiť predvolené nastavenie systému"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Štvorec"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Okrúhly štvorec"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Kruh"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Slza"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Tvar ikony sa mení"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Neznáme"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Odstrániť"</string>
<string name="abandoned_search" msgid="891119232568284442">"Vyhľadať"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 927b3893a..0b7d36ef8 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Širina %1$d, višina %2$d"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Dotaknite se elementa in ga pridržite, da ga ročno dodate"</string>
<string name="place_automatically" msgid="8064208734425456485">"Samodejno dodaj"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Iskanje po aplikacijah"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Nalaganje aplikacij …"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Ni aplikacij, ki bi ustrezale poizvedbi »<xliff:g id="QUERY">%1$s</xliff:g>«"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Iskanje programov"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Nalaganje aplikacij …"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Ni aplikacij, ki bi ustrezale poizvedbi »<xliff:g id="QUERY">%1$s</xliff:g>«"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Iskanje več aplikacij"</string>
<string name="notifications_header" msgid="1404149926117359025">"Obvestila"</string>
<string name="out_of_space" msgid="4691004494942118364">"Na tem začetnem zaslonu ni več prostora."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Obvestilne pike"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Vklopljeno"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Izklopljeno"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Potreben je dostop do obvestil"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Za prikaz obvestilnih pik vklopite obvestila aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Spremeni nastavitve"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikono na začetni zaslon"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Za nove aplikacije"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Spremeni obliko ikon"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Uporabi privzeto nastavitev sistema"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Zaobljen kvadrat"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Krog"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Solza"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Uveljavljanje spremenjene oblike ikon"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Neznano"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Odstrani"</string>
<string name="abandoned_search" msgid="891119232568284442">"Iskanje"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 2cfaee654..f41e02d33 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"Претражите апликације"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Апликације се учитавају..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Није пронађена ниједна апликација за „<xliff:g id="QUERY">%1$s</xliff:g>“"</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="out_of_space" msgid="4691004494942118364">"Нема више простора на овом почетном екрану."</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"Додај икону на почетни екран"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"За нове апликације"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Промените облик икона"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index aa6e99a49..6c598ff5d 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d bred gånger %2$d hög"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Placera manuellt genom att trycka länge"</string>
<string name="place_automatically" msgid="8064208734425456485">"Lägg till automatiskt"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Sök efter appar"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Läser in appar …"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Det gick inte att hitta några appar som matchar <xliff:g id="QUERY">%1$s</xliff:g>"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Sök efter appar"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Läser in appar …"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Inga appar som matchar <xliff:g id="QUERY">%1$s</xliff:g> hittades"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Sök efter fler appar"</string>
<string name="notifications_header" msgid="1404149926117359025">"Aviseringar"</string>
<string name="out_of_space" msgid="4691004494942118364">"Det finns inte plats för mer på den här startskärmen."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Aviseringsprickar"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"På"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Av"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Åtkomst till aviseringar krävs"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Aktivera appaviseringar för <xliff:g id="NAME">%1$s</xliff:g> om du vill att aviseringsprickar ska visas"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Ändra inställningar"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Lägg till ikonen på startskärmen"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"För nya appar"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Ändra form på ikoner"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Använd systemstandard"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Kvirkel"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Cirkel"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Droppe"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Ikonernas form ändras"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Okänt"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Ta bort"</string>
<string name="abandoned_search" msgid="891119232568284442">"Sök"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 3b6d373db..3de28e011 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Upana wa %1$d na kimo cha %2$d"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Gusa na ushikilie ili uweke mwenyewe"</string>
<string name="place_automatically" msgid="8064208734425456485">"Ongeza kiotomatiki"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Tafuta Programu"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Inapakia Programu..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Haikupata programu zinazolingana na \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tafuta programu"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Inapakia programu..."</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Haikupata programu zozote zinazolingana na \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Tafuta programu zaidi"</string>
<string name="notifications_header" msgid="1404149926117359025">"Arifa"</string>
<string name="out_of_space" msgid="4691004494942118364">"Hakuna nafasi katika skrini hii ya Mwanzo."</string>
@@ -81,17 +81,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Vitone vya arifa"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Imewashwa"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Imezimwa"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Inahitaji idhini ya kufikia arifa"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Ili kuonyesha Vitone vya Arifa, washa kipengele cha arifa za programu katika <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Badilisha mipangilio"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ongeza aikoni kwenye Skrini ya kwanza"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Kwa ajili ya programu mpya"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Badilisha umbo la aikoni"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Tumia umbo chaguo-msingi la mfumo"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Mraba"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Mstatili wenye pembe duara"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Mduara"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Umbo la chozi"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Inabadilisha umbo la aikoni"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Yasiyojulikana"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Ondoa"</string>
<string name="abandoned_search" msgid="891119232568284442">"Tafuta"</string>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index e836d7d78..b21120758 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -17,7 +17,6 @@
<resources>
<!-- All Apps -->
<dimen name="all_apps_button_scale_down">8dp</dimen>
- <dimen name="all_apps_search_bar_height">54dp</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-sw720dp/styles.xml b/res/values-sw720dp/styles.xml
index bb0dbc221..72894dcf3 100644
--- a/res/values-sw720dp/styles.xml
+++ b/res/values-sw720dp/styles.xml
@@ -26,7 +26,7 @@
<item name="android:windowNoTitle">true</item>
<item name="android:windowActionModeOverlay">true</item>
<item name="android:colorEdgeEffect">?android:attr/textColorSecondary</item>
- <item name="android:keyboardLayout">@layout/all_apps_search_container</item>
+ <item name="android:keyboardLayout">@layout/search_container_all_apps</item>
</style>
<!-- Workspace -->
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index e03931e04..b37009988 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"ค้นหาแอป"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"กำลังโหลดแอป…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"ไม่พบแอปที่ตรงกับ \"<xliff:g id="QUERY">%1$s</xliff:g>\""</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="out_of_space" msgid="4691004494942118364">"ไม่มีที่ว่างในหน้าจอหลักนี้"</string>
@@ -76,20 +76,21 @@
<string name="allow_rotation_title" msgid="7728578836261442095">"อนุญาตให้หมุนหน้าจอหลัก"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"เมื่อหมุนโทรศัพท์"</string>
<string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"การตั้งค่าการแสดงผลปัจจุบันไม่อนุญาตให้มีการหมุน"</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_change_settings" msgid="1376365968844349552">"เปลี่ยนการตั้งค่า"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"เพิ่มไอคอนในหน้าจอหลัก"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"สำหรับแอปใหม่"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"เปลี่ยนรูปร่างไอคอน"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 12bc0133f..54135c9d5 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ang lapad at %2$d ang taas"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Pindutin nang matagal upang manual na ilagay"</string>
<string name="place_automatically" msgid="8064208734425456485">"Awtomatikong idagdag"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Mga App sa Paghahanap"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Nilo-load ang Mga App…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Walang nakitang Mga App na tumutugma sa \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Maghanap ng mga app"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Naglo-load ng mga app…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Walang nahanap na app na tumutugma sa \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Maghanap ng higit pang mga app"</string>
<string name="notifications_header" msgid="1404149926117359025">"Mga Notification"</string>
<string name="out_of_space" msgid="4691004494942118364">"Wala nang lugar sa Home screen na ito."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Mga notification dot"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Naka-on"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Naka-off"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Kinakailangan ng access sa notification"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Upang ipakita ang Mga Notification Dot, i-on ang mga notification ng app para sa <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Baguhin ang mga setting"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Idagdag ang icon sa Home screen"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para sa mga bagong app"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Baguhin ang hugis ng icon"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Gamitin ang default ng system"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Parisukat"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Bilog"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Teardrop"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Inilalapat ang mga pagbabago sa hugis ng icon"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Hindi kilala"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Alisin"</string>
<string name="abandoned_search" msgid="891119232568284442">"Maghanap"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index b245bfff1..cb8b50af2 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"genişlik: %1$d, yükseklik: %2$d"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Manuel olarak yerleştirmek için dokunun ve basılı tutun"</string>
<string name="place_automatically" msgid="8064208734425456485">"Otomatik olarak ekle"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Uygulamalarda Ara"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Uygulamalar Yükleniyor…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ile eşleşen uygulama bulunamadı"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Uygulamalarda ara"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Uygulamalar yükleniyor…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ile eşleşen uygulama bulunamadı"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Başka uygulamalar ara"</string>
<string name="notifications_header" msgid="1404149926117359025">"Bildirimler"</string>
<string name="out_of_space" msgid="4691004494942118364">"Bu Ana ekranda yer kalmadı."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Bildirim noktaları"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Açık"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Kapalı"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Bildirim erişimi gerekli"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Bildirim Noktaları\'nı göstermek için <xliff:g id="NAME">%1$s</xliff:g> uygulamasının bildirimlerini açın"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Ayarları değiştir"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ana ekrana simge ekle"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Yeni uygulamalar için"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Simge şeklini değiştir"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Sistem varsayılanını kullan"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Kare"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Kare-daire"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Daire"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Gözyaşı damlası"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Simge şekli değişiklikleri uygulanıyor"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Bilinmiyor"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Kaldır"</string>
<string name="abandoned_search" msgid="891119232568284442">"Ara"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 8d3391089..a9e010921 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"Пошук додатків"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Завантаження додатків…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Немає додатків для запиту \"<xliff:g id="QUERY">%1$s</xliff:g>\""</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="out_of_space" msgid="4691004494942118364">"На цьому головному екрані більше немає місця."</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"Додати значок на головний екран"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Для нових додатків"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Змінити форму значка"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index f6cb8f23e..83e1ceaba 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Rộng %1$d x cao %2$d"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Chạm và giữ để đặt theo cách thủ công"</string>
<string name="place_automatically" msgid="8064208734425456485">"Tự động thêm"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Tìm kiếm ứng dụng"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Đang tải ứng dụng..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Không tìm thấy ứng dụng nào phù hợp với \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Tìm kiếm ứng dụng"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Đang tải ứng dụng…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Không tìm thấy ứng dụng nào phù hợp với \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Tìm kiếm thêm ứng dụng"</string>
<string name="notifications_header" msgid="1404149926117359025">"Thông báo"</string>
<string name="out_of_space" msgid="4691004494942118364">"Không còn chỗ trên Màn hình chính này."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Dấu chấm thông báo"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Đang bật"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Đã tắt"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Cần quyền truy cập thông báo"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Để hiển thị Dấu chấm thông báo, hãy bật thông báo ứng dụng cho <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Thay đổi cài đặt"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Thêm biểu tượng vào màn hình chính"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Cho ứng dụng mới"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Thay đổi hình dạng biểu tượng"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Sử dụng mặc định của hệ thống"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Hình vuông"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Hình vuông cạnh bo tròn"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Hình tròn"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"Hình giọt nước"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Đang áp dụng các thay đổi hình dạng biểu tượng"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Không xác định"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Xóa"</string>
<string name="abandoned_search" msgid="891119232568284442">"Tìm kiếm"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 5dcef74d1..bef12fb61 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"搜索应用"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"正在加载应用…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"未找到与“<xliff:g id="QUERY">%1$s</xliff:g>”相符的应用"</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="out_of_space" msgid="4691004494942118364">"此主屏幕上已没有空间。"</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"将图标添加到主屏幕"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"适用于新应用"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"更改图标形状"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 2bbc160f7..7ac555395 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"搜尋應用程式"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"正在載入應用程式…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"無法找到與「<xliff:g id="QUERY">%1$s</xliff:g>」相符的應用程式"</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="out_of_space" msgid="4691004494942118364">"主畫面已無空間。"</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"將圖示加到主畫面"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"適用於新安裝的應用程式"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"變更圖示形狀"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index f1605f686..e0c4c9973 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -35,9 +35,9 @@
<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="7084713969757597256">"搜尋應用程式"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"正在載入應用程式…"</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"找不到符合「<xliff:g id="QUERY">%1$s</xliff:g>」的應用程式"</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="out_of_space" msgid="4691004494942118364">"這個主螢幕已無空間。"</string>
@@ -79,17 +79,18 @@
<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="auto_add_shortcuts_label" msgid="8222286205987725611">"將圖示加到主螢幕"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"適用於新安裝的應用程式"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"變更圖示形狀"</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>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <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>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 12d14bdaf..ef6fdeb10 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -35,9 +35,9 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ububanzi ngokungu-%2$d ukuya phezulu"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Thinta futhi ubambe ukuze ubeke ngokwenza"</string>
<string name="place_automatically" msgid="8064208734425456485">"Engeza ngokuzenzakalelayo"</string>
- <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Sesha Izinhlelo Zokusebenza"</string>
- <string name="all_apps_loading_message" msgid="7557140873644765180">"Ilayisha izinhlelo zokusebenza..."</string>
- <string name="all_apps_no_search_results" msgid="6332185285860416787">"Azikho izinhlelo zokusebenza ezitholakele ezifana ne-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Sesha izinhlelo zokusebenza"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Ilayisha izinhlelo zokusebenza..."</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Azikho izinhlelo zokusebenza ezitholiwe ezifana ne-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Sesha izinhlelo zokusebenza eziningi"</string>
<string name="notifications_header" msgid="1404149926117359025">"Izaziso"</string>
<string name="out_of_space" msgid="4691004494942118364">"Asisekho isikhala kulesi sikrini Sasekhaya."</string>
@@ -79,17 +79,18 @@
<string name="icon_badging_title" msgid="874121399231955394">"Amachashazi esaziso"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Kuvuliwe"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Kuvaliwe"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"Ukufinyelela izaziso kuyadingeka"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Ukuze ubonisa amcashazi esaziso, vula izaziso zohlelo lokusebenza ze-<xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Shintsha izilungiselelo"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Engeza isithonjana eskrinini sasekhaya"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Kwezinhlelo zokusebenza ezintsha"</string>
- <!-- no translation found for icon_shape_override_label (2977264953998281004) -->
- <skip />
+ <string name="icon_shape_override_label" msgid="2977264953998281004">"Shintsha isimo sesithonjana"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Sebenzisa okuzenzakalelayo kwesistimu"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Isikwele"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"I-Squircle"</string>
<string name="icon_shape_circle" msgid="6550072265930144217">"Indingiliza"</string>
<string name="icon_shape_teardrop" msgid="4525869388200835463">"I-Teardrop"</string>
- <!-- no translation found for icon_shape_override_progress (3461735694970239908) -->
- <skip />
+ <string name="icon_shape_override_progress" msgid="3461735694970239908">"Ifaka izinguquko zesimo sesithonjana"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Akwaziwa"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Susa"</string>
<string name="abandoned_search" msgid="891119232568284442">"Sesha"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index db1a75da9..e9c62a783 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -124,7 +124,7 @@
<item type="id" name="preview_image_id" />
<!-- Popup items -->
- <integer name="config_popupOpenCloseDuration">220</integer>
+ <integer name="config_popupOpenCloseDuration">150</integer>
<integer name="config_popupArrowOpenDuration">80</integer>
<integer name="config_removeNotificationViewDuration">300</integer>
@@ -140,4 +140,10 @@
<item type="id" name="action_resize" />
<item type="id" name="action_deep_shortcuts" />
<item type="id" name="action_dismiss_notification" />
+
+<!-- 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" />
+
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a4dff7190..28af70596 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -16,8 +16,8 @@
<resources>
<!-- Dynamic Grid -->
- <dimen name="dynamic_grid_edge_margin">16dp</dimen>
- <dimen name="dynamic_grid_page_indicator_size">32dp</dimen>
+ <dimen name="dynamic_grid_edge_margin">8dp</dimen>
+ <dimen name="dynamic_grid_min_page_indicator_size">32dp</dimen>
<dimen name="dynamic_grid_page_indicator_line_height">1dp</dimen>
<dimen name="dynamic_grid_page_indicator_gutter_width">50dp</dimen>
<dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
@@ -30,7 +30,7 @@
<!-- Minimum space between workspace and hotseat in spring loaded mode -->
<dimen name="dynamic_grid_min_spring_loaded_space">8dp</dimen>
- <!-- dynamic_grid_edge_margin / 2 -->
+ <dimen name="dynamic_grid_cell_layout_padding">5.5dp</dimen>
<dimen name="dynamic_grid_cell_padding_x">8dp</dimen>
<!-- Hotseat -->
@@ -213,6 +213,7 @@
<dimen name="notification_footer_height">32dp</dimen>
<dimen name="notification_header_text_size">13sp</dimen>
<dimen name="notification_header_count_text_size">12sp</dimen>
+ <dimen name="notification_main_title_size">16sp</dimen>
<dimen name="notification_main_text_size">14sp</dimen>
<dimen name="notification_icon_size">24dp</dimen>
<dimen name="notification_footer_icon_size">18dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index da6da04c2..1197b1cf2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -59,11 +59,11 @@
<!-- All Apps -->
<!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
- <string name="all_apps_search_bar_hint">Search Apps</string>
+ <string name="all_apps_search_bar_hint">Search apps</string>
<!-- Loading apps text. [CHAR_LIMIT=50] -->
- <string name="all_apps_loading_message">Loading Apps&#8230;</string>
+ <string name="all_apps_loading_message">Loading apps&#8230;</string>
<!-- No-search-results text. [CHAR_LIMIT=50] -->
- <string name="all_apps_no_search_results">No Apps found matching \"<xliff:g id="query" example="Android">%1$s</xliff:g>\"</string>
+ <string name="all_apps_no_search_results">No apps found matching \"<xliff:g id="query" example="Android">%1$s</xliff:g>\"</string>
<!-- Label for the button which allows the user to get app search results. [CHAR_LIMIT=50] -->
<string name="all_apps_search_market_message">Search for more apps</string>
@@ -178,6 +178,12 @@
<string name="icon_badging_desc_on">On</string>
<!-- Text to indicate that the system icon badging setting is off [CHAR LIMIT=100] -->
<string name="icon_badging_desc_off">Off</string>
+ <!-- Title for the dialog shown when the app does not has notification access, explaining the requirement for notification access [CHAR LIMIT=50] -->
+ <string name="title_missing_notification_access">Notification access needed</string>
+ <!-- Message explaining to the user that the notification access is required by the app for showing 'Notification dots' [CHAR LIMIT=NONE] -->
+ <string name="msg_missing_notification_access">To show Notification Dots, turn on app notifications for <xliff:g id="name" example="My App">%1$s</xliff:g></string>
+ <!-- Button text in the confirmation dialog which would take the user to the system settings [CHAR LIMIT=50] -->
+ <string name="title_change_settings">Change settings</string>
<!-- Label for the setting that allows the automatic placement of launcher shortcuts for applications and games installed on the device [CHAR LIMIT=40] -->
<string name="auto_add_shortcuts_label">Add icon to Home screen</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index d11b00208..5bdf5125a 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -25,7 +25,7 @@
<item name="android:windowShowWallpaper">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:colorEdgeEffect">#FF757575</item>
- <item name="android:keyboardLayout">@layout/all_apps_search_container</item>
+ <item name="android:keyboardLayout">@layout/search_container_all_apps</item>
</style>
<style name="BaseLauncherThemeWithCustomAttrs" parent="@style/BaseLauncherTheme">
@@ -140,6 +140,13 @@
<style name="PopupItem">
<item name="android:colorControlHighlight">?attr/popupColorTertiary</item>
</style>
+ <style name="PopupGutter">
+ <item name="android:backgroundTintMode">multiply</item>
+ <item name="android:backgroundTint">?attr/popupColorSecondary</item>
+ <item name="android:background">@drawable/gutter_horizontal</item>
+ <item name="android:elevation">@dimen/notification_elevation</item>
+ <item name="android:outlineProvider">none</item>
+ </style>
<!-- Drop targets -->
<style name="DropTargetButtonBase">
diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml
index c76f118e8..28a35b829 100644
--- a/res/xml/launcher_preferences.xml
+++ b/res/xml/launcher_preferences.xml
@@ -16,17 +16,18 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
- <Preference
+ <com.android.launcher3.views.ButtonPreference
android:key="pref_icon_badging"
android:title="@string/icon_badging_title"
- android:persistent="false">
+ android:persistent="false"
+ android:widgetLayout="@layout/notification_pref_warning" >
<intent android:action="android.settings.NOTIFICATION_SETTINGS">
<!-- This extra highlights the "Allow icon badges" field in Notification settings -->
<extra
android:name=":settings:fragment_args_key"
android:value="notification_badging" />
</intent>
- </Preference>
+ </com.android.launcher3.views.ButtonPreference>
<SwitchPreference
android:key="pref_add_icon_to_home"
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index 70be7dae4..b249c9530 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -9,10 +9,13 @@ import android.content.Context;
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;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.LoaderTask;
+import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.util.ContentWriter;
public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
@@ -22,6 +25,12 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
if (AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED.equals(intent.getAction())) {
+ int hostId = intent.getIntExtra(AppWidgetManager.EXTRA_HOST_ID, 0);
+ Log.d(TAG, "Widget ID map received for host:" + hostId);
+ if (hostId != LauncherAppWidgetHost.APPWIDGET_HOST_ID) {
+ return;
+ }
+
final int[] oldIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS);
final int[] newIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
if (oldIds.length == newIds.length) {
@@ -30,7 +39,8 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
.postAtFrontOfQueue(new Runnable() {
@Override
public void run() {
- restoreAppWidgetIds(context, asyncResult, oldIds, newIds);
+ restoreAppWidgetIds(context, oldIds, newIds);
+ asyncResult.finish();
}
});
} else {
@@ -42,11 +52,26 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
/**
* Updates the app widgets whose id has changed during the restore process.
*/
- static void restoreAppWidgetIds(Context context, PendingResult asyncResult,
- int[] oldWidgetIds, int[] newWidgetIds) {
+ @WorkerThread
+ static void restoreAppWidgetIds(Context context, int[] oldWidgetIds, int[] newWidgetIds) {
+ AppWidgetHost appWidgetHost = new LauncherAppWidgetHost(context);
+ if (FeatureFlags.GO_DISABLE_WIDGETS) {
+ Log.e(TAG, "Skipping widget ID remap as widgets not supported");
+ appWidgetHost.deleteHost();
+ return;
+ }
+ if (!RestoreDbTask.isPending(context)) {
+ // Someone has already gone through our DB once, probably LoaderTask. Skip any further
+ // modifications of the DB.
+ Log.e(TAG, "Skipping widget ID remap as DB already in use");
+ for (int widgetId : newWidgetIds) {
+ Log.d(TAG, "Deleting widgetId: " + widgetId);
+ appWidgetHost.deleteAppWidgetId(widgetId);
+ }
+ return;
+ }
final ContentResolver cr = context.getContentResolver();
final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
- AppWidgetHost appWidgetHost = new AppWidgetHost(context, Launcher.APPWIDGET_HOST_ID);
for (int i = 0; i < oldWidgetIds.length; i++) {
Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
@@ -86,6 +111,5 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
if (app != null) {
app.getModel().forceReload();
}
- asyncResult.finish();
}
}
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 2b59ede47..e49649502 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -19,6 +19,7 @@ package com.android.launcher3;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.Intent;
import android.view.View.AccessibilityDelegate;
import com.android.launcher3.logging.UserEventDispatcher;
@@ -63,4 +64,9 @@ public abstract class BaseActivity extends Activity {
}
return mSystemUiController;
}
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 6f2c89779..aeb82b376 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -44,6 +44,7 @@ import com.android.launcher3.IconCache.IconLoadRequest;
import com.android.launcher3.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.badge.BadgeRenderer;
+import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.FolderIconPreviewVerifier;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.graphics.HolographicOutlineHelper;
@@ -438,6 +439,13 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
super.setTextColor(colors);
}
+ public boolean shouldTextBeVisible() {
+ // Text should be visible everywhere but the hotseat.
+ Object tag = getParent() instanceof FolderIcon ? ((View) getParent()).getTag() : getTag();
+ ItemInfo info = tag instanceof ItemInfo ? (ItemInfo) tag : null;
+ return info == null || info.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+ }
+
public void setTextVisibility(boolean visible) {
if (visible) {
super.setTextColor(mTextColor);
@@ -459,7 +467,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
* @param fadeIn Whether the text should fade in or fade out.
*/
public ObjectAnimator createTextAlphaAnimator(boolean fadeIn) {
- return ObjectAnimator.ofInt(this, TEXT_ALPHA_PROPERTY, fadeIn ? Color.alpha(mTextColor) : 0);
+ int toAlpha = shouldTextBeVisible() && fadeIn ? Color.alpha(mTextColor) : 0;
+ return ObjectAnimator.ofInt(this, TEXT_ALPHA_PROPERTY, toAlpha);
}
@Override
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index d99a30ae7..aac80052e 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -606,7 +606,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
// Hotseat icons - remove text
if (child instanceof BubbleTextView) {
BubbleTextView bubbleChild = (BubbleTextView) child;
- bubbleChild.setTextVisibility(mContainerType != HOTSEAT);
+ bubbleChild.setTextVisibility(bubbleChild.shouldTextBeVisible());
}
child.setScaleX(mChildScale);
@@ -860,10 +860,10 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
// Expand the background drawing bounds by the padding baked into the background drawable
mBackground.getPadding(mTempRect);
mBackground.setBounds(
- left - mTempRect.left,
- top - mTempRect.top,
- right + mTempRect.right,
- bottom + mTempRect.bottom);
+ left - mTempRect.left - getPaddingLeft(),
+ top - mTempRect.top - getPaddingTop(),
+ right + mTempRect.right + getPaddingRight(),
+ bottom + mTempRect.bottom + getPaddingBottom());
}
/**
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index dcfb268d1..031bfe115 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -63,6 +63,8 @@ public class DeviceProfile {
*/
private static final float MAX_HORIZONTAL_PADDING_PERCENT = 0.14f;
+ private static final float TALL_DEVICE_ASPECT_RATIO_THRESHOLD = 1.82f;
+
// Overview mode
private final int overviewModeMinIconZoneHeightPx;
private final int overviewModeMaxIconZoneHeightPx;
@@ -71,7 +73,8 @@ public class DeviceProfile {
private final float overviewModeIconZoneRatio;
// Workspace
- private int desiredWorkspaceLeftRightMarginPx;
+ private final int desiredWorkspaceLeftRightMarginPx;
+ public final int cellLayoutPaddingLeftRightPx;
public final int edgeMarginPx;
public final Rect defaultWidgetPadding;
private final int defaultPageSpacingPx;
@@ -80,7 +83,7 @@ public class DeviceProfile {
public final int workspaceSpringLoadedBottomSpace;
// Page indicator
- private final int pageIndicatorSizePx;
+ private int pageIndicatorSizePx;
private final int pageIndicatorLandGutterPx;
private final int pageIndicatorLandWorkspaceOffsetPx;
@@ -171,8 +174,11 @@ public class DeviceProfile {
this.getClass().getName());
defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
- desiredWorkspaceLeftRightMarginPx = edgeMarginPx;
- pageIndicatorSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_size);
+ desiredWorkspaceLeftRightMarginPx = isVerticalBarLayout() ? 0 : edgeMarginPx;
+ cellLayoutPaddingLeftRightPx =
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_padding);
+ pageIndicatorSizePx = res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_min_page_indicator_size);
pageIndicatorLandGutterPx = res.getDimensionPixelSize(
R.dimen.dynamic_grid_page_indicator_gutter_width);
pageIndicatorLandWorkspaceOffsetPx =
@@ -228,8 +234,24 @@ public class DeviceProfile {
availableHeightPx = maxSize.y;
}
- // Calculate the remaining vars
+ // Calculate all of the remaining variables.
updateAvailableDimensions(dm, res);
+
+ // Now that we have all of the variables calculated, we can tune certain sizes.
+ float aspectRatio = ((float) Math.max(availableWidthPx, availableHeightPx))
+ / Math.min(availableWidthPx, availableHeightPx);
+ boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0;
+ if (!isVerticalBarLayout() && isPhone && isTallDevice) {
+ // We increase the page indicator size when there is extra space.
+ // ie. For a display with a large aspect ratio, we can keep the icons on the workspace
+ // in portrait mode closer together by increasing the page indicator size.
+ // Note: This calculation was created after noticing a pattern in the design spec.
+ pageIndicatorSizePx = getCellSize().y - iconSizePx - iconDrawablePaddingPx;
+
+ // Recalculate the available dimensions using the new page indicator size.
+ updateAvailableDimensions(dm, res);
+ }
+
computeAllAppsButtonSize(context);
// This is done last, after iconSizePx is calculated above.
@@ -244,9 +266,7 @@ public class DeviceProfile {
isLandscape);
// Hide labels on the workspace.
- profile.iconTextSizePx = 0;
- profile.cellHeightPx = profile.iconSizePx + profile.iconDrawablePaddingPx
- + Utilities.calculateTextHeight(profile.iconTextSizePx);
+ profile.adjustToHideWorkspaceLabels();
// We use these scales to measure and layout the widgets using their full invariant profile
// sizes and then draw them scaled and centered to fit in their multi-window mode cellspans.
@@ -270,6 +290,24 @@ public class DeviceProfile {
}
/**
+ * Adjusts the profile so that the labels on the Workspace are hidden.
+ * It is important to call this method after the All Apps variables have been set.
+ */
+ private void adjustToHideWorkspaceLabels() {
+ iconTextSizePx = 0;
+ iconDrawablePaddingPx = 0;
+ cellHeightPx = iconSizePx;
+
+ // In normal cases, All Apps cell height should equal the Workspace cell height.
+ // Since we are removing labels from the Workspace, we need to manually compute the
+ // All Apps cell height.
+ allAppsCellHeightPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx
+ + Utilities.calculateTextHeight(allAppsIconTextSizePx)
+ // Top and bottom padding is equal to the drawable padding
+ + allAppsIconDrawablePaddingPx * 2;
+ }
+
+ /**
* Determine the exact visual footprint of the all apps button, taking into account scaling
* and internal padding of the drawable.
*/
@@ -307,8 +345,7 @@ public class DeviceProfile {
if (isVerticalBarLayout()) {
// Always hide the Workspace text with vertical bar layout.
- iconTextSizePx = 0;
- allAppsCellHeightPx += Utilities.calculateTextHeight(allAppsIconTextSizePx);
+ adjustToHideWorkspaceLabels();
}
cellWidthPx = iconSizePx + iconDrawablePaddingPx;
@@ -344,7 +381,7 @@ public class DeviceProfile {
updateFolderCellSize(1f, dm, res);
// Don't let the folder get too close to the edges of the screen.
- int folderMargin = 4 * edgeMarginPx;
+ int folderMargin = edgeMarginPx;
// Check if the icons fit within the available height.
float usedHeight = folderCellHeightPx * inv.numFolderRows + folderBottomPanelSize;
@@ -412,7 +449,8 @@ public class DeviceProfile {
// Since we are only concerned with the overall padding, layout direction does
// not matter.
Point padding = getTotalWorkspacePadding();
- result.x = calculateCellWidth(availableWidthPx - padding.x, inv.numColumns);
+ int cellPadding = cellLayoutPaddingLeftRightPx * 2;
+ result.x = calculateCellWidth(availableWidthPx - padding.x - cellPadding, inv.numColumns);
result.y = calculateCellHeight(availableHeightPx - padding.y, inv.numRows);
return result;
}
@@ -484,8 +522,8 @@ public class DeviceProfile {
return new Rect(mInsets.left,
mInsets.top + dropTargetBarSizePx + edgeMarginPx,
mInsets.left + availableWidthPx,
- mInsets.top + availableHeightPx - hotseatBarHeightPx - pageIndicatorSizePx -
- edgeMarginPx);
+ mInsets.top + availableHeightPx - hotseatBarHeightPx
+ - pageIndicatorSizePx - edgeMarginPx);
}
}
@@ -548,7 +586,7 @@ public class DeviceProfile {
lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
lp.width = searchBarBounds.x;
lp.height = searchBarBounds.y;
- lp.topMargin = mInsets.top + edgeMarginPx / 2;
+ lp.topMargin = mInsets.top + edgeMarginPx;
searchBar.setLayoutParams(lp);
// Layout the workspace
@@ -579,15 +617,18 @@ public class DeviceProfile {
? hotseatBarLeftNavBarRightPaddingPx
: hotseatBarRightNavBarRightPaddingPx;
- hotseat.getLayout().setPadding(mInsets.left, mInsets.top, mInsets.right + paddingRight,
+ hotseat.getLayout().setPadding(mInsets.left + cellLayoutPaddingLeftRightPx,
+ mInsets.top, mInsets.right + paddingRight + cellLayoutPaddingLeftRightPx,
workspacePadding.bottom);
} else if (isTablet) {
// Pad the hotseat with the workspace padding calculated above
lp.gravity = Gravity.BOTTOM;
lp.width = LayoutParams.MATCH_PARENT;
lp.height = hotseatBarHeightPx + mInsets.bottom;
- hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left,
- hotseatBarTopPaddingPx, hotseatAdjustment + workspacePadding.right,
+ hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left
+ + cellLayoutPaddingLeftRightPx,
+ hotseatBarTopPaddingPx,
+ hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx,
hotseatBarBottomPaddingPx + mInsets.bottom);
} else {
// For phones, layout the hotseat without any bottom margin
@@ -595,8 +636,10 @@ public class DeviceProfile {
lp.gravity = Gravity.BOTTOM;
lp.width = LayoutParams.MATCH_PARENT;
lp.height = hotseatBarHeightPx + mInsets.bottom;
- hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left,
- hotseatBarTopPaddingPx, hotseatAdjustment + workspacePadding.right,
+ hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left
+ + cellLayoutPaddingLeftRightPx,
+ hotseatBarTopPaddingPx,
+ hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx,
hotseatBarBottomPaddingPx + mInsets.bottom);
}
hotseat.setLayoutParams(lp);
@@ -636,7 +679,7 @@ public class DeviceProfile {
// Layout the AllAppsRecyclerView
View view = launcher.findViewById(R.id.apps_list_view);
- int paddingLeftRight = hasVerticalBarLayout ? 0 : edgeMarginPx;
+ int paddingLeftRight = desiredWorkspaceLeftRightMarginPx + cellLayoutPaddingLeftRightPx;
view.setPadding(paddingLeftRight, view.getPaddingTop(), paddingLeftRight,
view.getPaddingBottom());
diff --git a/src/com/android/launcher3/FirstFrameAnimatorHelper.java b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
index a51ddd4b8..3cbc989eb 100644
--- a/src/com/android/launcher3/FirstFrameAnimatorHelper.java
+++ b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
@@ -23,7 +23,6 @@ import android.util.Log;
import android.view.View;
import android.view.ViewPropertyAnimator;
import android.view.ViewTreeObserver;
-
import com.android.launcher3.util.Thunk;
/*
@@ -33,10 +32,11 @@ import com.android.launcher3.util.Thunk;
*/
public class FirstFrameAnimatorHelper extends AnimatorListenerAdapter
implements ValueAnimator.AnimatorUpdateListener {
+ private static final String TAG = "FirstFrameAnimatorHlpr";
private static final boolean DEBUG = false;
private static final int MAX_DELAY = 1000;
private static final int IDEAL_FRAME_DURATION = 16;
- private View mTarget;
+ private final View mTarget;
private long mStartFrame;
private long mStartTime = -1;
private boolean mHandlingOnAnimationUpdate;
@@ -77,7 +77,7 @@ public class FirstFrameAnimatorHelper extends AnimatorListenerAdapter
sGlobalFrameCounter++;
if (DEBUG) {
long newTime = System.currentTimeMillis();
- Log.d("FirstFrameAnimatorHelper", "TICK " + (newTime - mTime));
+ Log.d(TAG, "TICK " + (newTime - mTime));
mTime = newTime;
}
}
@@ -139,7 +139,7 @@ public class FirstFrameAnimatorHelper extends AnimatorListenerAdapter
public void print(ValueAnimator animation) {
float flatFraction = animation.getCurrentPlayTime() / (float) animation.getDuration();
- Log.d("FirstFrameAnimatorHelper", sGlobalFrameCounter +
+ Log.d(TAG, sGlobalFrameCounter +
"(" + (sGlobalFrameCounter - mStartFrame) + ") " + mTarget + " dirty? " +
mTarget.isDirty() + " " + flatFraction + " " + this + " " + animation);
}
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 383e6efd0..3bcd7afb4 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -41,7 +41,6 @@ import android.os.UserHandle;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
-
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
@@ -52,7 +51,6 @@ 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;
@@ -70,7 +68,7 @@ public class IconCache {
private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
// Empty class name is used for storing package default entry.
- private static final String EMPTY_CLASS_NAME = ".";
+ public static final String EMPTY_CLASS_NAME = ".";
private static final boolean DEBUG = false;
private static final boolean DEBUG_IGNORE_CACHE = false;
@@ -91,7 +89,7 @@ public class IconCache {
private final Context mContext;
private final PackageManager mPackageManager;
- private IconProvider mIconProvider;
+ private final IconProvider mIconProvider;
@Thunk final UserManagerCompat mUserManager;
private final LauncherAppsCompat mLauncherApps;
private final HashMap<ComponentKey, CacheEntry> mCache =
@@ -122,7 +120,8 @@ public class IconCache {
}
private Drawable getFullResDefaultActivityIcon() {
- return getFullResIcon(Resources.getSystem(), android.R.mipmap.sym_def_app_icon);
+ return getFullResIcon(Resources.getSystem(), Utilities.isAtLeastO() ?
+ android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon);
}
private Drawable getFullResIcon(Resources resources, int iconId) {
@@ -193,7 +192,7 @@ public class IconCache {
* Remove any records for the supplied package name from memory.
*/
private void removeFromMemCacheLocked(String packageName, UserHandle user) {
- HashSet<ComponentKey> forDeletion = new HashSet<ComponentKey>();
+ HashSet<ComponentKey> forDeletion = new HashSet<>();
for (ComponentKey key: mCache.keySet()) {
if (key.componentName.getPackageName().equals(packageName)
&& key.user.equals(user)) {
@@ -219,7 +218,6 @@ public class IconCache {
}
} catch (NameNotFoundException e) {
Log.d(TAG, "Package not found", e);
- return;
}
}
@@ -264,7 +262,7 @@ public class IconCache {
Set<String> ignorePackages) {
long userSerial = mUserManager.getSerialNumberForUser(user);
PackageManager pm = mContext.getPackageManager();
- HashMap<String, PackageInfo> pkgInfoMap = new HashMap<String, PackageInfo>();
+ HashMap<String, PackageInfo> pkgInfoMap = new HashMap<>();
for (PackageInfo info : pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES)) {
pkgInfoMap.put(info.packageName, info);
}
@@ -274,7 +272,7 @@ public class IconCache {
componentMap.put(app.getComponentName(), app);
}
- HashSet<Integer> itemsToRemove = new HashSet<Integer>();
+ HashSet<Integer> itemsToRemove = new HashSet<>();
Stack<LauncherActivityInfo> appsToUpdate = new Stack<>();
Cursor c = null;
@@ -704,7 +702,7 @@ public class IconCache {
private final HashMap<String, PackageInfo> mPkgInfoMap;
private final Stack<LauncherActivityInfo> mAppsToAdd;
private final Stack<LauncherActivityInfo> mAppsToUpdate;
- private final HashSet<String> mUpdatedPackages = new HashSet<String>();
+ private final HashSet<String> mUpdatedPackages = new HashSet<>();
@Thunk SerializedIconUpdateTask(long userSerial, HashMap<String, PackageInfo> pkgInfoMap,
Stack<LauncherActivityInfo> appsToAdd,
@@ -753,7 +751,7 @@ public class IconCache {
}
private static final class IconDB extends SQLiteCacheHelper {
- private final static int DB_VERSION = 16;
+ private final static int DB_VERSION = 17;
private final static int RELEASE_VERSION = DB_VERSION +
(FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ? 0 : 1);
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index 11c5309f2..c5be096a2 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -137,7 +137,18 @@ public class ItemInfo {
}
public ComponentName getTargetComponent() {
- return getIntent() == null ? null : getIntent().getComponent();
+ Intent intent = getIntent();
+ if (intent == null) {
+ return null;
+ }
+ ComponentName cn = intent.getComponent();
+ if (itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT && cn == null) {
+ // Legacy shortcuts may not have a componentName but just a packageName. In that case
+ // create a dummy componentName instead of adding additional check everywhere.
+ String pkg = intent.getPackage();
+ return pkg == null ? null : new ComponentName(pkg, IconCache.EMPTY_CLASS_NAME);
+ }
+ return cn;
}
public void writeToValues(ContentWriter writer) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 26c5c9d00..4b3148626 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -209,10 +209,8 @@ public class Launcher extends BaseActivity
private boolean mIsSafeModeEnabled;
- public static final int APPWIDGET_HOST_ID = 1024;
public static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT = 500;
private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
- private static final int ACTIVITY_START_DELAY = 1000;
// How long to wait before the new-shortcut animation automatically pans the workspace
private static final int NEW_APPS_PAGE_MOVE_DELAY = 500;
@@ -274,6 +272,7 @@ public class Launcher extends BaseActivity
private boolean mHasFocus = false;
private ObjectAnimator mScrimAnimator;
+ private boolean mShouldFadeInScrim;
private PopupDataProvider mPopupDataProvider;
@@ -396,7 +395,10 @@ public class Launcher extends BaseActivity
mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
- mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
+ mAppWidgetHost = new LauncherAppWidgetHost(this);
+ if (Utilities.ATLEAST_MARSHMALLOW) {
+ mAppWidgetHost.addProviderChangeListener(this);
+ }
mAppWidgetHost.startListening();
// If we are getting an onCreate, we can actually preempt onResume and unset mPaused here,
@@ -467,8 +469,12 @@ public class Launcher extends BaseActivity
mLauncherCallbacks.onCreate(savedInstanceState);
}
- // Listen for broadcasts screen off
- registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
+ // Listen for broadcasts
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(Intent.ACTION_USER_PRESENT); // When the device wakes up + keyguard is gone
+ registerReceiver(mReceiver, filter);
+ mShouldFadeInScrim = true;
getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
@@ -488,7 +494,7 @@ public class Launcher extends BaseActivity
}
@Override
- public View findViewById(int id) {
+ public <T extends View> T findViewById(int id) {
return mLauncherView.findViewById(id);
}
@@ -783,7 +789,7 @@ public class Launcher extends BaseActivity
}
@Override
- protected void onActivityResult(
+ public void onActivityResult(
final int requestCode, final int resultCode, final Intent data) {
handleActivityResult(requestCode, resultCode, data);
if (mLauncherCallbacks != null) {
@@ -906,7 +912,7 @@ public class Launcher extends BaseActivity
NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
}
- if (mIsResumeFromActionScreenOff && mDragLayer.getBackground() != null) {
+ if (mShouldFadeInScrim && mDragLayer.getBackground() != null) {
if (mScrimAnimator != null) {
mScrimAnimator.cancel();
}
@@ -923,6 +929,7 @@ public class Launcher extends BaseActivity
mScrimAnimator.setStartDelay(getWindow().getTransitionBackgroundFadeDuration());
mScrimAnimator.start();
}
+ mShouldFadeInScrim = false;
}
@Override
@@ -1458,23 +1465,25 @@ public class Launcher extends BaseActivity
mWorkspace.addInScreen(view, info);
} else {
// Adding a shortcut to a Folder.
- final long folderIconId = container;
- FolderIcon folderIcon = (FolderIcon) mWorkspace.getFirstMatch(new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View view) {
- return info != null && info.id == folderIconId;
- }
- });
-
+ FolderIcon folderIcon = findFolderIcon(container);
if (folderIcon != null) {
FolderInfo folderInfo = (FolderInfo) folderIcon.getTag();
folderInfo.add(info, args.rank, false);
} else {
- Log.e(TAG, "Could not find folder with id " + folderIconId + " to add shortcut.");
+ Log.e(TAG, "Could not find folder with id " + container + " to add shortcut.");
}
}
}
+ 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;
+ }
+ });
+ }
+
/**
* Add a widget to the workspace.
*
@@ -1534,6 +1543,11 @@ public class Launcher extends BaseActivity
}
}
mIsResumeFromActionScreenOff = true;
+ mShouldFadeInScrim = true;
+ } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
+ // ACTION_USER_PRESENT is sent after onStart/onResume. This covers the case where
+ // the user unlocked and the Launcher is not in the foreground.
+ mShouldFadeInScrim = false;
}
}
};
@@ -2257,7 +2271,7 @@ public class Launcher extends BaseActivity
onClickFolderIcon(v);
}
} else if ((FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && v instanceof PageIndicator) ||
- (v == mAllAppsButton && mAllAppsButton != null)) {
+ (v == mAllAppsButton && mAllAppsButton != null)) {
onClickAllAppsButton(v);
} else if (tag instanceof AppInfo) {
startAppShortcutOrInfoActivity(v);
@@ -2308,8 +2322,9 @@ public class Launcher extends BaseActivity
}
/**
- * Event handler for the "grid" button that appears on the home screen, which
- * enters all apps mode.
+ * Event handler for the "grid" button or "caret" that appears on the home screen, which
+ * enters all apps mode. In verticalBarLayout the caret can be seen when all apps is open, and
+ * so in that case reverses the action.
*
* @param v The view that was clicked.
*/
@@ -2319,6 +2334,8 @@ public class Launcher extends BaseActivity
getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
ControlType.ALL_APPS_BUTTON);
showAppsView(true /* animated */, true /* updatePredictedApps */);
+ } else {
+ showWorkspace(true);
}
}
@@ -3046,7 +3063,6 @@ public class Launcher extends BaseActivity
List<ComponentKey> apps = mLauncherCallbacks.getPredictedApps();
if (apps != null) {
mAppsView.setPredictedApps(apps);
- getUserEventDispatcher().setPredictedApps(apps);
}
}
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 6e8c59b66..5573c5c15 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -16,12 +16,20 @@
package com.android.launcher3;
+import android.app.Activity;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
+import android.content.ActivityNotFoundException;
import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
import android.util.SparseArray;
import android.view.LayoutInflater;
+import android.widget.Toast;
+
+import com.android.launcher3.config.FeatureFlags;
import java.util.ArrayList;
@@ -33,14 +41,16 @@ import java.util.ArrayList;
*/
public class LauncherAppWidgetHost extends AppWidgetHost {
- private final ArrayList<Runnable> mProviderChangeListeners = new ArrayList<Runnable>();
+ public static final int APPWIDGET_HOST_ID = 1024;
+
+ private final ArrayList<ProviderChangedListener> mProviderChangeListeners = new ArrayList<>();
private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
- private Launcher mLauncher;
+ private final Context mContext;
- public LauncherAppWidgetHost(Launcher launcher, int hostId) {
- super(launcher, hostId);
- mLauncher = launcher;
+ public LauncherAppWidgetHost(Context context) {
+ super(context, APPWIDGET_HOST_ID);
+ mContext = context;
}
@Override
@@ -53,6 +63,10 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
@Override
public void startListening() {
+ if (FeatureFlags.GO_DISABLE_WIDGETS) {
+ return;
+ }
+
try {
super.startListening();
} catch (Exception e) {
@@ -66,24 +80,38 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
}
}
- public void addProviderChangeListener(Runnable callback) {
+ @Override
+ public void stopListening() {
+ if (FeatureFlags.GO_DISABLE_WIDGETS) {
+ return;
+ }
+
+ super.stopListening();
+ }
+
+ @Override
+ public int allocateAppWidgetId() {
+ if (FeatureFlags.GO_DISABLE_WIDGETS) {
+ return AppWidgetManager.INVALID_APPWIDGET_ID;
+ }
+
+ return super.allocateAppWidgetId();
+ }
+
+ public void addProviderChangeListener(ProviderChangedListener callback) {
mProviderChangeListeners.add(callback);
}
- public void removeProviderChangeListener(Runnable callback) {
+ public void removeProviderChangeListener(ProviderChangedListener callback) {
mProviderChangeListeners.remove(callback);
}
protected void onProvidersChanged() {
if (!mProviderChangeListeners.isEmpty()) {
- for (Runnable callback : new ArrayList<>(mProviderChangeListeners)) {
- callback.run();
+ for (ProviderChangedListener callback : new ArrayList<>(mProviderChangeListeners)) {
+ callback.notifyWidgetProvidersChanged();
}
}
-
- if (Utilities.ATLEAST_MARSHMALLOW) {
- mLauncher.notifyWidgetProvidersChanged();
- }
}
public AppWidgetHostView createView(Context context, int appWidgetId,
@@ -109,7 +137,7 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
// will update.
LauncherAppWidgetHostView view = mViews.get(appWidgetId);
if (view == null) {
- view = onCreateView(mLauncher, appWidgetId, appWidget);
+ view = onCreateView(mContext, appWidgetId, appWidget);
}
view.setAppWidget(appWidgetId, appWidget);
view.switchToErrorView();
@@ -124,11 +152,11 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
@Override
protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo.fromProviderInfo(
- mLauncher, appWidget);
+ mContext, appWidget);
super.onProviderChanged(appWidgetId, info);
// The super method updates the dimensions of the providerInfo. Update the
// launcher spans accordingly.
- info.initSpans(mLauncher);
+ info.initSpans(mContext);
}
@Override
@@ -142,4 +170,53 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
super.clearViews();
mViews.clear();
}
+
+ public void startBindFlow(BaseActivity activity,
+ int appWidgetId, AppWidgetProviderInfo info, int requestCode) {
+
+ if (FeatureFlags.GO_DISABLE_WIDGETS) {
+ sendActionCancelled(activity, requestCode);
+ return;
+ }
+
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND)
+ .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
+ .putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.provider)
+ .putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE, info.getProfile());
+ // TODO: we need to make sure that this accounts for the options bundle.
+ // intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
+ activity.startActivityForResult(intent, requestCode);
+ }
+
+
+ public void startConfigActivity(BaseActivity activity, int widgetId, int requestCode) {
+ if (FeatureFlags.GO_DISABLE_WIDGETS) {
+ sendActionCancelled(activity, requestCode);
+ return;
+ }
+
+ try {
+ startAppWidgetConfigureActivityForResult(activity, widgetId, 0, requestCode, null);
+ } catch (ActivityNotFoundException | SecurityException e) {
+ Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+ sendActionCancelled(activity, requestCode);
+ }
+ }
+
+ private void sendActionCancelled(final BaseActivity activity, final int requestCode) {
+ new Handler().post(new Runnable() {
+ @Override
+ public void run() {
+ activity.onActivityResult(requestCode, Activity.RESULT_CANCELED, null);
+ }
+ });
+ }
+
+ /**
+ * Listener for getting notifications on provider changes.
+ */
+ public interface ProviderChangedListener {
+
+ void notifyWidgetProvidersChanged();
+ }
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 82bee0e4c..f1638fda2 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -133,7 +133,7 @@ public class LauncherModel extends BroadcastReceiver
}
};
- public interface Callbacks {
+ public interface Callbacks extends LauncherAppWidgetHost.ProviderChangedListener {
public boolean setLoadOnResume();
public int getCurrentWorkspaceScreen();
public void clearPendingBinds();
@@ -159,7 +159,6 @@ public class LauncherModel extends BroadcastReceiver
HashSet<String> packageNames, HashSet<ComponentName> components,
UserHandle user);
public void bindAppInfosRemoved(ArrayList<AppInfo> appInfos);
- public void notifyWidgetProvidersChanged();
public void bindAllWidgets(MultiHashMap<PackageItemInfo, WidgetItem> widgets);
public void onPageBoundSynchronously(int page);
public void executeOnNextDraw(ViewOnDrawExecutor executor);
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 4813571f5..dc83f36ad 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -1031,7 +1031,7 @@ public class LauncherProvider extends ContentProvider {
}
public AppWidgetHost newLauncherWidgetHost() {
- return new AppWidgetHost(mContext, Launcher.APPWIDGET_HOST_ID);
+ return new LauncherAppWidgetHost(mContext);
}
@Override
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index e7349f040..44b9704f2 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -387,7 +387,6 @@ public class LauncherStateTransitionAnimation {
private void startAnimationToWorkspaceFromAllApps(final Workspace.State fromWorkspaceState,
final Workspace.State toWorkspaceState, final boolean animated, int type,
final Runnable onCompleteRunnable) {
- final AllAppsContainerView appsView = mLauncher.getAppsView();
// No alpha anim from all apps
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks(1f) {
@Override
@@ -417,12 +416,11 @@ public class LauncherStateTransitionAnimation {
@Override
void onTransitionComplete() {
mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
- appsView.reset();
}
};
// Only animate the search bar if animating to spring loaded mode from all apps
startAnimationToWorkspaceFromOverlay(fromWorkspaceState, toWorkspaceState,
- mLauncher.getStartViewForAllAppsRevealAnimation(), appsView,
+ mLauncher.getStartViewForAllAppsRevealAnimation(), mLauncher.getAppsView(),
animated, type, onCompleteRunnable, cb);
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 255677a53..87f3ddaf4 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -24,7 +24,6 @@ import android.animation.TimeInterpolator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Bundle;
@@ -49,7 +48,7 @@ import android.view.animation.Interpolator;
import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.pageindicators.PageIndicator;
-import com.android.launcher3.util.LauncherEdgeEffect;
+import com.android.launcher3.touch.OverScroll;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
@@ -70,6 +69,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
public static final int PAGE_SNAP_ANIMATION_DURATION = 750;
protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
+ // OverScroll constants
+ private final static int OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION = 270;
+
private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f;
// The page is moved more than halfway, automatically move to the next page on touch up.
private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.4f;
@@ -145,6 +147,13 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
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
@Thunk int mPageIndicatorViewId;
protected PageIndicator mPageIndicator;
@@ -178,16 +187,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
// Convenience/caching
private static final Matrix sTmpInvMatrix = new Matrix();
private static final float[] sTmpPoint = new float[2];
- private static final int[] sTmpIntPoint = new int[2];
private static final Rect sTmpRect = new Rect();
protected final Rect mInsets = new Rect();
protected final boolean mIsRtl;
- // Edge effect
- private final LauncherEdgeEffect mEdgeGlowLeft = new LauncherEdgeEffect();
- private final LauncherEdgeEffect mEdgeGlowRight = new LauncherEdgeEffect();
-
public PagedView(Context context) {
this(context, null);
}
@@ -227,10 +231,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * density);
setOnHierarchyChangeListener(this);
setWillNotDraw(false);
-
- int edgeEffectColor = Themes.getAttrColor(getContext(), android.R.attr.colorEdgeEffect);
- mEdgeGlowLeft.setColor(edgeEffectColor);
- mEdgeGlowRight.setColor(edgeEffectColor);
}
protected void setDefaultInterpolator(Interpolator interpolator) {
@@ -404,9 +404,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
if (getChildCount() == 0) {
return;
}
+ int prevPage = mCurrentPage;
mCurrentPage = validateNewPage(currentPage);
updateCurrentPageScroll();
- notifyPageSwitchListener();
+ notifyPageSwitchListener(prevPage);
invalidate();
}
@@ -414,7 +415,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
* Should be called whenever the page changes. In the case of a scroll, we wait until the page
* has settled.
*/
- protected void notifyPageSwitchListener() {
+ protected void notifyPageSwitchListener(int prevPage) {
updatePageIndicator();
}
@@ -476,7 +477,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
protected int getUnboundedScrollX() {
- return getScrollX();
+ return mUnboundedScrollX;
}
@Override
@@ -499,6 +500,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
x = Math.max(x, mFreeScrollMinScrollX);
}
+ mUnboundedScrollX = x;
+
boolean isXBeforeFirstPage = mIsRtl ? (x > mMaxScrollX) : (x < 0);
boolean isXAfterLastPage = mIsRtl ? (x < 0) : (x > mMaxScrollX);
if (isXBeforeFirstPage) {
@@ -526,6 +529,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
overScroll(0);
mWasInOverscroll = false;
}
+ mOverScrollX = x;
super.scrollTo(x, y);
}
@@ -565,7 +569,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
if (mScroller.computeScrollOffset()) {
// Don't bother scrolling if the page does not need to be moved
if (getUnboundedScrollX() != mScroller.getCurrX()
- || getScrollY() != mScroller.getCurrY()) {
+ || getScrollY() != mScroller.getCurrY()
+ || mOverScrollX != mScroller.getCurrX()) {
float scaleX = mFreeScroll ? getScaleX() : 1f;
int scrollX = (int) (mScroller.getCurrX() * (1 / scaleX));
scrollTo(scrollX, mScroller.getCurrY());
@@ -577,9 +582,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
} else if (mNextPage != INVALID_PAGE && shouldInvalidate) {
sendScrollAccessibilityEvent();
+ int prevPage = mCurrentPage;
mCurrentPage = validateNewPage(mNextPage);
mNextPage = INVALID_PAGE;
- notifyPageSwitchListener();
+ notifyPageSwitchListener(prevPage);
// We don't want to trigger a page end moving unless the page has settled
// and the user has stopped scrolling
@@ -916,6 +922,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
@Override
public void onChildViewRemoved(View parent, View child) {
updateFreescrollBounds();
+ mCurrentPage = validateNewPage(mCurrentPage);
invalidate();
}
@@ -973,47 +980,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
@Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
- if (getPageCount() > 0) {
- if (!mEdgeGlowLeft.isFinished()) {
- final int restoreCount = canvas.save();
- Rect display = mViewport;
- canvas.translate(display.left, display.top);
- canvas.rotate(270);
-
- getEdgeVerticalPosition(sTmpIntPoint);
- canvas.translate(display.top - sTmpIntPoint[1], 0);
- mEdgeGlowLeft.setSize(sTmpIntPoint[1] - sTmpIntPoint[0], display.width());
- if (mEdgeGlowLeft.draw(canvas)) {
- postInvalidateOnAnimation();
- }
- canvas.restoreToCount(restoreCount);
- }
- if (!mEdgeGlowRight.isFinished()) {
- final int restoreCount = canvas.save();
- Rect display = mViewport;
- canvas.translate(display.left + mPageScrolls[mIsRtl ? 0 : (getPageCount() - 1)], display.top);
- canvas.rotate(90);
-
- getEdgeVerticalPosition(sTmpIntPoint);
-
- canvas.translate(sTmpIntPoint[0] - display.top, -display.width());
- mEdgeGlowRight.setSize(sTmpIntPoint[1] - sTmpIntPoint[0], display.width());
- if (mEdgeGlowRight.draw(canvas)) {
- postInvalidateOnAnimation();
- }
- canvas.restoreToCount(restoreCount);
- }
- }
- }
-
- /**
- * Returns the top and bottom position for the edge effect.
- */
- protected abstract void getEdgeVerticalPosition(int[] pos);
-
- @Override
public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
int page = indexToPage(indexOfChild(child));
if (page != mCurrentPage || !mScroller.isFinished()) {
@@ -1355,14 +1321,15 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
protected void dampedOverScroll(float amount) {
- int screenSize = getViewportWidth();
- float f = (amount / screenSize);
- if (f < 0) {
- mEdgeGlowLeft.onPull(-f);
- } else if (f > 0) {
- mEdgeGlowRight.onPull(f);
+ if (Float.compare(amount, 0f) == 0) return;
+
+ int overScrollAmount = OverScroll.dampedScroll(amount, getViewportWidth());
+ if (amount < 0) {
+ mOverScrollX = overScrollAmount;
+ super.scrollTo(mOverScrollX, getScrollY());
} else {
- return;
+ mOverScrollX = mMaxScrollX + overScrollAmount;
+ super.scrollTo(mOverScrollX, getScrollY());
}
invalidate();
}
@@ -1715,8 +1682,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mCancelTap = false;
mTouchState = TOUCH_STATE_REST;
mActivePointerId = INVALID_POINTER;
- mEdgeGlowLeft.onRelease();
- mEdgeGlowRight.onRelease();
}
/**
@@ -1830,7 +1795,18 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
protected void snapToDestination() {
- snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION);
+ snapToPage(getPageNearestToCenterOfScreen(), getPageSnapDuration());
+ }
+
+ protected boolean isInOverScroll() {
+ return (mOverScrollX > mMaxScrollX || mOverScrollX < 0);
+ }
+
+ protected int getPageSnapDuration() {
+ if (isInOverScroll()) {
+ return OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION;
+ }
+ return PAGE_SNAP_ANIMATION_DURATION;
}
public static class ScrollInterpolator implements Interpolator {
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index b7b75f87d..d5d5eab76 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -17,7 +17,15 @@
package com.android.launcher3;
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.database.ContentObserver;
import android.os.Bundle;
import android.os.Handler;
@@ -26,8 +34,11 @@ import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.provider.Settings;
import android.provider.Settings.System;
+import android.view.View;
import com.android.launcher3.graphics.IconShapeOverride;
+import com.android.launcher3.notification.NotificationListener;
+import com.android.launcher3.views.ButtonPreference;
/**
* Settings activity for Launcher. Currently implements the following setting: Allow rotation
@@ -37,15 +48,19 @@ public class SettingsActivity extends Activity {
private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging";
// TODO: use Settings.Secure.NOTIFICATION_BADGING
private static final String NOTIFICATION_BADGING = "notification_badging";
+ /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
+ private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- // Display the fragment as the main content.
- getFragmentManager().beginTransaction()
- .replace(android.R.id.content, new LauncherSettingsFragment())
- .commit();
+ if (savedInstanceState == null) {
+ // Display the fragment as the main content.
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, new LauncherSettingsFragment())
+ .commit();
+ }
}
/**
@@ -83,17 +98,22 @@ public class SettingsActivity extends Activity {
rotationPref.setDefaultValue(Utilities.getAllowRotationDefaultValue(getActivity()));
}
- Preference iconBadgingPref = findPreference(ICON_BADGING_PREFERENCE_KEY);
+ ButtonPreference iconBadgingPref =
+ (ButtonPreference) findPreference(ICON_BADGING_PREFERENCE_KEY);
if (!Utilities.isAtLeastO()) {
getPreferenceScreen().removePreference(
findPreference(SessionCommitReceiver.ADD_ICON_PREFERENCE_KEY));
getPreferenceScreen().removePreference(iconBadgingPref);
} else {
// Listen to system notification badge settings while this UI is active.
- mIconBadgingObserver = new IconBadgingObserver(iconBadgingPref, resolver);
+ mIconBadgingObserver = new IconBadgingObserver(
+ iconBadgingPref, resolver, getFragmentManager());
resolver.registerContentObserver(
Settings.Secure.getUriFor(NOTIFICATION_BADGING),
false, mIconBadgingObserver);
+ resolver.registerContentObserver(
+ Settings.Secure.getUriFor(NOTIFICATION_ENABLED_LISTENERS),
+ false, mIconBadgingObserver);
mIconBadgingObserver.onChange(true);
}
@@ -151,24 +171,74 @@ public class SettingsActivity extends Activity {
* Content observer which listens for system badging setting changes,
* and updates the launcher badging setting subtext accordingly.
*/
- private static class IconBadgingObserver extends ContentObserver {
+ private static class IconBadgingObserver extends ContentObserver
+ implements View.OnClickListener {
- private final Preference mBadgingPref;
+ private final ButtonPreference mBadgingPref;
private final ContentResolver mResolver;
+ private final FragmentManager mFragmentManager;
- public IconBadgingObserver(Preference badgingPref, ContentResolver resolver) {
+ public IconBadgingObserver(ButtonPreference badgingPref, ContentResolver resolver,
+ FragmentManager fragmentManager) {
super(new Handler());
mBadgingPref = badgingPref;
mResolver = resolver;
+ mFragmentManager = fragmentManager;
}
@Override
public void onChange(boolean selfChange) {
boolean enabled = Settings.Secure.getInt(mResolver, NOTIFICATION_BADGING, 1) == 1;
- mBadgingPref.setSummary(enabled
- ? R.string.icon_badging_desc_on
- : R.string.icon_badging_desc_off);
+ 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.setButtonOnClickListener(serviceEnabled ? null : this);
+ mBadgingPref.setSummary(summary);
+
+ }
+
+ @Override
+ public void onClick(View view) {
+ new NotificationAccessConfirmation().show(mFragmentManager, "notification_access");
}
}
+ 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);
+ Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .putExtra(":settings:fragment_args_key", cn.flattenToString());
+ getActivity().startActivity(intent);
+ }
+ }
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 9100fe28d..3aa2db000 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -28,7 +28,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
@@ -654,27 +653,4 @@ public final class Utilities {
return hashSet;
}
- /**
- * @return creates a new alpha mask bitmap out of an existing bitmap
- */
- public static Bitmap convertToAlphaMask(Bitmap b, int applyAlpha) {
- Bitmap a = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ALPHA_8);
- Canvas c = new Canvas(a);
- Paint paint = new Paint();
- paint.setAlpha(applyAlpha);
- c.drawBitmap(b, 0f, 0f, paint);
- return a;
- }
-
- /**
- * @return a new white 1x1 bitmap with ALPHA_8
- */
- public static Bitmap createOnePixBitmap() {
- Bitmap a = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
- Canvas c = new Canvas(a);
- Paint paint = new Paint();
- paint.setColor(Color.WHITE);
- c.drawPaint(paint);
- return a;
- }
}
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index ad1be7e90..a65ea9b10 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -111,7 +111,7 @@ public class WidgetPreviewLoader {
* sizes (landscape vs portrait).
*/
private static class CacheDb extends SQLiteCacheHelper {
- private static final int DB_VERSION = 8;
+ private static final int DB_VERSION = 9;
private static final String TABLE_NAME = "shortcut_and_widget_previews";
private static final String COLUMN_COMPONENT = "componentName";
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 767e33278..a2270d6c5 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -52,8 +52,10 @@ import android.view.accessibility.AccessibilityManager;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.Toast;
+
import com.android.launcher3.Launcher.CustomContentCallbacks;
import com.android.launcher3.Launcher.LauncherOverlay;
+import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.UninstallDropTarget.DropTargetSource;
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
import com.android.launcher3.accessibility.OverviewAccessibilityDelegate;
@@ -75,6 +77,7 @@ import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
+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.ItemInfoMatcher;
@@ -85,6 +88,7 @@ import com.android.launcher3.util.VerticalFlingDetector;
import com.android.launcher3.util.WallpaperOffsetInterpolator;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
+
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
@@ -300,8 +304,8 @@ public class Workspace extends PagedView
boolean mScrollInteractionBegan;
boolean mStartedSendingScrollEvents;
float mLastOverlayScroll = 0;
- // Total over scrollX in the overlay direction.
- private int mUnboundedScrollX;
+ boolean mOverlayShown = false;
+
private boolean mForceDrawAdjacentPages = false;
// Total over scrollX in the overlay direction.
private float mOverlayTranslation;
@@ -599,12 +603,12 @@ public class Workspace extends PagedView
// In transposed layout, we add the QSB in the Grid. As workspace does not touch the
// edges, we do not need a full width QSB.
qsb = LayoutInflater.from(getContext())
- .inflate(R.layout.qsb_container,firstPage, false);
+ .inflate(R.layout.search_container_workspace,firstPage, false);
}
CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, firstPage.getCountX(), 1);
lp.canReorder = false;
- if (!firstPage.addViewToCellLayout(qsb, 0, R.id.qsb_container, lp, true)) {
+ if (!firstPage.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true)) {
Log.e(TAG, "Failed to add to item at (0, 0) to CellLayout");
}
}
@@ -622,7 +626,7 @@ public class Workspace extends PagedView
}
// Recycle the QSB widget
- View qsb = findViewById(R.id.qsb_container);
+ View qsb = findViewById(R.id.search_container_workspace);
if (qsb != null) {
((ViewGroup) qsb.getParent()).removeView(qsb);
}
@@ -665,6 +669,10 @@ public class Workspace extends PagedView
newScreen.setOnLongClickListener(mLongClickListener);
newScreen.setOnClickListener(mLauncher);
newScreen.setSoundEffectsEnabled(false);
+
+ int paddingLeftRight = mLauncher.getDeviceProfile().cellLayoutPaddingLeftRightPx;
+ newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, 0);
+
mWorkspaceScreens.put(screenId, newScreen);
mScreenOrder.add(insertIndex, screenId);
addView(newScreen, insertIndex);
@@ -1321,18 +1329,10 @@ public class Workspace extends PagedView
onOverlayScrollChanged(0);
}
- @Override
- protected int getUnboundedScrollX() {
- if (isScrollingOverlay()) {
- return mUnboundedScrollX;
- }
-
- return super.getUnboundedScrollX();
- }
private boolean isScrollingOverlay() {
return mLauncherOverlay != null &&
- ((mIsRtl && mUnboundedScrollX > mMaxScrollX) || (!mIsRtl && mUnboundedScrollX < 0));
+ ((mIsRtl && getUnboundedScrollX() > mMaxScrollX) || (!mIsRtl && getUnboundedScrollX() < 0));
}
@Override
@@ -1352,12 +1352,6 @@ public class Workspace extends PagedView
}
@Override
- public void scrollTo(int x, int y) {
- mUnboundedScrollX = x;
- super.scrollTo(x, y);
- }
-
- @Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
@@ -1410,7 +1404,7 @@ public class Workspace extends PagedView
@Override
protected boolean shouldFlingForVelocity(int velocityX) {
// When the overlay is moving, the fling or settle transition is controlled by the overlay.
- return Float.compare(mOverlayTranslation, 0) == 0 &&
+ return Float.compare(Math.abs(mOverlayTranslation), 0) == 0 &&
super.shouldFlingForVelocity(velocityX);
}
@@ -1420,6 +1414,20 @@ public class Workspace extends PagedView
* The overlay scroll is being controlled locally, just update our overlay effect
*/
public void onOverlayScrollChanged(float scroll) {
+
+ if (Float.compare(scroll, 1f) == 0) {
+ if (!mOverlayShown) {
+ mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
+ Action.Direction.LEFT, ContainerType.WORKSPACE, 0);
+ }
+ mOverlayShown = true;
+ } else if (Float.compare(scroll, 0f) == 0) {
+ if (mOverlayShown) {
+ mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
+ Action.Direction.RIGHT, ContainerType.WORKSPACE, -1);
+ }
+ mOverlayShown = false;
+ }
float offset = 0f;
float slip = 0f;
@@ -1530,16 +1538,13 @@ public class Workspace extends PagedView
}
@Override
- protected void getEdgeVerticalPosition(int[] pos) {
- View child = getChildAt(getPageCount() - 1);
- pos[0] = child.getTop();
- pos[1] = child.getBottom();
- }
-
- @Override
- protected void notifyPageSwitchListener() {
- super.notifyPageSwitchListener();
-
+ protected void notifyPageSwitchListener(int prevPage) {
+ super.notifyPageSwitchListener(prevPage);
+ if (prevPage != mCurrentPage) {
+ int swipeDirection = (prevPage < mCurrentPage) ? Action.Direction.RIGHT : Action.Direction.LEFT;
+ mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
+ swipeDirection, ContainerType.WORKSPACE, prevPage);
+ }
if (hasCustomContent() && getNextPage() == 0 && !mCustomContentShowing) {
mCustomContentShowing = true;
if (mCustomContentCallbacks != null) {
@@ -1634,16 +1639,21 @@ public class Workspace extends PagedView
}
private void updatePageAlphaValues() {
- if (mWorkspaceFadeInAdjacentScreens &&
- !workspaceInModalState() &&
- !mIsSwitchingState) {
+ if (!workspaceInModalState() && !mIsSwitchingState) {
int screenCenter = getScrollX() + getViewportWidth() / 2;
for (int i = numCustomPages(); i < getChildCount(); i++) {
CellLayout child = (CellLayout) getChildAt(i);
if (child != null) {
float scrollProgress = getScrollProgress(screenCenter, child, i);
float alpha = 1 - Math.abs(scrollProgress);
- child.getShortcutsAndWidgets().setAlpha(alpha);
+ if (mWorkspaceFadeInAdjacentScreens) {
+ child.getShortcutsAndWidgets().setAlpha(alpha);
+ } else {
+ // Pages that are off-screen aren't important for accessibility.
+ child.getShortcutsAndWidgets().setImportantForAccessibility(
+ alpha > 0 ? IMPORTANT_FOR_ACCESSIBILITY_AUTO
+ : IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ }
}
}
}
@@ -1889,13 +1899,20 @@ public class Workspace extends PagedView
return;
}
+ ArrayList<Long> prevScreenOrder = (ArrayList<Long>) mScreenOrder.clone();
mScreenOrder.clear();
int count = getChildCount();
for (int i = 0; i < count; i++) {
CellLayout cl = ((CellLayout) getChildAt(i));
mScreenOrder.add(getIdForScreen(cl));
}
- mLauncher.getUserEventDispatcher().logOverviewReorder();
+
+ for (int i = 0; i < prevScreenOrder.size(); i++) {
+ if (mScreenOrder.get(i) != prevScreenOrder.get(i)) {
+ mLauncher.getUserEventDispatcher().logOverviewReorder();
+ break;
+ }
+ }
LauncherModel.updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
// Re-enable auto layout transitions for page deletion.
@@ -2365,7 +2382,7 @@ public class Workspace extends PagedView
fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,
postAnimationRunnable);
} else {
- fi.prepareCreate(v);
+ fi.prepareCreateAnimation(v);
fi.addItem(destInfo);
fi.addItem(sourceInfo);
}
@@ -3974,8 +3991,9 @@ public class Workspace extends PagedView
}
}
- private void moveToScreen(int page, boolean animate) {
- if (!workspaceInModalState()) {
+ void moveToDefaultScreen(boolean animate) {
+ int page = getDefaultPage();
+ if (!workspaceInModalState() && getNextPage() != page) {
if (animate) {
snapToPage(page);
} else {
@@ -3988,10 +4006,6 @@ public class Workspace extends PagedView
}
}
- void moveToDefaultScreen(boolean animate) {
- moveToScreen(getDefaultPage(), animate);
- }
-
void moveToCustomContentScreen(boolean animate) {
if (hasCustomContent()) {
int ccIndex = getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID);
@@ -4068,7 +4082,7 @@ public class Workspace extends PagedView
* Used as a workaround to ensure that the AppWidgetService receives the
* PACKAGE_ADDED broadcast before updating widgets.
*/
- private class DeferredWidgetRefresh implements Runnable {
+ private class DeferredWidgetRefresh implements Runnable, ProviderChangedListener {
private final ArrayList<LauncherAppWidgetInfo> mInfos;
private final LauncherAppWidgetHost mHost;
private final Handler mHandler;
@@ -4111,6 +4125,11 @@ public class Workspace extends PagedView
}
});
}
+
+ @Override
+ public void notifyWidgetProvidersChanged() {
+ run();
+ }
}
private class StateTransitionListener extends AnimatorListenerAdapter
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
index 816121995..b7c500fa6 100644
--- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -50,8 +50,7 @@ public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDele
if ((host.getParent() instanceof DeepShortcutView)) {
info.addAction(mActions.get(ADD_TO_WORKSPACE));
} else if (host instanceof NotificationMainView) {
- NotificationMainView notificationView = (NotificationMainView) host;
- if (notificationView.canChildBeDismissed(notificationView)) {
+ if (((NotificationMainView) host).canChildBeDismissed()) {
info.addAction(mActions.get(DISMISS_NOTIFICATION));
}
}
@@ -88,8 +87,7 @@ public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDele
if (!(host instanceof NotificationMainView)) {
return false;
}
- NotificationMainView notificationView = (NotificationMainView) host;
- notificationView.onChildDismissed(notificationView);
+ ((NotificationMainView) host).onChildDismissed();
announceConfirmation(R.string.notification_dismissed);
return true;
}
diff --git a/src/com/android/launcher3/allapps/AllAppsCaretController.java b/src/com/android/launcher3/allapps/AllAppsCaretController.java
index 622322bfc..583b49f7b 100644
--- a/src/com/android/launcher3/allapps/AllAppsCaretController.java
+++ b/src/com/android/launcher3/allapps/AllAppsCaretController.java
@@ -22,13 +22,14 @@ import android.view.animation.Interpolator;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.pageindicators.CaretDrawable;
+import com.android.launcher3.touch.SwipeDetector;
public class AllAppsCaretController {
// Determines when the caret should flip. Should be accessed via getThreshold()
private static final float CARET_THRESHOLD = 0.015f;
private static final float CARET_THRESHOLD_LAND = 0.5f;
// The velocity at which the caret will peak (i.e. exhibit a 90 degree bend)
- private static final float PEAK_VELOCITY = VerticalPullDetector.RELEASE_VELOCITY_PX_MS * .7f;
+ private static final float PEAK_VELOCITY = SwipeDetector.RELEASE_VELOCITY_PX_MS * .7f;
private Launcher mLauncher;
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 47b68a2ee..0083d47f2 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -21,7 +21,6 @@ import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.InsetDrawable;
import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.util.AttributeSet;
@@ -220,17 +219,16 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
});
// Load the all apps recycler view
- mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);
+ mAppsRecyclerView = findViewById(R.id.apps_list_view);
mAppsRecyclerView.setApps(mApps);
mAppsRecyclerView.setLayoutManager(mLayoutManager);
mAppsRecyclerView.setAdapter(mAdapter);
mAppsRecyclerView.setHasFixedSize(true);
if (FeatureFlags.LAUNCHER3_PHYSICS) {
mAppsRecyclerView.setSpringAnimationHandler(mSpringAnimationHandler);
- mAppsRecyclerView.addOnScrollListener(new SpringMotionOnScrollListener());
}
- mSearchContainer = findViewById(R.id.search_container);
+ mSearchContainer = findViewById(R.id.search_container_all_apps);
mSearchUiManager = (SearchUiManager) mSearchContainer;
mSearchUiManager.initialize(mApps, mAppsRecyclerView);
@@ -359,7 +357,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
@Override
public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) {
- targetParent.containerType = mAppsRecyclerView.getContainerType(v);
+ // This is filled in {@link AllAppsRecyclerView}
}
@Override
@@ -403,35 +401,4 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
public SpringAnimationHandler getSpringAnimationHandler() {
return mSpringAnimationHandler;
}
-
- public class SpringMotionOnScrollListener extends RecyclerView.OnScrollListener {
-
- private int mScrollState = RecyclerView.SCROLL_STATE_IDLE;
-
- @Override
- public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
- if (mScrollState == RecyclerView.SCROLL_STATE_DRAGGING
- || (dx == 0 && dy == 0)) {
- if (mSpringAnimationHandler.isRunning()){
- mSpringAnimationHandler.skipToEnd();
- }
- return;
- }
-
- int first = mLayoutManager.findFirstVisibleItemPosition();
- int last = mLayoutManager.findLastVisibleItemPosition();
-
- // We only show the spring animation when at the top or bottom, so we wait until the
- // first or last row is visible to ensure that all animations run in sync.
- if ((first == 0 && dy < 0) || (last == mAdapter.getItemCount() - 1 && dy > 0)) {
- mSpringAnimationHandler.animateToFinalPosition(0);
- }
- }
-
- @Override
- public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
- super.onScrollStateChanged(recyclerView, newState);
- mScrollState = newState;
- }
- }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 1054a5633..ba4fbe061 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -481,19 +481,17 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
* 5 6 7 8 9
*/
private int getAppPosition(int position, int numPredictedApps, int appsPerRow) {
- int appPosition = position;
- int numDividerViews = 1 + (numPredictedApps == 0 ? 0 : 1);
-
- int allAppsStartAt = numDividerViews + numPredictedApps;
- if (numDividerViews == 1 || position < allAppsStartAt) {
- appPosition -= 1;
- } else {
- // We cannot assume that the predicted row will always be full.
- int numPredictedAppsOffset = appsPerRow - numPredictedApps;
- appPosition = position + numPredictedAppsOffset - numDividerViews;
+ if (position < numPredictedApps) {
+ // Predicted apps are first in the adapter.
+ return position;
}
- return appPosition;
+ // There is at most 1 divider view between the predicted apps and the alphabetical apps.
+ int numDividerViews = numPredictedApps == 0 ? 0 : 1;
+
+ // This offset takes into consideration an incomplete row of predicted apps.
+ int numPredictedAppsOffset = appsPerRow - numPredictedApps;
+ return position + numPredictedAppsOffset - numDividerViews;
}
/**
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 2b2fddcdd..331900cf1 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -15,12 +15,14 @@
*/
package com.android.launcher3.allapps;
+import android.animation.ObjectAnimator;
import android.content.Context;
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.Property;
import android.util.SparseIntArray;
import android.view.MotionEvent;
import android.view.View;
@@ -28,18 +30,23 @@ import android.view.View;
import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.ItemInfo;
import com.android.launcher3.R;
import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.DrawableFactory;
+import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
+import com.android.launcher3.touch.OverScroll;
+import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import java.util.List;
/**
* A RecyclerView with custom fast scroll support for the all apps view.
*/
-public class AllAppsRecyclerView extends BaseRecyclerView {
+public class AllAppsRecyclerView extends BaseRecyclerView implements LogContainerProvider {
private AlphabeticalAppsList mApps;
private AllAppsFastScrollHelper mFastScrollHelper;
@@ -54,6 +61,22 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
private int mEmptySearchBackgroundTopOffset;
private SpringAnimationHandler mSpringAnimationHandler;
+ private OverScrollHelper mOverScrollHelper;
+ private SwipeDetector mPullDetector;
+
+ private float mContentTranslationY = 0;
+ public static final Property<AllAppsRecyclerView, Float> CONTENT_TRANS_Y =
+ new Property<AllAppsRecyclerView, Float>(Float.class, "appsRecyclerViewContentTransY") {
+ @Override
+ public Float get(AllAppsRecyclerView allAppsRecyclerView) {
+ return allAppsRecyclerView.getContentTranslationY();
+ }
+
+ @Override
+ public void set(AllAppsRecyclerView allAppsRecyclerView, Float y) {
+ allAppsRecyclerView.setContentTranslationY(y);
+ }
+ };
public AllAppsRecyclerView(Context context) {
this(context, null);
@@ -74,14 +97,28 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
addOnItemTouchListener(this);
mEmptySearchBackgroundTopOffset = res.getDimensionPixelSize(
R.dimen.all_apps_empty_search_bg_top_offset);
+
+ mOverScrollHelper = new OverScrollHelper();
+ mPullDetector = new SwipeDetector(getContext(), mOverScrollHelper, SwipeDetector.VERTICAL);
+ mPullDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, true);
}
public void setSpringAnimationHandler(SpringAnimationHandler springAnimationHandler) {
- mSpringAnimationHandler = springAnimationHandler;
+ if (FeatureFlags.LAUNCHER3_PHYSICS) {
+ mSpringAnimationHandler = springAnimationHandler;
+ addOnScrollListener(new SpringMotionOnScrollListener());
+ }
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) {
+ mPullDetector.onTouchEvent(ev);
+ return super.onInterceptTouchEvent(rv, ev) || mOverScrollHelper.isInOverScroll();
}
@Override
public boolean onTouchEvent(MotionEvent e) {
+ mPullDetector.onTouchEvent(e);
if (FeatureFlags.LAUNCHER3_PHYSICS && mSpringAnimationHandler != null) {
mSpringAnimationHandler.addMovement(e);
}
@@ -168,6 +205,8 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
@Override
public void onDraw(Canvas c) {
+ c.translate(0, mContentTranslationY);
+
// Draw the background
if (mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) {
mEmptySearchBackground.draw(c);
@@ -176,6 +215,19 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
super.onDraw(c);
}
+ public float getContentTranslationY() {
+ return mContentTranslationY;
+ }
+
+ /**
+ * Use this method instead of calling {@link #setTranslationY(float)}} directly to avoid drawing
+ * on top of other Views.
+ */
+ public void setContentTranslationY(float y) {
+ mContentTranslationY = y;
+ invalidate();
+ }
+
@Override
protected boolean verifyDrawable(Drawable who) {
return who == mEmptySearchBackground || super.verifyDrawable(who);
@@ -186,9 +238,10 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
updateEmptySearchBackgroundBounds();
}
- public int getContainerType(View v) {
+ @Override
+ public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) {
if (mApps.hasFilter()) {
- return ContainerType.SEARCHRESULT;
+ targetParent.containerType = ContainerType.SEARCHRESULT;
} else {
if (v instanceof BubbleTextView) {
BubbleTextView icon = (BubbleTextView) v;
@@ -197,11 +250,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
AlphabeticalAppsList.AdapterItem item = items.get(position);
if (item.viewType == AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON) {
- return ContainerType.PREDICTION;
+ targetParent.containerType = ContainerType.PREDICTION;
+ target.predictedRank = item.rowAppIndex;
+ return;
}
}
}
- return ContainerType.ALLAPPS;
+ targetParent.containerType = ContainerType.ALLAPPS;
}
}
@@ -434,4 +489,104 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
y + mEmptySearchBackground.getIntrinsicHeight());
}
+ private class SpringMotionOnScrollListener extends RecyclerView.OnScrollListener {
+
+ @Override
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ if (mOverScrollHelper.isInOverScroll()) {
+ // OverScroll will handle animating the springs.
+ return;
+ }
+
+ // We only start the spring animation when we hit the top/bottom, to ensure
+ // that all of the animations start at the same time.
+ if (dy < 0 && !canScrollVertically(-1)) {
+ mSpringAnimationHandler.animateToFinalPosition(0, 1);
+ } else if (dy > 0 && !canScrollVertically(1)) {
+ mSpringAnimationHandler.animateToFinalPosition(0, -1);
+ }
+ }
+ }
+
+ private class OverScrollHelper implements SwipeDetector.Listener {
+
+ private static final float MAX_RELEASE_VELOCITY = 5000; // px / s
+ private static final float MAX_OVERSCROLL_PERCENTAGE = 0.07f;
+
+ private boolean mIsInOverScroll;
+
+ // We use this value to calculate the actual amount the user has overscrolled.
+ private float mFirstDisplacement = 0;
+
+ private boolean mAlreadyScrollingUp;
+ private int mFirstScrollYOnScrollUp;
+
+ @Override
+ public void onDragStart(boolean start) {
+ }
+
+ @Override
+ public boolean onDrag(float displacement, float velocity) {
+ boolean isScrollingUp = displacement > 0;
+ if (isScrollingUp) {
+ if (!mAlreadyScrollingUp) {
+ mFirstScrollYOnScrollUp = getCurrentScrollY();
+ mAlreadyScrollingUp = true;
+ }
+ } else {
+ mAlreadyScrollingUp = false;
+ }
+
+ // Only enter overscroll if the user is interacting with the RecyclerView directly
+ // and if one of the following criteria are met:
+ // - User scrolls down when they're already at the bottom.
+ // - User starts scrolling up, hits the top, and continues scrolling up.
+ mIsInOverScroll = !mScrollbar.isDraggingThumb() &&
+ ((!canScrollVertically(1) && displacement < 0) ||
+ (!canScrollVertically(-1) && isScrollingUp && mFirstScrollYOnScrollUp != 0));
+
+ if (mIsInOverScroll) {
+ if (Float.compare(mFirstDisplacement, 0) == 0) {
+ // Because users can scroll before entering overscroll, we need to
+ // subtract the amount where the user was not in overscroll.
+ mFirstDisplacement = displacement;
+ }
+ float overscrollY = displacement - mFirstDisplacement;
+ setContentTranslationY(getDampedOverScroll(overscrollY));
+ }
+
+ return mIsInOverScroll;
+ }
+
+ @Override
+ public void onDragEnd(float velocity, boolean fling) {
+ float y = getContentTranslationY();
+ if (Float.compare(y, 0) != 0) {
+ if (FeatureFlags.LAUNCHER3_PHYSICS) {
+ // We calculate our own velocity to give the springs the desired effect.
+ velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY;
+ // We want to negate the velocity because we are moving to 0 from -1 due to the
+ // downward motion. (y-axis -1 is above 0).
+ mSpringAnimationHandler.animateToPositionWithVelocity(0, -1, -velocity);
+ }
+
+ ObjectAnimator.ofFloat(AllAppsRecyclerView.this,
+ AllAppsRecyclerView.CONTENT_TRANS_Y, 0)
+ .setDuration(100)
+ .start();
+ }
+ mIsInOverScroll = false;
+ mFirstDisplacement = 0;
+ mFirstScrollYOnScrollUp = 0;
+ mAlreadyScrollingUp = false;
+ }
+
+ public boolean isInOverScroll() {
+ return mIsInOverScroll;
+ }
+
+ private float getDampedOverScroll(float y) {
+ return OverScroll.dampedScroll(y, getHeight());
+ }
+ }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 4d112c632..6896b37d9 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -25,7 +25,7 @@ import com.android.launcher3.Workspace;
import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.GradientView;
-import com.android.launcher3.graphics.ScrimView;
+import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.SystemUiController;
@@ -42,7 +42,7 @@ import com.android.launcher3.util.TouchController;
* If release velocity < THRES1, snap according to either top or bottom depending on whether it's
* closer to top or closer to the page indicator.
*/
-public class AllAppsTransitionController implements TouchController, VerticalPullDetector.Listener,
+public class AllAppsTransitionController implements TouchController, SwipeDetector.Listener,
SearchUiManager.OnScrollRangeChangeListener {
private static final String TAG = "AllAppsTrans";
@@ -52,8 +52,8 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
private final Interpolator mHotseatAccelInterpolator = new AccelerateInterpolator(1.5f);
private final Interpolator mDecelInterpolator = new DecelerateInterpolator(3f);
private final Interpolator mFastOutSlowInInterpolator = new FastOutSlowInInterpolator();
- private final VerticalPullDetector.ScrollInterpolator mScrollInterpolator
- = new VerticalPullDetector.ScrollInterpolator();
+ private final SwipeDetector.ScrollInterpolator mScrollInterpolator
+ = new SwipeDetector.ScrollInterpolator();
private static final float PARALLAX_COEFFICIENT = .125f;
private static final int SINGLE_FRAME_MS = 16;
@@ -69,7 +69,7 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
private float mStatusBarHeight;
private final Launcher mLauncher;
- private final VerticalPullDetector mDetector;
+ private final SwipeDetector mDetector;
private final ArgbEvaluator mEvaluator;
private final boolean mIsDarkTheme;
@@ -100,14 +100,12 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
private boolean mIsTranslateWithoutWorkspace = false;
private AnimatorSet mDiscoBounceAnimation;
private GradientView mGradientView;
- private ScrimView mScrimView;
private SpringAnimationHandler mSpringAnimationHandler;
public AllAppsTransitionController(Launcher l) {
mLauncher = l;
- mDetector = new VerticalPullDetector(l);
- mDetector.setListener(this);
+ mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL);
mShiftRange = DEFAULT_SHIFT_RANGE;
mProgress = 1f;
@@ -136,17 +134,17 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
if (mDetector.isIdleState()) {
if (mLauncher.isAllAppsVisible()) {
- directionsToDetectScroll |= VerticalPullDetector.DIRECTION_DOWN;
+ directionsToDetectScroll |= SwipeDetector.DIRECTION_NEGATIVE;
} else {
- directionsToDetectScroll |= VerticalPullDetector.DIRECTION_UP;
+ directionsToDetectScroll |= SwipeDetector.DIRECTION_POSITIVE;
}
} else {
if (isInDisallowRecatchBottomZone()) {
- directionsToDetectScroll |= VerticalPullDetector.DIRECTION_UP;
+ directionsToDetectScroll |= SwipeDetector.DIRECTION_POSITIVE;
} else if (isInDisallowRecatchTopZone()) {
- directionsToDetectScroll |= VerticalPullDetector.DIRECTION_DOWN;
+ directionsToDetectScroll |= SwipeDetector.DIRECTION_NEGATIVE;
} else {
- directionsToDetectScroll |= VerticalPullDetector.DIRECTION_BOTH;
+ directionsToDetectScroll |= SwipeDetector.DIRECTION_BOTH;
ignoreSlopWhenSettling = true;
}
}
@@ -228,7 +226,8 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
}
mLauncher.showAppsView(true /* animated */, false /* updatePredictedApps */);
if (hasSpringAnimationHandler()) {
- mSpringAnimationHandler.animateToFinalPosition(0);
+ // The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.)
+ mSpringAnimationHandler.animateToFinalPosition(0 /* pos */, 1 /* startValue */);
}
} else {
calculateDuration(velocity, Math.abs(mShiftRange - mAppsView.getTranslationY()));
@@ -301,13 +300,6 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
mGradientView.setVisibility(View.VISIBLE);
}
mGradientView.setProgress(progress);
-
- // scrim
- if (mScrimView == null) {
- mScrimView = (ScrimView) mLauncher.findViewById(R.id.scrim_bg);
- mScrimView.setVisibility(View.VISIBLE);
- }
- mScrimView.setProgress(progress);
}
/**
@@ -366,7 +358,7 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
}
private void calculateDuration(float velocity, float disp) {
- mAnimationDuration = mDetector.calculateDuration(velocity, disp / mShiftRange);
+ mAnimationDuration = SwipeDetector.calculateDuration(velocity, disp / mShiftRange);
}
public boolean animateToAllApps(AnimatorSet animationOut, long duration) {
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index 5cb12d592..39e208874 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -202,7 +202,8 @@ public class AppsSearchContainerLayout extends FrameLayout
if (!dp.isVerticalBarLayout()) {
Rect insets = mLauncher.getDragLayer().getInsets();
int hotseatBottom = bottom - dp.hotseatBarBottomPaddingPx - insets.bottom;
- int searchTopMargin = insets.top + (mMinHeight - mSearchBoxHeight);
+ int searchTopMargin = insets.top + (mMinHeight - mSearchBoxHeight)
+ + ((MarginLayoutParams) getLayoutParams()).bottomMargin;
listener.onScrollRangeChanged(hotseatBottom - searchTopMargin);
} else {
listener.onScrollRangeChanged(bottom);
diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
index 43033024f..cdbaf708d 100644
--- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
@@ -20,6 +20,7 @@ import android.os.Handler;
import com.android.launcher3.AppInfo;
import com.android.launcher3.util.ComponentKey;
+import java.text.Collator;
import java.util.ArrayList;
import java.util.List;
@@ -61,8 +62,9 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
// apps that don't match all of the words in the query.
final String queryTextLower = query.toLowerCase();
final ArrayList<ComponentKey> result = new ArrayList<>();
+ StringMatcher matcher = StringMatcher.getInstance();
for (AppInfo info : mApps) {
- if (matches(info, queryTextLower)) {
+ if (matches(info, queryTextLower, matcher)) {
result.add(info.toComponentKey());
}
}
@@ -70,6 +72,10 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
}
public static boolean matches(AppInfo info, String query) {
+ return matches(info, query, StringMatcher.getInstance());
+ }
+
+ public static boolean matches(AppInfo info, String query, StringMatcher matcher) {
int queryLength = query.length();
String title = info.title.toString();
@@ -90,7 +96,7 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
nextType = i < (titleLength - 1) ?
Character.getType(title.codePointAt(i + 1)) : Character.UNASSIGNED;
if (isBreak(thisType, lastType, nextType) &&
- title.substring(i, i + queryLength).equalsIgnoreCase(query)) {
+ matcher.matches(query, title.substring(i, i + queryLength))) {
return true;
}
}
@@ -106,6 +112,13 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
* 4) Any capital character before a small character
*/
private static boolean isBreak(int thisType, int prevType, int nextType) {
+ switch (prevType) {
+ case Character.UNASSIGNED:
+ case Character.SPACE_SEPARATOR:
+ case Character.LINE_SEPARATOR:
+ case Character.PARAGRAPH_SEPARATOR:
+ return true;
+ }
switch (thisType) {
case Character.UPPERCASE_LETTER:
if (nextType == Character.UPPERCASE_LETTER) {
@@ -136,4 +149,41 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
return prevType == Character.UNASSIGNED;
}
}
+
+ public static class StringMatcher {
+
+ private static final char MAX_UNICODE = '\uFFFF';
+
+ private final Collator mCollator;
+
+ StringMatcher() {
+ // On android N and above, Collator uses ICU implementation which has a much better
+ // support for non-latin locales.
+ mCollator = Collator.getInstance();
+ mCollator.setStrength(Collator.PRIMARY);
+ mCollator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
+ }
+
+ /**
+ * Returns true if {@param query} is a prefix of {@param target}
+ */
+ public boolean matches(String query, String target) {
+ switch (mCollator.compare(query, target)) {
+ case 0:
+ return true;
+ case -1:
+ // The target string can contain a modifier which would make it larger than
+ // the query string (even though the length is same). If the query becomes
+ // larger after appending a unicode character, it was originally a prefix of
+ // the target string and hence should match.
+ return mCollator.compare(query + MAX_UNICODE, target) > -1;
+ default:
+ return false;
+ }
+ }
+
+ public static StringMatcher getInstance() {
+ return new StringMatcher();
+ }
+ }
}
diff --git a/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java b/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java
index 7c5fa1ced..d01b26c8f 100644
--- a/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java
+++ b/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java
@@ -56,7 +56,7 @@ public class RoundedRectRevealOutlineProvider extends RevealOutlineAnimation {
@Override
public boolean shouldRemoveElevationDuringAnimation() {
- return true;
+ return false;
}
@Override
diff --git a/src/com/android/launcher3/anim/SpringAnimationHandler.java b/src/com/android/launcher3/anim/SpringAnimationHandler.java
index 038f82682..3e58adc3f 100644
--- a/src/com/android/launcher3/anim/SpringAnimationHandler.java
+++ b/src/com/android/launcher3/anim/SpringAnimationHandler.java
@@ -111,22 +111,54 @@ public class SpringAnimationHandler<T> {
mShouldComputeVelocity = true;
}
- public void animateToFinalPosition(float position) {
- if (DEBUG) Log.d(TAG, "animateToFinalPosition#computeVelocity=" + mShouldComputeVelocity);
+ public void animateToFinalPosition(float position, int startValue) {
+ animateToFinalPosition(position, startValue, mShouldComputeVelocity);
+ }
+
+ /**
+ * @param position The final animation position.
+ * @param startValue < 0 if scrolling from start to end; > 0 if scrolling from end to start
+ * The magnitude of the number changes how the spring will move.
+ * @param setVelocity If true, we set the velocity to {@link #mCurrentVelocity} before
+ * starting the animation.
+ */
+ private void animateToFinalPosition(float position, int startValue, boolean setVelocity) {
+ if (DEBUG) {
+ Log.d(TAG, "animateToFinalPosition#position=" + position + ", startValue=" + startValue);
+ }
if (mShouldComputeVelocity) {
- computeVelocity();
- setStartVelocity(mCurrentVelocity);
+ mCurrentVelocity = computeVelocity();
}
int size = mAnimations.size();
for (int i = 0; i < size; ++i) {
+ mAnimations.get(i).setStartValue(startValue);
+ if (setVelocity) {
+ mAnimations.get(i).setStartVelocity(mCurrentVelocity);
+ }
mAnimations.get(i).animateToFinalPosition(position);
}
reset();
}
+ /**
+ * Similar to {@link #animateToFinalPosition(float, int)}, but used in cases where we want to
+ * manually set the velocity.
+ */
+ public void animateToPositionWithVelocity(float position, int startValue, float velocity) {
+ if (DEBUG) {
+ Log.d(TAG, "animateToPosition#pos=" + position + ", start=" + startValue
+ + ", velocity=" + velocity);
+ }
+
+ mCurrentVelocity = velocity;
+ mShouldComputeVelocity = false;
+ animateToFinalPosition(position, startValue, true);
+ }
+
+
public boolean isRunning() {
// All the animations run at the same time so we can just check the first one.
return !mAnimations.isEmpty() && mAnimations.get(0).isRunning();
@@ -150,25 +182,20 @@ public class SpringAnimationHandler<T> {
mVelocityTracker = null;
}
mCurrentVelocity = 0;
+ mShouldComputeVelocity = false;
}
- private void setStartVelocity(float velocity) {
- int size = mAnimations.size();
- for (int i = 0; i < size; ++i) {
- mAnimations.get(i).setStartVelocity(velocity);
- }
- }
- private void computeVelocity() {
+ private float computeVelocity() {
getVelocityTracker().computeCurrentVelocity(1000 /* millis */);
- mCurrentVelocity = isVerticalDirection()
+ float velocity = isVerticalDirection()
? getVelocityTracker().getYVelocity()
: getVelocityTracker().getXVelocity();
- mCurrentVelocity *= VELOCITY_DAMPING_FACTOR;
- mShouldComputeVelocity = false;
+ velocity *= VELOCITY_DAMPING_FACTOR;
- if (DEBUG) Log.d(TAG, "computeVelocity=" + mCurrentVelocity);
+ if (DEBUG) Log.d(TAG, "computeVelocity=" + velocity);
+ return velocity;
}
private boolean isVerticalDirection() {
@@ -206,7 +233,6 @@ public class SpringAnimationHandler<T> {
*/
public static SpringAnimation forView(View view, FloatPropertyCompat property, float finalPos) {
SpringAnimation spring = new SpringAnimation(view, property, finalPos);
- spring.setStartValue(1f);
spring.setSpring(new SpringForce(finalPos));
return spring;
}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
index 3efbbfba5..4e00eae9d 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -16,15 +16,12 @@
package com.android.launcher3.compat;
-import android.app.Activity;
-import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
import android.os.UserHandle;
-import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
@@ -76,9 +73,6 @@ public abstract class AppWidgetManagerCompat {
public abstract boolean bindAppWidgetIdIfAllowed(
int appWidgetId, AppWidgetProviderInfo info, Bundle options);
- public abstract void startConfigActivity(AppWidgetProviderInfo info, int widgetId,
- Activity activity, AppWidgetHost host, int requestCode);
-
public abstract LauncherAppWidgetProviderInfo findProvider(
ComponentName provider, UserHandle user);
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
index f239f5c31..cb3bd6c7d 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -16,24 +16,21 @@
package com.android.launcher3.compat;
-import android.app.Activity;
-import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetProviderInfo;
-import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.annotation.Nullable;
-import android.widget.Toast;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -49,6 +46,9 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
@Override
public List<AppWidgetProviderInfo> getAllProviders(@Nullable PackageUserKey packageUser) {
+ if (FeatureFlags.GO_DISABLE_WIDGETS) {
+ return Collections.emptyList();
+ }
if (packageUser == null) {
ArrayList<AppWidgetProviderInfo> providers = new ArrayList<AppWidgetProviderInfo>();
for (UserHandle user : mUserManager.getUserProfiles()) {
@@ -71,24 +71,20 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
@Override
public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info,
Bundle options) {
+ if (FeatureFlags.GO_DISABLE_WIDGETS) {
+ return false;
+ }
return mAppWidgetManager.bindAppWidgetIdIfAllowed(
appWidgetId, info.getProfile(), info.provider, options);
}
@Override
- public void startConfigActivity(AppWidgetProviderInfo info, int widgetId, Activity activity,
- AppWidgetHost host, int requestCode) {
- try {
- host.startAppWidgetConfigureActivityForResult(activity, widgetId, 0, requestCode, null);
- } catch (ActivityNotFoundException | SecurityException e) {
- Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- }
- }
-
- @Override
public LauncherAppWidgetProviderInfo findProvider(ComponentName provider, UserHandle user) {
- for (AppWidgetProviderInfo info : mAppWidgetManager
- .getInstalledProvidersForProfile(user)) {
+ if (FeatureFlags.GO_DISABLE_WIDGETS) {
+ return null;
+ }
+ for (AppWidgetProviderInfo info :
+ getAllProviders(new PackageUserKey(provider.getPackageName(), user))) {
if (info.provider.equals(provider)) {
return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
}
@@ -99,6 +95,9 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
@Override
public HashMap<ComponentKey, AppWidgetProviderInfo> getAllProvidersMap() {
HashMap<ComponentKey, AppWidgetProviderInfo> result = new HashMap<>();
+ if (FeatureFlags.GO_DISABLE_WIDGETS) {
+ return result;
+ }
for (UserHandle user : mUserManager.getUserProfiles()) {
for (AppWidgetProviderInfo info :
mAppWidgetManager.getInstalledProvidersForProfile(user)) {
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
index 1c48a13bd..44158edbf 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
@@ -20,8 +20,10 @@ 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;
+import java.util.Collections;
import java.util.List;
class AppWidgetManagerCompatVO extends AppWidgetManagerCompatVL {
@@ -32,6 +34,9 @@ class AppWidgetManagerCompatVO extends AppWidgetManagerCompatVL {
@Override
public List<AppWidgetProviderInfo> getAllProviders(@Nullable PackageUserKey packageUser) {
+ if (FeatureFlags.GO_DISABLE_WIDGETS) {
+ return Collections.emptyList();
+ }
if (packageUser == null) {
return super.getAllProviders(null);
}
diff --git a/src/com/android/launcher3/compat/WallpaperColorsCompat.java b/src/com/android/launcher3/compat/WallpaperColorsCompat.java
index 58d2a8028..e25b9d929 100644
--- a/src/com/android/launcher3/compat/WallpaperColorsCompat.java
+++ b/src/com/android/launcher3/compat/WallpaperColorsCompat.java
@@ -21,6 +21,7 @@ package com.android.launcher3.compat;
public class WallpaperColorsCompat {
public static final int HINT_SUPPORTS_DARK_TEXT = 0x1;
+ public static final int HINT_SUPPORTS_DARK_THEME = 0x2;
private final int mPrimaryColor;
private final int mSecondaryColor;
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
new file mode 100644
index 000000000..9e0a3b3b5
--- /dev/null
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -0,0 +1,73 @@
+/*
+ * 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.config;
+
+/**
+ * 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}.
+ *
+ * This class is kept package-private to prevent direct access.
+ */
+abstract class BaseFlags {
+
+ BaseFlags() {}
+
+ public static final boolean IS_DOGFOOD_BUILD = false;
+
+ // Custom flags go below this
+ public static boolean LAUNCHER3_DISABLE_ICON_NORMALIZATION = false;
+ public static boolean LAUNCHER3_LEGACY_FOLDER_ICON = false;
+ public static boolean LAUNCHER3_DISABLE_PINCH_TO_OVERVIEW = false;
+ public static boolean LAUNCHER3_ALL_APPS_PULL_UP = true;
+ public static boolean LAUNCHER3_NEW_FOLDER_ANIMATION = true;
+ // When enabled allows to use any point on the fast scrollbar to start dragging.
+ public static final boolean LAUNCHER3_DIRECT_SCROLL = true;
+ // When enabled while all-apps open, the soft input will be set to adjust resize .
+ public static final boolean LAUNCHER3_UPDATE_SOFT_INPUT_MODE = 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 uses the AllAppsRadialGradientAndScrimDrawable for all apps
+ public static final boolean LAUNCHER3_GRADIENT_ALL_APPS = true;
+ // When enabled allows use of physics based motions in the Launcher.
+ public static final boolean LAUNCHER3_PHYSICS = true;
+ // 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;
+ // When enabled fling down gesture on the first workspace triggers search.
+ public static final boolean PULLDOWN_SEARCH = false;
+ // When enabled the status bar may show dark icons based on the top of the wallpaper.
+ public static final boolean LIGHT_STATUS_BAR = false;
+ // When enabled icons are badged with the number of notifications associated with that app.
+ public static final boolean BADGE_ICONS = true;
+ // When enabled, icons not supporting {@link AdaptiveIconDrawable} will be wrapped in {@link FixedScaleDrawable}.
+ public static final boolean LEGACY_ICON_TREATMENT = true;
+ // When enabled, adaptive icons would have shadows baked when being stored to icon cache.
+ public static final boolean ADAPTIVE_ICON_SHADOW = true;
+ // When enabled, app discovery will be enabled if service is implemented
+ public static final boolean DISCOVERY_ENABLED = false;
+ // When enabled, the qsb will be moved to the hotseat.
+ public static final boolean QSB_IN_HOTSEAT = true;
+
+ // Features to control Launcher3Go behavior
+ public static final boolean GO_DISABLE_WIDGETS = false;
+}
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 01893bdaf..c843e7266 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -16,14 +16,8 @@
package com.android.launcher3.dragndrop;
-import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
-import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
-import static com.android.launcher3.logging.LoggerUtils.newItemTarget;
-import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
-
import android.annotation.TargetApi;
import android.app.ActivityOptions;
-import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -45,8 +39,8 @@ import android.view.View.OnTouchListener;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.InstallShortcutReceiver;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetHost;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -61,6 +55,11 @@ import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.WidgetHostViewLoader;
import com.android.launcher3.widget.WidgetImageView;
+import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
+import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
+import static com.android.launcher3.logging.LoggerUtils.newItemTarget;
+import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
+
@TargetApi(Build.VERSION_CODES.O)
public class AddItemActivity extends BaseActivity implements OnLongClickListener, OnTouchListener {
@@ -78,7 +77,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
private LivePreviewWidgetCell mWidgetCell;
// Widget request specific options.
- private AppWidgetHost mAppWidgetHost;
+ private LauncherAppWidgetHost mAppWidgetHost;
private AppWidgetManagerCompat mAppWidgetManager;
private PendingAddWidgetInfo mPendingWidgetInfo;
private int mPendingBindWidgetId;
@@ -212,7 +211,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
mWidgetCell.setPreview(PinItemDragListener.getPreview(mRequest));
mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
- mAppWidgetHost = new AppWidgetHost(this, Launcher.APPWIDGET_HOST_ID);
+ mAppWidgetHost = new LauncherAppWidgetHost(this);
mPendingWidgetInfo = new PendingAddWidgetInfo(widgetInfo);
mPendingWidgetInfo.spanX = Math.min(mIdp.numColumns, widgetInfo.spanX);
@@ -256,13 +255,8 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
}
// request bind widget
- Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mPendingBindWidgetId);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER,
- mPendingWidgetInfo.componentName);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE,
- mRequest.getAppWidgetProviderInfo(this).getProfile());
- startActivityForResult(intent, REQUEST_BIND_APPWIDGET);
+ mAppWidgetHost.startBindFlow(this, mPendingBindWidgetId,
+ mRequest.getAppWidgetProviderInfo(this), REQUEST_BIND_APPWIDGET);
}
private void acceptWidget(int widgetId) {
@@ -280,7 +274,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
}
@Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_BIND_APPWIDGET) {
int widgetId = data != null
? data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mPendingBindWidgetId)
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 022b3b8b1..b6e38bb15 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -16,23 +16,18 @@
package com.android.launcher3.dragndrop;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.FloatArrayEvaluator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.pm.LauncherActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
@@ -44,13 +39,11 @@ import android.graphics.drawable.InsetDrawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
-import android.support.animation.DynamicAnimation;
+import android.support.animation.FloatPropertyCompat;
import android.support.animation.SpringAnimation;
import android.support.animation.SpringForce;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.ItemInfo;
@@ -76,12 +69,16 @@ import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.util.Arrays;
import java.util.List;
-public class DragView extends FrameLayout {
+public class DragView extends View {
+ private static final ColorMatrix sTempMatrix1 = new ColorMatrix();
+ private static final ColorMatrix sTempMatrix2 = new ColorMatrix();
+
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;
@Thunk Paint mPaint;
@@ -114,16 +111,11 @@ public class DragView extends FrameLayout {
private int mAnimatedShiftY;
// Below variable only needed IF FeatureFlags.LAUNCHER3_SPRING_ICONS is {@code true}
- private SpringAnimation mSpringX, mSpringY;
- private ImageView mFgImageView, mBgImageView;
+ private Drawable mBgSpringDrawable, mFgSpringDrawable;
+ private SpringFloatValue mTranslateX, mTranslateY;
private Path mScaledMaskPath;
private Drawable mBadge;
-
- // Following three values are fine tuned with motion ux designer
- private final static int STIFFNESS = 4000;
- private final static float DAMPENING_RATIO = 1f;
- private final static int PARALLAX_MAX_IN_DP = 8;
- private final int mDelta;
+ private ColorMatrixColorFilter mBaseFilter;
/**
* Construct the drag view.
@@ -193,12 +185,11 @@ public class DragView extends FrameLayout {
mBlurSizeOutline = getResources().getDimensionPixelSize(R.dimen.blur_size_medium_outline);
setElevation(getResources().getDimension(R.dimen.drag_elevation));
- setWillNotDraw(false);
- mDelta = (int)(getResources().getDisplayMetrics().density * PARALLAX_MAX_IN_DP);
}
/**
- * Initialize {@code #mIconDrawable} only if the icon type is app icon (not shortcut or folder).
+ * Initialize {@code #mIconDrawable} if the item can be represented using
+ * an {@link AdaptiveIconDrawable} or {@link FolderAdaptiveIcon}.
*/
@TargetApi(Build.VERSION_CODES.O)
public void setItemInfo(final ItemInfo info) {
@@ -206,7 +197,8 @@ public class DragView extends FrameLayout {
return;
}
if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
- info.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ info.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
+ info.itemType != LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
return;
}
// Load the adaptive icon on a background thread and add the view in ui thread.
@@ -216,51 +208,103 @@ public class DragView extends FrameLayout {
public void run() {
LauncherAppState appState = LauncherAppState.getInstance(mLauncher);
Object[] outObj = new Object[1];
- Drawable dr = getFullDrawable(info, appState, outObj);
+ final Drawable dr = getFullDrawable(info, appState, outObj);
if (dr instanceof AdaptiveIconDrawable) {
int w = mBitmap.getWidth();
int h = mBitmap.getHeight();
+ int blurMargin = (int) mLauncher.getResources()
+ .getDimension(R.dimen.blur_size_medium_outline) / 2;
+
+ Rect bounds = new Rect(0, 0, w, h);
+ bounds.inset(blurMargin, blurMargin);
+ Utilities.scaleRectAboutCenter(bounds,
+ IconNormalizer.getInstance(mLauncher).getScale(dr, null, null, null));
AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) dr;
- adaptiveIcon.setBounds(0, 0, w, h);
- float blurSizeOutline = mLauncher.getResources()
- .getDimension(R.dimen.blur_size_medium_outline);
- float normalizationScale = IconNormalizer.getInstance(mLauncher)
- .getScale(adaptiveIcon, null, null, null) * ((w - blurSizeOutline) / w);
-
- final Path mask = getMaskPath(adaptiveIcon, normalizationScale);
- mFgImageView = setupImageView(adaptiveIcon.getForeground(), normalizationScale);
- mBgImageView = setupImageView(adaptiveIcon.getBackground(), normalizationScale);
- mSpringX = setupSpringAnimation(-w/4, w/4, DynamicAnimation.TRANSLATION_X);
- mSpringY = setupSpringAnimation(-h/4, h/4, DynamicAnimation.TRANSLATION_Y);
+
+ // Shrink very tiny bit so that the clip path is smaller than the original bitmap
+ // that has anti aliased edges and shadows.
+ Rect shrunkBounds = new Rect(bounds);
+ Utilities.scaleRectAboutCenter(shrunkBounds, 0.98f);
+ adaptiveIcon.setBounds(shrunkBounds);
+ final Path mask = adaptiveIcon.getIconMask();
+
+ mTranslateX = new SpringFloatValue(DragView.this,
+ w * AdaptiveIconDrawable.getExtraInsetFraction());
+ mTranslateY = new SpringFloatValue(DragView.this,
+ h * AdaptiveIconDrawable.getExtraInsetFraction());
mBadge = getBadge(info, appState, outObj[0]);
- int blurMargin = (int) blurSizeOutline / 2;
- mBadge.setBounds(blurMargin, blurMargin, w - blurMargin, h - blurMargin);
+ mBadge.setBounds(bounds);
+
+ bounds.inset(
+ (int) (-bounds.width() * AdaptiveIconDrawable.getExtraInsetFraction()),
+ (int) (-bounds.height() * AdaptiveIconDrawable.getExtraInsetFraction())
+ );
+ mBgSpringDrawable = adaptiveIcon.getBackground();
+ if (mBgSpringDrawable == null) {
+ mBgSpringDrawable = new ColorDrawable(Color.TRANSPARENT);
+ }
+ mBgSpringDrawable.setBounds(bounds);
+ mFgSpringDrawable = adaptiveIcon.getForeground();
+ if (mFgSpringDrawable == null) {
+ mFgSpringDrawable = new ColorDrawable(Color.TRANSPARENT);
+ }
+ mFgSpringDrawable.setBounds(bounds);
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// Assign the variable on the UI thread to avoid race conditions.
mScaledMaskPath = mask;
- addView(mBgImageView);
- addView(mFgImageView);
- setWillNotDraw(true);
+
+ // Do not draw the background in case of folder as its translucent
+ mDrawBitmap = !(dr instanceof FolderAdaptiveIcon);
if (info.isDisabled()) {
FastBitmapDrawable d = new FastBitmapDrawable(null);
d.setIsDisabled(true);
- ColorFilter cf = d.getColorFilter();
- mBgImageView.setColorFilter(cf);
- mFgImageView.setColorFilter(cf);
- mBadge.setColorFilter(cf);
+ mBaseFilter = (ColorMatrixColorFilter) d.getColorFilter();
}
+ updateColorFilter();
}
});
}
}});
}
+ @TargetApi(Build.VERSION_CODES.O)
+ private void updateColorFilter() {
+ if (mCurrentFilter == null) {
+ mPaint.setColorFilter(null);
+
+ if (mScaledMaskPath != null) {
+ mBgSpringDrawable.setColorFilter(mBaseFilter);
+ mBgSpringDrawable.setColorFilter(mBaseFilter);
+ mBadge.setColorFilter(mBaseFilter);
+ }
+ } else {
+ ColorMatrixColorFilter currentFilter = new ColorMatrixColorFilter(mCurrentFilter);
+ mPaint.setColorFilter(currentFilter);
+
+ if (mScaledMaskPath != null) {
+ if (mBaseFilter != null) {
+ mBaseFilter.getColorMatrix(sTempMatrix1);
+ sTempMatrix2.set(mCurrentFilter);
+ sTempMatrix1.postConcat(sTempMatrix2);
+
+ currentFilter = new ColorMatrixColorFilter(sTempMatrix1);
+ }
+
+ mBgSpringDrawable.setColorFilter(currentFilter);
+ mFgSpringDrawable.setColorFilter(currentFilter);
+ mBadge.setColorFilter(currentFilter);
+ }
+ }
+
+ invalidate();
+ }
+
/**
* Returns the full drawable for {@param info}.
* @param outObj this is set to the internal data associated with {@param info},
@@ -291,6 +335,14 @@ public class DragView extends FrameLayout {
return sm.getShortcutIconDrawable(si.get(0),
appState.getInvariantDeviceProfile().fillResIconDpi);
}
+ } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
+ FolderAdaptiveIcon icon = FolderAdaptiveIcon.createFolderAdaptiveIcon(
+ mLauncher, info.id, new Point(mBitmap.getWidth(), mBitmap.getHeight()));
+ if (icon == null) {
+ return null;
+ }
+ outObj[0] = icon;
+ return icon;
} else {
return null;
}
@@ -318,84 +370,17 @@ public class DragView extends FrameLayout {
float insetFraction = (iconSize - badgeSize) / iconSize;
return new InsetDrawable(new FastBitmapDrawable(badge),
insetFraction, insetFraction, 0, 0);
+ } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
+ return ((FolderAdaptiveIcon) obj).getBadge();
} else {
return mLauncher.getPackageManager()
.getUserBadgedIcon(new FixedSizeEmptyDrawable(iconSize), info.user);
}
}
- private ImageView setupImageView(Drawable drawable, float normalizationScale) {
- FrameLayout.LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
- ImageView imageViewOut = new ImageView(getContext());
- imageViewOut.setLayoutParams(params);
- imageViewOut.setScaleType(ImageView.ScaleType.FIT_XY);
- imageViewOut.setScaleX(normalizationScale);
- imageViewOut.setScaleY(normalizationScale);
- imageViewOut.setImageDrawable(drawable);
- return imageViewOut;
- }
-
- private SpringAnimation setupSpringAnimation(int minValue, int maxValue,
- DynamicAnimation.ViewProperty property) {
- SpringAnimation s = new SpringAnimation(mFgImageView, property, 0);
- s.setMinValue(minValue).setMaxValue(maxValue);
- s.setSpring(new SpringForce(0)
- .setDampingRatio(DAMPENING_RATIO)
- .setStiffness(STIFFNESS));
- return s;
- }
-
- @TargetApi(Build.VERSION_CODES.O)
- private Path getMaskPath(AdaptiveIconDrawable dr, float normalizationScale) {
- Matrix m = new Matrix();
- // Shrink very tiny bit so that the clip path is smaller than the original bitmap
- // that has anti aliased edges and shadows.
- float s = normalizationScale * .97f;
- m.setScale(s, s, dr.getBounds().centerX(), dr.getBounds().centerY());
- Path p = new Path();
- dr.getIconMask().transform(m, p);
- return p;
- }
-
- private void applySpring(int x, int y) {
- if (mSpringX == null || mSpringY == null) {
- return;
- }
- mSpringX.animateToFinalPosition(Utilities.boundToRange(x, -mDelta, mDelta));
- mSpringY.animateToFinalPosition(Utilities.boundToRange(y, -mDelta, mDelta));
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- int w = right - left;
- int h = bottom - top;
- for (int i = 0; i < getChildCount(); i++) {
- getChildAt(i).layout(-w / 4, -h / 4, w + w / 4, h + h / 4);
- }
- }
-
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int w = mBitmap.getWidth();
- int h = mBitmap.getHeight();
- setMeasuredDimension(w, h);
- for (int i = 0; i < getChildCount(); i++) {
- getChildAt(i).measure(w, h);
- }
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- if (mScaledMaskPath != null) {
- int cnt = canvas.save();
- canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
- canvas.clipPath(mScaledMaskPath);
- super.dispatchDraw(canvas);
- canvas.restoreToCount(cnt);
- mBadge.draw(canvas);
- } else {
- super.dispatchDraw(canvas);
- }
+ setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
}
/** Sets the scale of the view over the normal workspace icon size. */
@@ -439,43 +424,37 @@ public class DragView extends FrameLayout {
return mDragRegion;
}
- // Draws drag shadow for system DND.
- @SuppressLint("WrongCall")
- public void drawDragShadow(Canvas canvas) {
- final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
- canvas.scale(getScaleX(), getScaleY());
- onDraw(canvas);
- canvas.restoreToCount(saveCount);
- }
-
- // Provides drag shadow metrics for system DND.
- public void provideDragShadowMetrics(Point size, Point touch) {
- size.set((int)(mBitmap.getWidth() * getScaleX()), (int)(mBitmap.getHeight() * getScaleY()));
-
- final float xGrowth = mBitmap.getWidth() * (getScaleX() - 1);
- final float yGrowth = mBitmap.getHeight() * (getScaleY() - 1);
- touch.set(
- mRegistrationX + (int)Math.round(xGrowth / 2),
- mRegistrationY + (int)Math.round(yGrowth / 2));
- }
-
@Override
protected void onDraw(Canvas canvas) {
mHasDrawn = true;
- boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null;
- if (crossFade) {
- int alpha = crossFade ? (int) (255 * (1 - mCrossFadeProgress)) : 255;
- mPaint.setAlpha(alpha);
+
+ if (mDrawBitmap) {
+ // Always draw the bitmap to mask anti aliasing due to clipPath
+ boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null;
+ if (crossFade) {
+ int alpha = crossFade ? (int) (255 * (1 - mCrossFadeProgress)) : 255;
+ mPaint.setAlpha(alpha);
+ }
+ canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
+ if (crossFade) {
+ mPaint.setAlpha((int) (255 * mCrossFadeProgress));
+ final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth();
+ float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight();
+ canvas.scale(sX, sY);
+ canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint);
+ canvas.restoreToCount(saveCount);
+ }
}
- canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
- if (crossFade) {
- mPaint.setAlpha((int) (255 * mCrossFadeProgress));
- final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
- float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth();
- float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight();
- canvas.scale(sX, sY);
- canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint);
- canvas.restoreToCount(saveCount);
+
+ if (mScaledMaskPath != null) {
+ int cnt = canvas.save();
+ canvas.clipPath(mScaledMaskPath);
+ mBgSpringDrawable.draw(canvas);
+ canvas.translate(mTranslateX.mValue, mTranslateY.mValue);
+ mFgSpringDrawable.draw(canvas);
+ canvas.restoreToCount(cnt);
+ mBadge.draw(canvas);
}
}
@@ -512,8 +491,7 @@ public class DragView extends FrameLayout {
animateFilterTo(m1.getArray());
} else {
if (mCurrentFilter == null) {
- mPaint.setColorFilter(null);
- invalidate();
+ updateColorFilter();
} else {
animateFilterTo(new ColorMatrix().getArray());
}
@@ -534,8 +512,7 @@ public class DragView extends FrameLayout {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
- mPaint.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
- invalidate();
+ updateColorFilter();
}
});
mFilterAnimator.start();
@@ -590,8 +567,10 @@ public class DragView extends FrameLayout {
* @param touchY the y coordinate the user touched in DragLayer coordinates
*/
public void move(int touchX, int touchY) {
- if (touchX > 0 && touchY > 0 && mLastTouchX > 0 && mLastTouchY > 0) {
- applySpring(mLastTouchX - touchX, mLastTouchY - touchY);
+ if (touchX > 0 && touchY > 0 && mLastTouchX > 0 && mLastTouchY > 0
+ && mScaledMaskPath != null) {
+ mTranslateX.animateToPos(mLastTouchX - touchX);
+ mTranslateY.animateToPos(mLastTouchY - touchY);
}
mLastTouchX = touchX;
mLastTouchY = touchY;
@@ -642,6 +621,48 @@ public class DragView extends FrameLayout {
return mInitialScale;
}
+ private static class SpringFloatValue {
+
+ private static final FloatPropertyCompat<SpringFloatValue> VALUE =
+ new FloatPropertyCompat<SpringFloatValue>("value") {
+ @Override
+ public float getValue(SpringFloatValue object) {
+ return object.mValue;
+ }
+
+ @Override
+ public void setValue(SpringFloatValue object, float value) {
+ object.mValue = value;
+ object.mView.invalidate();
+ }
+ };
+
+ // Following three values are fine tuned with motion ux designer
+ private final static int STIFFNESS = 4000;
+ private final static float DAMPENING_RATIO = 1f;
+ private final static int PARALLAX_MAX_IN_DP = 8;
+
+ private final View mView;
+ private final SpringAnimation mSpring;
+ private final float mDelta;
+
+ private float mValue;
+
+ public SpringFloatValue(View view, float range) {
+ mView = view;
+ mSpring = new SpringAnimation(this, VALUE, 0)
+ .setMinValue(-range).setMaxValue(range)
+ .setSpring(new SpringForce(0)
+ .setDampingRatio(DAMPENING_RATIO)
+ .setStiffness(STIFFNESS));
+ mDelta = view.getResources().getDisplayMetrics().density * PARALLAX_MAX_IN_DP;
+ }
+
+ public void animateToPos(float value) {
+ mSpring.animateToFinalPosition(Utilities.boundToRange(value, -mDelta, mDelta));
+ }
+ }
+
private static class FixedSizeEmptyDrawable extends ColorDrawable {
private final int mSize;
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
new file mode 100644
index 000000000..c90546088
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -0,0 +1,175 @@
+/*
+ * 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.dragndrop;
+
+import android.annotation.TargetApi;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.util.Log;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.R;
+import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.folder.PreviewBackground;
+import com.android.launcher3.util.Preconditions;
+
+import java.util.concurrent.Callable;
+
+/**
+ * {@link AdaptiveIconDrawable} representation of a {@link FolderIcon}
+ */
+@TargetApi(Build.VERSION_CODES.O)
+public class FolderAdaptiveIcon extends AdaptiveIconDrawable {
+ private static final String TAG = "FolderAdaptiveIcon";
+
+ private final Drawable mBadge;
+ private final Path mMask;
+
+ private FolderAdaptiveIcon(Drawable bg, Drawable fg, Drawable badge, Path mask) {
+ super(bg, fg);
+ mBadge = badge;
+ mMask = mask;
+ }
+
+ @Override
+ public Path getIconMask() {
+ return mMask;
+ }
+
+ public Drawable getBadge() {
+ return mBadge;
+ }
+
+ public static FolderAdaptiveIcon createFolderAdaptiveIcon(
+ final Launcher launcher, final long folderId, Point dragViewSize) {
+ Preconditions.assertNonUiThread();
+ int margin = launcher.getResources()
+ .getDimensionPixelSize(R.dimen.blur_size_medium_outline);
+
+ // Allocate various bitmaps on the background thread, because why not!
+ final Bitmap badge = Bitmap.createBitmap(
+ dragViewSize.x - margin, dragViewSize.y - margin, Bitmap.Config.ARGB_8888);
+
+ // The bitmap for the preview is generated larger than needed to allow for the spring effect
+ float sizeScaleFactor = 1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction();
+ final Bitmap preview = Bitmap.createBitmap(
+ (int) (dragViewSize.x * sizeScaleFactor), (int) (dragViewSize.y * sizeScaleFactor),
+ Bitmap.Config.ARGB_8888);
+
+ // Create the actual drawable on the UI thread to avoid race conditions with
+ // FolderIcon draw pass
+ try {
+ return new MainThreadExecutor().submit(new Callable<FolderAdaptiveIcon>() {
+ @Override
+ public FolderAdaptiveIcon call() throws Exception {
+ FolderIcon icon = launcher.findFolderIcon(folderId);
+ return icon == null ? null : createDrawableOnUiThread(icon, badge, preview);
+ }
+ }).get();
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to create folder icon", e);
+ return null;
+ }
+ }
+
+ /**
+ * Initializes various bitmaps on the UI thread and returns the final drawable.
+ */
+ private static FolderAdaptiveIcon createDrawableOnUiThread(FolderIcon icon,
+ Bitmap badgeBitmap, Bitmap previewBitmap) {
+ Preconditions.assertUIThread();
+ float margin = icon.getResources().getDimension(R.dimen.blur_size_medium_outline) / 2;
+
+ Canvas c = new Canvas();
+ PreviewBackground bg = icon.getFolderBackground();
+
+ // Initialize badge
+ c.setBitmap(badgeBitmap);
+ bg.drawShadow(c);
+ bg.drawBackgroundStroke(c);
+ icon.drawBadge(c);
+
+ // Initialize preview
+ float shiftFactor = AdaptiveIconDrawable.getExtraInsetFraction() /
+ (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
+ float previewShiftX = shiftFactor * previewBitmap.getWidth();
+ float previewShiftY = shiftFactor * previewBitmap.getHeight();
+
+ c.setBitmap(previewBitmap);
+ c.translate(previewShiftX, previewShiftY);
+ icon.getPreviewItemManager().draw(c);
+ c.setBitmap(null);
+
+ // Initialize mask
+ Path mask = new Path();
+ Matrix m = new Matrix();
+ m.setTranslate(margin, margin);
+ bg.getClipPath().transform(m, mask);
+
+ ShiftedBitmapDrawable badge = new ShiftedBitmapDrawable(badgeBitmap, margin, margin);
+ ShiftedBitmapDrawable foreground = new ShiftedBitmapDrawable(previewBitmap,
+ margin - previewShiftX, margin - previewShiftY);
+
+ return new FolderAdaptiveIcon(new ColorDrawable(bg.getBgColor()), foreground, badge, mask);
+ }
+
+ /**
+ * A simple drawable which draws a bitmap at a fixed position irrespective of the bounds
+ */
+ private static class ShiftedBitmapDrawable extends Drawable {
+
+ private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+ private final Bitmap mBitmap;
+ private final float mShiftX;
+ private final float mShiftY;
+
+ ShiftedBitmapDrawable(Bitmap bitmap, float shiftX, float shiftY) {
+ mBitmap = bitmap;
+ mShiftX = shiftX;
+ mShiftY = shiftY;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ canvas.drawBitmap(mBitmap, mShiftX, mShiftY, mPaint);
+ }
+
+ @Override
+ public void setAlpha(int i) { }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ mPaint.setColorFilter(colorFilter);
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java b/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java
index de614f031..baedf9063 100644
--- a/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java
+++ b/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java
@@ -50,19 +50,26 @@ public class ColorExtractionAlgorithm {
private static final float FIT_WEIGHT_S = 1.0f;
private static final float FIT_WEIGHT_L = 10.0f;
+ public static final int MAIN_COLOR_LIGHT = 0xffb0b0b0;
+ public static final int SECONDARY_COLOR_LIGHT = 0xff9e9e9e;
+ public static final int MAIN_COLOR_DARK = 0xff212121;
+ public static final int SECONDARY_COLOR_DARK = 0xff000000;
+
// Temporary variable to avoid allocations
private float[] mTmpHSL = new float[3];
- public @Nullable Pair<Integer, Integer> extractInto(WallpaperColorsCompat inWallpaperColors) {
+ public Pair<Integer, Integer> extractInto(WallpaperColorsCompat inWallpaperColors) {
if (inWallpaperColors == null) {
- return null;
+ return applyFallback(inWallpaperColors);
}
final List<Integer> mainColors = getMainColors(inWallpaperColors);
final int mainColorsSize = mainColors.size();
+ final boolean supportsDarkText = (inWallpaperColors.getColorHints() &
+ WallpaperColorsCompat.HINT_SUPPORTS_DARK_TEXT) != 0;
if (mainColorsSize == 0) {
- return null;
+ return applyFallback(inWallpaperColors);
}
// Tonal is not really a sort, it takes a color from the extracted
// palette and finds a best fit amongst a collection of pre-defined
@@ -86,7 +93,7 @@ public class ColorExtractionAlgorithm {
// Fail if not found
if (bestColor == null) {
- return null;
+ return applyFallback(inWallpaperColors);
}
int colorValue = bestColor;
@@ -101,14 +108,14 @@ public class ColorExtractionAlgorithm {
TonalPalette palette = findTonalPalette(hsl[0], hsl[1]);
if (palette == null) {
Log.w(TAG, "Could not find a tonal palette!");
- return null;
+ return applyFallback(inWallpaperColors);
}
// Figure out what's the main color index in the optimal palette
int fitIndex = bestFit(palette, hsl[0], hsl[1], hsl[2]);
if (fitIndex == -1) {
Log.w(TAG, "Could not find best fit!");
- return null;
+ return applyFallback(inWallpaperColors);
}
// Generate the 10 colors palette by offsetting each one of them
@@ -117,28 +124,48 @@ public class ColorExtractionAlgorithm {
float[] s = fit(palette.s, hsl[1], fitIndex, 0.0f, 1.0f);
float[] l = fit(palette.l, hsl[2], fitIndex, 0.0f, 1.0f);
- final int textInversionIndex = h.length - 3;
+ int primaryIndex = fitIndex;
+ int mainColor = getColorInt(primaryIndex, h, s, l);
- int primaryIndex;
- int secondaryIndex;
+ // We might want use the fallback in case the extracted color is brighter than our
+ // light fallback or darker than our dark fallback.
+ ColorUtils.colorToHSL(mainColor, mTmpHSL);
+ final float mainLuminosity = mTmpHSL[2];
+ ColorUtils.colorToHSL(MAIN_COLOR_LIGHT, mTmpHSL);
+ final float lightLuminosity = mTmpHSL[2];
+ if (mainLuminosity > lightLuminosity) {
+ return applyFallback(inWallpaperColors);
+ }
+ ColorUtils.colorToHSL(MAIN_COLOR_DARK, mTmpHSL);
+ final float darkLuminosity = mTmpHSL[2];
+ if (mainLuminosity < darkLuminosity) {
+ return applyFallback(inWallpaperColors);
+ }
// Dark colors:
// Stops at 4th color, only lighter if dark text is supported
- if (fitIndex < 2) {
+ if (supportsDarkText) {
+ primaryIndex = h.length - 1;
+ } else if (fitIndex < 2) {
primaryIndex = 0;
- } else if (fitIndex < textInversionIndex) {
- primaryIndex = Math.min(fitIndex, 3);
} else {
- primaryIndex = h.length - 1;
+ primaryIndex = Math.min(fitIndex, 3);
}
- secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2);
-
- int mainColor = getColorInt(primaryIndex, h, s, l);
+ int secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2);
int secondaryColor = getColorInt(secondaryIndex, h, s, l);
return new Pair<>(mainColor, secondaryColor);
}
+ public static Pair<Integer, Integer> applyFallback(WallpaperColorsCompat inWallpaperColors) {
+ boolean light = inWallpaperColors != null
+ && (inWallpaperColors.getColorHints()
+ & WallpaperColorsCompat.HINT_SUPPORTS_DARK_TEXT)!= 0;
+ int innerColor = light ? MAIN_COLOR_LIGHT : MAIN_COLOR_DARK;
+ int outerColor = light ? SECONDARY_COLOR_LIGHT : SECONDARY_COLOR_DARK;
+ return new Pair<>(innerColor, outerColor);
+ }
+
private int getColorInt(int fitIndex, float[] h, float[] s, float[] l) {
mTmpHSL[0] = fract(h[fitIndex]) * 360.0f;
mTmpHSL[1] = s[fitIndex];
diff --git a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
index 512e89a41..80a89e37d 100644
--- a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
+++ b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
@@ -81,9 +81,9 @@ public class WallpaperColorInfo implements WallpaperManagerCompat.OnColorsChange
mSupportsDarkText = wallpaperColors != null
? (wallpaperColors.getColorHints()
& WallpaperColorsCompat.HINT_SUPPORTS_DARK_TEXT) > 0 : false;
- float[] hsl = new float[3];
- ColorUtils.colorToHSL(mMainColor, hsl);
- mIsDark = hsl[2] < 0.2f;
+ mIsDark = wallpaperColors != null
+ ? (wallpaperColors.getColorHints()
+ & WallpaperColorsCompat.HINT_SUPPORTS_DARK_THEME) > 0 : false;
}
public void setOnThemeChangeListener(OnThemeChangeListener onThemeChangeListener) {
diff --git a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
index ff357c0bc..f25345ee8 100644
--- a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
@@ -1,15 +1,18 @@
package com.android.launcher3.folder;
+
public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule {
static final int MAX_NUM_ITEMS_IN_PREVIEW = 4;
private static final int MIN_NUM_ITEMS_IN_PREVIEW = 2;
- private static final int MAX_NUM_ITEMS_PER_ROW = 2;
- final float MIN_SCALE = 0.48f;
- final float MAX_SCALE = 0.58f;
- final float MAX_RADIUS_DILATION = 0.15f;
- final float ITEM_RADIUS_SCALE_FACTOR = 1.33f;
+ private static final float MIN_SCALE = 0.48f;
+ private static final float MAX_SCALE = 0.58f;
+ private static final float MAX_RADIUS_DILATION = 0.15f;
+ private static final float ITEM_RADIUS_SCALE_FACTOR = 1.33f;
+
+ private static final int EXIT_INDEX = -2;
+ private static final int ENTER_INDEX = -3;
private float[] mTmpPoint = new float[2];
@@ -31,21 +34,29 @@ public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule
@Override
public PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
PreviewItemDrawingParams params) {
-
float totalScale = scaleForItem(index, curNumItems);
float transX;
float transY;
float overlayAlpha = 0;
- // Items beyond those displayed in the preview are animated to the center
- if (index >= MAX_NUM_ITEMS_IN_PREVIEW) {
- transX = transY = mAvailableSpace / 2 - (mIconSize * totalScale) / 2;
+ if (index == getExitIndex()) {
+ // 0 1 * <-- Exit position (row 0, col 2)
+ // 2 3
+ getGridPosition(0, 2, mTmpPoint);
+ } else if (index == getEnterIndex()) {
+ // 0 1
+ // 2 3 * <-- Enter position (row 1, col 2)
+ getGridPosition(1, 2, mTmpPoint);
+ } else if (index >= MAX_NUM_ITEMS_IN_PREVIEW) {
+ // Items beyond those displayed in the preview are animated to the center
+ mTmpPoint[0] = mTmpPoint[1] = mAvailableSpace / 2 - (mIconSize * totalScale) / 2;
} else {
getPosition(index, curNumItems, mTmpPoint);
- transX = mTmpPoint[0];
- transY = mTmpPoint[1];
}
+ transX = mTmpPoint[0];
+ transY = mTmpPoint[1];
+
if (params == null) {
params = new PreviewItemDrawingParams(transX, transY, totalScale, overlayAlpha);
} else {
@@ -55,6 +66,27 @@ public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule
return params;
}
+ /**
+ * Builds a grid based on the positioning of the items when there are
+ * {@link #MAX_NUM_ITEMS_IN_PREVIEW} in the preview.
+ *
+ * Positions in the grid: 0 1 // 0 is row 0, col 1
+ * 2 3 // 3 is row 1, col 1
+ */
+ private void getGridPosition(int row, int col, float[] result) {
+ // We use position 0 and 3 to calculate the x and y distances between items.
+ getPosition(0, 4, result);
+ float left = result[0];
+ float top = result[1];
+
+ getPosition(3, 4, result);
+ float dx = result[0] - left;
+ float dy = result[1] - top;
+
+ result[0] = left + (col * dx);
+ result[1] = top + (row * dy);
+ }
+
private void getPosition(int index, int curNumItems, float[] result) {
// The case of two items is homomorphic to the case of one.
curNumItems = Math.max(curNumItems, 2);
@@ -127,4 +159,19 @@ public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule
public boolean clipToBackground() {
return true;
}
+
+ @Override
+ public boolean hasEnterExitIndices() {
+ return true;
+ }
+
+ @Override
+ public int getExitIndex() {
+ return EXIT_INDEX;
+ }
+
+ @Override
+ public int getEnterIndex() {
+ return ENTER_INDEX;
+ }
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 3c7c69810..85792d4cc 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -791,12 +791,15 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC
if (mFolderIcon != null) {
mFolderIcon.setVisibility(View.VISIBLE);
if (FeatureFlags.LAUNCHER3_NEW_FOLDER_ANIMATION) {
- mFolderIcon.mFolderName.setTextVisibility(true);
mFolderIcon.setBackgroundVisible(true);
- mFolderIcon.mBackground.fadeInBackgroundShadow();
+ mFolderIcon.mFolderName.setTextVisibility(true);
}
if (wasAnimated) {
- mFolderIcon.mBackground.animateBackgroundStroke();
+ if (FeatureFlags.LAUNCHER3_NEW_FOLDER_ANIMATION) {
+ mFolderIcon.mBackground.fadeInBackgroundShadow();
+ mFolderIcon.mBackground.animateBackgroundStroke();
+ mFolderIcon.onFolderClose(mContent.getCurrentPage());
+ }
if (mFolderIcon.hasBadge()) {
mFolderIcon.createBadgeScaleAnimator(0f, 1f).start();
}
@@ -818,6 +821,7 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC
mSuppressFolderDeletion = false;
clearDragInfo();
mState = STATE_SMALL;
+ mContent.setCurrentPage(0);
}
public boolean acceptDrop(DragObject d) {
@@ -1280,7 +1284,7 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC
};
View finalChild = mContent.getLastItem();
if (finalChild != null) {
- mFolderIcon.performDestroyAnimation(finalChild, onCompleteRunnable);
+ mFolderIcon.performDestroyAnimation(onCompleteRunnable);
} else {
onCompleteRunnable.run();
}
@@ -1355,8 +1359,11 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC
}
mContent.completePendingPageChanges();
- if (d.dragInfo instanceof PendingAddShortcutInfo) {
- PendingAddShortcutInfo pasi = (PendingAddShortcutInfo) d.dragInfo;
+ PendingAddShortcutInfo pasi = d.dragInfo instanceof PendingAddShortcutInfo
+ ? (PendingAddShortcutInfo) d.dragInfo : null;
+ ShortcutInfo pasiSi = pasi != null ? pasi.activityInfo.createShortcutInfo() : null;
+ if (pasi != null && pasiSi == null) {
+ // There is no ShortcutInfo, so we have to go through a configuration activity.
pasi.container = mInfo.id;
pasi.rank = mEmptyCellRank;
@@ -1366,7 +1373,9 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC
mRearrangeOnClose = true;
} else {
final ShortcutInfo si;
- if (d.dragInfo instanceof AppInfo) {
+ if (pasiSi != null) {
+ si = pasiSi;
+ } else if (d.dragInfo instanceof AppInfo) {
// Came from all apps -- make a copy.
si = ((AppInfo) d.dragInfo).makeShortcut();
} else {
@@ -1513,18 +1522,17 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC
return mItemsInReadingOrder;
}
- public List<BubbleTextView> getItemsOnCurrentPage() {
+ public List<BubbleTextView> getItemsOnPage(int page) {
ArrayList<View> allItems = getItemsInReadingOrder();
- int currentPage = mContent.getCurrentPage();
int lastPage = mContent.getPageCount() - 1;
int totalItemsInFolder = allItems.size();
int itemsPerPage = mContent.itemsPerPage();
- int numItemsOnCurrentPage = currentPage == lastPage
- ? totalItemsInFolder - (itemsPerPage * currentPage)
+ int numItemsOnCurrentPage = page == lastPage
+ ? totalItemsInFolder - (itemsPerPage * page)
: itemsPerPage;
- int startIndex = currentPage * itemsPerPage;
- int endIndex = startIndex + numItemsOnCurrentPage;
+ int startIndex = page * itemsPerPage;
+ int endIndex = Math.min(startIndex + numItemsOnCurrentPage, allItems.size());
List<BubbleTextView> itemsOnCurrentPage = new ArrayList<>(numItemsOnCurrentPage);
for (int i = startIndex; i < endIndex; ++i) {
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 3648c60e1..69705d594 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -69,7 +69,8 @@ public class FolderAnimationManager {
private final int mDelay;
private final TimeInterpolator mFolderInterpolator;
- private final TimeInterpolator mLargeFolderPreviewItemInterpolator;
+ private final TimeInterpolator mLargeFolderPreviewItemOpenInterpolator;
+ private final TimeInterpolator mLargeFolderPreviewItemCloseInterpolator;
private final PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
@@ -105,8 +106,10 @@ public class FolderAnimationManager {
mFolderInterpolator = AnimationUtils.loadInterpolator(mContext,
R.interpolator.folder_interpolator);
- mLargeFolderPreviewItemInterpolator = AnimationUtils.loadInterpolator(mContext,
- R.interpolator.large_folder_preview_item_interpolator);
+ mLargeFolderPreviewItemOpenInterpolator = AnimationUtils.loadInterpolator(mContext,
+ R.interpolator.large_folder_preview_item_open_interpolator);
+ mLargeFolderPreviewItemCloseInterpolator = AnimationUtils.loadInterpolator(mContext,
+ R.interpolator.large_folder_preview_item_close_interpolator);
}
@@ -116,13 +119,14 @@ public class FolderAnimationManager {
public AnimatorSet getAnimator() {
final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) mFolder.getLayoutParams();
FolderIcon.PreviewLayoutRule rule = mFolderIcon.getLayoutRule();
- final List<BubbleTextView> itemsInPreview = mFolderIcon.getItemsToDisplay();
+ final List<BubbleTextView> itemsInPreview = mFolderIcon.getPreviewItems();
// Match position of the FolderIcon
final Rect folderIconPos = new Rect();
float scaleRelativeToDragLayer = mLauncher.getDragLayer()
.getDescendantRectRelativeToSelf(mFolderIcon, folderIconPos);
- float initialSize = (mFolderIcon.mBackground.getRadius() * 2) * scaleRelativeToDragLayer;
+ int scaledRadius = mPreviewBackground.getScaledRadius();
+ float initialSize = (scaledRadius * 2) * scaleRelativeToDragLayer;
// Match size/scale of icons in the preview
float previewScale = rule.scaleForItem(0, itemsInPreview.size());
@@ -149,14 +153,9 @@ public class FolderAnimationManager {
final int paddingOffsetY = (int) ((mFolder.getPaddingTop() + mContent.getPaddingTop())
* initialScale);
- // Background can have a scaled radius in drag and drop mode.
- int radiusDiff = mFolderIcon.mBackground.getScaledRadius()
- - mFolderIcon.mBackground.getRadius();
-
- int initialX = folderIconPos.left + mFolderIcon.mBackground.getOffsetX() - paddingOffsetX
- - previewItemOffsetX + radiusDiff;
- int initialY = folderIconPos.top + mFolderIcon.mBackground.getOffsetY() - paddingOffsetY
- + radiusDiff;
+ int initialX = folderIconPos.left + mPreviewBackground.getOffsetX() - paddingOffsetX
+ - previewItemOffsetX;
+ int initialY = folderIconPos.top + mPreviewBackground.getOffsetY() - paddingOffsetY;
final float xDistance = initialX - lp.x;
final float yDistance = initialY - lp.y;
@@ -181,10 +180,10 @@ public class FolderAnimationManager {
AnimatorSet a = LauncherAnimUtils.createAnimatorSet();
// Initialize the Folder items' text.
- PropertyResetListener colorResetListener = new PropertyResetListener(
+ PropertyResetListener colorResetListener = new PropertyResetListener<>(
BubbleTextView.TEXT_ALPHA_PROPERTY,
Color.alpha(Themes.getAttrColor(mContext, android.R.attr.textColorSecondary)));
- for (BubbleTextView icon : mFolder.getItemsOnCurrentPage()) {
+ for (BubbleTextView icon : mFolder.getItemsOnPage(mFolder.mContent.getCurrentPage())) {
if (mIsOpening) {
icon.setTextVisibility(false);
}
@@ -198,13 +197,19 @@ public class FolderAnimationManager {
play(a, getAnimator(mFolder, SCALE_PROPERTY, initialScale, finalScale));
play(a, getAnimator(mFolderBackground, "color", initialColor, finalColor));
play(a, mFolderIcon.mFolderName.createTextAlphaAnimator(!mIsOpening));
- play(a, new RoundedRectRevealOutlineProvider(initialRadius, finalRadius, startRect,
- endRect).createRevealAnimator(mFolder, !mIsOpening));
+ RoundedRectRevealOutlineProvider outlineProvider = new RoundedRectRevealOutlineProvider(
+ initialRadius, finalRadius, startRect, endRect) {
+ @Override
+ public boolean shouldRemoveElevationDuringAnimation() {
+ return true;
+ }
+ };
+ play(a, outlineProvider.createRevealAnimator(mFolder, !mIsOpening));
// Animate the elevation midway so that the shadow is not noticeable in the background.
int midDuration = mDuration / 2;
Animator z = getAnimator(mFolder, View.TRANSLATION_Z, -mFolder.getElevation(), 0);
- play(a, z, midDuration, midDuration);
+ play(a, z, mIsOpening ? midDuration : 0, midDuration);
a.addListener(new AnimatorListenerAdapter() {
@Override
@@ -224,18 +229,28 @@ public class FolderAnimationManager {
animator.setInterpolator(mFolderInterpolator);
}
- addPreviewItemAnimators(a, initialScale / scaleRelativeToDragLayer, previewItemOffsetX);
+ int radiusDiff = scaledRadius - mPreviewBackground.getRadius();
+ addPreviewItemAnimators(a, initialScale / scaleRelativeToDragLayer,
+ // Background can have a scaled radius in drag and drop mode, so we need to add the
+ // difference to keep the preview items centered.
+ previewItemOffsetX + radiusDiff, radiusDiff);
return a;
}
/**
- * Animate the items that are displayed in the preview.
+ * Animate the items on the current page.
*/
private void addPreviewItemAnimators(AnimatorSet animatorSet, final float folderScale,
- int previewItemOffsetX) {
+ int previewItemOffsetX, int previewItemOffsetY) {
FolderIcon.PreviewLayoutRule rule = mFolderIcon.getLayoutRule();
- final List<BubbleTextView> itemsInPreview = mFolderIcon.getItemsToDisplay();
+ boolean isOnFirstPage = mFolder.mContent.getCurrentPage() == 0;
+ final List<BubbleTextView> itemsInPreview = isOnFirstPage
+ ? mFolderIcon.getPreviewItems()
+ : mFolderIcon.getPreviewItemsOnPage(mFolder.mContent.getCurrentPage());
final int numItemsInPreview = itemsInPreview.size();
+ final int numItemsInFirstPagePreview = isOnFirstPage
+ ? numItemsInPreview
+ : FolderIcon.NUM_ITEMS_IN_PREVIEW;
TimeInterpolator previewItemInterpolator = getPreviewItemInterpolator();
@@ -248,8 +263,8 @@ public class FolderAnimationManager {
btvLp.isLockedToGrid = true;
cwc.setupLp(btv);
- // Match scale of icons in the preview.
- float previewScale = rule.scaleForItem(i, numItemsInPreview);
+ // Match scale of icons in the preview of the items on the first page.
+ float previewScale = rule.scaleForItem(i, numItemsInFirstPagePreview);
float previewSize = rule.getIconSize() * previewScale;
float iconScale = previewSize / itemsInPreview.get(i).getIconSize();
@@ -260,14 +275,14 @@ public class FolderAnimationManager {
btv.setScaleY(scale);
// Match positions of the icons in the folder with their positions in the preview
- rule.computePreviewItemDrawingParams(i, numItemsInPreview, mTmpParams);
+ rule.computePreviewItemDrawingParams(i, numItemsInFirstPagePreview, mTmpParams);
// The PreviewLayoutRule assumes that the icon size takes up the entire width so we
// offset by the actual size.
int iconOffsetX = (int) ((btvLp.width - btv.getIconSize()) * iconScale) / 2;
final int previewPosX =
(int) ((mTmpParams.transX - iconOffsetX + previewItemOffsetX) / folderScale);
- final int previewPosY = (int) (mTmpParams.transY / folderScale);
+ final int previewPosY = (int) ((mTmpParams.transY + previewItemOffsetY) / folderScale);
final float xDistance = previewPosX - btvLp.x;
final float yDistance = previewPosY - btvLp.y;
@@ -287,14 +302,15 @@ public class FolderAnimationManager {
if (mFolder.getItemCount() > FolderIcon.NUM_ITEMS_IN_PREVIEW) {
// These delays allows the preview items to move as part of the Folder's motion,
// and its only necessary for large folders because of differing interpolators.
+ int delay = mIsOpening ? mDelay : mDelay * 2;
if (mIsOpening) {
- translationX.setStartDelay(mDelay);
- translationY.setStartDelay(mDelay);
- scaleAnimator.setStartDelay(mDelay);
+ translationX.setStartDelay(delay);
+ translationY.setStartDelay(delay);
+ scaleAnimator.setStartDelay(delay);
}
- translationX.setDuration(translationX.getDuration() - mDelay);
- translationY.setDuration(translationY.getDuration() - mDelay);
- scaleAnimator.setDuration(scaleAnimator.getDuration() - mDelay);
+ translationX.setDuration(translationX.getDuration() - delay);
+ translationY.setDuration(translationY.getDuration() - delay);
+ scaleAnimator.setDuration(scaleAnimator.getDuration() - delay);
}
animatorSet.addListener(new AnimatorListenerAdapter() {
@@ -337,7 +353,9 @@ public class FolderAnimationManager {
// With larger folders, we want the preview items to reach their final positions faster
// (when opening) and later (when closing) so that they appear aligned with the rest of
// the folder items when they are both visible.
- return mLargeFolderPreviewItemInterpolator;
+ return mIsOpening
+ ? mLargeFolderPreviewItemOpenInterpolator
+ : mLargeFolderPreviewItemCloseInterpolator;
}
return mFolderInterpolator;
}
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 1cc285ea5..6533b0463 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -37,7 +37,6 @@ import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
-import android.widget.TextView;
import com.android.launcher3.Alarm;
import com.android.launcher3.AppInfo;
@@ -71,6 +70,8 @@ import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.util.ArrayList;
import java.util.List;
+import static com.android.launcher3.folder.PreviewItemManager.INITIAL_ITEM_ANIMATION_DURATION;
+
/**
* An icon that can appear on in the workspace representing an {@link Folder}.
*/
@@ -87,9 +88,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
private CheckLongPressHelper mLongPressHelper;
private StylusEventHelper mStylusEventHelper;
- private static final int DROP_IN_ANIMATION_DURATION = 400;
- private static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
- private static final int FINAL_ITEM_ANIMATION_DURATION = 200;
+ static final int DROP_IN_ANIMATION_DURATION = 400;
// Flag whether the folder should open itself when an item is dragged over is enabled.
public static final boolean SPRING_LOADING_ENABLED = true;
@@ -99,27 +98,19 @@ public class FolderIcon extends FrameLayout implements FolderListener {
@Thunk BubbleTextView mFolderName;
- // These variables are all associated with the drawing of the preview; they are stored
- // as member variables for shared usage and to avoid computation on each frame
- private float mIntrinsicIconSize = -1;
- private int mTotalWidth = -1;
- private int mPrevTopPadding = -1;
-
PreviewBackground mBackground = new PreviewBackground();
private boolean mBackgroundIsVisible = true;
- private PreviewLayoutRule mPreviewLayoutRule;
+ FolderIconPreviewVerifier mPreviewVerifier;
+ PreviewLayoutRule mPreviewLayoutRule;
+ private PreviewItemManager mPreviewItemManager;
+ private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
boolean mAnimating = false;
private Rect mTempBounds = new Rect();
private float mSlop;
- FolderIconPreviewVerifier mPreviewVerifier;
- private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
- private ArrayList<PreviewItemDrawingParams> mDrawingParams = new ArrayList<>();
- private Drawable mReferenceDrawable = null;
-
private Alarm mOpenAlarm = new Alarm();
private FolderBadgeInfo mBadgeInfo = new FolderBadgeInfo();
@@ -158,6 +149,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
new StackFolderIconLayoutRule() :
new ClippedFolderIconLayoutRule();
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+ mPreviewItemManager = new PreviewItemManager(this);
}
public static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
@@ -213,7 +205,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
private void setFolder(Folder folder) {
mFolder = folder;
mPreviewVerifier = new FolderIconPreviewVerifier(mLauncher.getDeviceProfile().inv);
- updateItemDrawingParams(false);
+ mPreviewItemManager.updateItemDrawingParams(false);
}
private boolean willAcceptItem(ItemInfo item) {
@@ -229,7 +221,15 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
public void addItem(ShortcutInfo item) {
- mInfo.add(item, true);
+ addItem(item, true);
+ }
+
+ public void addItem(ShortcutInfo item, boolean animate) {
+ mInfo.add(item, animate);
+ }
+
+ public void removeItem(ShortcutInfo item, boolean animate) {
+ mInfo.remove(item, animate);
}
public void onDragEnter(ItemInfo dragInfo) {
@@ -254,40 +254,28 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
};
- public Drawable prepareCreate(final View destView) {
- Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1];
- computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
- destView.getMeasuredWidth());
- return animateDrawable;
+ public Drawable prepareCreateAnimation(final View destView) {
+ return mPreviewItemManager.prepareCreateAnimation(destView);
}
public void performCreateAnimation(final ShortcutInfo destInfo, final View destView,
final ShortcutInfo srcInfo, final DragView srcView, Rect dstRect,
float scaleRelativeToDragLayer, Runnable postAnimationRunnable) {
-
- // These correspond two the drawable and view that the icon was dropped _onto_
- Drawable animateDrawable = prepareCreate(destView);
-
- mReferenceDrawable = animateDrawable;
-
+ prepareCreateAnimation(destView);
addItem(destInfo);
// This will animate the first item from it's position as an icon into its
// position as the first item in the preview
- animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION, false, null);
+ mPreviewItemManager.createFirstItemAnimation(false /* reverse */, null)
+ .start();
// This will animate the dragView (srcView) into the new folder
onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable);
}
- public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) {
- Drawable animateDrawable = ((TextView) finalView).getCompoundDrawables()[1];
- computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
- finalView.getMeasuredWidth());
-
- // This will animate the first item from it's position as an icon into its
- // position as the first item in the preview
- animateFirstItem(animateDrawable, FINAL_ITEM_ANIMATION_DURATION, true,
- onCompleteRunnable);
+ public void performDestroyAnimation(Runnable onCompleteRunnable) {
+ // This will animate the final item in the preview to be full size.
+ mPreviewItemManager.createFirstItemAnimation(true /* reverse */, onCompleteRunnable)
+ .start();
}
public void onDragExit() {
@@ -324,13 +312,39 @@ public class FolderIcon extends FrameLayout implements FolderListener {
workspace.resetTransitionTransform((CellLayout) getParent().getParent());
}
+ boolean itemAdded = false;
+ if (index >= mPreviewLayoutRule.maxNumItems()
+ && mPreviewLayoutRule.hasEnterExitIndices()) {
+ List<BubbleTextView> oldPreviewItems = getPreviewItemsOnPage(0);
+ addItem(item, false);
+ List<BubbleTextView> newPreviewItems = getPreviewItemsOnPage(0);
+
+ if (!oldPreviewItems.containsAll(newPreviewItems)) {
+ for (int i = 0; i < newPreviewItems.size(); ++i) {
+ if (newPreviewItems.get(i).getTag().equals(item)) {
+ // If the item dropped is going to be in the preview, we update the
+ // index here to reflect its position in the preview.
+ index = i;
+ }
+ }
+ mPreviewItemManager.onDrop(oldPreviewItems, newPreviewItems, item);
+ itemAdded = true;
+ } else {
+ removeItem(item, false);
+ }
+ }
+
+ if (!itemAdded) {
+ addItem(item);
+ }
+
int[] center = new int[2];
float scale = getLocalCenterForIndex(index, index + 1, center);
center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]);
center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]);
to.offset(center[0] - animateView.getMeasuredWidth() / 2,
- center[1] - animateView.getMeasuredHeight() / 2);
+ center[1] - animateView.getMeasuredHeight() / 2);
float finalAlpha = index < mPreviewLayoutRule.maxNumItems() ? 0.5f : 0f;
@@ -339,15 +353,14 @@ public class FolderIcon extends FrameLayout implements FolderListener {
1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
new DecelerateInterpolator(2), new AccelerateInterpolator(2),
postAnimationRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null);
- addItem(item);
+
mFolder.hideItem(item);
- final PreviewItemDrawingParams params = index < mDrawingParams.size() ?
- mDrawingParams.get(index) : null;
- if (params != null) params.hidden = true;
+ if (!itemAdded) mPreviewItemManager.hidePreviewItem(index, true);
+ final int finalIndex = index;
postDelayed(new Runnable() {
public void run() {
- if (params != null) params.hidden = false;
+ mPreviewItemManager.hidePreviewItem(finalIndex, false);
mFolder.showItem(item);
invalidate();
}
@@ -369,25 +382,6 @@ public class FolderIcon extends FrameLayout implements FolderListener {
onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable);
}
- private void computePreviewDrawingParams(int drawableSize, int totalSize) {
- if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize ||
- mPrevTopPadding != getPaddingTop()) {
- mIntrinsicIconSize = drawableSize;
- mTotalWidth = totalSize;
- mPrevTopPadding = getPaddingTop();
-
- mBackground.setup(mLauncher, this, mTotalWidth, getPaddingTop());
- mPreviewLayoutRule.init(mBackground.previewSize, mIntrinsicIconSize,
- Utilities.isRtl(getResources()));
-
- updateItemDrawingParams(false);
- }
- }
-
- private void computePreviewDrawingParams(Drawable d) {
- computePreviewDrawingParams(d.getIntrinsicWidth(), getMeasuredWidth());
- }
-
public void setBadgeInfo(FolderBadgeInfo badgeInfo) {
updateBadgeScale(mBadgeInfo.hasBadge(), badgeInfo.hasBadge());
mBadgeInfo = badgeInfo;
@@ -421,56 +415,21 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
private float getLocalCenterForIndex(int index, int curNumItems, int[] center) {
- mTmpParams = computePreviewItemDrawingParams(
+ mTmpParams = mPreviewItemManager.computePreviewItemDrawingParams(
Math.min(mPreviewLayoutRule.maxNumItems(), index), curNumItems, mTmpParams);
mTmpParams.transX += mBackground.basePreviewOffsetX;
mTmpParams.transY += mBackground.basePreviewOffsetY;
- float offsetX = mTmpParams.transX + (mTmpParams.scale * mIntrinsicIconSize) / 2;
- float offsetY = mTmpParams.transY + (mTmpParams.scale * mIntrinsicIconSize) / 2;
+
+ float intrinsicIconSize = mPreviewItemManager.getIntrinsicIconSize();
+ float offsetX = mTmpParams.transX + (mTmpParams.scale * intrinsicIconSize) / 2;
+ float offsetY = mTmpParams.transY + (mTmpParams.scale * intrinsicIconSize) / 2;
center[0] = Math.round(offsetX);
center[1] = Math.round(offsetY);
return mTmpParams.scale;
}
- PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
- PreviewItemDrawingParams params) {
- // We use an index of -1 to represent an icon on the workspace for the destroy and
- // create animations
- if (index == -1) {
- return getFinalIconParams(params);
- }
- return mPreviewLayoutRule.computePreviewItemDrawingParams(index, curNumItems, params);
- }
-
- private PreviewItemDrawingParams getFinalIconParams(PreviewItemDrawingParams params) {
- float iconSize = mLauncher.getDeviceProfile().iconSizePx;
-
- final float scale = iconSize / mReferenceDrawable.getIntrinsicWidth();
- final float trans = (mBackground.previewSize - iconSize) / 2;
-
- params.update(trans, trans, scale);
- return params;
- }
-
- private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) {
- canvas.save(Canvas.MATRIX_SAVE_FLAG);
- canvas.translate(params.transX, params.transY);
- canvas.scale(params.scale, params.scale);
- Drawable d = params.drawable;
-
- if (d != null) {
- Rect bounds = d.getBounds();
- canvas.save();
- canvas.translate(-bounds.left, -bounds.top);
- canvas.scale(mIntrinsicIconSize / bounds.width(), mIntrinsicIconSize / bounds.height());
- d.draw(canvas);
- canvas.restore();
- }
- canvas.restore();
- }
-
public void setFolderBackground(PreviewBackground bg) {
mBackground = bg;
mBackground.setInvalidateDelegate(this);
@@ -481,15 +440,21 @@ public class FolderIcon extends FrameLayout implements FolderListener {
invalidate();
}
+ public PreviewBackground getFolderBackground() {
+ return mBackground;
+ }
+
+ public PreviewItemManager getPreviewItemManager() {
+ return mPreviewItemManager;
+ }
+
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (!mBackgroundIsVisible) return;
- if (mReferenceDrawable != null) {
- computePreviewDrawingParams(mReferenceDrawable);
- }
+ mPreviewItemManager.recomputePreviewDrawingParams();
if (!mBackground.drawingDelegated()) {
mBackground.drawBackground(canvas);
@@ -506,21 +471,11 @@ public class FolderIcon extends FrameLayout implements FolderListener {
} else {
saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
if (mPreviewLayoutRule.clipToBackground()) {
- mBackground.clipCanvasSoftware(canvas, Region.Op.INTERSECT);
+ canvas.clipPath(mBackground.getClipPath(), Region.Op.INTERSECT);
}
}
- // The items are drawn in coordinates relative to the preview offset
- canvas.translate(mBackground.basePreviewOffsetX, mBackground.basePreviewOffsetY);
-
- // The first item should be drawn last (ie. on top of later items)
- for (int i = mDrawingParams.size() - 1; i >= 0; i--) {
- PreviewItemDrawingParams p = mDrawingParams.get(i);
- if (!p.hidden) {
- drawPreviewItem(canvas, p);
- }
- }
- canvas.translate(-mBackground.basePreviewOffsetX, -mBackground.basePreviewOffsetY);
+ mPreviewItemManager.draw(canvas);
if (mPreviewLayoutRule.clipToBackground() && canvas.isHardwareAccelerated()) {
mBackground.clipCanvasHardware(canvas);
@@ -531,6 +486,10 @@ public class FolderIcon extends FrameLayout implements FolderListener {
mBackground.drawBackgroundStroke(canvas);
}
+ drawBadge(canvas);
+ }
+
+ public void drawBadge(Canvas canvas) {
if ((mBadgeInfo != null && mBadgeInfo.hasBadge()) || mBadgeScale > 0) {
int offsetX = mBackground.getOffsetX();
int offsetY = mBackground.getOffsetY();
@@ -546,19 +505,6 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
}
- private void animateFirstItem(final Drawable d, int duration, final boolean reverse,
- final Runnable onCompleteRunnable) {
- FolderPreviewItemAnim anim;
- if (!reverse) {
- anim = new FolderPreviewItemAnim(this, mDrawingParams.get(0), -1, -1, 0, 2, duration,
- onCompleteRunnable);
- } else {
- anim = new FolderPreviewItemAnim(this, mDrawingParams.get(0), 0, 2, -1, -1, duration,
- onCompleteRunnable);
- }
- anim.start();
- }
-
public void setTextVisible(boolean visible) {
if (visible) {
mFolderName.setVisibility(VISIBLE);
@@ -571,15 +517,25 @@ public class FolderIcon extends FrameLayout implements FolderListener {
return mFolderName.getVisibility() == VISIBLE;
}
- public List<BubbleTextView> getItemsToDisplay() {
+ /**
+ * Returns the list of preview items displayed in the icon.
+ */
+ public List<BubbleTextView> getPreviewItems() {
+ return getPreviewItemsOnPage(0);
+ }
+
+ /**
+ * Returns the list of "preview items" on {@param page}.
+ */
+ public List<BubbleTextView> getPreviewItemsOnPage(int page) {
mPreviewVerifier.setFolderInfo(mFolder.getInfo());
List<BubbleTextView> itemsToDisplay = new ArrayList<>();
- List<View> allItems = mFolder.getItemsInReadingOrder();
- int numItems = allItems.size();
+ List<BubbleTextView> itemsOnPage = mFolder.getItemsOnPage(page);
+ int numItems = itemsOnPage.size();
for (int rank = 0; rank < numItems; ++rank) {
- if (mPreviewVerifier.isItemInPreview(rank)) {
- itemsToDisplay.add((BubbleTextView) allItems.get(rank));
+ if (mPreviewVerifier.isItemInPreview(page, rank)) {
+ itemsToDisplay.add(itemsOnPage.get(rank));
}
if (itemsToDisplay.size() == FolderIcon.NUM_ITEMS_IN_PREVIEW) {
@@ -591,63 +547,12 @@ public class FolderIcon extends FrameLayout implements FolderListener {
@Override
protected boolean verifyDrawable(@NonNull Drawable who) {
- for (int i = 0; i < mDrawingParams.size(); i++) {
- if (mDrawingParams.get(i).drawable == who) {
- return true;
- }
- }
- return super.verifyDrawable(who);
- }
-
- private void updateItemDrawingParams(boolean animate) {
- List<BubbleTextView> items = getItemsToDisplay();
- int nItemsInPreview = items.size();
-
- int prevNumItems = mDrawingParams.size();
-
- // We adjust the size of the list to match the number of items in the preview
- while (nItemsInPreview < mDrawingParams.size()) {
- mDrawingParams.remove(mDrawingParams.size() - 1);
- }
- while (nItemsInPreview > mDrawingParams.size()) {
- mDrawingParams.add(new PreviewItemDrawingParams(0, 0, 0, 0));
- }
-
- for (int i = 0; i < mDrawingParams.size(); i++) {
- PreviewItemDrawingParams p = mDrawingParams.get(i);
- p.drawable = items.get(i).getCompoundDrawables()[1];
-
- if (p.drawable != null && !mFolder.isOpen()) {
- // Set the callback to FolderIcon as it is responsible to drawing the icon. The
- // callback will be release when the folder is opened.
- p.drawable.setCallback(this);
- }
-
- if (!animate || FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON) {
- computePreviewItemDrawingParams(i, nItemsInPreview, p);
- if (mReferenceDrawable == null) {
- mReferenceDrawable = p.drawable;
- }
- } else {
- FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, i, prevNumItems, i,
- nItemsInPreview, DROP_IN_ANIMATION_DURATION, null);
-
- if (p.anim != null) {
- if (p.anim.hasEqualFinalState(anim)) {
- // do nothing, let the current animation finish
- continue;
- }
- p.anim.cancel();
- }
- p.anim = anim;
- p.anim.start();
- }
- }
+ return mPreviewItemManager.verifyDrawable(who) || super.verifyDrawable(who);
}
@Override
public void onItemsChanged(boolean animate) {
- updateItemDrawingParams(animate);
+ mPreviewItemManager.updateItemDrawingParams(animate);
invalidate();
requestLayout();
}
@@ -790,13 +695,22 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
}
+ public void onFolderClose(int currentPage) {
+ mPreviewItemManager.onFolderClose(currentPage);
+ }
+
interface PreviewLayoutRule {
PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
- PreviewItemDrawingParams params);
+ PreviewItemDrawingParams params);
void init(int availableSpace, float intrinsicIconSize, boolean rtl);
float scaleForItem(int index, int totalNumItems);
float getIconSize();
int maxNumItems();
boolean clipToBackground();
+
+ boolean hasEnterExitIndices();
+ int getExitIndex();
+ int getEnterIndex();
+
}
}
diff --git a/src/com/android/launcher3/folder/FolderIconPreviewVerifier.java b/src/com/android/launcher3/folder/FolderIconPreviewVerifier.java
index de962b021..d054a5d42 100644
--- a/src/com/android/launcher3/folder/FolderIconPreviewVerifier.java
+++ b/src/com/android/launcher3/folder/FolderIconPreviewVerifier.java
@@ -41,20 +41,31 @@ public class FolderIconPreviewVerifier {
public void setFolderInfo(FolderInfo info) {
int numItemsInFolder = info.contents.size();
+ FolderPagedView.calculateGridSize(numItemsInFolder, 0, 0, mMaxGridCountX,
+ mMaxGridCountY, mMaxItemsPerPage, mGridSize);
+ mGridCountX = mGridSize[0];
+
mDisplayingUpperLeftQuadrant = FeatureFlags.LAUNCHER3_NEW_FOLDER_ANIMATION
&& !FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON
&& numItemsInFolder > FolderIcon.NUM_ITEMS_IN_PREVIEW;
-
- if (mDisplayingUpperLeftQuadrant) {
- FolderPagedView.calculateGridSize(info.contents.size(), 0, 0, mMaxGridCountX,
- mMaxGridCountY, mMaxItemsPerPage, mGridSize);
- mGridCountX = mGridSize[0];
- }
}
+ /**
+ * Returns whether the item with {@param rank} is in the default Folder icon preview.
+ */
public boolean isItemInPreview(int rank) {
- if (mDisplayingUpperLeftQuadrant) {
- // Returns true iff the icon is in the 2x2 upper left quadrant of the Folder.
+ return isItemInPreview(0, rank);
+ }
+
+ /**
+ * @param page The page the item is on.
+ * @param rank The rank of the item.
+ * @return True iff the icon is in the 2x2 upper left quadrant of the Folder.
+ */
+ public boolean isItemInPreview(int page, int rank) {
+ // First page items are laid out such that the first 4 items are always in the upper
+ // left quadrant. For all other pages, we need to check the row and col.
+ if (page > 0 || mDisplayingUpperLeftQuadrant) {
int col = rank % mGridCountX;
int row = rank / mGridCountX;
return col < 2 && row < 2;
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index d0ac9f4b1..f4ac0a140 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -494,8 +494,8 @@ public class FolderPagedView extends PagedView {
}
@Override
- protected void notifyPageSwitchListener() {
- super.notifyPageSwitchListener();
+ protected void notifyPageSwitchListener(int prevPage) {
+ super.notifyPageSwitchListener(prevPage);
if (mFolder != null) {
mFolder.updateTextViewFocus();
}
@@ -701,10 +701,4 @@ public class FolderPagedView extends PagedView {
public int itemsPerPage() {
return mMaxItemsPerPage;
}
-
- @Override
- protected void getEdgeVerticalPosition(int[] pos) {
- pos[0] = 0;
- pos[1] = getViewportHeight();
- }
}
diff --git a/src/com/android/launcher3/folder/FolderPreviewItemAnim.java b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
index 0da7c5cb1..be075bc9a 100644
--- a/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
+++ b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
@@ -25,16 +25,16 @@ import com.android.launcher3.LauncherAnimUtils;
* Animates a Folder preview item.
*/
class FolderPreviewItemAnim {
+
+ private static PreviewItemDrawingParams sTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
+
private ValueAnimator mValueAnimator;
float finalScale;
float finalTransX;
float finalTransY;
- private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
-
/**
- * @param folderIcon The FolderIcon this preview will be drawn in.
* @param params layout params to animate
* @param index0 original index of the item to be animated
* @param items0 original number of items in the preview
@@ -43,20 +43,20 @@ class FolderPreviewItemAnim {
* @param duration duration in ms of the animation
* @param onCompleteRunnable runnable to execute upon animation completion
*/
- FolderPreviewItemAnim(final FolderIcon folderIcon, final PreviewItemDrawingParams params,
- int index0, int items0, int index1, int items1, int duration,
- final Runnable onCompleteRunnable) {
- folderIcon.computePreviewItemDrawingParams(index1, items1, mTmpParams);
+ FolderPreviewItemAnim(final PreviewItemManager previewItemManager,
+ final PreviewItemDrawingParams params, int index0, int items0, int index1, int items1,
+ int duration, final Runnable onCompleteRunnable) {
+ previewItemManager.computePreviewItemDrawingParams(index1, items1, sTmpParams);
- finalScale = mTmpParams.scale;
- finalTransX = mTmpParams.transX;
- finalTransY = mTmpParams.transY;
+ finalScale = sTmpParams.scale;
+ finalTransX = sTmpParams.transX;
+ finalTransY = sTmpParams.transY;
- folderIcon.computePreviewItemDrawingParams(index0, items0, mTmpParams);
+ previewItemManager.computePreviewItemDrawingParams(index0, items0, sTmpParams);
- final float scale0 = mTmpParams.scale;
- final float transX0 = mTmpParams.transX;
- final float transY0 = mTmpParams.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(){
@@ -66,7 +66,7 @@ class FolderPreviewItemAnim {
params.transX = transX0 + progress * (finalTransX - transX0);
params.transY = transY0 + progress * (finalTransY - transY0);
params.scale = scale0 + progress * (finalScale - scale0);
- folderIcon.invalidate();
+ previewItemManager.onParamsChanged();
}
});
mValueAnimator.addListener(new AnimatorListenerAdapter() {
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index 44ebbcda7..eba5d984d 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -88,7 +88,7 @@ public class PreviewBackground {
public boolean isClipping = true;
// Drawing / animation configurations
- private static final float ACCEPT_SCALE_FACTOR = 1.25f;
+ private static final float ACCEPT_SCALE_FACTOR = 1.20f;
private static final float ACCEPT_COLOR_MULTIPLIER = 1.5f;
// Expressed on a scale from 0 to 255.
@@ -195,19 +195,28 @@ public class PreviewBackground {
invalidate();
}
+ public int getBgColor() {
+ int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier);
+ return ColorUtils.setAlphaComponent(mBgColor, alpha);
+ }
+
public void drawBackground(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL);
- int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier);
- mPaint.setColor(ColorUtils.setAlphaComponent(mBgColor, alpha));
+ mPaint.setColor(getBgColor());
drawCircle(canvas, 0 /* deltaRadius */);
- // Draw shadow.
+ drawShadow(canvas);
+ }
+
+ public void drawShadow(Canvas canvas) {
if (mShadowShader == null) {
return;
}
+
float radius = getScaledRadius();
float shadowRadius = radius + mStrokeWidth;
+ mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.BLACK);
int offsetX = getOffsetX();
int offsetY = getOffsetY();
@@ -219,7 +228,7 @@ public class PreviewBackground {
} else {
saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
- clipCanvasSoftware(canvas, Region.Op.DIFFERENCE);
+ canvas.clipPath(getClipPath(), Region.Op.DIFFERENCE);
}
mShaderMatrix.setScale(shadowRadius, shadowRadius);
@@ -295,17 +304,17 @@ public class PreviewBackground {
radius - deltaRadius, mPaint);
}
- // It is the callers responsibility to save and restore the canvas layers.
- void clipCanvasSoftware(Canvas canvas, Region.Op op) {
+ public Path getClipPath() {
mPath.reset();
float r = getScaledRadius();
mPath.addCircle(r + getOffsetX(), r + getOffsetY(), r, Path.Direction.CW);
- canvas.clipPath(mPath, op);
+ 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();
@@ -336,6 +345,7 @@ public class PreviewBackground {
}
mDrawingDelegate = null;
+ isClipping = true;
invalidate();
}
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
new file mode 100644
index 000000000..2d979a661
--- /dev/null
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -0,0 +1,359 @@
+/*
+ * 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.folder;
+
+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;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.launcher3.folder.FolderIcon.DROP_IN_ANIMATION_DURATION;
+
+/**
+ * Manages the drawing and animations of {@link PreviewItemDrawingParams} for a {@link FolderIcon}.
+ */
+public class PreviewItemManager {
+
+ private FolderIcon mIcon;
+
+ // These variables are all associated with the drawing of the preview; they are stored
+ // as member variables for shared usage and to avoid computation on each frame
+ private float mIntrinsicIconSize = -1;
+ private int mTotalWidth = -1;
+ private int mPrevTopPadding = -1;
+ private Drawable mReferenceDrawable = null;
+
+ // These hold the first page preview items
+ private ArrayList<PreviewItemDrawingParams> mFirstPageParams = new ArrayList<>();
+ // These hold the current page preview items. It is empty if the current page is the first page.
+ private ArrayList<PreviewItemDrawingParams> mCurrentPageParams = new ArrayList<>();
+
+ private float mCurrentPageItemsTransX = 0;
+ private boolean mShouldSlideInFirstPage;
+
+ static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
+ private static final int FINAL_ITEM_ANIMATION_DURATION = 200;
+
+ private static final int SLIDE_IN_FIRST_PAGE_ANIMATION_DURATION_DELAY = 100;
+ private static final int SLIDE_IN_FIRST_PAGE_ANIMATION_DURATION = 300;
+ private static final int ITEM_SLIDE_IN_OUT_DISTANCE_PX = 200;
+
+ public PreviewItemManager(FolderIcon icon) {
+ mIcon = icon;
+ }
+
+ /**
+ * @param reverse If true, animates the final item in the preview to be full size. If false,
+ * animates the first item to its position in the preview.
+ */
+ public FolderPreviewItemAnim createFirstItemAnimation(final boolean reverse,
+ final Runnable onCompleteRunnable) {
+ return reverse
+ ? new FolderPreviewItemAnim(this, mFirstPageParams.get(0), 0, 2, -1, -1,
+ FINAL_ITEM_ANIMATION_DURATION, onCompleteRunnable)
+ : new FolderPreviewItemAnim(this, mFirstPageParams.get(0), -1, -1, 0, 2,
+ INITIAL_ITEM_ANIMATION_DURATION, onCompleteRunnable);
+ }
+
+ Drawable prepareCreateAnimation(final View destView) {
+ Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1];
+ computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
+ destView.getMeasuredWidth());
+ mReferenceDrawable = animateDrawable;
+ return animateDrawable;
+ }
+
+ public void recomputePreviewDrawingParams() {
+ if (mReferenceDrawable != null) {
+ computePreviewDrawingParams(mReferenceDrawable.getIntrinsicWidth(),
+ mIcon.getMeasuredWidth());
+ }
+ }
+
+ private void computePreviewDrawingParams(int drawableSize, int totalSize) {
+ if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize ||
+ mPrevTopPadding != mIcon.getPaddingTop()) {
+ mIntrinsicIconSize = drawableSize;
+ mTotalWidth = totalSize;
+ mPrevTopPadding = mIcon.getPaddingTop();
+
+ mIcon.mBackground.setup(mIcon.mLauncher, mIcon, mTotalWidth, mIcon.getPaddingTop());
+ mIcon.mPreviewLayoutRule.init(mIcon.mBackground.previewSize, mIntrinsicIconSize,
+ Utilities.isRtl(mIcon.getResources()));
+
+ updateItemDrawingParams(false);
+ }
+ }
+
+ PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
+ PreviewItemDrawingParams params) {
+ // We use an index of -1 to represent an icon on the workspace for the destroy and
+ // create animations
+ if (index == -1) {
+ return getFinalIconParams(params);
+ }
+ return mIcon.mPreviewLayoutRule.computePreviewItemDrawingParams(index, curNumItems, params);
+ }
+
+ private PreviewItemDrawingParams getFinalIconParams(PreviewItemDrawingParams params) {
+ float iconSize = mIcon.mLauncher.getDeviceProfile().iconSizePx;
+
+ final float scale = iconSize / mReferenceDrawable.getIntrinsicWidth();
+ final float trans = (mIcon.mBackground.previewSize - iconSize) / 2;
+
+ params.update(trans, trans, scale);
+ return params;
+ }
+
+ public void drawParams(Canvas canvas, ArrayList<PreviewItemDrawingParams> params,
+ float transX) {
+ canvas.translate(transX, 0);
+ // The first item should be drawn last (ie. on top of later items)
+ for (int i = params.size() - 1; i >= 0; i--) {
+ PreviewItemDrawingParams p = params.get(i);
+ if (!p.hidden) {
+ drawPreviewItem(canvas, p);
+ }
+ }
+ canvas.translate(-transX, 0);
+ }
+
+ public void draw(Canvas canvas) {
+ // The items are drawn in coordinates relative to the preview offset
+ PreviewBackground bg = mIcon.getFolderBackground();
+ canvas.translate(bg.basePreviewOffsetX, bg.basePreviewOffsetY);
+
+ float firstPageItemsTransX = 0;
+ if (mShouldSlideInFirstPage) {
+ drawParams(canvas, mCurrentPageParams, mCurrentPageItemsTransX);
+
+ firstPageItemsTransX = -ITEM_SLIDE_IN_OUT_DISTANCE_PX + mCurrentPageItemsTransX;
+ }
+
+ drawParams(canvas, mFirstPageParams, firstPageItemsTransX);
+ canvas.translate(-bg.basePreviewOffsetX, -bg.basePreviewOffsetY);
+ }
+
+ public void onParamsChanged() {
+ mIcon.invalidate();
+ }
+
+ private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) {
+ canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ canvas.translate(params.transX, params.transY);
+ canvas.scale(params.scale, params.scale);
+ Drawable d = params.drawable;
+
+ if (d != null) {
+ Rect bounds = d.getBounds();
+ canvas.save();
+ canvas.translate(-bounds.left, -bounds.top);
+ canvas.scale(mIntrinsicIconSize / bounds.width(), mIntrinsicIconSize / bounds.height());
+ d.draw(canvas);
+ canvas.restore();
+ }
+ canvas.restore();
+ }
+
+ public void hidePreviewItem(int index, boolean hidden) {
+ PreviewItemDrawingParams params = index < mFirstPageParams.size() ?
+ mFirstPageParams.get(index) : null;
+ if (params != null) {
+ params.hidden = hidden;
+ }
+ }
+
+ void buildParamsForPage(int page, ArrayList<PreviewItemDrawingParams> params, boolean animate) {
+ List<BubbleTextView> items = mIcon.getPreviewItemsOnPage(page);
+ int prevNumItems = params.size();
+
+ // We adjust the size of the list to match the number of items in the preview.
+ while (items.size() < params.size()) {
+ params.remove(params.size() - 1);
+ }
+ while (items.size() > params.size()) {
+ params.add(new PreviewItemDrawingParams(0, 0, 0, 0));
+ }
+
+ int numItemsInFirstPagePreview = page == 0 ? items.size() : FolderIcon.NUM_ITEMS_IN_PREVIEW;
+ for (int i = 0; i < params.size(); i++) {
+ PreviewItemDrawingParams p = params.get(i);
+ p.drawable = items.get(i).getCompoundDrawables()[1];
+
+ if (p.drawable != null && !mIcon.mFolder.isOpen()) {
+ // Set the callback to FolderIcon as it is responsible to drawing the icon. The
+ // callback will be released when the folder is opened.
+ p.drawable.setCallback(mIcon);
+ }
+
+ if (!animate || FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON) {
+ computePreviewItemDrawingParams(i, numItemsInFirstPagePreview, p);
+ if (mReferenceDrawable == null) {
+ mReferenceDrawable = p.drawable;
+ }
+ } else {
+ FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, i, prevNumItems, i,
+ numItemsInFirstPagePreview, DROP_IN_ANIMATION_DURATION, null);
+
+ if (p.anim != null) {
+ if (p.anim.hasEqualFinalState(anim)) {
+ // do nothing, let the current animation finish
+ continue;
+ }
+ p.anim.cancel();
+ }
+ p.anim = anim;
+ p.anim.start();
+ }
+ }
+ }
+
+ void onFolderClose(int currentPage) {
+ // If we are not closing on the first page, we animate the current page preview items
+ // out, and animate the first page preview items in.
+ mShouldSlideInFirstPage = currentPage != 0;
+ if (mShouldSlideInFirstPage) {
+ mCurrentPageItemsTransX = 0;
+ buildParamsForPage(currentPage, mCurrentPageParams, false);
+ onParamsChanged();
+
+ ValueAnimator slideAnimator = ValueAnimator.ofFloat(0, ITEM_SLIDE_IN_OUT_DISTANCE_PX);
+ slideAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ mCurrentPageItemsTransX = (float) valueAnimator.getAnimatedValue();
+ onParamsChanged();
+ }
+ });
+ slideAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCurrentPageParams.clear();
+ }
+ });
+ slideAnimator.setStartDelay(SLIDE_IN_FIRST_PAGE_ANIMATION_DURATION_DELAY);
+ slideAnimator.setDuration(SLIDE_IN_FIRST_PAGE_ANIMATION_DURATION);
+ slideAnimator.start();
+ }
+ }
+
+ void updateItemDrawingParams(boolean animate) {
+ buildParamsForPage(0, mFirstPageParams, animate);
+ }
+
+ boolean verifyDrawable(@NonNull Drawable who) {
+ for (int i = 0; i < mFirstPageParams.size(); i++) {
+ if (mFirstPageParams.get(i).drawable == who) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ float getIntrinsicIconSize() {
+ return mIntrinsicIconSize;
+ }
+
+ /**
+ * Handles the case where items in the preview are either:
+ * - Moving into the preview
+ * - Moving into a new position
+ * - Moving out of the preview
+ *
+ * @param oldParams The list of items in the old preview.
+ * @param newParams The list of items in the new preview.
+ * @param dropped The item that was dropped onto the FolderIcon.
+ */
+ public void onDrop(List<BubbleTextView> oldParams, List<BubbleTextView> newParams,
+ ShortcutInfo dropped) {
+ int numItems = newParams.size();
+ final ArrayList<PreviewItemDrawingParams> params = mFirstPageParams;
+ buildParamsForPage(0, params, false);
+
+ // New preview items for items that are moving in (except for the dropped item).
+ List<BubbleTextView> moveIn = new ArrayList<>();
+ for (BubbleTextView btv : newParams) {
+ if (!oldParams.contains(btv) && !btv.getTag().equals(dropped)) {
+ moveIn.add(btv);
+ }
+ }
+ for (int i = 0; i < moveIn.size(); ++i) {
+ int prevIndex = newParams.indexOf(moveIn.get(i));
+ PreviewItemDrawingParams p = params.get(prevIndex);
+ computePreviewItemDrawingParams(prevIndex, numItems, p);
+ updateTransitionParam(p, moveIn.get(i), mIcon.mPreviewLayoutRule.getEnterIndex(),
+ newParams.indexOf(moveIn.get(i)));
+ }
+
+ // Items that are moving into new positions within the preview.
+ for (int newIndex = 0; newIndex < newParams.size(); ++newIndex) {
+ int oldIndex = oldParams.indexOf(newParams.get(newIndex));
+ if (oldIndex >= 0 && newIndex != oldIndex) {
+ PreviewItemDrawingParams p = params.get(newIndex);
+ updateTransitionParam(p, newParams.get(newIndex), oldIndex, newIndex);
+ }
+ }
+
+ // Old preview items that need to be moved out.
+ List<BubbleTextView> moveOut = new ArrayList<>(oldParams);
+ moveOut.removeAll(newParams);
+ for (int i = 0; i < moveOut.size(); ++i) {
+ BubbleTextView item = moveOut.get(i);
+ int oldIndex = oldParams.indexOf(item);
+ PreviewItemDrawingParams p = computePreviewItemDrawingParams(oldIndex, numItems, null);
+ updateTransitionParam(p, item, oldIndex, mIcon.mPreviewLayoutRule.getExitIndex());
+ params.add(0, p); // We want these items first so that they are on drawn last.
+ }
+
+ for (int i = 0; i < params.size(); ++i) {
+ if (params.get(i).anim != null) {
+ params.get(i).anim.start();
+ }
+ }
+ }
+
+ private void updateTransitionParam(final PreviewItemDrawingParams p, BubbleTextView btv,
+ int prevIndex, int newIndex) {
+ p.drawable = btv.getCompoundDrawables()[1];
+ if (!mIcon.mFolder.isOpen()) {
+ // Set the callback to FolderIcon as it is responsible to drawing the icon. The
+ // callback will be released when the folder is opened.
+ p.drawable.setCallback(mIcon);
+ }
+
+ FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, prevIndex,
+ FolderIcon.NUM_ITEMS_IN_PREVIEW, newIndex, FolderIcon.NUM_ITEMS_IN_PREVIEW,
+ DROP_IN_ANIMATION_DURATION, null);
+ if (p.anim != null && !p.anim.hasEqualFinalState(anim)) {
+ p.anim.cancel();
+ }
+ p.anim = anim;
+ }
+}
diff --git a/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java b/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
index 138dc1c55..7d10556d0 100644
--- a/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
@@ -97,4 +97,19 @@ public class StackFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule {
public boolean clipToBackground() {
return false;
}
+
+ @Override
+ public boolean hasEnterExitIndices() {
+ return false;
+ }
+
+ @Override
+ public int getExitIndex() {
+ throw new RuntimeException("hasEnterExitIndices not supported");
+ }
+
+ @Override
+ public int getEnterIndex() {
+ throw new RuntimeException("hasEnterExitIndices not supported");
+ }
}
diff --git a/src/com/android/launcher3/graphics/GradientView.java b/src/com/android/launcher3/graphics/GradientView.java
index 9dd950454..678396df1 100644
--- a/src/com/android/launcher3/graphics/GradientView.java
+++ b/src/com/android/launcher3/graphics/GradientView.java
@@ -18,13 +18,14 @@ package com.android.launcher3.graphics;
import android.content.Context;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader;
+import android.support.v4.graphics.ColorUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
@@ -34,6 +35,7 @@ import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.dynamicui.WallpaperColorInfo;
+import com.android.launcher3.util.Themes;
/**
* Draws a translucent radial gradient background from an initial state with progress 0.0 to a
@@ -42,44 +44,44 @@ import com.android.launcher3.dynamicui.WallpaperColorInfo;
public class GradientView extends View implements WallpaperColorInfo.OnChangeListener {
private static final int DEFAULT_COLOR = Color.WHITE;
- private static final float GRADIENT_ALPHA_MASK_LENGTH_DP = 300;
+ private static final int ALPHA_MASK_HEIGHT_DP = 500;
+ private static final int ALPHA_MASK_WIDTH_DP = 2;
+ private static final int ALPHA_COLORS = 0xBF;
private static final boolean DEBUG = false;
- private final Bitmap mFinalGradientMask;
private final Bitmap mAlphaGradientMask;
+ private boolean mShowScrim = true;
private int mColor1 = DEFAULT_COLOR;
private int mColor2 = DEFAULT_COLOR;
private int mWidth;
private int mHeight;
private final RectF mAlphaMaskRect = new RectF();
private final RectF mFinalMaskRect = new RectF();
- private final Paint mPaint = new Paint();
+ private final Paint mPaintWithScrim = new Paint();
+ private final Paint mPaintNoScrim = new Paint();
private float mProgress;
- private final int mMaskHeight;
+ private final int mMaskHeight, mMaskWidth;
private final Context mAppContext;
private final Paint mDebugPaint = DEBUG ? new Paint() : null;
private final Interpolator mAccelerator = new AccelerateInterpolator();
private final float mAlphaStart;
private final WallpaperColorInfo mWallpaperColorInfo;
+ private final int mScrimColor;
public GradientView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mAppContext = context.getApplicationContext();
- this.mMaskHeight = Utilities.pxFromDp(GRADIENT_ALPHA_MASK_LENGTH_DP,
+ this.mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP,
+ mAppContext.getResources().getDisplayMetrics());
+ this.mMaskWidth = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP,
mAppContext.getResources().getDisplayMetrics());
Launcher launcher = Launcher.getLauncher(context);
this.mAlphaStart = launcher.getDeviceProfile().isVerticalBarLayout() ? 0 : 100;
+ this.mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
this.mWallpaperColorInfo = WallpaperColorInfo.getInstance(launcher);
updateColors();
-
- int finalAlpha = 0xBF;
- mFinalGradientMask = Utilities.convertToAlphaMask(
- Utilities.createOnePixBitmap(), finalAlpha);
- Bitmap alphaMaskFromResource = BitmapFactory.decodeResource(context.getResources(),
- R.drawable.all_apps_alpha_mask);
- mAlphaGradientMask = Utilities.convertToAlphaMask(
- alphaMaskFromResource, finalAlpha);
+ mAlphaGradientMask = createDitheredAlphaMask();
}
@Override
@@ -101,8 +103,10 @@ public class GradientView extends View implements WallpaperColorInfo.OnChangeLis
}
private void updateColors() {
- this.mColor1 = mWallpaperColorInfo.getMainColor();
- this.mColor2 = mWallpaperColorInfo.getSecondaryColor();
+ this.mColor1 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getMainColor(),
+ ALPHA_COLORS);
+ this.mColor2 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getSecondaryColor(),
+ ALPHA_COLORS);
if (mWidth + mHeight > 0) {
createRadialShader();
}
@@ -122,34 +126,53 @@ public class GradientView extends View implements WallpaperColorInfo.OnChangeLis
private void createRadialShader() {
final float gradientCenterY = 1.05f;
float radius = Math.max(mHeight, mWidth) * gradientCenterY;
-
float posScreenBottom = (radius - mHeight) / radius; // center lives below screen
- RadialGradient shader = new RadialGradient(
+
+ RadialGradient shaderNoScrim = new RadialGradient(
mWidth * 0.5f,
mHeight * gradientCenterY,
radius,
new int[] {mColor1, mColor1, mColor2},
new float[] {0f, posScreenBottom, 1f},
Shader.TileMode.CLAMP);
- mPaint.setShader(shader);
+ mPaintNoScrim.setShader(shaderNoScrim);
+
+ int color1 = ColorUtils.compositeColors(mScrimColor,mColor1);
+ int color2 = ColorUtils.compositeColors(mScrimColor,mColor2);
+ RadialGradient shaderWithScrim = new RadialGradient(
+ mWidth * 0.5f,
+ mHeight * gradientCenterY,
+ radius,
+ new int[] { color1, color1, color2 },
+ new float[] {0f, posScreenBottom, 1f},
+ Shader.TileMode.CLAMP);
+ mPaintWithScrim.setShader(shaderWithScrim);
}
public void setProgress(float progress) {
+ setProgress(progress, true);
+ }
+
+ public void setProgress(float progress, boolean showScrim) {
this.mProgress = progress;
+ this.mShowScrim = showScrim;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
+ Paint paint = mShowScrim ? mPaintWithScrim : mPaintNoScrim;
+
float head = 0.29f;
float linearProgress = head + (mProgress * (1f - head));
float startMaskY = (1f - linearProgress) * mHeight - mMaskHeight * linearProgress;
float interpolatedAlpha = (255 - mAlphaStart) * mAccelerator.getInterpolation(mProgress);
- mPaint.setAlpha((int) (mAlphaStart + interpolatedAlpha));
- mAlphaMaskRect.set(0, startMaskY, mWidth, startMaskY + mMaskHeight);
- mFinalMaskRect.set(0, startMaskY + mMaskHeight, mWidth, mHeight);
- canvas.drawBitmap(mAlphaGradientMask, null, mAlphaMaskRect, mPaint);
- canvas.drawBitmap(mFinalGradientMask, null, mFinalMaskRect, mPaint);
+ paint.setAlpha((int) (mAlphaStart + interpolatedAlpha));
+ float div = (float) Math.floor(startMaskY + mMaskHeight);
+ mAlphaMaskRect.set(0, startMaskY, mWidth, div);
+ mFinalMaskRect.set(0, div, mWidth, mHeight);
+ canvas.drawBitmap(mAlphaGradientMask, null, mAlphaMaskRect, paint);
+ canvas.drawRect(mFinalMaskRect, paint);
if (DEBUG) {
mDebugPaint.setColor(0xFF00FF00);
@@ -157,4 +180,20 @@ public class GradientView extends View implements WallpaperColorInfo.OnChangeLis
canvas.drawLine(0, startMaskY + mMaskHeight, mWidth, startMaskY + mMaskHeight, mDebugPaint);
}
}
+
+ public Bitmap createDitheredAlphaMask() {
+ Bitmap dst = Bitmap.createBitmap(mMaskWidth, mMaskHeight, Bitmap.Config.ALPHA_8);
+ Canvas c = new Canvas(dst);
+ Paint paint = new Paint(Paint.DITHER_FLAG);
+ LinearGradient lg = new LinearGradient(0, 0, 0, mMaskHeight,
+ new int[]{
+ 0x00FFFFFF,
+ ColorUtils.setAlphaComponent(Color.WHITE, (int) (0xFF * 0.95)),
+ 0xFFFFFFFF},
+ new float[]{0f, 0.8f, 1f},
+ Shader.TileMode.CLAMP);
+ paint.setShader(lg);
+ c.drawRect(0, 0, mMaskWidth, mMaskHeight, paint);
+ return dst;
+ }
} \ No newline at end of file
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 830ca82b3..d95567492 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -35,6 +35,7 @@ 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.IconCache;
@@ -45,6 +46,7 @@ import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.util.Provider;
/**
* Helper methods for generating various launcher icons
@@ -315,14 +317,41 @@ public class LauncherIcons {
public static Bitmap createShortcutIcon(ShortcutInfoCompat shortcutInfo, Context context,
boolean badged) {
+ return createShortcutIcon(shortcutInfo, context, badged, null);
+ }
+
+ public static Bitmap createShortcutIcon(ShortcutInfoCompat shortcutInfo, Context context,
+ final Bitmap fallbackIcon) {
+ Provider<Bitmap> fallbackIconProvider = new Provider<Bitmap>() {
+ @Override
+ public Bitmap get() {
+ // 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.
+ return fallbackIcon;
+ }
+ };
+ return createShortcutIcon(shortcutInfo, context, true, fallbackIconProvider);
+ }
+
+ public static Bitmap createShortcutIcon(ShortcutInfoCompat shortcutInfo, Context context,
+ boolean badged, @Nullable Provider<Bitmap> fallbackIconProvider) {
LauncherAppState app = LauncherAppState.getInstance(context);
Drawable unbadgedDrawable = DeepShortcutManager.getInstance(context)
.getShortcutIconDrawable(shortcutInfo,
app.getInvariantDeviceProfile().fillResIconDpi);
IconCache cache = app.getIconCache();
- Bitmap unbadgedBitmap = unbadgedDrawable == null
- ? cache.getDefaultIcon(Process.myUserHandle())
- : LauncherIcons.createScaledBitmapWithoutShadow(unbadgedDrawable, context, 0);
+ Bitmap unbadgedBitmap = null;
+ if (unbadgedDrawable != null) {
+ unbadgedBitmap = LauncherIcons.createScaledBitmapWithoutShadow(
+ unbadgedDrawable, context, 0);
+ } else {
+ if (fallbackIconProvider != null) {
+ unbadgedBitmap = fallbackIconProvider.get();
+ }
+ if (unbadgedBitmap == null) {
+ unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle());
+ }
+ }
if (!badged) {
return unbadgedBitmap;
diff --git a/src/com/android/launcher3/graphics/ScrimView.java b/src/com/android/launcher3/graphics/ScrimView.java
deleted file mode 100644
index 6d1f30a41..000000000
--- a/src/com/android/launcher3/graphics/ScrimView.java
+++ /dev/null
@@ -1,115 +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.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.RectF;
-import android.support.v4.graphics.ColorUtils;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.Interpolator;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.Themes;
-
-public class ScrimView extends View {
-
- private static final boolean DEBUG = false;
-
- private static final int MASK_HEIGHT_DP = 300;
- private static final float MASK_START_LENGTH_FACTOR = 1f;
- private static final boolean APPLY_ALPHA = true;
-
- private final Bitmap mFinalScrimMask;
- private final Bitmap mAlphaScrimMask;
-
- private final int mMaskHeight;
- private int mVisibleHeight;
- private final int mHeadStart;
-
- private final RectF mAlphaMaskRect = new RectF();
- private final RectF mFinalMaskRect = new RectF();
- private final Paint mPaint = new Paint();
- private float mProgress;
- private final Interpolator mAccelerator = new AccelerateInterpolator();
- private final Paint mDebugPaint = DEBUG ? new Paint() : null;
- private final int mAlphaStart;
-
- public ScrimView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mMaskHeight = Utilities.pxFromDp(MASK_HEIGHT_DP, getResources().getDisplayMetrics());
- mHeadStart = (int) (mMaskHeight * MASK_START_LENGTH_FACTOR);
- mAlphaStart = Launcher.getLauncher(context)
- .getDeviceProfile().isVerticalBarLayout() ? 0 : 55;
-
- int scrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
- int scrimAlpha = Color.alpha(scrimColor);
- mPaint.setColor(scrimColor);
- mFinalScrimMask = Utilities.convertToAlphaMask(
- Utilities.createOnePixBitmap(), scrimAlpha);
- Bitmap alphaMaskFromResource = BitmapFactory.decodeResource(getResources(),
- R.drawable.all_apps_alpha_mask);
- mAlphaScrimMask = Utilities.convertToAlphaMask(alphaMaskFromResource, scrimAlpha);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int width = MeasureSpec.getSize(widthMeasureSpec);
- mVisibleHeight = MeasureSpec.getSize(heightMeasureSpec);
- setMeasuredDimension(width, mVisibleHeight * 2);
- setProgress(mProgress);
- }
-
- public void setProgress(float progress) {
- mProgress = progress;
- float initialY = mVisibleHeight - mHeadStart;
- float fullTranslationY = mVisibleHeight;
- float linTranslationY = initialY - progress * fullTranslationY;
- setTranslationY(linTranslationY);
-
- if (APPLY_ALPHA) {
- int alpha = mAlphaStart + (int) ((255f - mAlphaStart)
- * mAccelerator.getInterpolation(progress));
- mPaint.setAlpha(alpha);
- invalidate();
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- mAlphaMaskRect.set(0, 0, getWidth(), mMaskHeight);
- mFinalMaskRect.set(0, mMaskHeight, getWidth(), getHeight());
- canvas.drawBitmap(mAlphaScrimMask, null, mAlphaMaskRect, mPaint);
- canvas.drawBitmap(mFinalScrimMask, null, mFinalMaskRect, mPaint);
-
- if (DEBUG) {
- mDebugPaint.setColor(0xFF0000FF);
- canvas.drawLine(0, mAlphaMaskRect.top, getWidth(), mAlphaMaskRect.top, mDebugPaint);
- canvas.drawLine(0, mAlphaMaskRect.bottom, getWidth(), mAlphaMaskRect.bottom, mDebugPaint);
- }
- }
-
-}
diff --git a/src/com/android/launcher3/graphics/ShadowGenerator.java b/src/com/android/launcher3/graphics/ShadowGenerator.java
index fffea8e3e..60eeef5df 100644
--- a/src/com/android/launcher3/graphics/ShadowGenerator.java
+++ b/src/com/android/launcher3/graphics/ShadowGenerator.java
@@ -53,27 +53,38 @@ public class ShadowGenerator {
private final Canvas mCanvas;
private final Paint mBlurPaint;
private final Paint mDrawPaint;
+ private final BlurMaskFilter mDefaultBlurMaskFilter;
private ShadowGenerator(Context context) {
mIconSize = LauncherAppState.getIDP(context).iconBitmapSize;
mCanvas = new Canvas();
mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
- mBlurPaint.setMaskFilter(new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL));
mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+ mDefaultBlurMaskFilter = new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL);
}
public synchronized Bitmap recreateIcon(Bitmap icon) {
+ return recreateIcon(icon, true, mDefaultBlurMaskFilter, AMBIENT_SHADOW_ALPHA,
+ KEY_SHADOW_ALPHA);
+ }
+
+ public synchronized Bitmap recreateIcon(Bitmap icon, boolean resize,
+ BlurMaskFilter blurMaskFilter, int ambientAlpha, int keyAlpha) {
+ int width = resize ? mIconSize : icon.getWidth();
+ int height = resize ? mIconSize : icon.getHeight();
int[] offset = new int[2];
+
+ mBlurPaint.setMaskFilter(blurMaskFilter);
Bitmap shadow = icon.extractAlpha(mBlurPaint, offset);
- Bitmap result = Bitmap.createBitmap(mIconSize, mIconSize, Config.ARGB_8888);
+ Bitmap result = Bitmap.createBitmap(width, height, Config.ARGB_8888);
mCanvas.setBitmap(result);
// Draw ambient shadow
- mDrawPaint.setAlpha(AMBIENT_SHADOW_ALPHA);
+ mDrawPaint.setAlpha(ambientAlpha);
mCanvas.drawBitmap(shadow, offset[0], offset[1], mDrawPaint);
// Draw key shadow
- mDrawPaint.setAlpha(KEY_SHADOW_ALPHA);
+ mDrawPaint.setAlpha(keyAlpha);
mCanvas.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconSize, mDrawPaint);
// Draw the icon
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index 329b7d561..ebb69c43b 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -25,6 +25,7 @@ import com.android.launcher3.InfoDropTarget;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.UninstallDropTarget;
+import com.android.launcher3.userevent.nano.LauncherLogExtensions.TargetExtension;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
@@ -66,8 +67,14 @@ public class LoggerUtils {
}
public static String getActionStr(Action action) {
+ String str = "";
switch (action.type) {
- case Action.Type.TOUCH: return getFieldName(action.touch, Action.Touch.class);
+ case Action.Type.TOUCH:
+ str += getFieldName(action.touch, Action.Touch.class);
+ if (action.touch == Action.Touch.SWIPE) {
+ str += " direction=" + getFieldName(action.dir, Action.Direction.class);
+ }
+ return str;
case Action.Type.COMMAND: return getFieldName(action.command, Action.Command.class);
default: return UNKNOWN;
}
@@ -153,6 +160,13 @@ public class LoggerUtils {
return t;
}
+ public static Target newTarget(int targetType, TargetExtension extension) {
+ Target t = new Target();
+ t.type = targetType;
+ t.extension = extension;
+ return t;
+ }
+
public static Target newTarget(int targetType) {
Target t = new Target();
t.type = targetType;
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index edbb88c93..d5c6515c0 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -20,6 +20,7 @@ import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.util.Log;
@@ -35,11 +36,10 @@ 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.LogConfig;
-import java.util.List;
import java.util.Locale;
+import java.util.UUID;
import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
@@ -62,13 +62,21 @@ public class UserEventDispatcher {
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, boolean isInLandscapeMode,
boolean isInMultiWindowMode) {
+ SharedPreferences sharedPrefs = Utilities.getDevicePrefs(context);
+ String uuidStr = sharedPrefs.getString(UUID_STORAGE, null);
+ if (uuidStr == null) {
+ uuidStr = UUID.randomUUID().toString();
+ sharedPrefs.edit().putString(UUID_STORAGE, uuidStr).apply();
+ }
UserEventDispatcher ued = Utilities.getOverrideObject(UserEventDispatcher.class,
context.getApplicationContext(), R.string.user_event_dispatcher_class);
ued.mIsInLandscapeMode = isInLandscapeMode;
ued.mIsInMultiWindowMode = isInMultiWindowMode;
+ ued.mUuidStr = uuidStr;
return ued;
}
@@ -116,9 +124,7 @@ public class UserEventDispatcher {
private long mActionDurationMillis;
private boolean mIsInMultiWindowMode;
private boolean mIsInLandscapeMode;
-
- // Used for filling in predictedRank on {@link Target}s.
- private List<ComponentKey> mPredictedApps;
+ private String mUuidStr;
// APP_ICON SHORTCUT WIDGET
// --------------------------------------------------------------
@@ -127,32 +133,11 @@ public class UserEventDispatcher {
// intentHash required
// --------------------------------------------------------------
- protected LauncherEvent createLauncherEvent(View v, int intentHashCode, ComponentName cn) {
- LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP),
- newItemTarget(v), newTarget(Target.Type.CONTAINER));
-
- // TODO: make idx percolate up the view hierarchy if needed.
- int idx = 0;
- if (fillInLogContainerData(event, v)) {
- ItemInfo itemInfo = (ItemInfo) v.getTag();
- event.srcTarget[idx].intentHash = intentHashCode;
- if (cn != null) {
- event.srcTarget[idx].packageNameHash = cn.getPackageName().hashCode();
- event.srcTarget[idx].componentHash = cn.hashCode();
- if (mPredictedApps != null) {
- event.srcTarget[idx].predictedRank = mPredictedApps.indexOf(
- new ComponentKey(cn, itemInfo.user));
- }
- }
- }
- return event;
- }
-
/**
* Fills in the container data on the given event if the given view is not null.
* @return whether container data was added.
*/
- private boolean fillInLogContainerData(LauncherEvent event, @Nullable View v) {
+ 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) {
@@ -164,20 +149,31 @@ public class UserEventDispatcher {
}
public void logAppLaunch(View v, Intent intent) {
- LauncherEvent ev = createLauncherEvent(v, intent.hashCode(), intent.getComponent());
- if (ev == null) {
- return;
+ LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP),
+ newItemTarget(v), newTarget(Target.Type.CONTAINER));
+
+ if (fillInLogContainerData(event, v)) {
+ fillIntentInfo(event.srcTarget[0], intent);
+ }
+ dispatchUserEvent(event, intent);
+ }
+
+ protected void fillIntentInfo(Target target, Intent intent) {
+ target.intentHash = intent.hashCode();
+ ComponentName cn = intent.getComponent();
+ if (cn != null) {
+ target.packageNameHash = (mUuidStr + cn.getPackageName()).hashCode();
+ target.componentHash = (mUuidStr + cn.flattenToString()).hashCode();
}
- dispatchUserEvent(ev, intent);
}
public void logNotificationLaunch(View v, PendingIntent intent) {
- ComponentName dummyComponent = new ComponentName(intent.getCreatorPackage(), "--dummy--");
- LauncherEvent ev = createLauncherEvent(v, intent.hashCode(), dummyComponent);
- if (ev == null) {
- return;
+ LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP),
+ newItemTarget(v), newTarget(Target.Type.CONTAINER));
+ if (fillInLogContainerData(event, v)) {
+ event.srcTarget[0].packageNameHash = (mUuidStr + intent.getCreatorPackage()).hashCode();
}
- dispatchUserEvent(ev, null);
+ dispatchUserEvent(event, null);
}
public void logActionCommand(int command, int containerType) {
@@ -262,10 +258,6 @@ public class UserEventDispatcher {
resetElapsedContainerMillis();
}
- public void setPredictedApps(List<ComponentKey> predictedApps) {
- mPredictedApps = predictedApps;
- }
-
/* 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() {
@@ -337,7 +329,10 @@ public class UserEventDispatcher {
}
private static String getTargetsStr(Target[] targets) {
- return "child:" + LoggerUtils.getTargetStr(targets[0]) +
- (targets.length > 1 ? "\tparent:" + LoggerUtils.getTargetStr(targets[1]) : "");
+ String result = "child:" + LoggerUtils.getTargetStr(targets[0]);
+ for (int i = 1; i < targets.length; i++) {
+ result += "\tparent:" + LoggerUtils.getTargetStr(targets[i]);
+ }
+ return result;
}
}
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 1a2c04d6e..bc7da9b12 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -184,9 +184,13 @@ public class LoaderCursor extends CursorWrapper {
icon = LauncherIcons.createIconBitmap(
BitmapFactory.decodeByteArray(data, 0, data.length), mContext);
} catch (Exception e) {
+ Log.e(TAG, "Failed to load icon for info " + info, e);
return null;
}
}
+ if (icon == null) {
+ Log.e(TAG, "Failed to load icon for info " + info);
+ }
return icon;
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index bb2d0b6af..c56325ad5 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -24,8 +24,8 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.PackageInstaller;
+import android.graphics.Bitmap;
import android.os.Handler;
-import android.os.Looper;
import android.os.Process;
import android.os.SystemClock;
import android.os.Trace;
@@ -66,6 +66,7 @@ import com.android.launcher3.util.LooperIdleLock;
import com.android.launcher3.util.ManagedProfileHeuristic;
import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.Provider;
import java.util.ArrayList;
import java.util.Collections;
@@ -459,8 +460,18 @@ public class LoaderTask implements Runnable {
continue;
}
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);
+ }
+ };
info.iconBitmap = LauncherIcons
- .createShortcutIcon(pinnedShortcut, context);
+ .createShortcutIcon(pinnedShortcut, context,
+ true /* badged */, fallbackIconProvider);
if (pmHelper.isAppSuspended(
pinnedShortcut.getPackage(), info.user)) {
info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
@@ -537,6 +548,11 @@ public class LoaderTask implements Runnable {
break;
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ if (FeatureFlags.GO_DISABLE_WIDGETS) {
+ c.markDeleted("Only legacy shortcuts can have null package");
+ continue;
+ }
+ // Follow through
case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
// Read all Launcher-specific widget details
boolean customWidget = c.itemType ==
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 6f325858d..17cc238d4 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -85,10 +85,10 @@ public class ShortcutsChangedTask extends BaseModelUpdateTask {
removedShortcutInfos.addAll(shortcutInfos);
continue;
}
- for (ShortcutInfo shortcutInfo : shortcutInfos) {
+ for (final ShortcutInfo shortcutInfo : shortcutInfos) {
shortcutInfo.updateFromDeepShortcutInfo(fullDetails, context);
- shortcutInfo.iconBitmap =
- LauncherIcons.createShortcutIcon(fullDetails, context);
+ shortcutInfo.iconBitmap = LauncherIcons.createShortcutIcon(fullDetails, context,
+ shortcutInfo.iconBitmap);
updatedShortcutInfos.add(shortcutInfo);
}
}
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index 568200646..802771f04 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -85,7 +85,8 @@ public class UserLockStateChangedTask extends BaseModelUpdateTask {
}
si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
si.updateFromDeepShortcutInfo(shortcut, context);
- si.iconBitmap = LauncherIcons.createShortcutIcon(shortcut, context);
+ si.iconBitmap = LauncherIcons.createShortcutIcon(shortcut, context,
+ si.iconBitmap);
} else {
si.isDisabled |= ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
}
diff --git a/src/com/android/launcher3/notification/FlingAnimationUtils.java b/src/com/android/launcher3/notification/FlingAnimationUtils.java
deleted file mode 100644
index a1f7e49c0..000000000
--- a/src/com/android/launcher3/notification/FlingAnimationUtils.java
+++ /dev/null
@@ -1,356 +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.notification;
-
-import android.animation.Animator;
-import android.content.Context;
-import android.view.ViewPropertyAnimator;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
-
-/**
- * Utility class to calculate general fling animation when the finger is released.
- *
- * This class was copied from com.android.systemui.statusbar.
- */
-public class FlingAnimationUtils {
-
- private static final float LINEAR_OUT_SLOW_IN_X2 = 0.35f;
- private static final float LINEAR_OUT_SLOW_IN_X2_MAX = 0.68f;
- private static final float LINEAR_OUT_FASTER_IN_X2 = 0.5f;
- private static final float LINEAR_OUT_FASTER_IN_Y2_MIN = 0.4f;
- private static final float LINEAR_OUT_FASTER_IN_Y2_MAX = 0.5f;
- private static final float MIN_VELOCITY_DP_PER_SECOND = 250;
- private static final float HIGH_VELOCITY_DP_PER_SECOND = 3000;
-
- private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 0.75f;
- private final float mSpeedUpFactor;
- private final float mY2;
-
- private float mMinVelocityPxPerSecond;
- private float mMaxLengthSeconds;
- private float mHighVelocityPxPerSecond;
- private float mLinearOutSlowInX2;
-
- private AnimatorProperties mAnimatorProperties = new AnimatorProperties();
- private PathInterpolator mInterpolator;
- private float mCachedStartGradient = -1;
- private float mCachedVelocityFactor = -1;
-
- public FlingAnimationUtils(Context ctx, float maxLengthSeconds) {
- this(ctx, maxLengthSeconds, 0.0f);
- }
-
- /**
- * @param maxLengthSeconds the longest duration an animation can become in seconds
- * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
- * the end of the animation. 0 means it's at the beginning and no
- * acceleration will take place.
- */
- public FlingAnimationUtils(Context ctx, float maxLengthSeconds, float speedUpFactor) {
- this(ctx, maxLengthSeconds, speedUpFactor, -1.0f, 1.0f);
- }
-
- /**
- * @param maxLengthSeconds the longest duration an animation can become in seconds
- * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
- * the end of the animation. 0 means it's at the beginning and no
- * acceleration will take place.
- * @param x2 the x value to take for the second point of the bezier spline. If a value below 0
- * is provided, the value is automatically calculated.
- * @param y2 the y value to take for the second point of the bezier spline
- */
- public FlingAnimationUtils(Context ctx, float maxLengthSeconds, float speedUpFactor, float x2,
- float y2) {
- mMaxLengthSeconds = maxLengthSeconds;
- mSpeedUpFactor = speedUpFactor;
- if (x2 < 0) {
- mLinearOutSlowInX2 = interpolate(LINEAR_OUT_SLOW_IN_X2,
- LINEAR_OUT_SLOW_IN_X2_MAX,
- mSpeedUpFactor);
- } else {
- mLinearOutSlowInX2 = x2;
- }
- mY2 = y2;
-
- mMinVelocityPxPerSecond
- = MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
- mHighVelocityPxPerSecond
- = HIGH_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
- }
-
- private static float interpolate(float start, float end, float amount) {
- return start * (1.0f - amount) + end * amount;
- }
-
- /**
- * Applies the interpolator and length to the animator, such that the fling animation is
- * consistent with the finger motion.
- *
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
- */
- public void apply(Animator animator, float currValue, float endValue, float velocity) {
- apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
- }
-
- /**
- * Applies the interpolator and length to the animator, such that the fling animation is
- * consistent with the finger motion.
- *
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
- */
- public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
- float velocity) {
- apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
- }
-
- /**
- * Applies the interpolator and length to the animator, such that the fling animation is
- * consistent with the finger motion.
- *
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
- * @param maxDistance the maximum distance for this interaction; the maximum animation length
- * gets multiplied by the ratio between the actual distance and this value
- */
- public void apply(Animator animator, float currValue, float endValue, float velocity,
- float maxDistance) {
- AnimatorProperties properties = getProperties(currValue, endValue, velocity,
- maxDistance);
- animator.setDuration(properties.duration);
- animator.setInterpolator(properties.interpolator);
- }
-
- /**
- * Applies the interpolator and length to the animator, such that the fling animation is
- * consistent with the finger motion.
- *
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
- * @param maxDistance the maximum distance for this interaction; the maximum animation length
- * gets multiplied by the ratio between the actual distance and this value
- */
- public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
- float velocity, float maxDistance) {
- AnimatorProperties properties = getProperties(currValue, endValue, velocity,
- maxDistance);
- animator.setDuration(properties.duration);
- animator.setInterpolator(properties.interpolator);
- }
-
- private AnimatorProperties getProperties(float currValue,
- float endValue, float velocity, float maxDistance) {
- float maxLengthSeconds = (float) (mMaxLengthSeconds
- * Math.sqrt(Math.abs(endValue - currValue) / maxDistance));
- float diff = Math.abs(endValue - currValue);
- float velAbs = Math.abs(velocity);
- float velocityFactor = mSpeedUpFactor == 0.0f
- ? 1.0f : Math.min(velAbs / HIGH_VELOCITY_DP_PER_SECOND, 1.0f);
- float startGradient = interpolate(LINEAR_OUT_SLOW_IN_START_GRADIENT,
- mY2 / mLinearOutSlowInX2, velocityFactor);
- float durationSeconds = startGradient * diff / velAbs;
- Interpolator slowInInterpolator = getInterpolator(startGradient, velocityFactor);
- if (durationSeconds <= maxLengthSeconds) {
- mAnimatorProperties.interpolator = slowInInterpolator;
- } else if (velAbs >= mMinVelocityPxPerSecond) {
-
- // Cross fade between fast-out-slow-in and linear interpolator with current velocity.
- durationSeconds = maxLengthSeconds;
- VelocityInterpolator velocityInterpolator
- = new VelocityInterpolator(durationSeconds, velAbs, diff);
- InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
- velocityInterpolator, slowInInterpolator, Interpolators.LINEAR_OUT_SLOW_IN);
- mAnimatorProperties.interpolator = superInterpolator;
- } else {
-
- // Just use a normal interpolator which doesn't take the velocity into account.
- durationSeconds = maxLengthSeconds;
- mAnimatorProperties.interpolator = Interpolators.FAST_OUT_SLOW_IN;
- }
- mAnimatorProperties.duration = (long) (durationSeconds * 1000);
- return mAnimatorProperties;
- }
-
- private Interpolator getInterpolator(float startGradient, float velocityFactor) {
- if (startGradient != mCachedStartGradient
- || velocityFactor != mCachedVelocityFactor) {
- float speedup = mSpeedUpFactor * (1.0f - velocityFactor);
- mInterpolator = new PathInterpolator(speedup,
- speedup * startGradient,
- mLinearOutSlowInX2, mY2);
- mCachedStartGradient = startGradient;
- mCachedVelocityFactor = velocityFactor;
- }
- return mInterpolator;
- }
-
- /**
- * Applies the interpolator and length to the animator, such that the fling animation is
- * consistent with the finger motion for the case when the animation is making something
- * disappear.
- *
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
- * @param maxDistance the maximum distance for this interaction; the maximum animation length
- * gets multiplied by the ratio between the actual distance and this value
- */
- public void applyDismissing(Animator animator, float currValue, float endValue,
- float velocity, float maxDistance) {
- AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
- maxDistance);
- animator.setDuration(properties.duration);
- animator.setInterpolator(properties.interpolator);
- }
-
- /**
- * Applies the interpolator and length to the animator, such that the fling animation is
- * consistent with the finger motion for the case when the animation is making something
- * disappear.
- *
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
- * @param maxDistance the maximum distance for this interaction; the maximum animation length
- * gets multiplied by the ratio between the actual distance and this value
- */
- public void applyDismissing(ViewPropertyAnimator animator, float currValue, float endValue,
- float velocity, float maxDistance) {
- AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
- maxDistance);
- animator.setDuration(properties.duration);
- animator.setInterpolator(properties.interpolator);
- }
-
- private AnimatorProperties getDismissingProperties(float currValue, float endValue,
- float velocity, float maxDistance) {
- float maxLengthSeconds = (float) (mMaxLengthSeconds
- * Math.pow(Math.abs(endValue - currValue) / maxDistance, 0.5f));
- float diff = Math.abs(endValue - currValue);
- float velAbs = Math.abs(velocity);
- float y2 = calculateLinearOutFasterInY2(velAbs);
-
- float startGradient = y2 / LINEAR_OUT_FASTER_IN_X2;
- Interpolator mLinearOutFasterIn = new PathInterpolator(0, 0, LINEAR_OUT_FASTER_IN_X2, y2);
- float durationSeconds = startGradient * diff / velAbs;
- if (durationSeconds <= maxLengthSeconds) {
- mAnimatorProperties.interpolator = mLinearOutFasterIn;
- } else if (velAbs >= mMinVelocityPxPerSecond) {
-
- // Cross fade between linear-out-faster-in and linear interpolator with current
- // velocity.
- durationSeconds = maxLengthSeconds;
- VelocityInterpolator velocityInterpolator
- = new VelocityInterpolator(durationSeconds, velAbs, diff);
- InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
- velocityInterpolator, mLinearOutFasterIn, Interpolators.LINEAR_OUT_SLOW_IN);
- mAnimatorProperties.interpolator = superInterpolator;
- } else {
-
- // Just use a normal interpolator which doesn't take the velocity into account.
- durationSeconds = maxLengthSeconds;
- mAnimatorProperties.interpolator = Interpolators.FAST_OUT_LINEAR_IN;
- }
- mAnimatorProperties.duration = (long) (durationSeconds * 1000);
- return mAnimatorProperties;
- }
-
- /**
- * Calculates the y2 control point for a linear-out-faster-in path interpolator depending on the
- * velocity. The faster the velocity, the more "linear" the interpolator gets.
- *
- * @param velocity the velocity of the gesture.
- * @return the y2 control point for a cubic bezier path interpolator
- */
- private float calculateLinearOutFasterInY2(float velocity) {
- float t = (velocity - mMinVelocityPxPerSecond)
- / (mHighVelocityPxPerSecond - mMinVelocityPxPerSecond);
- t = Math.max(0, Math.min(1, t));
- return (1 - t) * LINEAR_OUT_FASTER_IN_Y2_MIN + t * LINEAR_OUT_FASTER_IN_Y2_MAX;
- }
-
- /**
- * @return the minimum velocity a gesture needs to have to be considered a fling
- */
- public float getMinVelocityPxPerSecond() {
- return mMinVelocityPxPerSecond;
- }
-
- /**
- * An interpolator which interpolates two interpolators with an interpolator.
- */
- private static final class InterpolatorInterpolator implements Interpolator {
-
- private Interpolator mInterpolator1;
- private Interpolator mInterpolator2;
- private Interpolator mCrossfader;
-
- InterpolatorInterpolator(Interpolator interpolator1, Interpolator interpolator2,
- Interpolator crossfader) {
- mInterpolator1 = interpolator1;
- mInterpolator2 = interpolator2;
- mCrossfader = crossfader;
- }
-
- @Override
- public float getInterpolation(float input) {
- float t = mCrossfader.getInterpolation(input);
- return (1 - t) * mInterpolator1.getInterpolation(input)
- + t * mInterpolator2.getInterpolation(input);
- }
- }
-
- /**
- * An interpolator which interpolates with a fixed velocity.
- */
- private static final class VelocityInterpolator implements Interpolator {
-
- private float mDurationSeconds;
- private float mVelocity;
- private float mDiff;
-
- private VelocityInterpolator(float durationSeconds, float velocity, float diff) {
- mDurationSeconds = durationSeconds;
- mVelocity = velocity;
- mDiff = diff;
- }
-
- @Override
- public float getInterpolation(float input) {
- float time = input * mDurationSeconds;
- return time * mVelocity / mDiff;
- }
- }
-
- private static class AnimatorProperties {
- Interpolator interpolator;
- long duration;
- }
-
-}
diff --git a/src/com/android/launcher3/notification/NotificationFooterLayout.java b/src/com/android/launcher3/notification/NotificationFooterLayout.java
index b83c9b95d..2455eabea 100644
--- a/src/com/android/launcher3/notification/NotificationFooterLayout.java
+++ b/src/com/android/launcher3/notification/NotificationFooterLayout.java
@@ -206,7 +206,10 @@ public class NotificationFooterLayout extends FrameLayout {
@Override
public void onAnimationEnd(Animator animation) {
((ViewGroup) getParent()).findViewById(R.id.divider).setVisibility(GONE);
- ((ViewGroup) getParent()).removeView(NotificationFooterLayout.this);
+ // Keep view around because gutter is aligned to it, but remove height to
+ // both hide the view and keep calculations correct for last dismissal.
+ getLayoutParams().height = 0;
+ requestLayout();
}
});
collapseFooter.start();
diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java
index 0b08ef835..78c64d7da 100644
--- a/src/com/android/launcher3/notification/NotificationItemView.java
+++ b/src/com/android/launcher3/notification/NotificationItemView.java
@@ -17,6 +17,8 @@
package com.android.launcher3.notification;
import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.app.Notification;
import android.content.Context;
import android.graphics.Rect;
@@ -28,11 +30,14 @@ import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
+import com.android.launcher3.anim.PropertyResetListener;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
import com.android.launcher3.popup.PopupItemView;
+import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.Themes;
@@ -48,10 +53,11 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
private static final Rect sTempRect = new Rect();
+ private TextView mHeaderText;
private TextView mHeaderCount;
private NotificationMainView mMainView;
private NotificationFooterLayout mFooter;
- private SwipeHelper mSwipeHelper;
+ private SwipeDetector mSwipeDetector;
private boolean mAnimatingNextIcon;
private int mNotificationHeaderTextColor = Notification.COLOR_DEFAULT;
@@ -70,11 +76,14 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mHeaderCount = (TextView) findViewById(R.id.notification_count);
- mMainView = (NotificationMainView) findViewById(R.id.main_view);
- mFooter = (NotificationFooterLayout) findViewById(R.id.footer);
- mSwipeHelper = new SwipeHelper(SwipeHelper.X, mMainView, getContext());
- mSwipeHelper.setDisableHardwareLayers(true);
+ mHeaderText = findViewById(R.id.notification_text);
+ mHeaderCount = findViewById(R.id.notification_count);
+ mMainView = findViewById(R.id.main_view);
+ mFooter = findViewById(R.id.footer);
+
+ mSwipeDetector = new SwipeDetector(getContext(), mMainView, SwipeDetector.HORIZONTAL);
+ mSwipeDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false);
+ mMainView.setSwipeDetector(mSwipeDetector);
}
public NotificationMainView getMainView() {
@@ -87,6 +96,8 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
}
public Animator animateHeightRemoval(int heightToRemove, boolean shouldRemoveFromTop) {
+ AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
+
Rect startRect = new Rect(mPillRect);
Rect endRect = new Rect(mPillRect);
if (shouldRemoveFromTop) {
@@ -94,8 +105,18 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
} else {
endRect.bottom -= heightToRemove;
}
- return new RoundedRectRevealOutlineProvider(getBackgroundRadius(), getBackgroundRadius(),
- startRect, endRect, mRoundedCorners).createRevealAnimator(this, false);
+ anim.play(new RoundedRectRevealOutlineProvider(getBackgroundRadius(), getBackgroundRadius(),
+ startRect, endRect, mRoundedCorners).createRevealAnimator(this, false));
+
+ View bottomGutter = findViewById(R.id.gutter_bottom);
+ if (bottomGutter != null && bottomGutter.getVisibility() == VISIBLE) {
+ Animator translateGutter = ObjectAnimator.ofFloat(bottomGutter, TRANSLATION_Y,
+ -heightToRemove);
+ translateGutter.addListener(new PropertyResetListener<>(TRANSLATION_Y, 0f));
+ anim.play(translateGutter);
+ }
+
+ return anim;
}
public void updateHeader(int notificationCount, @Nullable IconPalette palette) {
@@ -106,6 +127,7 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
IconPalette.resolveContrastColor(getContext(), palette.dominantColor,
Themes.getAttrColor(getContext(), R.attr.popupColorPrimary));
}
+ mHeaderText.setTextColor(mNotificationHeaderTextColor);
mHeaderCount.setTextColor(mNotificationHeaderTextColor);
}
}
@@ -117,7 +139,8 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
return false;
}
getParent().requestDisallowInterceptTouchEvent(true);
- return mSwipeHelper.onInterceptTouchEvent(ev);
+ mSwipeDetector.onTouchEvent(ev);
+ return mSwipeDetector.isDraggingOrSettling();
}
@Override
@@ -126,7 +149,7 @@ public class NotificationItemView extends PopupItemView implements LogContainerP
// The notification hasn't been populated yet.
return false;
}
- return mSwipeHelper.onTouchEvent(ev) || super.onTouchEvent(ev);
+ return mSwipeDetector.onTouchEvent(ev) || super.onTouchEvent(ev);
}
public void applyNotificationInfos(final List<NotificationInfo> notificationInfos) {
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index baaa66aea..73d89aa18 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -28,6 +28,7 @@ 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.config.FeatureFlags;
@@ -47,6 +48,8 @@ import java.util.Set;
@TargetApi(Build.VERSION_CODES.O)
public class NotificationListener extends NotificationListenerService {
+ public static final String TAG = "NotificationListener";
+
private static final int MSG_NOTIFICATION_POSTED = 1;
private static final int MSG_NOTIFICATION_REMOVED = 2;
private static final int MSG_NOTIFICATION_FULL_REFRESH = 3;
@@ -71,9 +74,19 @@ public class NotificationListener extends NotificationListenerService {
mUiHandler.obtainMessage(message.what, message.obj).sendToTarget();
break;
case MSG_NOTIFICATION_FULL_REFRESH:
- final List<StatusBarNotification> activeNotifications = sIsConnected
- ? filterNotifications(getActiveNotifications())
- : new ArrayList<StatusBarNotification>();
+ List<StatusBarNotification> activeNotifications;
+ if (sIsConnected) {
+ try {
+ activeNotifications = filterNotifications(getActiveNotifications());
+ } catch (SecurityException ex) {
+ Log.e(TAG, "SecurityException: failed to fetch notifications");
+ activeNotifications = new ArrayList<StatusBarNotification>();
+
+ }
+ } else {
+ activeNotifications = new ArrayList<StatusBarNotification>();
+ }
+
mUiHandler.obtainMessage(message.what, activeNotifications).sendToTarget();
break;
}
@@ -127,8 +140,9 @@ public class NotificationListener extends NotificationListenerService {
}
sNotificationsChangedListener = listener;
- if (sNotificationListenerInstance != null) {
- sNotificationListenerInstance.onNotificationFullRefresh();
+ NotificationListener notificationListener = getInstanceIfConnected();
+ if (notificationListener != null) {
+ notificationListener.onNotificationFullRefresh();
}
}
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java
index 9b8dd648f..5aff28db4 100644
--- a/src/com/android/launcher3/notification/NotificationMainView.java
+++ b/src/com/android/launcher3/notification/NotificationMainView.java
@@ -23,15 +23,17 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.RippleDrawable;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
+import com.android.launcher3.touch.OverScroll;
+import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.Themes;
@@ -39,7 +41,7 @@ import com.android.launcher3.util.Themes;
* A {@link android.widget.FrameLayout} that contains a single notification,
* e.g. icon + title + text.
*/
-public class NotificationMainView extends FrameLayout implements SwipeHelper.Callback {
+public class NotificationMainView extends FrameLayout implements SwipeDetector.Listener {
private NotificationInfo mNotificationInfo;
private ViewGroup mTextAndBackground;
@@ -47,6 +49,8 @@ public class NotificationMainView extends FrameLayout implements SwipeHelper.Cal
private TextView mTitleView;
private TextView mTextView;
+ private SwipeDetector mSwipeDetector;
+
public NotificationMainView(Context context) {
this(context, null, 0);
}
@@ -78,6 +82,10 @@ public class NotificationMainView extends FrameLayout implements SwipeHelper.Cal
applyNotificationInfo(mainNotification, iconView, false);
}
+ public void setSwipeDetector(SwipeDetector swipeDetector) {
+ mSwipeDetector = swipeDetector;
+ }
+
/**
* Sets the content of this view, animating it after a new icon shifts up if necessary.
*/
@@ -113,29 +121,11 @@ public class NotificationMainView extends FrameLayout implements SwipeHelper.Cal
}
- // SwipeHelper.Callback's
-
- @Override
- public View getChildAtPosition(MotionEvent ev) {
- return this;
- }
-
- @Override
- public boolean canChildBeDismissed(View v) {
+ public boolean canChildBeDismissed() {
return mNotificationInfo != null && mNotificationInfo.dismissable;
}
- @Override
- public boolean isAntiFalsingNeeded() {
- return false;
- }
-
- @Override
- public void onBeginDrag(View v) {
- }
-
- @Override
- public void onChildDismissed(View v) {
+ public void onChildDismissed() {
Launcher launcher = Launcher.getLauncher(getContext());
launcher.getPopupDataProvider().cancelNotification(
mNotificationInfo.notificationKey);
@@ -145,22 +135,55 @@ public class NotificationMainView extends FrameLayout implements SwipeHelper.Cal
LauncherLogProto.ItemType.NOTIFICATION);
}
+ // SwipeDetector.Listener's
@Override
- public void onDragCancelled(View v) {
- }
+ public void onDragStart(boolean start) { }
- @Override
- public void onChildSnappedBack(View animView, float targetLeft) {
- }
@Override
- public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
- // Don't fade out.
+ public boolean onDrag(float displacement, float velocity) {
+ setTranslationX(canChildBeDismissed()
+ ? displacement : OverScroll.dampedScroll(displacement, getWidth()));
+ animate().cancel();
return true;
}
@Override
- public float getFalsingThresholdFactor() {
- return 1;
+ public void onDragEnd(float velocity, boolean fling) {
+ final boolean willExit;
+ final float endTranslation;
+
+ if (!canChildBeDismissed()) {
+ willExit = false;
+ endTranslation = 0;
+ } else if (fling) {
+ willExit = true;
+ endTranslation = velocity < 0 ? - getWidth() : getWidth();
+ } else if (Math.abs(getTranslationX()) > getWidth() / 2) {
+ willExit = true;
+ endTranslation = (getTranslationX() < 0 ? -getWidth() : getWidth());
+ } else {
+ willExit = false;
+ endTranslation = 0;
+ }
+
+ SwipeDetector.ScrollInterpolator interpolator = new SwipeDetector.ScrollInterpolator();
+ interpolator.setVelocityAtZero(velocity);
+
+ long duration = SwipeDetector.calculateDuration(velocity,
+ (endTranslation - getTranslationX()) / getWidth());
+ animate()
+ .setDuration(duration)
+ .setInterpolator(interpolator)
+ .translationX(endTranslation)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ mSwipeDetector.finishedScrolling();
+ if (willExit) {
+ onChildDismissed();
+ }
+ }
+ }).start();
}
}
diff --git a/src/com/android/launcher3/notification/SwipeHelper.java b/src/com/android/launcher3/notification/SwipeHelper.java
deleted file mode 100644
index ebbe5fc6a..000000000
--- a/src/com/android/launcher3/notification/SwipeHelper.java
+++ /dev/null
@@ -1,687 +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.notification;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.graphics.RectF;
-import android.os.Handler;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.accessibility.AccessibilityEvent;
-import com.android.launcher3.R;
-
-/**
- * This class was copied from com.android.systemui.
- */
-public class SwipeHelper {
- private static final String TAG = "SwipeHelper";
- private static final boolean DEBUG_INVALIDATE = false;
- private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
- private static final boolean CONSTRAIN_SWIPE = true;
- private static final boolean FADE_OUT_DURING_SWIPE = true;
- private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
-
- public static final int X = 0;
- public static final int Y = 1;
-
- private static final float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
- private static final int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
- private static final int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
- private static final int MAX_DISMISS_VELOCITY = 4000; // dp/sec
- private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
-
- static final float SWIPE_PROGRESS_FADE_END = 0.5f; // fraction of thumbnail width
- // beyond which swipe progress->0
- private float mMinSwipeProgress = 0f;
- private float mMaxSwipeProgress = 1f;
-
- private final FlingAnimationUtils mFlingAnimationUtils;
- private float mPagingTouchSlop;
- private final Callback mCallback;
- private final Handler mHandler;
- private final int mSwipeDirection;
- private final VelocityTracker mVelocityTracker;
-
- private float mInitialTouchPos;
- private float mPerpendicularInitialTouchPos;
- private boolean mDragging;
- private boolean mSnappingChild;
- private View mCurrView;
- private boolean mCanCurrViewBeDimissed;
- private float mDensityScale;
- private float mTranslation = 0;
-
- private boolean mLongPressSent;
- private LongPressListener mLongPressListener;
- private Runnable mWatchLongPress;
- private final long mLongPressTimeout;
-
- final private int[] mTmpPos = new int[2];
- private final int mFalsingThreshold;
- private boolean mTouchAboveFalsingThreshold;
- private boolean mDisableHwLayers;
-
- private final ArrayMap<View, Animator> mDismissPendingMap = new ArrayMap<>();
-
- public SwipeHelper(int swipeDirection, Callback callback, Context context) {
- mCallback = callback;
- mHandler = new Handler();
- mSwipeDirection = swipeDirection;
- mVelocityTracker = VelocityTracker.obtain();
- mDensityScale = context.getResources().getDisplayMetrics().density;
- mPagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
-
- mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); // extra long-press!
- mFalsingThreshold = context.getResources().getDimensionPixelSize(
- R.dimen.swipe_helper_falsing_threshold);
- mFlingAnimationUtils = new FlingAnimationUtils(context, getMaxEscapeAnimDuration() / 1000f);
- }
-
- public void setLongPressListener(LongPressListener listener) {
- mLongPressListener = listener;
- }
-
- public void setDensityScale(float densityScale) {
- mDensityScale = densityScale;
- }
-
- public void setPagingTouchSlop(float pagingTouchSlop) {
- mPagingTouchSlop = pagingTouchSlop;
- }
-
- public void setDisableHardwareLayers(boolean disableHwLayers) {
- mDisableHwLayers = disableHwLayers;
- }
-
- private float getPos(MotionEvent ev) {
- return mSwipeDirection == X ? ev.getX() : ev.getY();
- }
-
- private float getPerpendicularPos(MotionEvent ev) {
- return mSwipeDirection == X ? ev.getY() : ev.getX();
- }
-
- protected float getTranslation(View v) {
- return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
- }
-
- private float getVelocity(VelocityTracker vt) {
- return mSwipeDirection == X ? vt.getXVelocity() :
- vt.getYVelocity();
- }
-
- protected ObjectAnimator createTranslationAnimation(View v, float newPos) {
- ObjectAnimator anim = ObjectAnimator.ofFloat(v,
- mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos);
- return anim;
- }
-
- private float getPerpendicularVelocity(VelocityTracker vt) {
- return mSwipeDirection == X ? vt.getYVelocity() :
- vt.getXVelocity();
- }
-
- protected Animator getViewTranslationAnimator(View v, float target,
- AnimatorUpdateListener listener) {
- ObjectAnimator anim = createTranslationAnimation(v, target);
- if (listener != null) {
- anim.addUpdateListener(listener);
- }
- return anim;
- }
-
- protected void setTranslation(View v, float translate) {
- if (v == null) {
- return;
- }
- if (mSwipeDirection == X) {
- v.setTranslationX(translate);
- } else {
- v.setTranslationY(translate);
- }
- }
-
- protected float getSize(View v) {
- return mSwipeDirection == X ? v.getMeasuredWidth() :
- v.getMeasuredHeight();
- }
-
- public void setMinSwipeProgress(float minSwipeProgress) {
- mMinSwipeProgress = minSwipeProgress;
- }
-
- public void setMaxSwipeProgress(float maxSwipeProgress) {
- mMaxSwipeProgress = maxSwipeProgress;
- }
-
- private float getSwipeProgressForOffset(View view, float translation) {
- float viewSize = getSize(view);
- float result = Math.abs(translation / viewSize);
- return Math.min(Math.max(mMinSwipeProgress, result), mMaxSwipeProgress);
- }
-
- private float getSwipeAlpha(float progress) {
- return Math.min(0, Math.max(1, progress / SWIPE_PROGRESS_FADE_END));
- }
-
- private void updateSwipeProgressFromOffset(View animView, boolean dismissable) {
- updateSwipeProgressFromOffset(animView, dismissable, getTranslation(animView));
- }
-
- private void updateSwipeProgressFromOffset(View animView, boolean dismissable,
- float translation) {
- float swipeProgress = getSwipeProgressForOffset(animView, translation);
- if (!mCallback.updateSwipeProgress(animView, dismissable, swipeProgress)) {
- if (FADE_OUT_DURING_SWIPE && dismissable) {
- float alpha = swipeProgress;
- if (!mDisableHwLayers) {
- if (alpha != 0f && alpha != 1f) {
- animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- } else {
- animView.setLayerType(View.LAYER_TYPE_NONE, null);
- }
- }
- animView.setAlpha(getSwipeAlpha(swipeProgress));
- }
- }
- invalidateGlobalRegion(animView);
- }
-
- // invalidate the view's own bounds all the way up the view hierarchy
- public static void invalidateGlobalRegion(View view) {
- invalidateGlobalRegion(
- view,
- new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
- }
-
- // invalidate a rectangle relative to the view's coordinate system all the way up the view
- // hierarchy
- public static void invalidateGlobalRegion(View view, RectF childBounds) {
- //childBounds.offset(view.getTranslationX(), view.getTranslationY());
- if (DEBUG_INVALIDATE)
- Log.v(TAG, "-------------");
- while (view.getParent() != null && view.getParent() instanceof View) {
- view = (View) view.getParent();
- view.getMatrix().mapRect(childBounds);
- view.invalidate((int) Math.floor(childBounds.left),
- (int) Math.floor(childBounds.top),
- (int) Math.ceil(childBounds.right),
- (int) Math.ceil(childBounds.bottom));
- if (DEBUG_INVALIDATE) {
- Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left)
- + "," + (int) Math.floor(childBounds.top)
- + "," + (int) Math.ceil(childBounds.right)
- + "," + (int) Math.ceil(childBounds.bottom));
- }
- }
- }
-
- public void removeLongPressCallback() {
- if (mWatchLongPress != null) {
- mHandler.removeCallbacks(mWatchLongPress);
- mWatchLongPress = null;
- }
- }
-
- public boolean onInterceptTouchEvent(final MotionEvent ev) {
- final int action = ev.getAction();
-
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- mTouchAboveFalsingThreshold = false;
- mDragging = false;
- mSnappingChild = false;
- mLongPressSent = false;
- mVelocityTracker.clear();
- mCurrView = mCallback.getChildAtPosition(ev);
-
- if (mCurrView != null) {
- onDownUpdate(mCurrView);
- mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
- mVelocityTracker.addMovement(ev);
- mInitialTouchPos = getPos(ev);
- mPerpendicularInitialTouchPos = getPerpendicularPos(ev);
- mTranslation = getTranslation(mCurrView);
- if (mLongPressListener != null) {
- if (mWatchLongPress == null) {
- mWatchLongPress = new Runnable() {
- @Override
- public void run() {
- if (mCurrView != null && !mLongPressSent) {
- mLongPressSent = true;
- mCurrView.sendAccessibilityEvent(
- AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
- mCurrView.getLocationOnScreen(mTmpPos);
- final int x = (int) ev.getRawX() - mTmpPos[0];
- final int y = (int) ev.getRawY() - mTmpPos[1];
- mLongPressListener.onLongPress(mCurrView, x, y);
- }
- }
- };
- }
- mHandler.postDelayed(mWatchLongPress, mLongPressTimeout);
- }
- }
- break;
-
- case MotionEvent.ACTION_MOVE:
- if (mCurrView != null && !mLongPressSent) {
- mVelocityTracker.addMovement(ev);
- float pos = getPos(ev);
- float perpendicularPos = getPerpendicularPos(ev);
- float delta = pos - mInitialTouchPos;
- float deltaPerpendicular = perpendicularPos - mPerpendicularInitialTouchPos;
- if (Math.abs(delta) > mPagingTouchSlop
- && Math.abs(delta) > Math.abs(deltaPerpendicular)) {
- mCallback.onBeginDrag(mCurrView);
- mDragging = true;
- mInitialTouchPos = getPos(ev);
- mTranslation = getTranslation(mCurrView);
- removeLongPressCallback();
- }
- }
- break;
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- final boolean captured = (mDragging || mLongPressSent);
- mDragging = false;
- mCurrView = null;
- mLongPressSent = false;
- removeLongPressCallback();
- if (captured) return true;
- break;
- }
- return mDragging || mLongPressSent;
- }
-
- /**
- * @param view The view to be dismissed
- * @param velocity The desired pixels/second speed at which the view should move
- * @param useAccelerateInterpolator Should an accelerating Interpolator be used
- */
- public void dismissChild(final View view, float velocity, boolean useAccelerateInterpolator) {
- dismissChild(view, velocity, null /* endAction */, 0 /* delay */,
- useAccelerateInterpolator, 0 /* fixedDuration */, false /* isDismissAll */);
- }
-
- /**
- * @param animView The view to be dismissed
- * @param velocity The desired pixels/second speed at which the view should move
- * @param endAction The action to perform at the end
- * @param delay The delay after which we should start
- * @param useAccelerateInterpolator Should an accelerating Interpolator be used
- * @param fixedDuration If not 0, this exact duration will be taken
- */
- public void dismissChild(final View animView, float velocity, final Runnable endAction,
- long delay, boolean useAccelerateInterpolator, long fixedDuration,
- boolean isDismissAll) {
- final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
- float newPos;
- boolean isLayoutRtl = animView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-
- // if we use the Menu to dismiss an item in landscape, animate up
- boolean animateUpForMenu = velocity == 0 && (getTranslation(animView) == 0 || isDismissAll)
- && mSwipeDirection == Y;
- // if the language is rtl we prefer swiping to the left
- boolean animateLeftForRtl = velocity == 0 && (getTranslation(animView) == 0 || isDismissAll)
- && isLayoutRtl;
- boolean animateLeft = velocity < 0
- || (velocity == 0 && getTranslation(animView) < 0 && !isDismissAll);
-
- if (animateLeft || animateLeftForRtl || animateUpForMenu) {
- newPos = -getSize(animView);
- } else {
- newPos = getSize(animView);
- }
- long duration;
- if (fixedDuration == 0) {
- duration = MAX_ESCAPE_ANIMATION_DURATION;
- if (velocity != 0) {
- duration = Math.min(duration,
- (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math
- .abs(velocity))
- );
- } else {
- duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
- }
- } else {
- duration = fixedDuration;
- }
-
- if (!mDisableHwLayers) {
- animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- }
- AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
- }
- };
-
- Animator anim = getViewTranslationAnimator(animView, newPos, updateListener);
- if (anim == null) {
- return;
- }
- if (useAccelerateInterpolator) {
- anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
- anim.setDuration(duration);
- } else {
- mFlingAnimationUtils.applyDismissing(anim, getTranslation(animView),
- newPos, velocity, getSize(animView));
- }
- if (delay > 0) {
- anim.setStartDelay(delay);
- }
- anim.addListener(new AnimatorListenerAdapter() {
- private boolean mCancelled;
-
- public void onAnimationCancel(Animator animation) {
- mCancelled = true;
- }
-
- public void onAnimationEnd(Animator animation) {
- updateSwipeProgressFromOffset(animView, canBeDismissed);
- mDismissPendingMap.remove(animView);
- if (!mCancelled) {
- mCallback.onChildDismissed(animView);
- }
- if (endAction != null) {
- endAction.run();
- }
- if (!mDisableHwLayers) {
- animView.setLayerType(View.LAYER_TYPE_NONE, null);
- }
- }
- });
-
- prepareDismissAnimation(animView, anim);
- mDismissPendingMap.put(animView, anim);
- anim.start();
- }
-
- /**
- * Called to update the dismiss animation.
- */
- protected void prepareDismissAnimation(View view, Animator anim) {
- // Do nothing
- }
-
- public void snapChild(final View animView, final float targetLeft, float velocity) {
- final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
- AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
- }
- };
-
- Animator anim = getViewTranslationAnimator(animView, targetLeft, updateListener);
- if (anim == null) {
- return;
- }
- int duration = SNAP_ANIM_LEN;
- anim.setDuration(duration);
- anim.addListener(new AnimatorListenerAdapter() {
- public void onAnimationEnd(Animator animator) {
- mSnappingChild = false;
- updateSwipeProgressFromOffset(animView, canBeDismissed);
- mCallback.onChildSnappedBack(animView, targetLeft);
- }
- });
- prepareSnapBackAnimation(animView, anim);
- mSnappingChild = true;
- anim.start();
- }
-
- /**
- * Called to update the snap back animation.
- */
- protected void prepareSnapBackAnimation(View view, Animator anim) {
- // Do nothing
- }
-
- /**
- * Called when there's a down event.
- */
- public void onDownUpdate(View currView) {
- // Do nothing
- }
-
- /**
- * Called on a move event.
- */
- protected void onMoveUpdate(View view, float totalTranslation, float delta) {
- // Do nothing
- }
-
- /**
- * Called in {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)} when the current
- * view is being animated to dismiss or snap.
- */
- public void onTranslationUpdate(View animView, float value, boolean canBeDismissed) {
- updateSwipeProgressFromOffset(animView, canBeDismissed, value);
- }
-
- private void snapChildInstantly(final View view) {
- final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
- setTranslation(view, 0);
- updateSwipeProgressFromOffset(view, canAnimViewBeDismissed);
- }
-
- /**
- * Called when a view is updated to be non-dismissable, if the view was being dismissed before
- * the update this will handle snapping it back into place.
- *
- * @param view the view to snap if necessary.
- * @param animate whether to animate the snap or not.
- * @param targetLeft the target to snap to.
- */
- public void snapChildIfNeeded(final View view, boolean animate, float targetLeft) {
- if ((mDragging && mCurrView == view) || mSnappingChild) {
- return;
- }
- boolean needToSnap = false;
- Animator dismissPendingAnim = mDismissPendingMap.get(view);
- if (dismissPendingAnim != null) {
- needToSnap = true;
- dismissPendingAnim.cancel();
- } else if (getTranslation(view) != 0) {
- needToSnap = true;
- }
- if (needToSnap) {
- if (animate) {
- snapChild(view, targetLeft, 0.0f /* velocity */);
- } else {
- snapChildInstantly(view);
- }
- }
- }
-
- public boolean onTouchEvent(MotionEvent ev) {
- if (mLongPressSent) {
- return true;
- }
-
- if (!mDragging) {
- if (mCallback.getChildAtPosition(ev) != null) {
-
- // We are dragging directly over a card, make sure that we also catch the gesture
- // even if nobody else wants the touch event.
- onInterceptTouchEvent(ev);
- return true;
- } else {
-
- // We are not doing anything, make sure the long press callback
- // is not still ticking like a bomb waiting to go off.
- removeLongPressCallback();
- return false;
- }
- }
-
- mVelocityTracker.addMovement(ev);
- final int action = ev.getAction();
- switch (action) {
- case MotionEvent.ACTION_OUTSIDE:
- case MotionEvent.ACTION_MOVE:
- if (mCurrView != null) {
- float delta = getPos(ev) - mInitialTouchPos;
- float absDelta = Math.abs(delta);
- if (absDelta >= getFalsingThreshold()) {
- mTouchAboveFalsingThreshold = true;
- }
- // don't let items that can't be dismissed be dragged more than
- // maxScrollDistance
- if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) {
- float size = getSize(mCurrView);
- float maxScrollDistance = 0.25f * size;
- if (absDelta >= size) {
- delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
- } else {
- delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2));
- }
- }
-
- setTranslation(mCurrView, mTranslation + delta);
- updateSwipeProgressFromOffset(mCurrView, mCanCurrViewBeDimissed);
- onMoveUpdate(mCurrView, mTranslation + delta, delta);
- }
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- if (mCurrView == null) {
- break;
- }
- mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, getMaxVelocity());
- float velocity = getVelocity(mVelocityTracker);
-
- if (!handleUpEvent(ev, mCurrView, velocity, getTranslation(mCurrView))) {
- if (isDismissGesture(ev)) {
- // flingadingy
- dismissChild(mCurrView, velocity,
- !swipedFastEnough() /* useAccelerateInterpolator */);
- } else {
- // snappity
- mCallback.onDragCancelled(mCurrView);
- snapChild(mCurrView, 0 /* leftTarget */, velocity);
- }
- mCurrView = null;
- }
- mDragging = false;
- break;
- }
- return true;
- }
-
- private int getFalsingThreshold() {
- float factor = mCallback.getFalsingThresholdFactor();
- return (int) (mFalsingThreshold * factor);
- }
-
- private float getMaxVelocity() {
- return MAX_DISMISS_VELOCITY * mDensityScale;
- }
-
- protected float getEscapeVelocity() {
- return getUnscaledEscapeVelocity() * mDensityScale;
- }
-
- protected float getUnscaledEscapeVelocity() {
- return SWIPE_ESCAPE_VELOCITY;
- }
-
- protected long getMaxEscapeAnimDuration() {
- return MAX_ESCAPE_ANIMATION_DURATION;
- }
-
- protected boolean swipedFarEnough() {
- float translation = getTranslation(mCurrView);
- return DISMISS_IF_SWIPED_FAR_ENOUGH && Math.abs(translation) > 0.4 * getSize(mCurrView);
- }
-
- protected boolean isDismissGesture(MotionEvent ev) {
- boolean falsingDetected = mCallback.isAntiFalsingNeeded() && !mTouchAboveFalsingThreshold;
- return !falsingDetected && (swipedFastEnough() || swipedFarEnough())
- && ev.getActionMasked() == MotionEvent.ACTION_UP
- && mCallback.canChildBeDismissed(mCurrView);
- }
-
- protected boolean swipedFastEnough() {
- float velocity = getVelocity(mVelocityTracker);
- float translation = getTranslation(mCurrView);
- boolean ret = (Math.abs(velocity) > getEscapeVelocity())
- && (velocity > 0) == (translation > 0);
- return ret;
- }
-
- protected boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
- float translation) {
- return false;
- }
-
- public interface Callback {
- View getChildAtPosition(MotionEvent ev);
-
- boolean canChildBeDismissed(View v);
-
- boolean isAntiFalsingNeeded();
-
- void onBeginDrag(View v);
-
- void onChildDismissed(View v);
-
- void onDragCancelled(View v);
-
- /**
- * Called when the child is snapped to a position.
- *
- * @param animView the view that was snapped.
- * @param targetLeft the left position the view was snapped to.
- */
- void onChildSnappedBack(View animView, float targetLeft);
-
- /**
- * Updates the swipe progress on a child.
- *
- * @return if true, prevents the default alpha fading.
- */
- boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress);
-
- /**
- * @return The factor the falsing threshold should be multiplied with
- */
- float getFalsingThresholdFactor();
- }
-
- /**
- * Equivalent to View.OnLongClickListener with coordinates
- */
- public interface LongPressListener {
- /**
- * Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
- * @return whether the longpress was handled
- */
- boolean onLongPress(View v, int x, int y);
- }
-} \ No newline at end of file
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
index 8bcb9794a..682d5a967 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
@@ -57,7 +57,7 @@ public class PageIndicatorCaretLandscape extends PageIndicator {
protected void onDraw(Canvas canvas) {
Rect drawableBounds = getCaretDrawable().getBounds();
int count = canvas.save();
- canvas.translate(getWidth() - drawableBounds.width(),
+ canvas.translate((getWidth() - drawableBounds.width()) / 2,
getHeight() - drawableBounds.height());
getCaretDrawable().draw(canvas);
canvas.restoreToCount(count);
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
index 6b992fc22..29834d764 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
@@ -21,7 +21,9 @@ import android.widget.ImageView;
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.dynamicui.ExtractedColors;
+import com.android.launcher3.dynamicui.WallpaperColorInfo;
/**
* A PageIndicator that briefly shows a fraction of a line when moving between pages.
@@ -128,6 +130,10 @@ public class PageIndicatorLineCaret extends PageIndicator {
mLauncher = Launcher.getLauncher(context);
mLineHeight = res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_line_height);
setCaretDrawable(new CaretDrawable(context));
+
+ boolean darkText = WallpaperColorInfo.getInstance(context).supportsDarkText();
+ mActiveAlpha = darkText ? BLACK_ALPHA : WHITE_ALPHA;
+ mLinePaint.setColor(darkText ? Color.BLACK : Color.WHITE);
}
@Override
@@ -219,6 +225,9 @@ public class PageIndicatorLineCaret extends PageIndicator {
* - mostly opaque black if the hotseat is black (ignoring alpha)
*/
public void updateColor(ExtractedColors extractedColors) {
+ if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+ return;
+ }
int originalLineAlpha = mLinePaint.getAlpha();
int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX);
if (color != Color.TRANSPARENT) {
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 77375fa48..c3e2d8b89 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -20,6 +20,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
@@ -43,7 +44,6 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AccelerateDecelerateInterpolator;
-import android.widget.FrameLayout;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
@@ -53,7 +53,6 @@ import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherModel;
-import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
@@ -118,6 +117,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
private boolean mIsLeftAligned;
protected boolean mIsAboveIcon;
private View mArrow;
+ private int mGravity;
protected Animator mOpenCloseAnimator;
private boolean mDeferContainerRemoval;
@@ -285,9 +285,11 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
int roundedCorners = ROUNDED_TOP_CORNERS | ROUNDED_BOTTOM_CORNERS;
if (shouldUnroundTopCorners) {
roundedCorners &= ~ROUNDED_TOP_CORNERS;
+ mNotificationItemView.findViewById(R.id.gutter_top).setVisibility(VISIBLE);
}
if (shouldUnroundBottomCorners) {
roundedCorners &= ~ROUNDED_BOTTOM_CORNERS;
+ mNotificationItemView.findViewById(R.id.gutter_bottom).setVisibility(VISIBLE);
}
int backgroundColor = Themes.getAttrColor(mLauncher, R.attr.popupColorTertiary);
mNotificationItemView.setBackgroundWithCorners(backgroundColor, roundedCorners);
@@ -308,9 +310,15 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
}
if (itemTypeToPopulate != PopupPopulator.Item.SYSTEM_SHORTCUT_ICON
&& numNotifications > 0) {
+ int prevHeight = item.getLayoutParams().height;
// Condense shortcuts height when there are notifications.
item.getLayoutParams().height = res.getDimensionPixelSize(
R.dimen.bg_popup_item_condensed_height);
+ if (item instanceof DeepShortcutView) {
+ float iconScale = (float) item.getLayoutParams().height / prevHeight;
+ ((DeepShortcutView) item).getIconView().setScaleX(iconScale);
+ ((DeepShortcutView) item).getIconView().setScaleY(iconScale);
+ }
}
mShortcutsItemView.addShortcutView(item, itemTypeToPopulate);
if (shouldUnroundBottomCorners) {
@@ -320,8 +328,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
addView(item);
}
}
- int backgroundColor = Themes.getAttrColor(mLauncher, mNotificationItemView == null
- ? R.attr.popupColorPrimary : R.attr.popupColorSecondary);
+ int backgroundColor = Themes.getAttrColor(mLauncher, R.attr.popupColorPrimary);
mShortcutsItemView.setBackgroundWithCorners(backgroundColor, shortcutsItemRoundedCorners);
if (numNotifications > 0) {
mShortcutsItemView.hideShortcuts(mIsAboveIcon, MAX_SHORTCUTS_IF_NOTIFICATIONS);
@@ -347,6 +354,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet();
final Resources res = getResources();
+ final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration);
+ final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
// Rectangular reveal.
int itemsTotalHeight = 0;
@@ -360,8 +369,13 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
mEndRect.set(0, top, getMeasuredWidth(), top + itemsTotalHeight);
final ValueAnimator revealAnim = new RoundedRectRevealOutlineProvider
(radius, radius, mStartRect, mEndRect).createRevealAnimator(this, false);
- revealAnim.setDuration((long) res.getInteger(R.integer.config_popupOpenCloseDuration));
- revealAnim.setInterpolator(new AccelerateDecelerateInterpolator());
+ revealAnim.setDuration(revealDuration);
+ revealAnim.setInterpolator(revealInterpolator);
+
+ Animator fadeIn = ObjectAnimator.ofFloat(this, ALPHA, 0, 1);
+ fadeIn.setDuration(revealDuration);
+ fadeIn.setInterpolator(revealInterpolator);
+ openAnim.play(fadeIn);
// Animate the arrow.
mArrow.setScaleX(0);
@@ -385,6 +399,29 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
openAnim.start();
}
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ enforceContainedWithinScreen(l, r);
+
+ }
+
+ private void enforceContainedWithinScreen(int left, int right) {
+ DragLayer dragLayer = mLauncher.getDragLayer();
+ if (getTranslationX() + left < 0 ||
+ getTranslationX() + right > dragLayer.getWidth()) {
+ // If we are still off screen, center horizontally too.
+ mGravity |= Gravity.CENTER_HORIZONTAL;
+ }
+
+ if (Gravity.isHorizontal(mGravity)) {
+ setX(dragLayer.getWidth() / 2 - getMeasuredWidth() / 2);
+ }
+ if (Gravity.isVertical(mGravity)) {
+ setY(dragLayer.getHeight() / 2 - getMeasuredHeight() / 2);
+ }
+ }
+
/**
* Returns the point at which the center of the arrow merges with the first popup item.
*/
@@ -476,9 +513,10 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
}
y -= insets.top;
- if (y < dragLayer.getTop() || y + height > dragLayer.getBottom()) {
+ mGravity = 0;
+ if (y + height > dragLayer.getBottom() - insets.bottom) {
// The container is opening off the screen, so just center it in the drag layer instead.
- ((FrameLayout.LayoutParams) getLayoutParams()).gravity = Gravity.CENTER_VERTICAL;
+ mGravity = Gravity.CENTER_VERTICAL;
// Put the container next to the icon, preferring the right side in ltr (left in rtl).
int rightSide = leftAlignedX + iconWidth - insets.left;
int leftSide = rightAlignedX - iconWidth - insets.left;
@@ -502,18 +540,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
mIsAboveIcon = true;
}
- if (x < dragLayer.getLeft() || x + width > dragLayer.getRight()) {
- // If we are still off screen, center horizontally too.
- ((FrameLayout.LayoutParams) getLayoutParams()).gravity |= Gravity.CENTER_HORIZONTAL;
- }
-
- int gravity = ((FrameLayout.LayoutParams) getLayoutParams()).gravity;
- if (!Gravity.isHorizontal(gravity)) {
- setX(x);
- }
- if (!Gravity.isVertical(gravity)) {
- setY(y);
- }
+ setX(x);
+ setY(y);
}
private boolean isAlignedWithStart() {
@@ -541,7 +569,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
}
View arrowView = new View(getContext());
- if (Gravity.isVertical(((FrameLayout.LayoutParams) getLayoutParams()).gravity)) {
+ if (Gravity.isVertical(mGravity)) {
// This is only true if there wasn't room for the container next to the icon,
// so we centered it instead. In that case we don't want to show the arrow.
arrowView.setVisibility(INVISIBLE);
@@ -845,10 +873,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet();
final Resources res = getResources();
-
- // Animate the arrow.
- Animator arrowScale = createArrowScaleAnim(0).setDuration(res.getInteger(
- R.integer.config_popupArrowOpenDuration));
+ final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration);
+ final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
// Rectangular reveal (reversed).
int itemsTotalHeight = 0;
@@ -864,11 +890,19 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
}
final ValueAnimator revealAnim = new RoundedRectRevealOutlineProvider(
radius, radius, mStartRect, mEndRect).createRevealAnimator(this, true);
- revealAnim.setDuration((long) res.getInteger(R.integer.config_popupOpenCloseDuration));
- revealAnim.setInterpolator(new AccelerateDecelerateInterpolator());
+ revealAnim.setDuration(revealDuration);
+ revealAnim.setInterpolator(revealInterpolator);
+ closeAnim.play(revealAnim);
+
+ Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0);
+ fadeOut.setDuration(revealDuration);
+ fadeOut.setInterpolator(revealInterpolator);
+ closeAnim.play(fadeOut);
// Animate original icon's text back in.
- closeAnim.play(mOriginalIcon.createTextAlphaAnimator(true /* fadeIn */));
+ Animator fadeText = mOriginalIcon.createTextAlphaAnimator(true /* fadeIn */);
+ fadeText.setDuration(revealDuration);
+ closeAnim.play(fadeText);
closeAnim.addListener(new AnimatorListenerAdapter() {
@Override
@@ -882,7 +916,6 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
}
});
mOpenCloseAnimator = closeAnim;
- closeAnim.playSequentially(arrowScale, revealAnim);
closeAnim.start();
mOriginalIcon.forceHideBadge(false);
}
@@ -897,9 +930,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
}
mIsOpen = false;
mDeferContainerRemoval = false;
- boolean isInHotseat = ((ItemInfo) mOriginalIcon.getTag()).container
- == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
- mOriginalIcon.setTextVisibility(!isInHotseat);
+ mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible());
mOriginalIcon.forceHideBadge(false);
mLauncher.getDragController().removeDragListener(this);
mLauncher.getDragLayer().removeView(this);
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 00e2644a5..523016008 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -134,7 +134,7 @@ public class RestoreDbTask {
}
public static void setPending(Context context, boolean isPending) {
- FileLog.d(TAG, "Restore data received through full backup");
+ FileLog.d(TAG, "Restore data received through full backup " + isPending);
Utilities.getPrefs(context).edit().putBoolean(RESTORE_TASK_PENDING, isPending).commit();
}
}
diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java
index 4dc3c1c0d..d26f9f646 100644
--- a/src/com/android/launcher3/qsb/QsbContainerView.java
+++ b/src/com/android/launcher3/qsb/QsbContainerView.java
@@ -39,12 +39,14 @@ import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.config.FeatureFlags;
/**
* A frame layout which contains a QSB. This internally uses fragment to bind the view, which
* allows it to contain the logic for {@link Fragment#startActivityForResult(Intent, int)}.
+ *
+ * Note: AppWidgetManagerCompat can be disabled using FeatureFlags. In QSB, we should use
+ * AppWidgetManager directly, so that it keeps working in that case.
*/
public class QsbContainerView extends FrameLayout {
@@ -106,7 +108,7 @@ public class QsbContainerView extends FrameLayout {
return QsbWidgetHostView.getDefaultView(container);
}
- AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(activity);
+ AppWidgetManager widgetManager = AppWidgetManager.getInstance(activity);
InvariantDeviceProfile idp = LauncherAppState.getIDP(activity);
Bundle opts = new Bundle();
@@ -129,7 +131,8 @@ public class QsbContainerView extends FrameLayout {
}
widgetId = mQsbWidgetHost.allocateAppWidgetId();
- isWidgetBound = widgetManager.bindAppWidgetIdIfAllowed(widgetId, mWidgetInfo, opts);
+ isWidgetBound = widgetManager.bindAppWidgetIdIfAllowed(
+ widgetId, mWidgetInfo.getProfile(), mWidgetInfo.provider, opts);
if (!isWidgetBound) {
mQsbWidgetHost.deleteAppWidgetId(widgetId);
widgetId = -1;
diff --git a/src/com/android/launcher3/shortcuts/ShortcutsItemView.java b/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
index 8785a56f9..b4fa04e42 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
@@ -24,7 +24,6 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
@@ -35,6 +34,7 @@ import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
+import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
@@ -144,18 +144,8 @@ public class ShortcutsItemView extends PopupItemView implements View.OnLongClick
if (mSystemShortcutIcons == null) {
mSystemShortcutIcons = (LinearLayout) mLauncher.getLayoutInflater().inflate(
R.layout.system_shortcut_icons, mContent, false);
-
- View divider = LayoutInflater.from(getContext()).inflate(
- R.layout.horizontal_divider, this, false);
-
boolean iconsAreBelowShortcuts = mShortcutsLayout.getChildCount() > 0;
- if (iconsAreBelowShortcuts) {
- mContent.addView(divider);
- mContent.addView(mSystemShortcutIcons);
- } else {
- mContent.addView(divider, 0);
- mContent.addView(mSystemShortcutIcons, 0);
- }
+ mContent.addView(mSystemShortcutIcons, iconsAreBelowShortcuts ? -1 : 0);
}
mSystemShortcutIcons.addView(shortcutView, index);
} else {
@@ -280,6 +270,9 @@ public class ShortcutsItemView extends PopupItemView implements View.OnLongClick
// Make sure the text and icon stay centered in the shortcut.
animation.play(translateYFrom(shortcut.getBubbleText(), heightDiff / 2 * fromDir));
animation.play(translateYFrom(shortcut.getIconView(), heightDiff / 2 * fromDir));
+ // Scale icons back up to full size.
+ animation.play(LauncherAnimUtils.ofPropertyValuesHolder(shortcut.getIconView(),
+ new PropertyListBuilder().scale(1f).build()));
}
return animation;
}
diff --git a/src/com/android/launcher3/touch/OverScroll.java b/src/com/android/launcher3/touch/OverScroll.java
new file mode 100644
index 000000000..dc801ec4c
--- /dev/null
+++ b/src/com/android/launcher3/touch/OverScroll.java
@@ -0,0 +1,55 @@
+/*
+ * 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.touch;
+
+/**
+ * Utility methods for overscroll damping and related effect.
+ */
+public class OverScroll {
+
+ private static final float OVERSCROLL_DAMP_FACTOR = 0.07f;
+
+ /**
+ * This curve determines how the effect of scrolling over the limits of the page diminishes
+ * as the user pulls further and further from the bounds
+ *
+ * @param f The percentage of how much the user has overscrolled.
+ * @return A transformed percentage based on the influence curve.
+ */
+ private static float overScrollInfluenceCurve(float f) {
+ f -= 1.0f;
+ return f * f * f + 1.0f;
+ }
+
+ /**
+ * @param amount The original amount overscrolled.
+ * @param max The maximum amount that the View can overscroll.
+ * @return The dampened overscroll amount.
+ */
+ public static int dampedScroll(float amount, int max) {
+ if (Float.compare(amount, 0) == 0) return 0;
+
+ float f = amount / max;
+ f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
+
+ // Clamp this factor, f, to -1 < f < 1
+ if (Math.abs(f) >= 1) {
+ f /= Math.abs(f);
+ }
+
+ return Math.round(OVERSCROLL_DAMP_FACTOR * f * max);
+ }
+}
diff --git a/src/com/android/launcher3/allapps/VerticalPullDetector.java b/src/com/android/launcher3/touch/SwipeDetector.java
index 13c4f63f0..be4648eef 100644
--- a/src/com/android/launcher3/allapps/VerticalPullDetector.java
+++ b/src/com/android/launcher3/touch/SwipeDetector.java
@@ -1,32 +1,52 @@
-package com.android.launcher3.allapps;
+/*
+ * 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.touch;
+import static android.view.MotionEvent.INVALID_POINTER_ID;
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.ViewConfiguration;
import android.view.animation.Interpolator;
/**
- * One dimensional scroll gesture detector for all apps container pull up interaction.
- * Client (e.g., AllAppsTransitionController) of this class can register a listener.
- * <p/>
- * Features that this gesture detector can support.
+ * One dimensional scroll/drag/swipe gesture detector.
+ *
+ * Definition of swipe is different from android system in that this detector handles
+ * 'swipe to dismiss', 'swiping up/down a container' but also keeps scrolling state before
+ * swipe action happens
*/
-public class VerticalPullDetector {
+public class SwipeDetector {
private static final boolean DBG = false;
- private static final String TAG = "VerticalPullDetector";
-
- private final float mTouchSlop;
+ private static final String TAG = "SwipeDetector";
private int mScrollConditions;
- public static final int DIRECTION_UP = 1 << 0;
- public static final int DIRECTION_DOWN = 1 << 1;
- public static final int DIRECTION_BOTH = DIRECTION_DOWN | DIRECTION_UP;
+ public static final int DIRECTION_POSITIVE = 1 << 0;
+ public static final int DIRECTION_NEGATIVE = 1 << 1;
+ public static final int DIRECTION_BOTH = DIRECTION_NEGATIVE | DIRECTION_POSITIVE;
private static final float ANIMATION_DURATION = 1200;
private static final float FAST_FLING_PX_MS = 10;
+ protected int mActivePointerId = INVALID_POINTER_ID;
+
/**
* The minimum release velocity in pixels per millisecond that triggers fling..
*/
@@ -47,6 +67,42 @@ public class VerticalPullDetector {
SETTLING // onDragEnd
}
+ public static abstract class Direction {
+
+ abstract float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint);
+
+ /**
+ * Distance in pixels a touch can wander before we think the user is scrolling.
+ */
+ abstract float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos);
+ }
+
+ public static final Direction VERTICAL = new Direction() {
+
+ @Override
+ float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint) {
+ return ev.getY(pointerIndex) - refPoint.y;
+ }
+
+ @Override
+ float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos) {
+ return Math.abs(ev.getX(pointerIndex) - downPos.x);
+ }
+ };
+
+ public static final Direction HORIZONTAL = new Direction() {
+
+ @Override
+ float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint) {
+ return ev.getX(pointerIndex) - refPoint.x;
+ }
+
+ @Override
+ float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos) {
+ return Math.abs(ev.getY(pointerIndex) - downPos.y);
+ }
+ };
+
//------------------- ScrollState transition diagram -----------------------------------
//
// IDLE -> (mDisplacement > mTouchSlop) -> DRAGGING
@@ -93,27 +149,24 @@ public class VerticalPullDetector {
return mState == ScrollState.DRAGGING;
}
- private float mDownX;
- private float mDownY;
+ private final PointF mDownPos = new PointF();
+ private final PointF mLastPos = new PointF();
+ private final Direction mDir;
+
+ private final float mTouchSlop;
+
+ /* Client of this gesture detector can register a callback. */
+ private final Listener mListener;
- private float mLastY;
private long mCurrentMillis;
private float mVelocity;
private float mLastDisplacement;
- private float mDisplacementY;
- private float mDisplacementX;
+ private float mDisplacement;
private float mSubtractDisplacement;
private boolean mIgnoreSlopWhenSettling;
- /* Client of this gesture detector can register a callback. */
- private Listener mListener;
-
- public void setListener(Listener l) {
- mListener = l;
- }
-
public interface Listener {
void onDragStart(boolean start);
@@ -122,8 +175,15 @@ public class VerticalPullDetector {
void onDragEnd(float velocity, boolean fling);
}
- public VerticalPullDetector(Context context) {
- mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ public SwipeDetector(@NonNull Context context, @NonNull Listener l, @NonNull Direction dir) {
+ this(ViewConfiguration.get(context).getScaledTouchSlop(), l, dir);
+ }
+
+ @VisibleForTesting
+ protected SwipeDetector(float touchSlope, @NonNull Listener l, @NonNull Direction dir) {
+ mTouchSlop = touchSlope;
+ mListener = l;
+ mDir = dir;
}
public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
@@ -131,51 +191,65 @@ public class VerticalPullDetector {
mIgnoreSlopWhenSettling = ignoreSlop;
}
- private boolean shouldScrollStart() {
- // reject cases where the slop condition is not met.
- if (Math.abs(mDisplacementY) < mTouchSlop) {
+ private boolean shouldScrollStart(MotionEvent ev, int pointerIndex) {
+ // reject cases where the angle or slop condition is not met.
+ if (Math.max(mDir.getActiveTouchSlop(ev, pointerIndex, mDownPos), mTouchSlop)
+ > Math.abs(mDisplacement)) {
return false;
}
- // reject cases where the angle condition is not met.
- float deltaY = Math.abs(mDisplacementY);
- float deltaX = Math.max(Math.abs(mDisplacementX), 1);
- if (deltaX > deltaY) {
- return false;
- }
// Check if the client is interested in scroll in current direction.
- if (((mScrollConditions & DIRECTION_DOWN) > 0 && mDisplacementY > 0) ||
- ((mScrollConditions & DIRECTION_UP) > 0 && mDisplacementY < 0)) {
+ if (((mScrollConditions & DIRECTION_NEGATIVE) > 0 && mDisplacement > 0) ||
+ ((mScrollConditions & DIRECTION_POSITIVE) > 0 && mDisplacement < 0)) {
return true;
}
return false;
}
public boolean onTouchEvent(MotionEvent ev) {
- switch (ev.getAction()) {
+ switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
- mDownX = ev.getX();
- mDownY = ev.getY();
+ mActivePointerId = ev.getPointerId(0);
+ mDownPos.set(ev.getX(), ev.getY());
+ mLastPos.set(mDownPos);
mLastDisplacement = 0;
- mDisplacementY = 0;
+ mDisplacement = 0;
mVelocity = 0;
if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
setState(ScrollState.DRAGGING);
}
break;
+ //case MotionEvent.ACTION_POINTER_DOWN:
+ case MotionEvent.ACTION_POINTER_UP:
+ int ptrIdx = ev.getActionIndex();
+ int ptrId = ev.getPointerId(ptrIdx);
+ if (ptrId == mActivePointerId) {
+ final int newPointerIdx = ptrIdx == 0 ? 1 : 0;
+ mDownPos.set(
+ ev.getX(newPointerIdx) - (mLastPos.x - mDownPos.x),
+ ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y));
+ mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx));
+ mActivePointerId = ev.getPointerId(newPointerIdx);
+ }
+ break;
case MotionEvent.ACTION_MOVE:
- mDisplacementX = ev.getX() - mDownX;
- mDisplacementY = ev.getY() - mDownY;
- computeVelocity(ev);
+ int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (pointerIndex == INVALID_POINTER_ID) {
+ 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()) {
+ if (mState != ScrollState.DRAGGING && shouldScrollStart(ev, pointerIndex)) {
setState(ScrollState.DRAGGING);
}
if (mState == ScrollState.DRAGGING) {
reportDragging();
}
+ mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
@@ -185,12 +259,8 @@ public class VerticalPullDetector {
}
break;
default:
- //TODO: add multi finger tracking by tracking active pointer.
break;
}
- // Do house keeping.
- mLastDisplacement = mDisplacementY;
- mLastY = ev.getY();
return true;
}
@@ -210,7 +280,7 @@ public class VerticalPullDetector {
if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
mSubtractDisplacement = 0;
}
- if (mDisplacementY > 0) {
+ if (mDisplacement > 0) {
mSubtractDisplacement = mTouchSlop;
} else {
mSubtractDisplacement = -mTouchSlop;
@@ -218,14 +288,14 @@ public class VerticalPullDetector {
}
private boolean reportDragging() {
- float delta = mDisplacementY - mLastDisplacement;
- if (delta != 0) {
+ if (mDisplacement != mLastDisplacement) {
if (DBG) {
Log.d(TAG, String.format("onDrag disp=%.1f, velocity=%.1f",
- mDisplacementY, mVelocity));
+ mDisplacement, mVelocity));
}
- return mListener.onDrag(mDisplacementY - mSubtractDisplacement, mVelocity);
+ mLastDisplacement = mDisplacement;
+ return mListener.onDrag(mDisplacement - mSubtractDisplacement, mVelocity);
}
return true;
}
@@ -233,19 +303,15 @@ public class VerticalPullDetector {
private void reportDragEnd() {
if (DBG) {
Log.d(TAG, String.format("onScrollEnd disp=%.1f, velocity=%.1f",
- mDisplacementY, mVelocity));
+ mDisplacement, mVelocity));
}
mListener.onDragEnd(mVelocity, Math.abs(mVelocity) > RELEASE_VELOCITY_PX_MS);
}
/**
- * Computes the damped velocity using the two motion events and the previous velocity.
+ * Computes the damped velocity.
*/
- private float computeVelocity(MotionEvent to) {
- return computeVelocity(to.getY() - mLastY, to.getEventTime());
- }
-
public float computeVelocity(float delta, long currentMillis) {
long previousMillis = mCurrentMillis;
mCurrentMillis = currentMillis;
@@ -275,7 +341,7 @@ public class VerticalPullDetector {
return (1.0f - alpha) * from + alpha * to;
}
- public long calculateDuration(float velocity, float progressNeeded) {
+ public static long calculateDuration(float velocity, float progressNeeded) {
// TODO: make these values constants after tuning.
float velocityDivisor = Math.max(2f, Math.abs(0.5f * velocity));
float travelDistance = Math.max(0.2f, progressNeeded);
diff --git a/src/com/android/launcher3/util/LauncherEdgeEffect.java b/src/com/android/launcher3/util/LauncherEdgeEffect.java
deleted file mode 100644
index 3e3b255ad..000000000
--- a/src/com/android/launcher3/util/LauncherEdgeEffect.java
+++ /dev/null
@@ -1,365 +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.util;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-
-/**
- * This class differs from the framework {@link android.widget.EdgeEffect}:
- * 1) It does not use PorterDuffXfermode
- * 2) The width to radius factor is smaller (0.5 instead of 0.75)
- */
-public class LauncherEdgeEffect {
-
- // Time it will take the effect to fully recede in ms
- private static final int RECEDE_TIME = 600;
-
- // Time it will take before a pulled glow begins receding in ms
- private static final int PULL_TIME = 167;
-
- // Time it will take in ms for a pulled glow to decay to partial strength before release
- private static final int PULL_DECAY_TIME = 2000;
-
- private static final float MAX_ALPHA = 0.5f;
-
- private static final float MAX_GLOW_SCALE = 2.f;
-
- private static final float PULL_GLOW_BEGIN = 0.f;
-
- // Minimum velocity that will be absorbed
- private static final int MIN_VELOCITY = 100;
- // Maximum velocity, clamps at this value
- private static final int MAX_VELOCITY = 10000;
-
- private static final float EPSILON = 0.001f;
-
- private static final double ANGLE = Math.PI / 6;
- private static final float SIN = (float) Math.sin(ANGLE);
- private static final float COS = (float) Math.cos(ANGLE);
-
- private float mGlowAlpha;
- private float mGlowScaleY;
-
- private float mGlowAlphaStart;
- private float mGlowAlphaFinish;
- private float mGlowScaleYStart;
- private float mGlowScaleYFinish;
-
- private long mStartTime;
- private float mDuration;
-
- private final Interpolator mInterpolator;
-
- private static final int STATE_IDLE = 0;
- private static final int STATE_PULL = 1;
- private static final int STATE_ABSORB = 2;
- private static final int STATE_RECEDE = 3;
- private static final int STATE_PULL_DECAY = 4;
-
- private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 0.8f;
-
- private static final int VELOCITY_GLOW_FACTOR = 6;
-
- private int mState = STATE_IDLE;
-
- private float mPullDistance;
-
- private final Rect mBounds = new Rect();
- private final Paint mPaint = new Paint();
- private float mRadius;
- private float mBaseGlowScale;
- private float mDisplacement = 0.5f;
- private float mTargetDisplacement = 0.5f;
-
- /**
- * Construct a new EdgeEffect with a theme appropriate for the provided context.
- */
- public LauncherEdgeEffect() {
- mPaint.setAntiAlias(true);
- mPaint.setStyle(Paint.Style.FILL);
- mInterpolator = new DecelerateInterpolator();
- }
-
- /**
- * Set the size of this edge effect in pixels.
- *
- * @param width Effect width in pixels
- * @param height Effect height in pixels
- */
- public void setSize(int width, int height) {
- final float r = width * 0.5f / SIN;
- final float y = COS * r;
- final float h = r - y;
- final float or = height * 0.75f / SIN;
- final float oy = COS * or;
- final float oh = or - oy;
-
- mRadius = r;
- mBaseGlowScale = h > 0 ? Math.min(oh / h, 1.f) : 1.f;
-
- mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h));
- }
-
- /**
- * Reports if this EdgeEffect's animation is finished. If this method returns false
- * after a call to {@link #draw(Canvas)} the host widget should schedule another
- * drawing pass to continue the animation.
- *
- * @return true if animation is finished, false if drawing should continue on the next frame.
- */
- public boolean isFinished() {
- return mState == STATE_IDLE;
- }
-
- /**
- * Immediately finish the current animation.
- * After this call {@link #isFinished()} will return true.
- */
- public void finish() {
- mState = STATE_IDLE;
- }
-
- /**
- * A view should call this when content is pulled away from an edge by the user.
- * This will update the state of the current visual effect and its associated animation.
- * The host view should always {@link android.view.View#invalidate()} after this
- * and draw the results accordingly.
- *
- * <p>Views using EdgeEffect should favor {@link #onPull(float, float)} when the displacement
- * of the pull point is known.</p>
- *
- * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
- * 1.f (full length of the view) or negative values to express change
- * back toward the edge reached to initiate the effect.
- */
- public void onPull(float deltaDistance) {
- onPull(deltaDistance, 0.5f);
- }
-
- /**
- * A view should call this when content is pulled away from an edge by the user.
- * This will update the state of the current visual effect and its associated animation.
- * The host view should always {@link android.view.View#invalidate()} after this
- * and draw the results accordingly.
- *
- * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
- * 1.f (full length of the view) or negative values to express change
- * back toward the edge reached to initiate the effect.
- * @param displacement The displacement from the starting side of the effect of the point
- * initiating the pull. In the case of touch this is the finger position.
- * Values may be from 0-1.
- */
- public void onPull(float deltaDistance, float displacement) {
- final long now = AnimationUtils.currentAnimationTimeMillis();
- mTargetDisplacement = displacement;
- if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) {
- return;
- }
- if (mState != STATE_PULL) {
- mGlowScaleY = Math.max(PULL_GLOW_BEGIN, mGlowScaleY);
- }
- mState = STATE_PULL;
-
- mStartTime = now;
- mDuration = PULL_TIME;
-
- mPullDistance += deltaDistance;
-
- final float absdd = Math.abs(deltaDistance);
- mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA,
- mGlowAlpha + (absdd * PULL_DISTANCE_ALPHA_GLOW_FACTOR));
-
- if (mPullDistance == 0) {
- mGlowScaleY = mGlowScaleYStart = 0;
- } else {
- final float scale = (float) (Math.max(0, 1 - 1 /
- Math.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3d) / 0.7d);
-
- mGlowScaleY = mGlowScaleYStart = scale;
- }
-
- mGlowAlphaFinish = mGlowAlpha;
- mGlowScaleYFinish = mGlowScaleY;
- }
-
- /**
- * Call when the object is released after being pulled.
- * This will begin the "decay" phase of the effect. After calling this method
- * the host view should {@link android.view.View#invalidate()} and thereby
- * draw the results accordingly.
- */
- public void onRelease() {
- mPullDistance = 0;
-
- if (mState != STATE_PULL && mState != STATE_PULL_DECAY) {
- return;
- }
-
- mState = STATE_RECEDE;
- mGlowAlphaStart = mGlowAlpha;
- mGlowScaleYStart = mGlowScaleY;
-
- mGlowAlphaFinish = 0.f;
- mGlowScaleYFinish = 0.f;
-
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
- mDuration = RECEDE_TIME;
- }
-
- /**
- * Call when the effect absorbs an impact at the given velocity.
- * Used when a fling reaches the scroll boundary.
- *
- * <p>When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller},
- * the method <code>getCurrVelocity</code> will provide a reasonable approximation
- * to use here.</p>
- *
- * @param velocity Velocity at impact in pixels per second.
- */
- public void onAbsorb(int velocity) {
- mState = STATE_ABSORB;
- velocity = Math.min(Math.max(MIN_VELOCITY, Math.abs(velocity)), MAX_VELOCITY);
-
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
- mDuration = 0.15f + (velocity * 0.02f);
-
- // The glow depends more on the velocity, and therefore starts out
- // nearly invisible.
- mGlowAlphaStart = 0.3f;
- mGlowScaleYStart = Math.max(mGlowScaleY, 0.f);
-
-
- // Growth for the size of the glow should be quadratic to properly
- // respond
- // to a user's scrolling speed. The faster the scrolling speed, the more
- // intense the effect should be for both the size and the saturation.
- mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, 1.f);
- // Alpha should change for the glow as well as size.
- mGlowAlphaFinish = Math.max(
- mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA));
- mTargetDisplacement = 0.5f;
- }
-
- /**
- * Set the color of this edge effect in argb.
- *
- * @param color Color in argb
- */
- public void setColor(int color) {
- mPaint.setColor(color);
- }
-
- /**
- * Return the color of this edge effect in argb.
- * @return The color of this edge effect in argb
- */
- public int getColor() {
- return mPaint.getColor();
- }
-
- /**
- * Draw into the provided canvas. Assumes that the canvas has been rotated
- * accordingly and the size has been set. The effect will be drawn the full
- * width of X=0 to X=width, beginning from Y=0 and extending to some factor <
- * 1.f of height.
- *
- * @param canvas Canvas to draw into
- * @return true if drawing should continue beyond this frame to continue the
- * animation
- */
- public boolean draw(Canvas canvas) {
- update();
-
- final float centerX = mBounds.centerX();
- final float centerY = mBounds.height() - mRadius;
-
- canvas.scale(1.f, Math.min(mGlowScaleY, 1.f) * mBaseGlowScale, centerX, 0);
-
- final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f;
- float translateX = mBounds.width() * displacement / 2;
- mPaint.setAlpha((int) (0xff * mGlowAlpha));
- canvas.drawCircle(centerX + translateX, centerY, mRadius, mPaint);
-
- boolean oneLastFrame = false;
- if (mState == STATE_RECEDE && mGlowScaleY == 0) {
- mState = STATE_IDLE;
- oneLastFrame = true;
- }
-
- return mState != STATE_IDLE || oneLastFrame;
- }
-
- /**
- * Return the maximum height that the edge effect will be drawn at given the original
- * {@link #setSize(int, int) input size}.
- * @return The maximum height of the edge effect
- */
- public int getMaxHeight() {
- return (int) (mBounds.height() * MAX_GLOW_SCALE + 0.5f);
- }
-
- private void update() {
- final long time = AnimationUtils.currentAnimationTimeMillis();
- final float t = Math.min((time - mStartTime) / mDuration, 1.f);
-
- final float interp = mInterpolator.getInterpolation(t);
-
- mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp;
- mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp;
- mDisplacement = (mDisplacement + mTargetDisplacement) / 2;
-
- if (t >= 1.f - EPSILON) {
- switch (mState) {
- case STATE_ABSORB:
- mState = STATE_RECEDE;
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
- mDuration = RECEDE_TIME;
-
- mGlowAlphaStart = mGlowAlpha;
- mGlowScaleYStart = mGlowScaleY;
-
- // After absorb, the glow should fade to nothing.
- mGlowAlphaFinish = 0.f;
- mGlowScaleYFinish = 0.f;
- break;
- case STATE_PULL:
- mState = STATE_PULL_DECAY;
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
- mDuration = PULL_DECAY_TIME;
-
- mGlowAlphaStart = mGlowAlpha;
- mGlowScaleYStart = mGlowScaleY;
-
- // After pull, the glow should fade to nothing.
- mGlowAlphaFinish = 0.f;
- mGlowScaleYFinish = 0.f;
- break;
- case STATE_PULL_DECAY:
- mState = STATE_RECEDE;
- break;
- case STATE_RECEDE:
- mState = STATE_IDLE;
- break;
- }
- }
- }
-}
diff --git a/src/com/android/launcher3/views/ButtonPreference.java b/src/com/android/launcher3/views/ButtonPreference.java
new file mode 100644
index 000000000..4697e25e4
--- /dev/null
+++ b/src/com/android/launcher3/views/ButtonPreference.java
@@ -0,0 +1,70 @@
+/*
+ * 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 View.OnClickListener mClickListener;
+
+ 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 setButtonOnClickListener(View.OnClickListener clickListener) {
+ if (mClickListener != clickListener) {
+ mClickListener = clickListener;
+ notifyChanged();
+ }
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+
+ ViewGroup widgetFrame = view.findViewById(android.R.id.widget_frame);
+ if (widgetFrame != null) {
+ View button = widgetFrame.getChildAt(0);
+ if (button != null) {
+ button.setOnClickListener(mClickListener);
+ }
+ widgetFrame.setVisibility(
+ (mClickListener == null || button == null) ? View.GONE : View.VISIBLE);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
index c0b5fe156..c8203f7f2 100644
--- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -23,6 +23,7 @@ import android.graphics.Color;
import android.graphics.Region;
import android.support.v4.graphics.ColorUtils;
import android.util.AttributeSet;
+import android.widget.TextView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
@@ -50,13 +51,12 @@ public class DoubleShadowBubbleTextView extends BubbleTextView {
@Override
public void onDraw(Canvas canvas) {
- // If text is transparent, don't draw any shadow
- int alpha = Color.alpha(getCurrentTextColor());
- if (alpha == 0) {
- getPaint().clearShadowLayer();
+ // If text is transparent or shadow alpha is 0, don't draw any shadow
+ if (mShadowInfo.skipDoubleShadow(this)) {
super.onDraw(canvas);
return;
}
+ int alpha = Color.alpha(getCurrentTextColor());
// We enhance the shadow by drawing the shadow twice
getPaint().setShadowLayer(mShadowInfo.ambientShadowBlur, 0, 0,
@@ -97,5 +97,25 @@ public class DoubleShadowBubbleTextView extends BubbleTextView {
keyShadowColor = a.getColor(R.styleable.ShadowInfo_keyShadowColor, 0);
a.recycle();
}
+
+ public boolean skipDoubleShadow(TextView textView) {
+ int textAlpha = Color.alpha(textView.getCurrentTextColor());
+ int keyShadowAlpha = Color.alpha(keyShadowColor);
+ int ambientShadowAlpha = Color.alpha(ambientShadowColor);
+ if (textAlpha == 0 || (keyShadowAlpha == 0 && ambientShadowAlpha == 0)) {
+ textView.getPaint().clearShadowLayer();
+ return true;
+ } else if (ambientShadowAlpha > 0) {
+ textView.getPaint().setShadowLayer(ambientShadowBlur, 0, 0,
+ ColorUtils.setAlphaComponent(ambientShadowColor, textAlpha));
+ return true;
+ } else if (keyShadowAlpha > 0) {
+ textView.getPaint().setShadowLayer(keyShadowBlur, 0.0f, keyShadowOffset,
+ ColorUtils.setAlphaComponent(keyShadowColor, textAlpha));
+ return true;
+ } else {
+ return false;
+ }
+ }
}
}
diff --git a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
index e8f13a13c..62b6903f7 100644
--- a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.widget;
-import com.android.launcher3.LauncherSettings;
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.compat.ShortcutConfigActivityInfo;
diff --git a/src/com/android/launcher3/widget/WidgetAddFlowHandler.java b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
index 629f30c26..5387be839 100644
--- a/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
+++ b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
@@ -15,10 +15,8 @@
*/
package com.android.launcher3.widget;
-import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
-import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
@@ -26,7 +24,6 @@ import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.util.PendingRequestArgs;
/**
@@ -56,15 +53,8 @@ public class WidgetAddFlowHandler implements Parcelable {
public void startBindFlow(Launcher launcher, int appWidgetId, ItemInfo info, int requestCode) {
launcher.setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, this, info));
-
- Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, mProviderInfo.provider);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE,
- mProviderInfo.getProfile());
- // TODO: we need to make sure that this accounts for the options bundle.
- // intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
- launcher.startActivityForResult(intent, requestCode);
+ launcher.getAppWidgetHost()
+ .startBindFlow(launcher, appWidgetId, mProviderInfo, requestCode);
}
/**
@@ -85,9 +75,7 @@ public class WidgetAddFlowHandler implements Parcelable {
return false;
}
launcher.setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, this, info));
-
- AppWidgetManagerCompat.getInstance(launcher).startConfigActivity(
- mProviderInfo, appWidgetId, launcher, launcher.getAppWidgetHost(), requestCode);
+ launcher.getAppWidgetHost().startConfigActivity(launcher, appWidgetId, requestCode);
return true;
}
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index fff3472ae..0b4bf628e 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -40,14 +40,16 @@ import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.VerticalPullDetector;
+import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.graphics.GradientView;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.SystemUiController;
+import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TouchController;
import java.util.List;
@@ -56,7 +58,7 @@ import java.util.List;
* Bottom sheet for the "Widgets" system shortcut in the long-press popup.
*/
public class WidgetsBottomSheet extends AbstractFloatingView implements Insettable, TouchController,
- VerticalPullDetector.Listener, View.OnClickListener, View.OnLongClickListener,
+ SwipeDetector.Listener, View.OnClickListener, View.OnLongClickListener,
DragController.DragListener {
private int mTranslationYOpen;
@@ -67,9 +69,10 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
private ItemInfo mOriginalItemInfo;
private ObjectAnimator mOpenCloseAnimator;
private Interpolator mFastOutSlowInInterpolator;
- private VerticalPullDetector.ScrollInterpolator mScrollInterpolator;
+ private SwipeDetector.ScrollInterpolator mScrollInterpolator;
private Rect mInsets;
- private VerticalPullDetector mVerticalPullDetector;
+ private SwipeDetector mSwipeDetector;
+ private GradientView mGradientBackground;
public WidgetsBottomSheet(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -82,10 +85,10 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
mOpenCloseAnimator = LauncherAnimUtils.ofPropertyValuesHolder(this);
mFastOutSlowInInterpolator =
AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
- mScrollInterpolator = new VerticalPullDetector.ScrollInterpolator();
+ mScrollInterpolator = new SwipeDetector.ScrollInterpolator();
mInsets = new Rect();
- mVerticalPullDetector = new VerticalPullDetector(context);
- mVerticalPullDetector.setListener(this);
+ mSwipeDetector = new SwipeDetector(context, this, SwipeDetector.VERTICAL);
+ mGradientBackground = (GradientView) mLauncher.findViewById(R.id.gradient_bg);
}
@Override
@@ -178,15 +181,17 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
return;
}
mIsOpen = true;
+ boolean isSheetDark = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
mLauncher.getSystemUiController().updateUiState(
- SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, SystemUiController.FLAG_LIGHT_NAV);
+ SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET,
+ isSheetDark ? SystemUiController.FLAG_DARK_NAV : SystemUiController.FLAG_LIGHT_NAV);
if (animate) {
mOpenCloseAnimator.setValues(new PropertyListBuilder()
.translationY(mTranslationYOpen).build());
mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mVerticalPullDetector.finishedScrolling();
+ mSwipeDetector.finishedScrolling();
}
});
mOpenCloseAnimator.setInterpolator(mFastOutSlowInInterpolator);
@@ -208,13 +213,13 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
@Override
public void onAnimationEnd(Animator animation) {
mIsOpen = false;
- mVerticalPullDetector.finishedScrolling();
+ mSwipeDetector.finishedScrolling();
((ViewGroup) getParent()).removeView(WidgetsBottomSheet.this);
mLauncher.getSystemUiController().updateUiState(
SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
}
});
- mOpenCloseAnimator.setInterpolator(mVerticalPullDetector.isIdleState()
+ mOpenCloseAnimator.setInterpolator(mSwipeDetector.isIdleState()
? mFastOutSlowInInterpolator : mScrollInterpolator);
mOpenCloseAnimator.start();
} else {
@@ -253,7 +258,7 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
getPaddingRight() + rightInset, getPaddingBottom() + bottomInset);
}
- /* VerticalPullDetector.Listener */
+ /* SwipeDetector.Listener */
@Override
public void onDragStart(boolean start) {
@@ -267,15 +272,24 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
}
@Override
+ public void setTranslationY(float translationY) {
+ super.setTranslationY(translationY);
+ if (mGradientBackground == null) return;
+ float p = (mTranslationYClosed - translationY) / mTranslationYRange;
+ boolean showScrim = p <= 0;
+ mGradientBackground.setProgress(p, showScrim);
+ }
+
+ @Override
public void onDragEnd(float velocity, boolean fling) {
if ((fling && velocity > 0) || getTranslationY() > (mTranslationYRange) / 2) {
mScrollInterpolator.setVelocityAtZero(velocity);
- mOpenCloseAnimator.setDuration(mVerticalPullDetector.calculateDuration(velocity,
+ mOpenCloseAnimator.setDuration(SwipeDetector.calculateDuration(velocity,
(mTranslationYClosed - getTranslationY()) / mTranslationYRange));
close(true);
} else {
mIsOpen = false;
- mOpenCloseAnimator.setDuration(mVerticalPullDetector.calculateDuration(velocity,
+ mOpenCloseAnimator.setDuration(SwipeDetector.calculateDuration(velocity,
(getTranslationY() - mTranslationYOpen) / mTranslationYRange));
open(true);
}
@@ -283,17 +297,17 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
@Override
public boolean onControllerTouchEvent(MotionEvent ev) {
- return mVerticalPullDetector.onTouchEvent(ev);
+ return mSwipeDetector.onTouchEvent(ev);
}
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- int directionsToDetectScroll = mVerticalPullDetector.isIdleState() ?
- VerticalPullDetector.DIRECTION_DOWN : 0;
- mVerticalPullDetector.setDetectableScrollConditions(
+ int directionsToDetectScroll = mSwipeDetector.isIdleState() ?
+ SwipeDetector.DIRECTION_NEGATIVE : 0;
+ mSwipeDetector.setDetectableScrollConditions(
directionsToDetectScroll, false);
- mVerticalPullDetector.onTouchEvent(ev);
- return mVerticalPullDetector.isDraggingOrSettling();
+ mSwipeDetector.onTouchEvent(ev);
+ return mSwipeDetector.isDraggingOrSettling();
}
/* DragListener */
diff --git a/src_flags/com/android/launcher3/config/FeatureFlags.java b/src_flags/com/android/launcher3/config/FeatureFlags.java
index 42a110cfe..3ffb6c937 100644
--- a/src_flags/com/android/launcher3/config/FeatureFlags.java
+++ b/src_flags/com/android/launcher3/config/FeatureFlags.java
@@ -19,48 +19,7 @@ package com.android.launcher3.config;
/**
* Defines a set of flags used to control various launcher behaviors
*/
-public final class FeatureFlags {
-
- public static final boolean IS_DOGFOOD_BUILD = true;
+public final class FeatureFlags extends BaseFlags {
private FeatureFlags() {}
-
- // Custom flags go below this
- public static boolean LAUNCHER3_DISABLE_ICON_NORMALIZATION = false;
- public static boolean LAUNCHER3_LEGACY_FOLDER_ICON = false;
- public static boolean LAUNCHER3_USE_SYSTEM_DRAG_DRIVER = true;
- public static boolean LAUNCHER3_DISABLE_PINCH_TO_OVERVIEW = false;
- public static boolean LAUNCHER3_ALL_APPS_PULL_UP = true;
- public static boolean LAUNCHER3_NEW_FOLDER_ANIMATION = true;
- // When enabled allows to use any point on the fast scrollbar to start dragging.
- public static boolean LAUNCHER3_DIRECT_SCROLL = true;
- // When enabled while all-apps open, the soft input will be set to adjust resize .
- public static boolean LAUNCHER3_UPDATE_SOFT_INPUT_MODE = true;
- // When enabled the promise icon is visible in all apps while installation an app.
- public static boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = false;
- // When enabled uses the AllAppsRadialGradientAndScrimDrawable for all apps
- public static boolean LAUNCHER3_GRADIENT_ALL_APPS = true;
- // When enabled allows use of physics based motions in the Launcher.
- public static boolean LAUNCHER3_PHYSICS = true;
- // When enabled allows use of spring motions on the icons.
- public static 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;
- // When enabled fling down gesture on the first workspace triggers search.
- public static final boolean PULLDOWN_SEARCH = false;
- // When enabled the status bar may show dark icons based on the top of the wallpaper.
- public static final boolean LIGHT_STATUS_BAR = false;
- // When enabled icons are badged with the number of notifications associated with that app.
- public static final boolean BADGE_ICONS = true;
- // When enabled, icons not supporting {@link AdaptiveIconDrawable} will be wrapped in {@link FixedScaleDrawable}.
- public static final boolean LEGACY_ICON_TREATMENT = true;
- // When enabled, adaptive icons would have shadows baked when being stored to icon cache.
- public static final boolean ADAPTIVE_ICON_SHADOW = true;
- // When enabled, app discovery will be enabled if service is implemented
- public static final boolean DISCOVERY_ENABLED = false;
- // When enabled, the qsb will be moved to the hotseat.
- public static final boolean QSB_IN_HOTSEAT = true;
}
diff --git a/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java b/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
index 58dc0c43e..26ec69b1c 100644
--- a/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
+++ b/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
@@ -19,6 +19,7 @@ import android.content.ComponentName;
import android.test.InstrumentationTestCase;
import com.android.launcher3.AppInfo;
+import com.android.launcher3.Utilities;
import java.util.ArrayList;
import java.util.List;
@@ -75,6 +76,25 @@ public class DefaultAppSearchAlgorithmTest extends InstrumentationTestCase {
assertTrue(mAlgorithm.matches(getInfo("电子邮件"), "电子"));
assertFalse(mAlgorithm.matches(getInfo("电子邮件"), "子"));
assertFalse(mAlgorithm.matches(getInfo("电子邮件"), "邮件"));
+
+ assertFalse(mAlgorithm.matches(getInfo("Bot"), "ba"));
+ assertFalse(mAlgorithm.matches(getInfo("bot"), "ba"));
+ }
+
+ public void testMatchesVN() {
+ if (!Utilities.ATLEAST_NOUGAT) {
+ return;
+ }
+ assertTrue(mAlgorithm.matches(getInfo("다운로드"), "다"));
+ assertTrue(mAlgorithm.matches(getInfo("드라이브"), "드"));
+ assertTrue(mAlgorithm.matches(getInfo("다운로드 드라이브"), "ㄷ"));
+ assertTrue(mAlgorithm.matches(getInfo("운로 드라이브"), "ㄷ"));
+ assertTrue(mAlgorithm.matches(getInfo("abc"), "åbç"));
+ assertTrue(mAlgorithm.matches(getInfo("Alpha"), "ål"));
+
+ assertFalse(mAlgorithm.matches(getInfo("다운로드 드라이브"), "ㄷㄷ"));
+ assertFalse(mAlgorithm.matches(getInfo("로드라이브"), "ㄷ"));
+ assertFalse(mAlgorithm.matches(getInfo("abc"), "åç"));
}
private AppInfo getInfo(String title) {
diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index 29f738bab..5858e13c1 100644
--- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -47,11 +47,8 @@ public class RestoreDbTaskTest extends AndroidTestCase {
}
private int getCount(SQLiteDatabase db, String sql) {
- Cursor c = db.rawQuery(sql, null);
- try {
+ try (Cursor c = db.rawQuery(sql, null)) {
return c.getCount();
- } finally {
- c.getCount();
}
}
@@ -59,7 +56,7 @@ public class RestoreDbTaskTest extends AndroidTestCase {
private final long mProfileId;
- public MyDatabaseHelper(long profileId) {
+ MyDatabaseHelper(long profileId) {
super(getContext(), null, null);
mProfileId = profileId;
}
diff --git a/tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java b/tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
new file mode 100644
index 000000000..80d6341e7
--- /dev/null
+++ b/tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
@@ -0,0 +1,275 @@
+/*
+ * 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.testcomponent;
+
+import android.graphics.Point;
+import android.util.Pair;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utility class to generate MotionEvent event sequences for testing touch gesture detectors.
+ */
+public class TouchEventGenerator {
+
+ /**
+ * Amount of time between two generated events.
+ */
+ private static final long TIME_INCREMENT_MS = 20L;
+
+ /**
+ * Id of the fake device generating the events.
+ */
+ private static final int DEVICE_ID = 2104;
+
+ /**
+ * The fingers currently present on the emulated touch screen.
+ */
+ private Map<Integer, Point> mFingers;
+
+ /**
+ * Initial event time for the current sequence.
+ */
+ private long mInitialTime;
+
+ /**
+ * Time of the last generated event.
+ */
+ private long mLastEventTime;
+
+ /**
+ * Time of the next event.
+ */
+ private long mTime;
+
+ /**
+ * Receives the generated events.
+ */
+ public interface Listener {
+
+ /**
+ * Called when an event was generated.
+ */
+ void onTouchEvent(MotionEvent event);
+ }
+ private final Listener mListener;
+
+ public TouchEventGenerator(Listener listener) {
+ mListener = listener;
+ mFingers = new HashMap<Integer, Point>();
+ }
+
+ /**
+ * Adds a finger on the touchscreen.
+ */
+ public TouchEventGenerator put(int id, int x, int y, long ms) {
+ checkFingerExistence(id, false);
+ boolean isInitialDown = mFingers.isEmpty();
+ mFingers.put(id, new Point(x, y));
+ int action;
+ if (isInitialDown) {
+ action = MotionEvent.ACTION_DOWN;
+ } else {
+ action = MotionEvent.ACTION_POINTER_DOWN;
+ // Set the id of the changed pointer.
+ action |= id << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ }
+ generateEvent(action, ms);
+ return this;
+ }
+
+ /**
+ * Adds a finger on the touchscreen after advancing default time interval.
+ */
+ public TouchEventGenerator put(int id, int x, int y) {
+ return put(id, x, y, TIME_INCREMENT_MS);
+ }
+
+ /**
+ * Adjusts the position of a finger for an upcoming move event.
+ *
+ * @see #move(long ms)
+ */
+ public TouchEventGenerator position(int id, int x, int y) {
+ checkFingerExistence(id, true);
+ mFingers.get(id).set(x, y);
+ return this;
+ }
+
+ /**
+ * Commits the finger position changes of {@link #position(int, int, int)} by generating a move
+ * event.
+ *
+ * @see #position(int, int, int)
+ */
+ public TouchEventGenerator move(long ms) {
+ generateEvent(MotionEvent.ACTION_MOVE, ms);
+ return this;
+ }
+
+ /**
+ * Commits the finger position changes of {@link #position(int, int, int)} by generating a move
+ * event after advancing the default time interval.
+ *
+ * @see #position(int, int, int)
+ */
+ public TouchEventGenerator move() {
+ return move(TIME_INCREMENT_MS);
+ }
+
+ /**
+ * Moves a single finger on the touchscreen.
+ */
+ public TouchEventGenerator move(int id, int x, int y, long ms) {
+ return position(id, x, y).move(ms);
+ }
+
+ /**
+ * Moves a single finger on the touchscreen after advancing default time interval.
+ */
+ public TouchEventGenerator move(int id, int x, int y) {
+ return move(id, x, y, TIME_INCREMENT_MS);
+ }
+
+ /**
+ * Removes an existing finger from the touchscreen.
+ */
+ public TouchEventGenerator lift(int id, long ms) {
+ 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 |= id << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ }
+ generateEvent(action, ms);
+ mFingers.remove(id);
+ return this;
+ }
+
+ /**
+ * Removes a finger from the touchscreen.
+ */
+ public TouchEventGenerator lift(int id, int x, int y, long ms) {
+ checkFingerExistence(id, true);
+ mFingers.get(id).set(x, y);
+ return lift(id, ms);
+ }
+
+ /**
+ * Removes an existing finger from the touchscreen after advancing default time interval.
+ */
+ public TouchEventGenerator lift(int id) {
+ return lift(id, TIME_INCREMENT_MS);
+ }
+
+ /**
+ * Cancels an ongoing sequence.
+ */
+ public TouchEventGenerator cancel(long ms) {
+ generateEvent(MotionEvent.ACTION_CANCEL, ms);
+ mFingers.clear();
+ return this;
+ }
+
+ /**
+ * Cancels an ongoing sequence.
+ */
+ public TouchEventGenerator cancel() {
+ return cancel(TIME_INCREMENT_MS);
+ }
+
+ private void checkFingerExistence(int id, boolean shouldExist) {
+ if (shouldExist != mFingers.containsKey(id)) {
+ throw new IllegalArgumentException(
+ shouldExist ? "Finger does not exist" : "Finger already exists");
+ }
+ }
+
+ private void generateEvent(int action, long ms) {
+ mTime = mLastEventTime + ms;
+ Pair<PointerProperties[], PointerCoords[]> state = getFingerState();
+ MotionEvent event = MotionEvent.obtain(
+ mInitialTime,
+ mTime,
+ action,
+ state.first.length,
+ state.first,
+ state.second,
+ 0 /* metaState */,
+ 0 /* buttonState */,
+ 1.0f /* xPrecision */,
+ 1.0f /* yPrecision */,
+ DEVICE_ID,
+ 0 /* edgeFlags */,
+ InputDevice.SOURCE_TOUCHSCREEN,
+ 0 /* flags */);
+ mListener.onTouchEvent(event);
+ if (action == MotionEvent.ACTION_UP) {
+ resetTime();
+ }
+ event.recycle();
+ mLastEventTime = mTime;
+ }
+
+ /**
+ * Returns the description of the fingers' state expected by MotionEvent.
+ */
+ private Pair<PointerProperties[], PointerCoords[]> getFingerState() {
+ int nFingers = mFingers.size();
+ PointerProperties[] properties = new PointerProperties[nFingers];
+ PointerCoords[] coordinates = new PointerCoords[nFingers];
+
+ int index = 0;
+ for (Map.Entry<Integer, Point> entry : mFingers.entrySet()) {
+ int id = entry.getKey();
+ Point location = entry.getValue();
+
+ PointerProperties property = new PointerProperties();
+ property.id = id;
+ property.toolType = MotionEvent.TOOL_TYPE_FINGER;
+ properties[index] = property;
+
+ PointerCoords coordinate = new PointerCoords();
+ coordinate.x = location.x;
+ coordinate.y = location.y;
+ coordinate.pressure = 1.0f;
+ coordinates[index] = coordinate;
+
+ index++;
+ }
+
+ return new Pair<MotionEvent.PointerProperties[], MotionEvent.PointerCoords[]>(
+ properties, coordinates);
+ }
+
+ /**
+ * Resets the time references for a new sequence.
+ */
+ private void resetTime() {
+ mInitialTime = 0L;
+ mLastEventTime = -1L;
+ mTime = 0L;
+ }
+}
diff --git a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
new file mode 100644
index 000000000..ff83131d1
--- /dev/null
+++ b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.touch;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.testcomponent.TouchEventGenerator;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SwipeDetectorTest {
+
+ private static final String TAG = SwipeDetectorTest.class.getSimpleName();
+ public static void L(String s, Object... parts) {
+ Log.d(TAG, (parts.length == 0) ? s : String.format(s, parts));
+ }
+
+ private TouchEventGenerator mGenerator;
+ private SwipeDetector mDetector;
+ private int mTouchSlop;
+
+ @Mock
+ private SwipeDetector.Listener mMockListener;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mGenerator = new TouchEventGenerator(new TouchEventGenerator.Listener() {
+ @Override
+ public void onTouchEvent(MotionEvent event) {
+ mDetector.onTouchEvent(event);
+ }
+ });
+
+ mDetector = new SwipeDetector(mTouchSlop, mMockListener, SwipeDetector.VERTICAL);
+ mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false);
+ mTouchSlop = ViewConfiguration.get(InstrumentationRegistry.getTargetContext())
+ .getScaledTouchSlop();
+ L("mTouchSlop=", mTouchSlop);
+ }
+
+ @Test
+ public void testDragStart_vertical() throws Exception {
+ mGenerator.put(0, 100, 100);
+ mGenerator.move(0, 100, 100 + mTouchSlop);
+ // TODO: actually calculate the following parameters and do exact value checks.
+ verify(mMockListener).onDragStart(anyBoolean());
+ }
+
+ @Test
+ public void testDragStart_failed() throws Exception {
+ mGenerator.put(0, 100, 100);
+ mGenerator.move(0, 100 + mTouchSlop, 100);
+ // TODO: actually calculate the following parameters and do exact value checks.
+ verify(mMockListener, never()).onDragStart(anyBoolean());
+ }
+
+ @Test
+ public void testDragStart_horizontal() throws Exception {
+ mDetector = new SwipeDetector(mTouchSlop, mMockListener, SwipeDetector.HORIZONTAL);
+ mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false);
+
+ mGenerator.put(0, 100, 100);
+ mGenerator.move(0, 100 + mTouchSlop, 100);
+ // TODO: actually calculate the following parameters and do exact value checks.
+ verify(mMockListener).onDragStart(anyBoolean());
+ }
+
+ @Test
+ public void testDrag() throws Exception {
+ 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());
+ }
+
+ @Test
+ public void testDragEnd() throws Exception {
+ mGenerator.put(0, 100, 100);
+ mGenerator.move(0, 100, 100 + mTouchSlop);
+ mGenerator.move(0, 100, 100 + mTouchSlop * 2);
+ mGenerator.lift(0);
+ // TODO: actually calculate the following parameters and do exact value checks.
+ verify(mMockListener).onDragEnd(anyFloat(), anyBoolean());
+ }
+}
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 97f7b505a..221fed1fc 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -28,6 +28,7 @@ import android.support.test.uiautomator.UiSelector;
import android.test.suitebuilder.annotation.LargeTest;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetHost;
import com.android.launcher3.LauncherAppWidgetHostView;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
@@ -285,7 +286,7 @@ public class BindWidgetTest extends LauncherInstrumentationTestCase {
pendingInfo.minSpanY = item.minSpanY;
Bundle options = WidgetHostViewLoader.getDefaultOptionsForWidget(mTargetContext, pendingInfo);
- AppWidgetHost host = new AppWidgetHost(mTargetContext, Launcher.APPWIDGET_HOST_ID);
+ AppWidgetHost host = new LauncherAppWidgetHost(mTargetContext);
int widgetId = host.allocateAppWidgetId();
if (!mWidgetManager.bindAppWidgetIdIfAllowed(widgetId, info, options)) {
host.deleteAppWidgetId(widgetId);