diff options
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 & hold to pick up a shortcut."</string> + <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap & hold to pick up a shortcut or use custom actions."</string> + <string name="widget_button_text" msgid="4221900832360456858">"Shortcuts"</string> + <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shortcuts"</string> +</resources> diff --git a/go/res/values-en-rGB/strings.xml b/go/res/values-en-rGB/strings.xml 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 & hold to pick up a shortcut."</string> + <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap & hold to pick up a shortcut or use custom actions."</string> + <string name="widget_button_text" msgid="4221900832360456858">"Shortcuts"</string> + <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shortcuts"</string> +</resources> diff --git a/go/res/values-en-rIN/strings.xml b/go/res/values-en-rIN/strings.xml 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 & hold to pick up a shortcut."</string> + <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap & hold to pick up a shortcut or use custom actions."</string> + <string name="widget_button_text" msgid="4221900832360456858">"Shortcuts"</string> + <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shortcuts"</string> +</resources> diff --git a/go/res/values-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 & 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 & hold to pick up a shortcut.</string> + <!-- Accessibility spoken hint message in widget picker, which allows user to add a shortcut. Custom action is the label for additional accessibility actions available in this mode [CHAR_LIMIT=100] --> + <string name="long_accessible_way_to_add">Double-tap & hold to pick up a shortcut or use custom actions.</string> + <!-- Text for shortcut add button --> + <string name="widget_button_text">Shortcuts</string> + + <!-- Strings for widgets & more in the popup container/bottom sheet --> + <!-- Title for a bottom sheet that shows shortcuts for a particular app --> + <string name="widgets_bottom_sheet_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> shortcuts</string> + +</resources> diff --git a/go/src_flags/com/android/launcher3/config/FeatureFlags.java b/go/src_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 Binary files differdeleted file mode 100644 index ed53ff924..000000000 --- a/res/drawable/all_apps_alpha_mask.png +++ /dev/null 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 & 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 & 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 & 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 & 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…</string> + <string name="all_apps_loading_message">Loading apps…</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); |