Merge "Merge Android 12"
This commit is contained in:
+181
-4
@@ -16,6 +16,8 @@ package {
|
||||
default_applicable_licenses: ["packages_apps_Launcher3_license"],
|
||||
}
|
||||
|
||||
min_launcher3_sdk_version = "26"
|
||||
|
||||
// Added automatically by a large-scale-change
|
||||
// See: http://go/android-license-faq
|
||||
license {
|
||||
@@ -36,14 +38,15 @@ android_library {
|
||||
"androidx.test.runner",
|
||||
"androidx.test.rules",
|
||||
"androidx.test.uiautomator_uiautomator",
|
||||
"androidx.preference_preference",
|
||||
"SystemUISharedLib",
|
||||
],
|
||||
srcs: [
|
||||
"tests/tapl/**/*.java",
|
||||
"src/com/android/launcher3/util/SecureSettingsObserver.java",
|
||||
"src/com/android/launcher3/ResourceUtils.java",
|
||||
"src/com/android/launcher3/testing/TestProtocol.java",
|
||||
],
|
||||
resource_dirs: [ ],
|
||||
manifest: "tests/tapl/AndroidManifest.xml",
|
||||
platform_apis: true,
|
||||
}
|
||||
@@ -52,19 +55,37 @@ java_library_static {
|
||||
name: "launcher_log_protos_lite",
|
||||
srcs: [
|
||||
"protos/*.proto",
|
||||
"proto_overrides/*.proto",
|
||||
"protos_overrides/*.proto",
|
||||
],
|
||||
sdk_version: "current",
|
||||
proto: {
|
||||
type: "lite",
|
||||
local_include_dirs:[
|
||||
"protos",
|
||||
"proto_overrides",
|
||||
"protos_overrides",
|
||||
],
|
||||
},
|
||||
static_libs: ["libprotobuf-java-lite"],
|
||||
}
|
||||
|
||||
java_library_static {
|
||||
name: "launcher_quickstep_log_protos_lite",
|
||||
srcs: [
|
||||
"quickstep/protos_overrides/*.proto",
|
||||
],
|
||||
sdk_version: "current",
|
||||
proto: {
|
||||
type: "lite",
|
||||
local_include_dirs:[
|
||||
"quickstep/protos_overrides",
|
||||
],
|
||||
},
|
||||
static_libs: [
|
||||
"libprotobuf-java-lite",
|
||||
"launcher_log_protos_lite"
|
||||
],
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "LauncherPluginLib",
|
||||
|
||||
@@ -73,5 +94,161 @@ java_library {
|
||||
srcs: ["src_plugins/**/*.java"],
|
||||
|
||||
sdk_version: "current",
|
||||
min_sdk_version: "28",
|
||||
min_sdk_version: min_launcher3_sdk_version,
|
||||
}
|
||||
|
||||
// Library with all the dependencies for building Launcher3
|
||||
android_library {
|
||||
name: "Launcher3ResLib",
|
||||
srcs: [ ],
|
||||
resource_dirs: ["res"],
|
||||
static_libs: [
|
||||
"LauncherPluginLib",
|
||||
"launcher_quickstep_log_protos_lite",
|
||||
"androidx-constraintlayout_constraintlayout",
|
||||
"androidx.recyclerview_recyclerview",
|
||||
"androidx.dynamicanimation_dynamicanimation",
|
||||
"androidx.fragment_fragment",
|
||||
"androidx.preference_preference",
|
||||
"androidx.slice_slice-view",
|
||||
"androidx.cardview_cardview",
|
||||
"iconloader_base",
|
||||
],
|
||||
manifest: "AndroidManifest-common.xml",
|
||||
sdk_version: "current",
|
||||
min_sdk_version: min_launcher3_sdk_version,
|
||||
lint: {
|
||||
baseline_filename: "lint-baseline-res-lib.xml",
|
||||
},
|
||||
}
|
||||
|
||||
//
|
||||
// Build rule for Launcher3 dependencies lib.
|
||||
//
|
||||
android_library {
|
||||
name: "Launcher3CommonDepsLib",
|
||||
srcs: ["src_build_config/**/*.java"],
|
||||
static_libs: ["Launcher3ResLib"],
|
||||
sdk_version: "current",
|
||||
min_sdk_version: min_launcher3_sdk_version,
|
||||
manifest: "AndroidManifest-common.xml",
|
||||
lint: {
|
||||
baseline_filename: "lint-baseline-common-deps-lib.xml",
|
||||
},
|
||||
}
|
||||
|
||||
//
|
||||
// Build rule for Launcher3 app.
|
||||
//
|
||||
android_app {
|
||||
name: "Launcher3",
|
||||
|
||||
static_libs: [
|
||||
"Launcher3CommonDepsLib",
|
||||
],
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
"src_shortcuts_overrides/**/*.java",
|
||||
"src_ui_overrides/**/*.java",
|
||||
"ext_tests/src/**/*.java",
|
||||
],
|
||||
resource_dirs: [
|
||||
"ext_tests/res",
|
||||
],
|
||||
optimize: {
|
||||
proguard_flags_files: ["proguard.flags"],
|
||||
// Proguard is disable for testing. Derivarive prjects to keep proguard enabled
|
||||
enabled: false,
|
||||
},
|
||||
|
||||
sdk_version: "current",
|
||||
min_sdk_version: min_launcher3_sdk_version,
|
||||
target_sdk_version: "current",
|
||||
privileged: true,
|
||||
system_ext_specific: true,
|
||||
|
||||
overrides: [
|
||||
"Home",
|
||||
"Launcher2",
|
||||
],
|
||||
required: ["privapp_whitelist_com.android.launcher3"],
|
||||
|
||||
jacoco: {
|
||||
include_filter: ["com.android.launcher3.**"],
|
||||
},
|
||||
additional_manifests: [
|
||||
"AndroidManifest-common.xml",
|
||||
],
|
||||
lint: {
|
||||
baseline_filename: "lint-baseline-launcher3.xml",
|
||||
},
|
||||
}
|
||||
|
||||
// Library with all the dependencies for building quickstep
|
||||
android_library {
|
||||
name: "QuickstepResLib",
|
||||
srcs: [ ],
|
||||
resource_dirs: [
|
||||
"quickstep/res",
|
||||
],
|
||||
static_libs: [
|
||||
"Launcher3ResLib",
|
||||
"SystemUISharedLib",
|
||||
"SystemUI-statsd",
|
||||
],
|
||||
manifest: "quickstep/AndroidManifest.xml",
|
||||
min_sdk_version: "current",
|
||||
}
|
||||
|
||||
|
||||
// Source code used for test helpers
|
||||
filegroup {
|
||||
name: "launcher-src-ext-tests",
|
||||
srcs: ["ext_tests/src/**/*.java"],
|
||||
}
|
||||
|
||||
// Common source files used to build launcher
|
||||
filegroup {
|
||||
name: "launcher-src-no-build-config",
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
"src_shortcuts_overrides/**/*.java",
|
||||
"quickstep/src/**/*.java",
|
||||
],
|
||||
}
|
||||
|
||||
// Proguard files for Launcher3
|
||||
filegroup {
|
||||
name: "launcher-proguard-rules",
|
||||
srcs: ["proguard.flags"],
|
||||
}
|
||||
|
||||
|
||||
// Library with all the dependencies for building Launcher Go
|
||||
android_library {
|
||||
name: "LauncherGoResLib",
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
"quickstep/src/**/*.java",
|
||||
"go/src/**/*.java",
|
||||
"go/quickstep/src/**/*.java",
|
||||
],
|
||||
resource_dirs: [
|
||||
"go/res",
|
||||
"go/quickstep/res",
|
||||
],
|
||||
static_libs: [
|
||||
"Launcher3CommonDepsLib",
|
||||
"QuickstepResLib",
|
||||
],
|
||||
manifest: "quickstep/AndroidManifest-launcher.xml",
|
||||
additional_manifests: [
|
||||
"go/AndroidManifest.xml",
|
||||
"AndroidManifest-common.xml",
|
||||
],
|
||||
min_sdk_version: "current",
|
||||
lint: {
|
||||
baseline_filename: "lint-baseline-go-res-lib.xml",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+11
-100
@@ -16,86 +16,6 @@
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
#
|
||||
# Build rule for Launcher3 dependencies lib.
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_USE_AAPT2 := true
|
||||
LOCAL_AAPT2_ONLY := true
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_STATIC_ANDROID_LIBRARIES := \
|
||||
androidx.recyclerview_recyclerview \
|
||||
androidx.dynamicanimation_dynamicanimation \
|
||||
androidx.preference_preference \
|
||||
iconloader_base
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := \
|
||||
LauncherPluginLib \
|
||||
launcher_log_protos_lite
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(call all-proto-files-under, protos) \
|
||||
$(call all-proto-files-under, proto_overrides) \
|
||||
$(call all-java-files-under, src_build_config) \
|
||||
|
||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
|
||||
|
||||
LOCAL_PROGUARD_ENABLED := disabled
|
||||
|
||||
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_SDK_VERSION := current
|
||||
LOCAL_MIN_SDK_VERSION := 21
|
||||
LOCAL_MODULE := Launcher3CommonDepsLib
|
||||
LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
|
||||
LOCAL_LICENSE_CONDITIONS := notice
|
||||
LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
|
||||
LOCAL_PRIVILEGED_MODULE := true
|
||||
LOCAL_MANIFEST_FILE := AndroidManifest-common.xml
|
||||
|
||||
include $(BUILD_STATIC_JAVA_LIBRARY)
|
||||
|
||||
#
|
||||
# Build rule for Launcher3 app.
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_USE_AAPT2 := true
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(call all-java-files-under, src) \
|
||||
$(call all-java-files-under, src_shortcuts_overrides) \
|
||||
$(call all-java-files-under, src_ui_overrides) \
|
||||
$(call all-java-files-under, ext_tests/src)
|
||||
|
||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/ext_tests/res
|
||||
|
||||
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
|
||||
# Proguard is disable for testing. Derivarive prjects to keep proguard enabled
|
||||
LOCAL_PROGUARD_ENABLED := disabled
|
||||
|
||||
LOCAL_SDK_VERSION := current
|
||||
LOCAL_MIN_SDK_VERSION := 21
|
||||
LOCAL_PACKAGE_NAME := Launcher3
|
||||
LOCAL_PRIVILEGED_MODULE := true
|
||||
LOCAL_SYSTEM_EXT_MODULE := true
|
||||
LOCAL_OVERRIDES_PACKAGES := Home Launcher2
|
||||
LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.launcher3
|
||||
|
||||
LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest-common.xml
|
||||
|
||||
LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.launcher3.*
|
||||
|
||||
LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
|
||||
LOCAL_LICENSE_CONDITIONS := notice
|
||||
LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
#
|
||||
# Build rule for Launcher3 Go app for Android Go devices.
|
||||
#
|
||||
@@ -114,7 +34,7 @@ LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/go/res
|
||||
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
|
||||
|
||||
LOCAL_SDK_VERSION := current
|
||||
LOCAL_MIN_SDK_VERSION := 21
|
||||
LOCAL_MIN_SDK_VERSION := 26
|
||||
LOCAL_PACKAGE_NAME := Launcher3Go
|
||||
LOCAL_PRIVILEGED_MODULE := true
|
||||
LOCAL_SYSTEM_EXT_MODULE := true
|
||||
@@ -142,9 +62,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := \
|
||||
SystemUI-statsd \
|
||||
SystemUISharedLib \
|
||||
launcherprotosnano \
|
||||
launcher_log_protos_lite
|
||||
SystemUISharedLib
|
||||
ifneq (,$(wildcard frameworks/base))
|
||||
LOCAL_PRIVATE_PLATFORM_APIS := true
|
||||
else
|
||||
@@ -161,12 +79,9 @@ LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
|
||||
LOCAL_SRC_FILES := \
|
||||
$(call all-java-files-under, src) \
|
||||
$(call all-java-files-under, quickstep/src) \
|
||||
$(call all-java-files-under, quickstep/recents_ui_overrides/src) \
|
||||
$(call all-java-files-under, src_shortcuts_overrides)
|
||||
|
||||
LOCAL_RESOURCE_DIR := \
|
||||
$(LOCAL_PATH)/quickstep/res \
|
||||
$(LOCAL_PATH)/quickstep/recents_ui_overrides/res
|
||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
|
||||
LOCAL_PROGUARD_ENABLED := disabled
|
||||
|
||||
|
||||
@@ -195,9 +110,7 @@ LOCAL_SYSTEM_EXT_MODULE := true
|
||||
LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3
|
||||
LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.launcher3
|
||||
|
||||
LOCAL_RESOURCE_DIR := \
|
||||
$(LOCAL_PATH)/quickstep/res \
|
||||
$(LOCAL_PATH)/quickstep/recents_ui_overrides/res
|
||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
|
||||
|
||||
LOCAL_FULL_LIBS_MANIFEST_FILES := \
|
||||
$(LOCAL_PATH)/quickstep/AndroidManifest-launcher.xml \
|
||||
@@ -221,9 +134,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := \
|
||||
SystemUI-statsd \
|
||||
SystemUISharedLib \
|
||||
launcherprotosnano \
|
||||
launcher_log_protos_lite
|
||||
SystemUISharedLib
|
||||
ifneq (,$(wildcard frameworks/base))
|
||||
LOCAL_PRIVATE_PLATFORM_APIS := true
|
||||
else
|
||||
@@ -235,13 +146,13 @@ LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
|
||||
LOCAL_SRC_FILES := \
|
||||
$(call all-java-files-under, src) \
|
||||
$(call all-java-files-under, quickstep/src) \
|
||||
$(call all-java-files-under, quickstep/recents_ui_overrides/src) \
|
||||
$(call all-java-files-under, go/src)
|
||||
$(call all-java-files-under, go/src) \
|
||||
$(call all-java-files-under, go/quickstep/src)
|
||||
|
||||
LOCAL_RESOURCE_DIR := \
|
||||
$(LOCAL_PATH)/quickstep/res \
|
||||
$(LOCAL_PATH)/quickstep/recents_ui_overrides/res \
|
||||
$(LOCAL_PATH)/go/res
|
||||
$(LOCAL_PATH)/go/quickstep/res \
|
||||
$(LOCAL_PATH)/go/res \
|
||||
$(LOCAL_PATH)/quickstep/res
|
||||
|
||||
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
|
||||
LOCAL_PROGUARD_ENABLED := full
|
||||
@@ -254,7 +165,7 @@ LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.launcher3
|
||||
|
||||
LOCAL_FULL_LIBS_MANIFEST_FILES := \
|
||||
$(LOCAL_PATH)/go/AndroidManifest.xml \
|
||||
$(LOCAL_PATH)/quickstep/AndroidManifest-launcher.xml \
|
||||
$(LOCAL_PATH)/go/AndroidManifest-launcher.xml \
|
||||
$(LOCAL_PATH)/AndroidManifest-common.xml
|
||||
|
||||
LOCAL_MANIFEST_FILE := quickstep/AndroidManifest.xml
|
||||
|
||||
+19
-30
@@ -19,6 +19,7 @@
|
||||
-->
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.android.launcher3">
|
||||
|
||||
<!--
|
||||
@@ -29,13 +30,8 @@
|
||||
at compile time. Note that the components defined in AndroidManifest.xml are also required,
|
||||
with some minor changed based on the derivative app.
|
||||
-->
|
||||
<permission
|
||||
android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
|
||||
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
|
||||
android:protectionLevel="dangerous"
|
||||
android:label="@string/permlab_install_shortcut"
|
||||
android:description="@string/permdesc_install_shortcut" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.CALL_PHONE" />
|
||||
<uses-permission android:name="android.permission.SET_WALLPAPER" />
|
||||
<uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
|
||||
@@ -45,9 +41,8 @@
|
||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
||||
|
||||
<!-- TODO(b/150802536): Enabled only for ENABLE_FIXED_ROTATION_TRANSFORM feature flag -->
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
|
||||
<!-- for rotating surface by arbitrary degree -->
|
||||
<uses-permission android:name="android.permission.ROTATE_SURFACE_FLINGER" />
|
||||
|
||||
<!--
|
||||
Permissions required for read/write access to the workspace data. These permission name
|
||||
@@ -82,41 +77,27 @@
|
||||
android:restoreAnyVersion="true"
|
||||
android:supportsRtl="true" >
|
||||
|
||||
<!-- Intent received used to install shortcuts from other applications -->
|
||||
<receiver
|
||||
android:name="com.android.launcher3.InstallShortcutReceiver"
|
||||
android:permission="com.android.launcher.permission.INSTALL_SHORTCUT"
|
||||
android:enabled="@bool/enable_install_shortcut_api" >
|
||||
<intent-filter>
|
||||
<action android:name="com.android.launcher.action.INSTALL_SHORTCUT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- Intent received when a session is committed -->
|
||||
<receiver
|
||||
android:name="com.android.launcher3.SessionCommitReceiver" >
|
||||
android:name="com.android.launcher3.SessionCommitReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.content.pm.action.SESSION_COMMITTED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- Intent received used to initialize a restored widget -->
|
||||
<receiver android:name="com.android.launcher3.AppWidgetsRestoredReceiver" >
|
||||
<receiver android:name="com.android.launcher3.AppWidgetsRestoredReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_HOST_RESTORED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
|
||||
android:exported="false"
|
||||
android:process=":wallpaper_chooser"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
|
||||
<service
|
||||
android:name="com.android.launcher3.notification.NotificationListener"
|
||||
android:label="@string/notification_dots_service_title"
|
||||
android:enabled="@bool/notification_dots_enabled"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.notification.NotificationListenerService" />
|
||||
@@ -127,10 +108,10 @@
|
||||
android:value="true" />
|
||||
|
||||
<activity android:name="com.android.launcher3.dragndrop.AddItemActivity"
|
||||
android:theme="@style/AppItemActivityTheme"
|
||||
android:theme="@style/AddItemActivityTheme"
|
||||
android:excludeFromRecents="true"
|
||||
android:autoRemoveFromRecents="true"
|
||||
android:label="@string/action_add_to_workspace" >
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
|
||||
<action android:name="android.content.pm.action.CONFIRM_PIN_APPWIDGET" />
|
||||
@@ -165,6 +146,7 @@
|
||||
android:name="com.android.launcher3.settings.SettingsActivity"
|
||||
android:label="@string/settings_button_text"
|
||||
android:theme="@style/HomeSettingsTheme"
|
||||
android:exported="true"
|
||||
android:autoRemoveFromRecents="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
||||
@@ -187,6 +169,7 @@
|
||||
android:name="com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher"
|
||||
android:theme="@style/AppTheme"
|
||||
android:launchMode="singleTop"
|
||||
android:exported="true"
|
||||
android:enabled="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@@ -194,5 +177,11 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- [b/197780098] Disable eager initialization of Jetpack libraries. -->
|
||||
<provider
|
||||
android:name="androidx.startup.InitializationProvider"
|
||||
android:authorities="${applicationId}.androidx-startup"
|
||||
tools:node="remove" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
+3
-2
@@ -20,7 +20,7 @@
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.launcher3">
|
||||
<uses-sdk android:targetSdkVersion="29" android:minSdkVersion="25"/>
|
||||
<uses-sdk android:targetSdkVersion="30" android:minSdkVersion="26"/>
|
||||
<!--
|
||||
Manifest entries specific to Launcher3. This is merged with AndroidManifest-common.xml.
|
||||
Refer comments around specific entries on how to extend individual components.
|
||||
@@ -49,10 +49,11 @@
|
||||
android:stateNotNeeded="true"
|
||||
android:windowSoftInputMode="adjustPan"
|
||||
android:screenOrientation="unspecified"
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density"
|
||||
android:resizeableActivity="true"
|
||||
android:resumeWhilePausing="true"
|
||||
android:taskAffinity=""
|
||||
android:exported="true"
|
||||
android:enabled="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
@@ -38,6 +38,7 @@ tracyzhou@google.com
|
||||
peanutbutter@google.com
|
||||
xuqiu@google.com
|
||||
sreyasr@google.com
|
||||
thiruram@google.com
|
||||
|
||||
per-file FeatureFlags.java, globs = set noparent
|
||||
per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, zakcohen@google.com, mrcasey@google.com, adamcohen@google.com, hyunyoungs@google.com
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
apply plugin: 'java'
|
||||
|
||||
final String ANDROID_TOP = "${rootDir}/../../.."
|
||||
final String FRAMEWORK_PREBUILTS_DIR = "${ANDROID_TOP}/prebuilts/framework_intermediates/"
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.srcDirs = ["${ANDROID_TOP}/frameworks/lib/systemui/SharedLibWrapper/src"]
|
||||
}
|
||||
}
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/quickstep/libs", include: 'sysui_shared.jar')
|
||||
compileOnly fileTree(dir: "$ANDROID_TOP/prebuilts/fullsdk-${org.gradle.internal.os.OperatingSystem.current().isMacOsX() ? "darwin" : "linux"}/platforms/${COMPILE_SDK}", include: 'android.jar')
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
171450807
|
||||
170675311
|
||||
170338029
|
||||
170338170
|
||||
160544577
|
||||
171171594
|
||||
170488559
|
||||
171131394
|
||||
171131394
|
||||
171026321
|
||||
170648272
|
||||
170752716
|
||||
170611866
|
||||
170702596
|
||||
170487752
|
||||
170665892
|
||||
168608912
|
||||
170636685
|
||||
169771796
|
||||
141126144
|
||||
166614700
|
||||
168805872
|
||||
170263425
|
||||
169221288
|
||||
143965596
|
||||
169221287
|
||||
167259591
|
||||
156044202
|
||||
169438169
|
||||
164926736
|
||||
168653219
|
||||
169963211
|
||||
170121063
|
||||
169988381
|
||||
169980192
|
||||
169221288
|
||||
169385783
|
||||
168167693
|
||||
169796517
|
||||
169330678
|
||||
168818961
|
||||
168608912
|
||||
@@ -0,0 +1,39 @@
|
||||
141126144
|
||||
143965596
|
||||
156044202
|
||||
160544577
|
||||
164926736
|
||||
166614700
|
||||
167259591
|
||||
168167693
|
||||
168608912
|
||||
168653219
|
||||
168805872
|
||||
168818961
|
||||
169221287
|
||||
169221288
|
||||
169330678
|
||||
169385783
|
||||
169438169
|
||||
169771796
|
||||
169796517
|
||||
169963211
|
||||
169980192
|
||||
169988381
|
||||
170121063
|
||||
170263425
|
||||
170338029
|
||||
170338170
|
||||
170487752
|
||||
170488559
|
||||
170611866
|
||||
170636685
|
||||
170648272
|
||||
170665892
|
||||
170675311
|
||||
170702596
|
||||
170752716
|
||||
171026321
|
||||
171131394
|
||||
171171594
|
||||
171450807
|
||||
@@ -0,0 +1,24 @@
|
||||
144170434 twickham P1 FIXED Improve Overview -> Home transition ----
|
||||
149934536 twickham P2 FIXED Update gesture nav pullback logic ----
|
||||
154951045 peanutbutter P1 FIXED Odd animation occuring at times when swiping to home ----
|
||||
154964045 awickham P2 FIXED "Clear all" text is not in the middle of app's window vertically ----
|
||||
158701272 twickham P4 FIXED Discontinuities when long-swiping to home ----
|
||||
160361464 tracyzhou P2 FIXED Place launcher above the target app in live tile mode ----
|
||||
160568387 twickham P2 FIXED Can't get to app switcher by swiping up (motion pause not detected) ----
|
||||
160718310 xuqiu P1 FIXED With "Select" overview action selected, App icon is missing in other overview apps after orientation change ----
|
||||
160748731 sunnygoyal P2 ASSIGNED Unify prediction model with Launcher model ----
|
||||
160759508 twickham P2 FIXED Swipe up cannot back to home screen in overview. ----
|
||||
161273376 xuqiu P2 FIXED [Overview Actions] Add logging and helpful messages ----
|
||||
161536946 twickham P2 FIXED Haptics don't indicate snap-to in overview, ----
|
||||
161685099 winsonc P2 FIXED Screen still stay at the quick settings/notification when I swipe up with 3 finger to check the all apps. ----
|
||||
161801331 hyunyoungs P2 FIXED Change AllAppsSearch plugin to support only data fetch ----
|
||||
161901771 xuqiu P1 FIXED Overlapping layer of highlights with app layout getting darker when keep rotating the device from "Feedback" viewpoint in split screen ----
|
||||
161939759 sunnygoyal P2 FIXED RD1A: Going to overview in landscape mode clips the screen content ----
|
||||
162012217 perumaal P2 ASSIGNED Leaked Activity Caused by Gleams ----
|
||||
162454040 bookatz P2 ASSIGNED Create multiuser test that checks that opening an app works properly ----
|
||||
162480567 sfufa P4 FIXED Enable Item Decorations for search items ----
|
||||
162564471 tracyzhou P2 FIXED [Live tile] Handle tapping overview actions in live tile mode ----
|
||||
162623012 zakcohen P1 ASSIGNED Enable chips flag ----
|
||||
162812884 winsonc P2 ASSIGNED [R]The color have not changed in some page after turning on the dark theme. ----
|
||||
162861289 hyunyoungs P2 FIXED Add FocusIndicator support to DEVICE_SEARCH feature in S ----
|
||||
162871508 sfufa P2 ASSIGNED Introduce support for Hero app section ----
|
||||
+11
-17
@@ -21,8 +21,8 @@ android {
|
||||
buildToolsVersion BUILD_TOOLS_VERSION
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 25
|
||||
targetSdkVersion 28
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
@@ -81,8 +81,7 @@ android {
|
||||
java.srcDirs = ['src', 'src_plugins']
|
||||
manifest.srcFile 'AndroidManifest-common.xml'
|
||||
proto {
|
||||
srcDir 'protos/'
|
||||
srcDir 'proto_overrides/'
|
||||
srcDirs = ['protos/', 'protos_overrides/']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +149,6 @@ dependencies {
|
||||
implementation "androidx.preference:preference:${ANDROID_X_VERSION}"
|
||||
implementation project(':IconLoader')
|
||||
withQuickstepImplementation project(':SharedLibWrapper')
|
||||
implementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/libs", include: 'launcher_protos.jar')
|
||||
|
||||
// Recents lib dependency
|
||||
withQuickstepImplementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/quickstep/libs", include: 'sysui_shared.jar')
|
||||
@@ -171,18 +169,14 @@ dependencies {
|
||||
protobuf {
|
||||
// Configure the protoc executable
|
||||
protoc {
|
||||
artifact = 'com.google.protobuf:protoc:3.0.0'
|
||||
|
||||
generateProtoTasks {
|
||||
all().each { task ->
|
||||
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"
|
||||
}
|
||||
artifact = "com.google.protobuf:protoc:${protocVersion}"
|
||||
}
|
||||
generateProtoTasks {
|
||||
all().each { task ->
|
||||
task.builtins {
|
||||
remove java
|
||||
java {
|
||||
option "lite"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+934
@@ -0,0 +1,934 @@
|
||||
[34mCOMMAND>> git log f99351888c3e5a128559678304fefd647472bc7f..4c3952dc60fc78d3816012a86d7e71747ef34c74[m
|
||||
commit 4c3952dc60fc78d3816012a86d7e71747ef34c74
|
||||
Merge: cb403d9e5 70e8b1572
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Fri Oct 23 00:27:39 2020 +0000
|
||||
|
||||
Merge "Minor stylistic changes in Workspace.java." into ub-launcher3-master
|
||||
|
||||
commit cb403d9e5235c7323bc2fdffe6a264d17bb6d0a6
|
||||
Author: Pinyao Ting <pinyaoting@google.com>
|
||||
Date: Thu Oct 22 16:07:08 2020 -0700
|
||||
|
||||
flip default value of minimal device feature flag
|
||||
|
||||
Test: manual
|
||||
Change-Id: Iaf46dffb935bdf4b46e7c57d547bdc697250ec56
|
||||
|
||||
commit a97557a15eb111616d868120a9f4659f1b451fa2
|
||||
Merge: f5ce80b8a 932a327eb
|
||||
Author: Tracy Zhou <tracyzhou@google.com>
|
||||
Date: Thu Oct 22 18:22:56 2020 +0000
|
||||
|
||||
Merge "Consider overscroll adjustment of RecentsView for live tile" into ub-launcher3-master
|
||||
|
||||
commit 932a327ebf0587b8324b9fea7d31328b2f6719a8
|
||||
Author: Tracy Zhou <tracyzhou@google.com>
|
||||
Date: Wed Oct 21 23:29:00 2020 -0700
|
||||
|
||||
Consider overscroll adjustment of RecentsView for live tile
|
||||
|
||||
Fixes: 171450807
|
||||
Test: manual
|
||||
Change-Id: I83eebf1f6b61c67f289db51aabe5a971815d0df1
|
||||
|
||||
commit f5ce80b8a0a1636fc8159475177a07b281492c88
|
||||
Author: Hilary Huo <hhuo@google.com>
|
||||
Date: Wed Oct 14 16:35:55 2020 -0700
|
||||
|
||||
[pixel-search] Latency analysis, add logging statement in launcher
|
||||
|
||||
Bug: b/170675311
|
||||
Change-Id: I229ace399085bea1c3f9535eb713edd329dff8bd
|
||||
|
||||
commit 31b03941ef3aa17edc08c1b509d4fa23766f2d2c
|
||||
Merge: e0a50c9e3 0731273d5
|
||||
Author: Tracy Zhou <tracyzhou@google.com>
|
||||
Date: Wed Oct 21 20:03:57 2020 +0000
|
||||
|
||||
Merge "Track live tile better by considering resistance animation" into ub-launcher3-master
|
||||
|
||||
commit 0731273d5409149fca32dfb2ad76eab45f6ea79a
|
||||
Author: Tracy Zhou <tracyzhou@google.com>
|
||||
Date: Wed Oct 21 12:03:40 2020 -0700
|
||||
|
||||
Track live tile better by considering resistance animation
|
||||
|
||||
Fixes: 170338029
|
||||
Test: Manual
|
||||
Change-Id: I66536bae567aa94385d5e0352cec9d46d512927a
|
||||
|
||||
commit e0a50c9e3f1d4b9f113d6afae01ff2c4ed452fba
|
||||
Merge: d2c27a595 acfac6187
|
||||
Author: Alex Chau <alexchau@google.com>
|
||||
Date: Wed Oct 21 17:02:57 2020 +0000
|
||||
|
||||
Merge "Use Diplay.getMetrics in DisplayController" into ub-launcher3-master
|
||||
|
||||
commit d2c27a595065d43bbea37dd2a512d37080f5233e
|
||||
Merge: ff8febabb 8b488ccc2
|
||||
Author: Tracy Zhou <tracyzhou@google.com>
|
||||
Date: Wed Oct 21 07:19:48 2020 +0000
|
||||
|
||||
Merge "[Live Tile] Support launching running task animation" into ub-launcher3-master
|
||||
|
||||
commit 8b488ccc2e433a708c8b06f0b6866f2a305e4b0a
|
||||
Author: Tracy Zhou <tracyzhou@google.com>
|
||||
Date: Wed Oct 14 12:13:04 2020 -0700
|
||||
|
||||
[Live Tile] Support launching running task animation
|
||||
|
||||
Fixes: 170338170
|
||||
Test: manual
|
||||
Change-Id: I2526b7cfbacaea7899b8e2ed233f913630071d36
|
||||
|
||||
commit 70e8b157219e9090ba5e47fdfa51b2b92e98449d
|
||||
Author: Andy Wickham <awickham@google.com>
|
||||
Date: Wed Oct 7 23:00:06 2020 -0700
|
||||
|
||||
Minor stylistic changes in Workspace.java.
|
||||
|
||||
Change-Id: Ib07611f27cbc427d11abccd8b74ea144485752f7
|
||||
|
||||
commit acfac6187dd9d13d55b566a77a5da867a1813573
|
||||
Author: Alex Chau <alexchau@google.com>
|
||||
Date: Mon Oct 19 18:00:39 2020 +0100
|
||||
|
||||
Use Diplay.getMetrics in DisplayController
|
||||
|
||||
- This is a workaround of b/163815566, where DisplayMetrics is stale
|
||||
when onDisplayChanged is called.
|
||||
- Instead of relying on stale DisplayConext, get the DisplayMetrics
|
||||
from the Display directly.
|
||||
- Also optimized how DisplayController.Info is created by passing in
|
||||
Display only
|
||||
- Use mDisplayContext.getDisplay directly if availalbe
|
||||
|
||||
Bug: 163815566, 160544577
|
||||
Test: DPI looks correct on device boot
|
||||
Change-Id: I2a7454bb8cf2073ce592e8662781b87fc998444f
|
||||
(cherry picked from commit 177c38243dc3bf245d1f7db3c265dfb56522f441)
|
||||
|
||||
commit ff8febabb039a3c27ee068f85119860a048b917c
|
||||
Merge: b03d2b416 102746823
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Tue Oct 20 17:46:09 2020 +0000
|
||||
|
||||
Merge "Makes Plugin Settings gear adjust to dark mode." into ub-launcher3-master
|
||||
|
||||
commit b03d2b41616d479ba360fa4f97e57722c7f57b8e
|
||||
Merge: fb79f5541 caa1e9c39
|
||||
Author: Hyunyoung Song <hyunyoungs@google.com>
|
||||
Date: Tue Oct 20 15:25:56 2020 +0000
|
||||
|
||||
Merge "Search query method should support multiple consumers" into ub-launcher3-master
|
||||
|
||||
commit fb79f5541dcbe587002756bb40a3c632d38cc25a
|
||||
Merge: f6b05068d cf0b275a4
|
||||
Author: Schneider Victor-tulias <victortulias@google.com>
|
||||
Date: Tue Oct 20 13:51:06 2020 +0000
|
||||
|
||||
Merge "Add the ability to specify a list of tutorial steps in the gesture sandbox tutorial intent." into ub-launcher3-master
|
||||
|
||||
commit f6b05068d901d4e989b2e107c06f9c7a6e7b113f
|
||||
Author: Hyunyoung Song <hyunyoungs@google.com>
|
||||
Date: Tue Oct 20 00:19:29 2020 -0700
|
||||
|
||||
Invert the badging
|
||||
|
||||
Bug: 171171594
|
||||
Change-Id: If84fdc03254105c843e16f39f479505b16e1cd5f
|
||||
|
||||
commit caa1e9c39978cb3b467b5ac441eb39b5e883fa2e
|
||||
Author: Hyunyoung Song <hyunyoungs@google.com>
|
||||
Date: Mon Oct 12 13:56:02 2020 -0700
|
||||
|
||||
Search query method should support multiple consumers
|
||||
|
||||
Bug: 170488559
|
||||
Change-Id: I64bef9523d3c3950c4ca3a4b9ce1d506d1672200
|
||||
|
||||
commit 10274682339bb60cb24c50536b4f48f921970f3c
|
||||
Author: Andy Wickham <awickham@google.com>
|
||||
Date: Mon Oct 19 19:06:52 2020 -0700
|
||||
|
||||
Makes Plugin Settings gear adjust to dark mode.
|
||||
|
||||
It wasn't visible in dark mode before because it was
|
||||
black on black. This makes it adjust automatically.
|
||||
|
||||
Change-Id: I5176cffc01842509ddafc4f30ff5029a0c4b8050
|
||||
|
||||
commit 744a0fbeae8efaa942d21c61e25012d86f5ff81e
|
||||
Merge: 29c79947e 71f24588c
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Mon Oct 19 22:17:26 2020 +0000
|
||||
|
||||
Merge "Call click event on IME quick select for SearchResultIcon" into ub-launcher3-master
|
||||
|
||||
commit 29c79947ecf82f662d02004ba9a7289017fc0783
|
||||
Merge: 13a2a010d a68ac3e5d
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Mon Oct 19 18:42:05 2020 +0000
|
||||
|
||||
Merge "Removing condition for CUJ tracing/metrics" into ub-launcher3-master
|
||||
|
||||
commit 71f24588c0a66449a0c68bcb360a8c671914ce75
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Mon Oct 19 10:19:31 2020 -0700
|
||||
|
||||
Call click event on IME quick select for SearchResultIcon
|
||||
|
||||
Bug: 171131394
|
||||
Change-Id: I8a703e8d0ca10570e3f774510610d3fb4c0eaab8
|
||||
|
||||
commit 13a2a010decd87eeaf8932430c692f587d2de165
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Sun Oct 18 21:19:57 2020 -0700
|
||||
|
||||
Handle IME event for SearchResultIcon
|
||||
|
||||
Bug: 171131394
|
||||
Test: Manual
|
||||
Change-Id: I2ed1c61053c78aaecc3324418229d69634a72ae4
|
||||
|
||||
commit 1f79eeda76246534697e92740defc7f73c3c8d14
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Fri Oct 16 02:01:31 2020 -0700
|
||||
|
||||
Remove hardcoded itemTypes from SearchTarget
|
||||
|
||||
- Introduces componentName and userHandle members to SearchTarget
|
||||
- SearchTargetEvent now has searchTarget member
|
||||
- Builder pattern for SearchTarget and SearchTargetEvent
|
||||
- Search backend should add headers manually instead of launcher inferring sections
|
||||
|
||||
Bug: 171026321
|
||||
Test: Manual
|
||||
Change-Id: I28e0455e82b925277a17703b9aa061c8f9f15262
|
||||
|
||||
commit a68ac3e5dd23095cea7c872c0ff1c5042d1695ba
|
||||
Author: vadimt <vadimt@google.com>
|
||||
Date: Fri Oct 16 10:48:28 2020 -0700
|
||||
|
||||
Removing condition for CUJ tracing/metrics
|
||||
|
||||
Is doesn't reflect whether jank monitors is collecting metrics,
|
||||
which will eventually be always true anyways.
|
||||
|
||||
Change-Id: Iaebdc838ed2b2cebd32c8c48d7e45bdd93f76fb4
|
||||
|
||||
commit 9228ff53c2fb26850b7bd92d86214a6aaebb11d3
|
||||
Author: Sunny Goyal <sunnygoyal@google.com>
|
||||
Date: Mon Oct 12 13:43:51 2020 -0700
|
||||
|
||||
Trimming activity and task label
|
||||
|
||||
Bug: 170648272
|
||||
Change-Id: Icd099acee65305e0aa0f98a2a301a0df8a27cf07
|
||||
|
||||
commit 7a09177e500a53205f9969bb6cbd4251d54e8fde
|
||||
Merge: 37ed5ead3 314761a80
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Thu Oct 15 22:36:14 2020 +0000
|
||||
|
||||
Merge "Setup SearchResultIcon for single cell results" into ub-launcher3-master
|
||||
|
||||
commit 37ed5ead391df5747003b2d3a345be0347362f19
|
||||
Merge: d5bbe6809 702ed2788
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Thu Oct 15 22:06:12 2020 +0000
|
||||
|
||||
Merge "Fix the issue where shortcuts are removed in minimal device mode" into ub-launcher3-master
|
||||
|
||||
commit 314761a80819a6e64a136161f51eebb0f0528c4d
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Wed Oct 14 10:15:07 2020 -0700
|
||||
|
||||
Setup SearchResultIcon for single cell results
|
||||
|
||||
SearchResultIcon will be able to render apps, shortcuts and remote actions. It can also handle its own focused state drawing.
|
||||
|
||||
Screenshot: https://screenshot.googleplex.com/C3KgjJtLQTBPgaf
|
||||
|
||||
Bug: 170752716
|
||||
Test: Manual
|
||||
Change-Id: I460a9c128ea3f5814784e342c5d5fa5b7e310882
|
||||
|
||||
commit 702ed2788678ac744c768aad6a6302e7cf91a26b
|
||||
Author: Pinyao Ting <pinyaoting@google.com>
|
||||
Date: Wed Oct 14 11:17:04 2020 -0700
|
||||
|
||||
Fix the issue where shortcuts are removed in minimal device mode
|
||||
|
||||
When loading the workspace, Launcher pins/unpins shortcuts in comply
|
||||
with the loaded workspace. Since minimal device mode creates a mostly
|
||||
empty workspace, existing shortcuts are getting unpinned as a result.
|
||||
|
||||
To mitigate the issue this CL compares the db name and only invoke
|
||||
sanitizeData when it matches the one defined in InvariantDeviceProfile.
|
||||
|
||||
Bug: 170611866
|
||||
Test: manual
|
||||
1. add some deep shortcut in workspace (e.g. long tap on chrome, drag
|
||||
"incognito tab" to workspace)
|
||||
2. opt-in to sunshine fishfood (g/sunshine-teamfood)
|
||||
3. enable bedtime mode with minimal device in Settings -> Digital
|
||||
Wellbeing -> Show Your Data -> Bedtime mode -> Customize -> minimal
|
||||
device
|
||||
4. toggle bedtime mode, wait for apps in minimal device to show, then
|
||||
toggle off bedtime mode
|
||||
5. verify the deep shortcut still exist
|
||||
|
||||
Change-Id: Ie18216ecb288e7481aa2404c4cb3ea418aee85cb
|
||||
|
||||
commit cf0b275a48d3c9f91a346f7fc24b9604f6dde25a
|
||||
Author: Schneider Victor-tulias <victortulias@google.com>
|
||||
Date: Tue Oct 6 09:33:40 2020 -0400
|
||||
|
||||
Add the ability to specify a list of tutorial steps in the gesture sandbox tutorial intent.
|
||||
|
||||
Added tutorial_steps string array in the intent to allow specifying an ordered list of tutorial steps.
|
||||
|
||||
Change-Id: Ic42a65598a74a64f8441a22f58c6cd988a5762e3
|
||||
|
||||
commit d5bbe6809dcc056fbfc307909b171651f0fb3044
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Wed Oct 14 15:39:38 2020 -0700
|
||||
|
||||
Rename shrotcut container to deep-shrotcuts
|
||||
|
||||
Change-Id: If94f0dfa447235f3b1a652f7b6c749695b42d97c
|
||||
|
||||
commit 26c1105fa04c2bcc156051e51df90a6a253349bb
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Tue Oct 13 01:12:03 2020 -0700
|
||||
|
||||
[search api part 1] Setup centralized SearchEventTracker
|
||||
|
||||
- Rename AdapterItemWIthPayload to SearchAdapterItem, PayloadResultHandler to SearchTargetHandler
|
||||
- Setup SliceViewWrapper for self contained slices
|
||||
|
||||
Bug: 170702596
|
||||
Change-Id: I0baf984ec8123c95011abcc17372f8d055e98ad7
|
||||
|
||||
commit 057f2d0d7df67e3680e479ac76b48b30d8bcf884
|
||||
Merge: 4bb65ff51 9a6145efb
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Tue Oct 13 01:57:47 2020 +0000
|
||||
|
||||
Merge "Introduce shortcut container for hotseat event reporting" into ub-launcher3-master
|
||||
|
||||
commit 4bb65ff516c6d9a429971ab7e04780792d5cb751
|
||||
Merge: 69740e62b 2afcab804
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Tue Oct 13 00:07:36 2020 +0000
|
||||
|
||||
Merge "Search UI clean up" into ub-launcher3-master
|
||||
|
||||
commit 2afcab804b638ff3b9da5bad40c8f70bdcaae78d
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Mon Oct 12 15:38:14 2020 -0700
|
||||
|
||||
Search UI clean up
|
||||
|
||||
- Resolve spacing issue when work profile is installed
|
||||
- Cache play icons and use icon shape
|
||||
- Only draw focus indicator for the first result
|
||||
|
||||
Bug: 170487752
|
||||
Bug: 170665892
|
||||
Change-Id: I864d2e796786637132e127ef9b418c0a76c74d6e
|
||||
|
||||
commit 69740e62be3800fc918648009645f7a8e52cb73d
|
||||
Merge: 2d7bfc878 979da64d8
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Mon Oct 12 20:53:29 2020 +0000
|
||||
|
||||
Merge "Add app start source info of apps launched from launcher" into ub-launcher3-master
|
||||
|
||||
commit 2d7bfc8782e9ed01178672aeb09ba2a6a07f4f4c
|
||||
Author: Jon Miranda <jonmiranda@google.com>
|
||||
Date: Mon Oct 12 12:09:22 2020 -0700
|
||||
|
||||
Fix shadowRadius not being used in swipe up animation.
|
||||
|
||||
Bug: 168608912
|
||||
Change-Id: I08f7bb057237e5061d5f1fc29afb488b204ee385
|
||||
|
||||
commit a433fe1fb34715efb38ed094f39da49fce8cd51e
|
||||
Merge: 2de606fe7 0471b9836
|
||||
Author: Sunny Goyal <sunnygoyal@google.com>
|
||||
Date: Mon Oct 12 18:08:35 2020 +0000
|
||||
|
||||
Merge "Using FrameCallbacks instead of windowCallbacks for surface removal" into ub-launcher3-master
|
||||
|
||||
commit 9a6145efb85f2bbdaccc07166a55e22c15fe27db
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Mon Oct 12 09:33:00 2020 -0700
|
||||
|
||||
Introduce shortcut container for hotseat event reporting
|
||||
|
||||
Bug: 170636685
|
||||
Test: Manual
|
||||
Change-Id: I5abeb17976bbafdc8cc74fb8b9a586d544c682fc
|
||||
|
||||
commit 2de606fe731573c081fd2d6ba166e21ea6aa2e9c
|
||||
Author: Yogisha Dixit <ydixit@google.com>
|
||||
Date: Mon Oct 12 15:36:07 2020 +0100
|
||||
|
||||
Delete the minimal database to force refresh.
|
||||
|
||||
Bug: 169771796
|
||||
Test: manual
|
||||
Change-Id: Ic2188bb162f295c208346861fddc137ace19ddcb
|
||||
|
||||
commit 0471b9836c9e382dc14bdc3abdf8502fb2b9f266
|
||||
Author: Sunny Goyal <sunnygoyal@google.com>
|
||||
Date: Wed Sep 23 13:54:37 2020 -0700
|
||||
|
||||
Using FrameCallbacks instead of windowCallbacks for surface removal
|
||||
|
||||
WindowCallbacks is called during the draw pass, before the frame has
|
||||
been sent to the surfaceFlinger. Frame callback will provide a closer
|
||||
approximation for when the frame is actually rendered on screen.
|
||||
|
||||
Bug: 141126144
|
||||
Change-Id: I62aab526c2ca24b00b5e7b312b36080f26c7b439
|
||||
|
||||
commit 2727434c44d06882925369bf4b43687a06be4a3f
|
||||
Merge: 59f532fe9 1b9e199b3
|
||||
Author: Schneider Victor-tulias <victortulias@google.com>
|
||||
Date: Fri Oct 9 20:09:08 2020 +0000
|
||||
|
||||
Merge "Fix hotseat and prediction row to allow updates when empty." into ub-launcher3-master
|
||||
|
||||
commit 59f532fe9e2b1817c094641f3c7c517f42e4faf0
|
||||
Merge: d2bfce71f b5334e3f0
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Fri Oct 9 19:52:54 2020 +0000
|
||||
|
||||
Merge "Improve search section header" into ub-launcher3-master
|
||||
|
||||
commit 979da64d8254599c332d83bf94f3f1fc3fe45fef
|
||||
Author: Riddle Hsu <riddlehsu@google.com>
|
||||
Date: Tue Sep 22 21:52:40 2020 +0800
|
||||
|
||||
Add app start source info of apps launched from launcher
|
||||
|
||||
Bug: 166614700
|
||||
Test: Enable statsd log: "adb shell cmd stats print-logs"
|
||||
adb logcat | grep statsd | grep "(48)"
|
||||
The line may contain 0x100000->1[I] 0x110000->10[I]
|
||||
that means 1=from launcher and 10=latency 10ms.
|
||||
Change-Id: Iddaff7066b66e241ba58ec87129ddbe2c531dc7e
|
||||
(cherry picked from commit 7bdf3574a3bff06a377b4364877687bfa7619d06)
|
||||
|
||||
commit d2bfce71f776fd05633dfd915dfc664309274677
|
||||
Merge: ed4530fed 222afb970
|
||||
Author: Winson Chung <winsonc@google.com>
|
||||
Date: Fri Oct 9 16:39:06 2020 +0000
|
||||
|
||||
Merge "Comply with the ISystemUiProxy.aidl change" into ub-launcher3-master
|
||||
|
||||
commit ed4530fedda0bf876f91d0745fc70d0f30d42991
|
||||
Merge: 692d2109a 9d4a96ed0
|
||||
Author: Winson Chung <winsonc@google.com>
|
||||
Date: Fri Oct 9 16:39:06 2020 +0000
|
||||
|
||||
Merge "Add latency metrics for recents gesture" into ub-launcher3-master
|
||||
|
||||
commit 1b9e199b3d9c81c793758d96bb03e0c51c1b3fb1
|
||||
Author: Schneider Victor-tulias <victortulias@google.com>
|
||||
Date: Thu Oct 8 15:50:22 2020 -0400
|
||||
|
||||
Fix hotseat and prediction row to allow updates when empty.
|
||||
|
||||
Rotating the screen in the homescreen empties the hotseat, however it does not get populated while it is visible to the user. The user should not be able to see an empty hotseat or prediction row if predictions are available. It should therefore be possible to populate these when they are empty even if they are visible to the user.
|
||||
|
||||
Change-Id: I8e5252bd29050c2cd9d443aedcb3f3e305c0e2d7
|
||||
|
||||
commit b5334e3f07f0561808a2d6e9bba55f1e3a89191e
|
||||
Author: Hyunyoung Song <hyunyoungs@google.com>
|
||||
Date: Fri Oct 9 00:50:48 2020 -0700
|
||||
|
||||
Improve search section header
|
||||
|
||||
Change-Id: I47cf207f0d0ab792c0e7a47c9d1185eec087ec88
|
||||
|
||||
commit 692d2109a6702706d24b3b819d115882f7362509
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Thu Oct 8 18:42:48 2020 -0700
|
||||
|
||||
invalidate itemDecoration on predictedRow focus draw
|
||||
|
||||
Change-Id: I66c731f00ae1c1292c51ff281957f05fd2d70dfa
|
||||
|
||||
commit 8d5b118060bff7f7518a9a14c0be5d265621f14c
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Thu Oct 8 13:11:25 2020 -0700
|
||||
|
||||
Revert PredictionRow shuoldDraw check
|
||||
|
||||
+ Show Rounded play result icons
|
||||
|
||||
Bug: 168805872
|
||||
Test: Manual
|
||||
Change-Id: I663c7f7ca1f1ac072e5e9c441deabef7c3fbd97b
|
||||
|
||||
commit 86f8df6cf954ac27ab092b9ef8a4db3c9979c4cb
|
||||
Merge: 4d19854b2 16045060c
|
||||
Author: Hilary Huo <hhuo@google.com>
|
||||
Date: Thu Oct 8 18:43:51 2020 +0000
|
||||
|
||||
Merge "[pixel-search] add escape hatch" into ub-launcher3-master
|
||||
|
||||
commit 4d19854b25a54599fe9b0ac8be9d60cf6c21d7ba
|
||||
Merge: 0827e1e32 ab9ad20be
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Thu Oct 8 18:40:56 2020 +0000
|
||||
|
||||
Merge "Search UI cleanup" into ub-launcher3-master
|
||||
|
||||
commit 16045060c35639aea85afc572bea768d16e6c9f9
|
||||
Author: Hilary Huo <hhuo@google.com>
|
||||
Date: Thu Oct 8 10:18:41 2020 -0700
|
||||
|
||||
[pixel-search] add escape hatch
|
||||
|
||||
Change-Id: I33ffea1fc0859564955380d7d1db317293d1a2cb
|
||||
|
||||
commit 0827e1e32a5f99fa02418dae37270c6db8c989d2
|
||||
Merge: 3463f0a87 68d7a6e5b
|
||||
Author: Andy Wickham <awickham@google.com>
|
||||
Date: Thu Oct 8 16:53:29 2020 +0000
|
||||
|
||||
Merge "Adds feature flag for BC Smartspace." into ub-launcher3-master
|
||||
|
||||
commit ab9ad20be600d1cbdc6b54a491d5fbb4c2cf9c16
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Wed Oct 7 15:18:24 2020 -0700
|
||||
|
||||
Search UI cleanup
|
||||
|
||||
- offset all apps header padding with search input margin
|
||||
- avoid check shouldDraw check on HeaderRow. (race condition)
|
||||
|
||||
Bug: 170263425
|
||||
Change-Id: I11a1fbb448aa6afd18ec0984af9bb8b1d7600f69
|
||||
|
||||
commit 68d7a6e5b28af8cc55bdae7efc24cc7ebee81257
|
||||
Author: Andy Wickham <awickham@google.com>
|
||||
Date: Wed Oct 7 14:27:17 2020 -0700
|
||||
|
||||
Adds feature flag for BC Smartspace.
|
||||
|
||||
Change-Id: Iaf9fb7507d0ccd004a4e00188c75dadd6a059246
|
||||
|
||||
commit 3463f0a876ff486ce03e160134e0504158271a92
|
||||
Merge: 2470d812a 4b7f38b8f
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Wed Oct 7 20:09:04 2020 +0000
|
||||
|
||||
Merge "Align fallback result query with result text" into ub-launcher3-master
|
||||
|
||||
commit 2470d812a1ae989e67781e5056b534ad9a960819
|
||||
Merge: cae7d74d8 7a6e4c931
|
||||
Author: Vadim Tryshev <vadimt@google.com>
|
||||
Date: Wed Oct 7 20:04:09 2020 +0000
|
||||
|
||||
Merge "Annotating Quick Switch CUJ for 3-button mode" into ub-launcher3-master
|
||||
|
||||
commit cae7d74d898769727105850ea5473c2c0ae25fdb
|
||||
Merge: e9bf2bd14 1fddddb4f
|
||||
Author: Tony Wickham <twickham@google.com>
|
||||
Date: Wed Oct 7 18:32:48 2020 +0000
|
||||
|
||||
Merge "Update launcher_trace.proto for quick switch" into ub-launcher3-master
|
||||
|
||||
commit 7a6e4c931f13b369bfa4328196b4632d6d848a19
|
||||
Author: vadimt <vadimt@google.com>
|
||||
Date: Tue Oct 6 14:09:16 2020 -0700
|
||||
|
||||
Annotating Quick Switch CUJ for 3-button mode
|
||||
|
||||
Bug: 169221288
|
||||
Change-Id: Ief62345fe6004dde699f44aa0c90329b7cd84e8b
|
||||
|
||||
commit 4b7f38b8fa004b514244304fcc07ff514a2fa46b
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Tue Oct 6 18:37:46 2020 -0700
|
||||
|
||||
Align fallback result query with result text
|
||||
|
||||
screenshot: https://screenshot.googleplex.com/6Daj5vdmz2jmznX
|
||||
bug: 169438169
|
||||
test: Manual
|
||||
Change-Id: Ie621ed3c834aec5e9467607da4f685d05d152183
|
||||
|
||||
commit 222afb970434c7972589adfc509bd2c256ca6556
|
||||
Author: Hongwei Wang <hwwang@google.com>
|
||||
Date: Fri Oct 2 13:51:36 2020 -0700
|
||||
|
||||
Comply with the ISystemUiProxy.aidl change
|
||||
|
||||
Two methods are added to support communications between Launcher and
|
||||
SysUI when user swipes an auto PiP-able Activity to home.
|
||||
|
||||
Bug: 143965596
|
||||
Test: N/A
|
||||
Change-Id: I2c73a287a094e882bde3cd71c27f9f66ae20e64a
|
||||
(cherry picked from commit 88ddae38db924f700082a113670ce5a719116a95)
|
||||
|
||||
commit 9d4a96ed029fdad1e369d5eedd082938f0dc9e01
|
||||
Author: Riddle Hsu <riddlehsu@google.com>
|
||||
Date: Wed Sep 30 00:32:04 2020 +0800
|
||||
|
||||
Add latency metrics for recents gesture
|
||||
|
||||
Pass the touch down time to RecentsAnimation#startRecentsActivity.
|
||||
|
||||
Bug: 169221287
|
||||
Test: Enable statsd log: "adb shell cmd stats print-logs"
|
||||
Touch gesture navigation bar.
|
||||
adb logcat | grep statsd | grep "(48)"
|
||||
The line may contain 0x100000->4[I] 0x110000->20[I]
|
||||
that means 4=by recents and 20=latency 20ms.
|
||||
Change-Id: I81ee804895b7712f4d925736f5b4694c11a12cbe
|
||||
(cherry picked from commit 63623967b83edad56db58173ebb6687c685b9177)
|
||||
|
||||
commit e9bf2bd14c9a7a48f8f93687932d41b1418cf4e4
|
||||
Merge: 73ae75474 d028937e7
|
||||
Author: Tracy Zhou <tracyzhou@google.com>
|
||||
Date: Wed Oct 7 02:19:04 2020 +0000
|
||||
|
||||
Merge "[Live tile] Finish recents animation when the phone goes to sleep in live tile mode" into ub-launcher3-master
|
||||
|
||||
commit 1fddddb4f30505e0fc9bb2e7c0d88b38ad900e54
|
||||
Author: Tony Wickham <twickham@google.com>
|
||||
Date: Tue Sep 29 17:29:06 2020 -0700
|
||||
|
||||
Update launcher_trace.proto for quick switch
|
||||
|
||||
Sample output from one entry:
|
||||
entry {
|
||||
elapsed_realtime_nanos: 440461382888540
|
||||
launcher {
|
||||
touch_interaction_service {
|
||||
service_connected: true
|
||||
overview_component_obvserver {
|
||||
overview_activity_started: true
|
||||
overview_activity_resumed: false
|
||||
}
|
||||
input_consumer {
|
||||
name: "TYPE_OTHER_ACTIVITY:TYPE_ONE_HANDED"
|
||||
swipe_handler {
|
||||
gesture_state {
|
||||
endTarget: NEW_TASK
|
||||
}
|
||||
is_recents_attached_to_app_window: true
|
||||
scroll_offset: 846
|
||||
app_to_overview_progress: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bug: 167259591
|
||||
Change-Id: I7f199d88f1d736efcea6b9165b8c4b77a5d27c58
|
||||
|
||||
commit 73ae75474ec1dd8807d814ea6c22323905d2070c
|
||||
Merge: 8a6f3e40d 0ebbc1880
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Tue Oct 6 23:18:44 2020 +0000
|
||||
|
||||
Merge "Removing tracing for a gone flake" into ub-launcher3-master
|
||||
|
||||
commit 8a6f3e40d0321217c624055db7929c397e455e0c
|
||||
Merge: e29a9f796 565ed4ff6
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Tue Oct 6 22:49:40 2020 +0000
|
||||
|
||||
Merge "Update Search UI" into ub-launcher3-master
|
||||
|
||||
commit 0ebbc18803aaf8ef2f6db7d628d7ae1ce322e842
|
||||
Author: vadimt <vadimt@google.com>
|
||||
Date: Tue Oct 6 14:52:27 2020 -0700
|
||||
|
||||
Removing tracing for a gone flake
|
||||
|
||||
Bug: 156044202
|
||||
Change-Id: Ice142bb941fee7b731f46c2073fab17d83bbc871
|
||||
|
||||
commit 565ed4ff69b534812818a2b9aa8789a1aea210eb
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Wed Sep 30 10:42:07 2020 -0700
|
||||
|
||||
Update Search UI
|
||||
|
||||
[preview attached to bug]
|
||||
|
||||
Bug: 169438169
|
||||
Test: Manual
|
||||
Change-Id: I085f3dd38ac373c1afab82a637ec08715a6e0cc5
|
||||
|
||||
commit e29a9f7961e6db0915bc028ef7e871dcb2c8bde0
|
||||
Merge: 2c5ed10ff be17bdcd2
|
||||
Author: Jayaprakash Sundararaj <jayaprakashs@google.com>
|
||||
Date: Tue Oct 6 21:00:20 2020 +0000
|
||||
|
||||
Merge "[Search] Add logging to People and badding as to icons." into ub-launcher3-master
|
||||
|
||||
commit be17bdcd221f501c45876abe2249c1007858d0c0
|
||||
Author: jayaprakashs <jayaprakashs@google.com>
|
||||
Date: Mon Oct 5 09:01:52 2020 -0700
|
||||
|
||||
[Search] Add logging to People and badding as to icons.
|
||||
|
||||
Change-Id: I65948a2faca436216a94aa46139d425b8eade827
|
||||
|
||||
commit 2c5ed10ffa1a870de35f9b3c0c558270aff498dd
|
||||
Merge: b2b65a1ef 8ed9707cf
|
||||
Author: Tracy Zhou <tracyzhou@google.com>
|
||||
Date: Tue Oct 6 18:40:57 2020 +0000
|
||||
|
||||
Merge "[Live Tile] Support launching another task (other than the current running task) in Overview" into ub-launcher3-master
|
||||
|
||||
commit b2b65a1ef58b020923d112051535b6eb83b582df
|
||||
Merge: 3cf264f49 4c14f4b9e
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Tue Oct 6 17:45:35 2020 +0000
|
||||
|
||||
Merge "Avoid double search item highlight" into ub-launcher3-master
|
||||
|
||||
commit 8ed9707cf3a4300cb61942f08f0752c80eed086b
|
||||
Author: Tracy Zhou <tracyzhou@google.com>
|
||||
Date: Mon Sep 14 23:25:37 2020 -0700
|
||||
|
||||
[Live Tile] Support launching another task (other than the current running task) in Overview
|
||||
|
||||
- Get rid of the defer cancelation logic
|
||||
- Render animation on the task view of the task being launched upon task view appeared callback
|
||||
- Finish the recents animation upon the end of the recents window animation
|
||||
|
||||
Fixes: 164926736
|
||||
Test: manual
|
||||
Change-Id: Ibffb6a9c74c235efc8615a22b0306551532c7b61
|
||||
|
||||
commit 3cf264f498e37c482fa4c559bf48ffa791279585
|
||||
Author: Schneider Victor-tulias <victortulias@google.com>
|
||||
Date: Tue Sep 22 12:58:38 2020 -0700
|
||||
|
||||
Prevent hotseat updates if it is visible to the user.
|
||||
|
||||
Test: manual
|
||||
|
||||
Fixes: 168653219
|
||||
|
||||
Changing app icons under the user's finger could be disruptive. Added a checks for whether the hotseatand all apps predictions are visible and callbacks to update them when they become hidden.
|
||||
|
||||
Change-Id: Ib9e6e904e9f662ecfaeea6a2fe21d1d81ba39b96
|
||||
|
||||
commit b6aff1f56d55a36256446ec3970d92e9da39b98c
|
||||
Author: Hyunyoung Song <hyunyoungs@google.com>
|
||||
Date: Mon Oct 5 16:08:35 2020 -0700
|
||||
|
||||
Fix NPE inside RecentsOrientedState
|
||||
|
||||
Bug: 169963211
|
||||
Change-Id: I86dd337dc1b862f3fa99b91b47fa250076233f96
|
||||
|
||||
commit eab40983b9a48b933bde5ca95a82ebd4d83b233d
|
||||
Merge: 83ce7c0b5 020e628f2
|
||||
Author: Jonathan Miranda <jonmiranda@google.com>
|
||||
Date: Mon Oct 5 22:20:27 2020 +0000
|
||||
|
||||
Merge "Add shadow radius to windows during app launch / close animations." into ub-launcher3-master
|
||||
|
||||
commit 83ce7c0b5e461386bb92883a8d6cefe8365cd9ae
|
||||
Merge: 679d920bf d6b1f3c08
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Mon Oct 5 19:18:39 2020 +0000
|
||||
|
||||
Merge "Action icon should be used as a badge instead of main icon" into ub-launcher3-master
|
||||
|
||||
commit 679d920bf5151cffed4e8186c12c25d8d7907af9
|
||||
Merge: e108cc609 0c943966d
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Mon Oct 5 19:13:50 2020 +0000
|
||||
|
||||
Merge "Add null check for input receiver before updating batching" into ub-launcher3-master
|
||||
|
||||
commit e108cc609d0a7fd58f0c7e16ce45fa79be6dd272
|
||||
Merge: 470403eb5 f622e42bf
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Mon Oct 5 18:39:58 2020 +0000
|
||||
|
||||
Merge "Removing unused proto extensions" into ub-launcher3-master
|
||||
|
||||
commit 470403eb58879380e2edac2262dc7f40327b2a15
|
||||
Merge: a5130482a 1d7ed30db
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Mon Oct 5 18:29:54 2020 +0000
|
||||
|
||||
Merge "Remove widgets that no longer fit the workspace in their current spans." into ub-launcher3-master
|
||||
|
||||
commit 4c14f4b9eda8332347c81e0cf51c5de4dbc06399
|
||||
Author: Samuel Fufa <sfufa@google.com>
|
||||
Date: Mon Oct 5 10:50:00 2020 -0700
|
||||
|
||||
Avoid double search item highlight
|
||||
|
||||
Change-Id: Ic2e28b18f6d5e3ed32cd5646bc3bb4789c378e57
|
||||
|
||||
commit 0c943966d373d8ae7eef2b08e88ac44bf57d8a8d
|
||||
Author: Winson Chung <winsonc@google.com>
|
||||
Date: Mon Oct 5 10:23:27 2020 -0700
|
||||
|
||||
Add null check for input receiver before updating batching
|
||||
|
||||
- A change in the system (ie. sysui crash or nav mode change) could
|
||||
cause the input monitor to be disposed before the swipe animation
|
||||
settles
|
||||
|
||||
Bug: 170121063
|
||||
Test: Kill sysui while swiping up
|
||||
|
||||
Change-Id: I1417b109fecdb98fae6197c7038dbe9307470853
|
||||
|
||||
commit a5130482aee1b0592661bc1c6e178a0de7a163da
|
||||
Merge: b21819e18 7fcd74abb
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Mon Oct 5 17:14:21 2020 +0000
|
||||
|
||||
Merge "Suggest result should launch Bug: 169980192" into ub-launcher3-master
|
||||
|
||||
commit d028937e74a9ea6d36e463de4c87ed37283bbdf6
|
||||
Author: Tracy Zhou <tracyzhou@google.com>
|
||||
Date: Sat Oct 3 00:36:53 2020 -0700
|
||||
|
||||
[Live tile] Finish recents animation when the phone goes to sleep in live tile mode
|
||||
|
||||
Fixes: 169988381
|
||||
Test: manual
|
||||
Change-Id: Ic71d3e6767eadb6854dbd46581bf9d3242c161a4
|
||||
|
||||
commit 7fcd74abb399100ac8243be6ca28c09cc8adc8c8
|
||||
Author: Hyunyoung Song <hyunyoungs@google.com>
|
||||
Date: Fri Oct 2 19:20:11 2020 -0700
|
||||
|
||||
Suggest result should launch
|
||||
Bug: 169980192
|
||||
|
||||
Change-Id: I762245a5cc4740d093c9cb3b44a508e9e3f2b763
|
||||
|
||||
commit b21819e181e99504c22c6ca028261a1f2665c6f9
|
||||
Merge: 931bce369 a762b0241
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Fri Oct 2 22:07:12 2020 +0000
|
||||
|
||||
Merge "Annotating Quick Switch CUJ for non-3-button modes" into ub-launcher3-master
|
||||
|
||||
commit a762b02418695f5a1ff2f96586660de8c3610280
|
||||
Author: vadimt <vadimt@google.com>
|
||||
Date: Fri Oct 2 13:56:28 2020 -0700
|
||||
|
||||
Annotating Quick Switch CUJ for non-3-button modes
|
||||
|
||||
Bug: 169221288
|
||||
Change-Id: I7145a9e28a2f0a789d19d2a0e3d15630c6e50f6a
|
||||
|
||||
commit 931bce3697595a214023bc72923dad47a61d5711
|
||||
Merge: c935ba6b8 733e3c609
|
||||
Author: TreeHugger Robot <treehugger-gerrit@google.com>
|
||||
Date: Fri Oct 2 19:19:50 2020 +0000
|
||||
|
||||
Merge "Moving some initializations to the background thread" into ub-launcher3-master
|
||||
|
||||
commit c935ba6b8a2ec163533c0b19309dacb6199e6552
|
||||
Merge: a4111f250 58804ac52
|
||||
Author: Sunny Goyal <sunnygoyal@google.com>
|
||||
Date: Fri Oct 2 18:26:06 2020 +0000
|
||||
|
||||
Merge "Adding stats log for add item flow" into ub-launcher3-master
|
||||
|
||||
commit 733e3c609b7653a36e58747c881458ec00d98df8
|
||||
Author: Sunny Goyal <sunnygoyal@google.com>
|
||||
Date: Tue Sep 29 10:32:32 2020 -0700
|
||||
|
||||
Moving some initializations to the background thread
|
||||
|
||||
HandlerThread.getLooper blocks until the thread is ready. Instead
|
||||
moving all looper dependency to the new thread itself.
|
||||
|
||||
Change-Id: I240e8c56b855a991433a7fe93875059e6dab146b
|
||||
|
||||
commit 58804ac5257f45dddbf7a6db35cf8f369ee1e88e
|
||||
Author: Sunny Goyal <sunnygoyal@google.com>
|
||||
Date: Wed Sep 16 16:27:40 2020 -0700
|
||||
|
||||
Adding stats log for add item flow
|
||||
|
||||
Bug: 169385783
|
||||
Bug: 168167693
|
||||
Change-Id: I37395f1b118727f67e0f14c02f945b8213b165c8
|
||||
|
||||
commit a4111f250003328d1aef8bbaab59512208ec46cb
|
||||
Merge: 8d14dbe04 f6b72c4ad
|
||||
Author: Hilary Huo <hhuo@google.com>
|
||||
Date: Fri Oct 2 17:41:22 2020 +0000
|
||||
|
||||
Merge "[pixel-search] Bug fix: automatically launch screenshot + center&crop remoteaction icon" into ub-launcher3-master
|
||||
|
||||
commit f622e42bf6983d3adb95386bfd6375d281f1d4f2
|
||||
Author: Sunny Goyal <sunnygoyal@google.com>
|
||||
Date: Fri Oct 2 10:35:56 2020 -0700
|
||||
|
||||
Removing unused proto extensions
|
||||
|
||||
Change-Id: I6d0319c99934dad5176b6f70b895a4ca772ec45f
|
||||
|
||||
commit d6b1f3c086f9ac097cd03e1ee898b153478ec11a
|
||||
Author: Hyunyoung Song <hyunyoungs@google.com>
|
||||
Date: Fri Oct 2 00:26:35 2020 -0700
|
||||
|
||||
Action icon should be used as a badge instead of main icon
|
||||
|
||||
Bug: 169796517
|
||||
Change-Id: I3f07fdc2ae6e1af463701f942c26c3ca5d836ee2
|
||||
|
||||
commit f6b72c4ad1d2e082441a64c4d6a5a02ee8a251ca
|
||||
Author: Hilary Huo <hhuo@google.com>
|
||||
Date: Thu Oct 1 12:26:48 2020 -0700
|
||||
|
||||
[pixel-search] Bug fix: automatically launch screenshot + center&crop remoteaction icon
|
||||
|
||||
Bug: b/169330678
|
||||
Change-Id: Id5f8a0ce6d68f7ed9e4d1ff258ee3772229eb63b
|
||||
|
||||
commit 1d7ed30dba4b2c71fc7b0981532a872a13e5aedb
|
||||
Author: Jon Miranda <jonmiranda@google.com>
|
||||
Date: Wed Sep 23 12:15:43 2020 -0700
|
||||
|
||||
Remove widgets that no longer fit the workspace in their current spans.
|
||||
|
||||
This can happen when display size changes.
|
||||
We compare span sizes of widget in the db to the min sizes of the widget
|
||||
in the current display size. If the widget can no longer fit in its existing
|
||||
spans, we remove it.
|
||||
|
||||
Also update test widgets to have minWidth/minHeight of 1dp. This ensures that
|
||||
the spanX, spanY, min* values remain consistent between different test devices.
|
||||
|
||||
Bug: 168818961
|
||||
Change-Id: I723372e4582658f78b2f23ced9073cb77977a6b8
|
||||
|
||||
commit 020e628f22cc7975beab439c6da26af2f9ebc15b
|
||||
Author: Jon Miranda <jonmiranda@google.com>
|
||||
Date: Mon Sep 28 17:01:42 2020 -0700
|
||||
|
||||
Add shadow radius to windows during app launch / close animations.
|
||||
|
||||
Bug: 168608912
|
||||
Change-Id: I2ec50b0b3711c0861659f9c641bbc05fcdeaab45
|
||||
@@ -16,16 +16,11 @@
|
||||
|
||||
package com.android.launcher3.testing;
|
||||
|
||||
import static android.graphics.Bitmap.Config.ARGB_8888;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Debug;
|
||||
import android.system.Os;
|
||||
import android.view.View;
|
||||
|
||||
@@ -106,40 +101,15 @@ public class DebugTestInformationHandler extends TestInformationHandler {
|
||||
return response;
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_TOTAL_PSS_KB: {
|
||||
case TestProtocol.REQUEST_FORCE_GC: {
|
||||
runGcAndFinalizersSync();
|
||||
Debug.MemoryInfo mem = new Debug.MemoryInfo();
|
||||
Debug.getMemoryInfo(mem);
|
||||
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, mem.getTotalPss());
|
||||
return response;
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_JAVA_LEAK: {
|
||||
if (sLeaks == null) sLeaks = new LinkedList();
|
||||
|
||||
// Allocate and dirty the memory.
|
||||
final int leakSize = 1024 * 1024;
|
||||
final byte[] bytes = new byte[leakSize];
|
||||
for (int i = 0; i < leakSize; i += 239) {
|
||||
bytes[i] = (byte) (i % 256);
|
||||
}
|
||||
sLeaks.add(bytes);
|
||||
return response;
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_NATIVE_LEAK: {
|
||||
if (sLeaks == null) sLeaks = new LinkedList();
|
||||
|
||||
// Allocate and dirty a bitmap.
|
||||
final Bitmap bitmap = Bitmap.createBitmap(512, 512, ARGB_8888);
|
||||
bitmap.eraseColor(Color.RED);
|
||||
sLeaks.add(bitmap);
|
||||
return response;
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_VIEW_LEAK: {
|
||||
if (sLeaks == null) sLeaks = new LinkedList();
|
||||
sLeaks.add(new View(mContext));
|
||||
sLeaks.add(new View(mContext));
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -164,6 +134,12 @@ public class DebugTestInformationHandler extends TestInformationHandler {
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_GET_TEST_EVENTS: {
|
||||
if (sEvents == null) {
|
||||
// sEvents can be null if Launcher died and restarted after
|
||||
// REQUEST_START_EVENT_LOGGING.
|
||||
return response;
|
||||
}
|
||||
|
||||
synchronized (sEvents) {
|
||||
response.putStringArrayList(
|
||||
TestProtocol.TEST_INFO_RESPONSE_FIELD, new ArrayList<>(sEvents));
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
**
|
||||
** Copyright 2020, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.launcher3">
|
||||
<uses-sdk android:targetSdkVersion="29" android:minSdkVersion="25"/>
|
||||
<!--
|
||||
Manifest entries specific to Launcher3. This is merged with AndroidManifest-common.xml.
|
||||
Refer comments around specific entries on how to extend individual components.
|
||||
-->
|
||||
|
||||
<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/AppTheme"
|
||||
android:largeHeap="@bool/config_largeHeap"
|
||||
android:restoreAnyVersion="true"
|
||||
android:supportsRtl="true" >
|
||||
|
||||
<!--
|
||||
Main launcher activity. When extending only change the name, and keep all the
|
||||
attributes and intent filters the same
|
||||
-->
|
||||
<activity
|
||||
android:name="com.android.launcher3.Launcher3QuickStepGo"
|
||||
android:launchMode="singleTask"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:stateNotNeeded="true"
|
||||
android:windowSoftInputMode="adjustPan"
|
||||
android:screenOrientation="unspecified"
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density|uiMode"
|
||||
android:resizeableActivity="true"
|
||||
android:resumeWhilePausing="true"
|
||||
android:taskAffinity=""
|
||||
android:exported="true"
|
||||
android:enabled="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.HOME" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.MONKEY"/>
|
||||
<category android:name="android.intent.category.LAUNCHER_APP" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="com.android.launcher3.grid.control"
|
||||
android:value="${packageName}.grid_control" />
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
<uses-sdk android:targetSdkVersion="29" android:minSdkVersion="25"/>
|
||||
|
||||
<uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" />
|
||||
|
||||
<application
|
||||
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
|
||||
android:fullBackupOnly="true"
|
||||
@@ -46,6 +48,12 @@
|
||||
tools:node="replace" >
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name="com.android.launcher3.notification.NotificationListener"
|
||||
android:label="@string/notification_dots_service_title"
|
||||
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
|
||||
android:enabled="false"
|
||||
tools:node="replace" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<solid android:color="@color/arrow_tip_view_bg" />
|
||||
<corners android:radius="@dimen/tooltip_corner_radius" />
|
||||
</shape>
|
||||
@@ -0,0 +1,24 @@
|
||||
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M15.08,7.05c0.84,1.18 0.84,2.71 0,3.89l1.68,1.69c2.02,-2.02 2.02,-5.07 0,-7.27l-1.68,1.69zM20.07,2l-1.63,1.63c2.77,3.02 2.77,7.56 0,10.74L20.07,16c3.9,-3.89 3.91,-9.95 0,-14zM9,13c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM9,7c1.1,0 2,0.9 2,2s-0.9,2 -2,2 -2,-0.9 -2,-2 0.9,-2 2,-2zM9,14c-2.67,0 -8,1.34 -8,4v3h16v-3c0,-2.66 -5.33,-4 -8,-4zM15,19L3,19v-0.99C3.2,17.29 6.3,16 9,16s5.8,1.29 6,2v1z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,36 @@
|
||||
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16,3h-2v2h2c1.65,0 3,1.35 3,3v2h2V8C21,5.24 18.76,3 16,3z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M5,16v-2H3v2c0,2.76 2.24,5 5,5h2v-2H8C6.35,19 5,17.65 5,16z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,8.5c-1.93,0 -3.5,1.57 -3.5,3.5s1.57,3.5 3.5,3.5s3.5,-1.57 3.5,-3.5S13.93,8.5 12,8.5z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M18,18m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M5,8c0,-1.65 1.35,-3 3,-3h2V3H8C5.24,3 3,5.24 3,8v2h2V8z"/>
|
||||
</vector>
|
||||
+9
-14
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2020 The Android Open Source Project
|
||||
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -13,17 +12,13 @@
|
||||
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="@dimen/vertical_drag_handle_width"
|
||||
android:height="@dimen/vertical_drag_handle_height"
|
||||
android:viewportWidth="18.0"
|
||||
android:viewportHeight="6.0"
|
||||
android:tint="?attr/workspaceTextColor" >
|
||||
|
||||
<path
|
||||
android:pathData="M17,6c-0.15,0-0.3-0.03-0.45-0.11L9,2.12L1.45,5.89c-0.5,0.25-1.09,
|
||||
0.05-1.34-0.45S0.06,4.35,0.55,4.11l8-4c0.28-0.14,0.61-0.14,0.89,0l8,4c0.49,0.25,0.69,
|
||||
0.85,0.45,1.34C17.72,5.8,17.37,6,17,6z"
|
||||
android:fillColor="@android:color/white" />
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12.87,15.07l-2.54,-2.51 0.03,-0.03c1.74,-1.94 2.98,-4.17 3.71,-6.53L17,6L17,4h-7L10,2L8,2v2L1,4v1.99h11.17C11.5,7.92 10.44,9.75 9,11.35 8.07,10.32 7.3,9.19 6.69,8h-2c0.73,1.63 1.73,3.17 2.98,4.56l-5.09,5.02L4,19l5,-5 3.11,3.11 0.76,-2.04zM18.5,10h-2L12,22h2l1.12,-3h4.75L21,22h2l-4.5,-12zM15.88,17l1.62,-4.33L19.12,17h-3.24z"/>
|
||||
</vector>
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2017 The Android Open Source Project
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="?attr/popupColorSecondary"/>
|
||||
<foreground android:drawable="?attr/popupColorSecondary"/>
|
||||
</adaptive-icon>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="@dimen/go_button_corner_radius" />
|
||||
</shape>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="@dimen/modal_dialog_corner_radius" />
|
||||
</shape>
|
||||
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/niu_actions_dialog_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:layout_gravity="center">
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="@dimen/modal_dialog_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/round_rect_dialog"
|
||||
android:backgroundTint="?attr/modalDialogBackground"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center"
|
||||
android:paddingTop="@dimen/modal_dialog_padding"
|
||||
android:paddingLeft="@dimen/modal_dialog_padding"
|
||||
android:paddingRight="@dimen/modal_dialog_padding"
|
||||
android:paddingBottom="@dimen/modal_dialog_padding_bottom">
|
||||
|
||||
<TextView
|
||||
style="@style/ModalDialogTitle"
|
||||
android:id="@+id/niu_actions_dialog_header"/>
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/modal_dialog_vertical_spacer"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constraintHeight_max="@dimen/modal_dialog_text_height">
|
||||
|
||||
<TextView
|
||||
style="@style/ModalDialogText"
|
||||
android:id="@+id/niu_actions_dialog_description"/>
|
||||
</ScrollView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/modal_dialog_vertical_spacer"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<Button
|
||||
style="@style/ModalDialogButton"
|
||||
android:id="@+id/niu_actions_dialog_button_1"
|
||||
android:text="@string/dialog_cancel"/>
|
||||
|
||||
<Button
|
||||
style="@style/ModalDialogButton"
|
||||
android:id="@+id/niu_actions_dialog_button_2"
|
||||
android:text="@string/dialog_acknowledge"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<!-- NOTE! don't add dimensions for margins / gravity to root view in this file, they need to be
|
||||
loaded at runtime. -->
|
||||
<com.android.quickstep.views.GoOverviewActionsView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/action_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/overview_actions_height"
|
||||
android:layout_gravity="top|center_horizontal"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_translate"
|
||||
style="@style/GoOverviewActionButtonContainer">
|
||||
<ImageButton
|
||||
android:id="@+id/action_translate"
|
||||
style="@style/GoOverviewActionButton"
|
||||
android:src="@drawable/ic_translate"
|
||||
android:contentDescription="@string/action_translate" />
|
||||
<TextView
|
||||
style="@style/GoOverviewActionButtonCaption"
|
||||
android:text="@string/action_translate" />
|
||||
</LinearLayout>
|
||||
|
||||
<Space
|
||||
android:id="@+id/spacer_translate"
|
||||
android:layout_width="@dimen/go_overview_button_container_margin"
|
||||
android:layout_height="1dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_listen"
|
||||
style="@style/GoOverviewActionButtonContainer">
|
||||
<ImageButton
|
||||
android:id="@+id/action_listen"
|
||||
style="@style/GoOverviewActionButton"
|
||||
android:src="@drawable/ic_listen"
|
||||
android:contentDescription="@string/action_listen"
|
||||
android:background="@drawable/round_rect_button" />
|
||||
<TextView
|
||||
style="@style/GoOverviewActionButtonCaption"
|
||||
android:text="@string/action_listen" />
|
||||
</LinearLayout>
|
||||
|
||||
<Space
|
||||
android:id="@+id/spacer_listen"
|
||||
android:layout_width="@dimen/go_overview_button_container_margin"
|
||||
android:layout_height="1dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_screenshot"
|
||||
style="@style/GoOverviewActionButtonContainer">
|
||||
<ImageButton
|
||||
android:id="@+id/action_screenshot"
|
||||
style="@style/GoOverviewActionButton"
|
||||
android:src="@drawable/ic_screenshot"
|
||||
android:contentDescription="@string/action_screenshot"
|
||||
android:background="@drawable/round_rect_button" />
|
||||
<TextView
|
||||
style="@style/GoOverviewActionButtonCaption"
|
||||
android:text="@string/action_screenshot" />
|
||||
</LinearLayout>
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<!-- Will be enabled in a future version. -->
|
||||
<LinearLayout
|
||||
style="@style/GoOverviewActionButtonContainer"
|
||||
android:visibility="gone" >
|
||||
<ImageButton
|
||||
android:id="@+id/action_search"
|
||||
style="@style/GoOverviewActionButton"
|
||||
android:src="@drawable/ic_search"
|
||||
android:contentDescription="@string/action_search"
|
||||
android:background="@drawable/round_rect_button" />
|
||||
<TextView
|
||||
style="@style/GoOverviewActionButtonCaption"
|
||||
android:text="@string/action_search" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Unused. Included only for compatibility with parent class. -->
|
||||
<Button
|
||||
android:id="@+id/action_share"
|
||||
style="@style/GoOverviewActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableStart="@drawable/ic_share"
|
||||
android:text="@string/action_share"
|
||||
android:theme="@style/ThemeControlHighlightWorkspaceColor"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
</com.android.quickstep.views.GoOverviewActionsView>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<!-- Modal Dialogs -->
|
||||
<dimen name="modal_dialog_width">360dp</dimen>
|
||||
<dimen name="modal_dialog_text_height">168dp</dimen>
|
||||
</resources>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018 The Android Open Source Project
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -15,14 +15,10 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<!-- Task Menu layout styles. -->
|
||||
<style name="TaskMenu">
|
||||
<item name="android:orientation">horizontal</item>
|
||||
</style>
|
||||
|
||||
<!-- Task Menu Option layout styles. -->
|
||||
<style name="TaskMenu.Option">
|
||||
<item name="android:layout_width">0dp</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
</style>
|
||||
<!-- Attributes used for Overview theming -->
|
||||
<attr name="overviewButtonTextColor" format="color" />
|
||||
<attr name="overviewButtonIconColor" format="color" />
|
||||
<attr name="overviewButtonBackgroundColor" format="color" />
|
||||
<!-- Modal dialog theming -->
|
||||
<attr name="modalDialogBackground" format="color" />
|
||||
</resources>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<!-- Overview -->
|
||||
<color name="go_overview_text_color">#3C4043</color>
|
||||
<color name="go_overview_text_color_dark">#F8F9FA</color>
|
||||
<color name="go_overview_button_color">#70FFFFFF</color>
|
||||
<color name="go_overview_button_color_dark">#474747</color>
|
||||
<!-- Modal Dialogs -->
|
||||
<color name="go_modal_dialog_background">#FFFFFF</color>
|
||||
<color name="go_modal_dialog_background_dark">#424242</color>
|
||||
|
||||
<!-- Tooltip Color -->
|
||||
<color name="arrow_tip_view_bg">#1A73E8</color>
|
||||
<color name="arrow_tip_view_content">#FFFFFF</color>
|
||||
</resources>
|
||||
+9
-4
@@ -13,7 +13,12 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.launcher3.graphics.ShadowDrawable
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:src="@drawable/drag_handle_indicator_no_shadow"
|
||||
android:elevation="@dimen/vertical_drag_handle_elevation" />
|
||||
<resources>
|
||||
<!-- The component to receive app sharing Intents -->
|
||||
<string name="app_sharing_component" translatable="false"/>
|
||||
|
||||
<!-- Feature Flags -->
|
||||
<bool name="enable_niu_actions">true</bool>
|
||||
|
||||
<string name="task_overlay_factory_class" translatable="false">com.android.quickstep.TaskOverlayFactoryGo</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<dimen name="go_button_corner_radius">20dp</dimen>
|
||||
|
||||
<!-- Overview -->
|
||||
<dimen name="go_overview_button_width">60dp</dimen>
|
||||
<dimen name="go_overview_button_height">60dp</dimen>
|
||||
<dimen name="go_overview_button_container_width">80dp</dimen>
|
||||
<dimen name="go_overview_button_container_margin">16dp</dimen>
|
||||
<dimen name="go_overview_button_caption_margin">8dp</dimen>
|
||||
<dimen name="overview_actions_height">96dp</dimen>
|
||||
<dimen name="overview_proactive_row_height">0dp</dimen>
|
||||
<dimen name="overview_proactive_row_bottom_margin">24dp</dimen>
|
||||
<dimen name="task_corner_radius_override">28dp</dimen>
|
||||
|
||||
<!-- Modal Dialogs -->
|
||||
<dimen name="modal_dialog_width">288dp</dimen>
|
||||
<dimen name="modal_dialog_padding">24dp</dimen>
|
||||
<dimen name="modal_dialog_padding_bottom">8dp</dimen>
|
||||
<dimen name="modal_dialog_vertical_spacer">12dp</dimen>
|
||||
<dimen name="modal_dialog_corner_radius">8dp</dimen>
|
||||
<dimen name="modal_dialog_text_height">216dp</dimen>
|
||||
|
||||
<!-- Tooltip -->
|
||||
<dimen name="tooltip_corner_radius">8dp</dimen>
|
||||
<dimen name="tooltip_top_margin">3dp</dimen>
|
||||
</resources>
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<!-- Label for app share drop target. [CHAR_LIMIT=20] -->
|
||||
<string name="app_share_drop_target_label">Share App</string>
|
||||
|
||||
<!-- ******* Overview ******* -->
|
||||
<!-- Label for a button that lets the user listen to the content of the current app. [CHAR_LIMIT=40] -->
|
||||
<string name="action_listen">Listen</string>
|
||||
<!-- Label for a button that translates a screenshot of the current app. [CHAR_LIMIT=40] -->
|
||||
<string name="action_translate">Translate</string>
|
||||
<!-- Label for a button that triggers Search on a screenshot of the current app. [CHAR_LIMIT=40] -->
|
||||
<string name="action_search">Lens</string>
|
||||
|
||||
<!-- ******* Dialogs ******* -->
|
||||
<!-- Label for a button that acknowledges the contents of the dialog. [CHAR_LIMIT=40] -->
|
||||
<string name="dialog_acknowledge">GOT IT</string>
|
||||
<!-- Label for a button that cancels the dialog. [CHAR_LIMIT=40] -->
|
||||
<string name="dialog_cancel">CANCEL</string>
|
||||
<!-- Label for a button that redirects the user to Settings. [CHAR_LIMIT=40] -->
|
||||
<string name="dialog_settings">SETTINGS</string>
|
||||
|
||||
<!-- ******* NIU Actions First-Run Confirmation Dialog ******* -->
|
||||
<!-- Dialog title -->
|
||||
<string name="niu_actions_confirmation_title">Translate or listen to text on screen</string>
|
||||
<!-- Dialog content -->
|
||||
<string name="niu_actions_confirmation_text">Information such as text on your screen, web addresses, and screenshots may be shared with Google.\n\nTo change what information you share, go to <b>Settings > Apps > Default apps > Digital assistant app</b>.</string>
|
||||
|
||||
<!-- ******* NIU Actions Default Assistant Error Dialogs ******* -->
|
||||
<!-- Assistant not selected: Dialog title -->
|
||||
<string name="assistant_not_selected_title">Choose an assistant to use this feature</string>
|
||||
<!-- Assistant not selected: Dialog content -->
|
||||
<string name="assistant_not_selected_text">To listen to or translate text on your screen, choose a digital assistant app in Settings</string>
|
||||
<!-- Assistant not supported: Dialog title -->
|
||||
<string name="assistant_not_supported_title">Change your assistant to use this feature</string>
|
||||
<!-- Assistant not supported: Dialog content -->
|
||||
<string name="assistant_not_supported_text">To listen to or translate text on your screen, change your digital assistant app in Settings</string>
|
||||
|
||||
<!-- ******* NIU Actions Tooltip ******* -->
|
||||
<!-- Tooltip to highlight and explain the Listen button -->
|
||||
<string name="tooltip_listen">Tap here to listen to text on this screen</string>
|
||||
<!-- Tooltip to highlight and explain the Translate button -->
|
||||
<string name="tooltip_translate">Tap here to translate text on this screen</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<!-- App themes -->
|
||||
<style name="LauncherTheme" parent="@style/BaseLauncherTheme">
|
||||
<item name="overviewButtonTextColor">@color/go_overview_text_color</item>
|
||||
<item name="overviewButtonIconColor">@color/go_overview_text_color</item>
|
||||
<item name="overviewButtonBackgroundColor">@color/go_overview_button_color</item>
|
||||
<item name="modalDialogBackground">@color/go_modal_dialog_background</item>
|
||||
</style>
|
||||
|
||||
<style name="LauncherTheme.Dark" parent="@style/LauncherTheme">
|
||||
<item name="overviewButtonTextColor">@color/go_overview_text_color_dark</item>
|
||||
<item name="overviewButtonIconColor">@color/go_overview_text_color_dark</item>
|
||||
<item name="overviewButtonBackgroundColor">@color/go_overview_button_color_dark</item>
|
||||
<item name="modalDialogBackground">@color/go_modal_dialog_background_dark</item>
|
||||
</style>
|
||||
|
||||
<!-- Overview -->
|
||||
<style name="GoOverviewActionButton">
|
||||
<item name="android:tint">?attr/overviewButtonIconColor</item>
|
||||
<item name="android:backgroundTint">?attr/overviewButtonBackgroundColor</item>
|
||||
<item name="android:background">@drawable/round_rect_button</item>
|
||||
<item name="android:layout_width">@dimen/go_overview_button_width</item>
|
||||
<item name="android:layout_height">@dimen/go_overview_button_height</item>
|
||||
<item name="android:layout_gravity">center_horizontal</item>
|
||||
</style>
|
||||
|
||||
<style name="GoOverviewActionButtonCaption">
|
||||
<item name="android:fontFamily">sans-serif-medium</item>
|
||||
<item name="android:textSize">14dp</item>
|
||||
<item name="android:textColor">?attr/overviewButtonTextColor</item>
|
||||
<item name="android:lineHeight">20dp</item>
|
||||
<item name="android:textAlignment">center</item>
|
||||
<item name="android:importantForAccessibility">no</item>
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_marginTop">@dimen/go_overview_button_caption_margin</item>
|
||||
<item name="android:layout_gravity">center_horizontal</item>
|
||||
</style>
|
||||
|
||||
<style name="GoOverviewActionButtonContainer">
|
||||
<item name="android:layout_width">@dimen/go_overview_button_container_width</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:orientation">vertical</item>
|
||||
</style>
|
||||
|
||||
<!-- Modal Dialogs -->
|
||||
<style name="ModalDialogTitle">
|
||||
<item name="android:fontFamily">sans-serif-medium</item>
|
||||
<item name="android:textSize">20sp</item>
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
<item name="android:lineHeight">24dp</item>
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_gravity">center_horizontal</item>
|
||||
</style>
|
||||
|
||||
<style name="ModalDialogText">
|
||||
<item name="android:fontFamily">sans-serif-medium</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
<item name="android:lineHeight">24dp</item>
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_gravity">center_horizontal</item>
|
||||
</style>
|
||||
|
||||
<style name="ModalDialogButton" parent="@style/Widget.AppCompat.Button.Borderless">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textColor">?android:attr/colorAccent</item>
|
||||
<item name="android:lineHeight">20dp</item>
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Defines the Share system shortcut and its factory.
|
||||
* This shortcut can be added to the app long-press menu on the home screen.
|
||||
* Clicking the button will initiate peer-to-peer sharing of the app.
|
||||
*/
|
||||
public final class AppSharing {
|
||||
/**
|
||||
* This flag enables this feature. It is defined here rather than in launcher3's FeatureFlags
|
||||
* because it is unique to Go and not toggleable at runtime.
|
||||
*/
|
||||
public static final boolean ENABLE_APP_SHARING = true;
|
||||
|
||||
private static final String TAG = "AppSharing";
|
||||
private static final String FILE_PROVIDER_SUFFIX = ".overview.fileprovider";
|
||||
private static final String APP_EXSTENSION = ".apk";
|
||||
private static final String APP_MIME_TYPE = "application/application";
|
||||
|
||||
private final String mSharingComponent;
|
||||
|
||||
private AppSharing(Launcher launcher) {
|
||||
mSharingComponent = launcher.getText(R.string.app_sharing_component).toString();
|
||||
}
|
||||
|
||||
private boolean canShare(ItemInfo info) {
|
||||
/**
|
||||
* TODO: Implement once b/168831749 has been resolved
|
||||
* The implementation should check the validity of the app.
|
||||
* It should also check whether the app is free or paid, returning false in the latter case.
|
||||
* For now, all checks occur in the sharing app.
|
||||
* So, we simply check whether the sharing app is defined.
|
||||
*/
|
||||
return !TextUtils.isEmpty(mSharingComponent);
|
||||
}
|
||||
|
||||
private Uri getShareableUri(Context context, String path, String displayName) {
|
||||
String authority = BuildConfig.APPLICATION_ID + FILE_PROVIDER_SUFFIX;
|
||||
File pathFile = new File(path);
|
||||
return FileProvider.getUriForFile(context, authority, pathFile, displayName);
|
||||
}
|
||||
|
||||
private SystemShortcut<Launcher> getShortcut(Launcher launcher, ItemInfo info) {
|
||||
if (!canShare(info)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Share(launcher, info);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Share App system shortcut, used to initiate p2p sharing of a given app
|
||||
*/
|
||||
public final class Share extends SystemShortcut<Launcher> {
|
||||
public Share(Launcher target, ItemInfo itemInfo) {
|
||||
super(R.drawable.ic_share, R.string.app_share_drop_target_label, target, itemInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
|
||||
ComponentName targetComponent = mItemInfo.getTargetComponent();
|
||||
if (targetComponent == null) {
|
||||
Log.e(TAG, "Item missing target component");
|
||||
return;
|
||||
}
|
||||
String packageName = targetComponent.getPackageName();
|
||||
PackageManager packageManager = view.getContext().getPackageManager();
|
||||
String sourceDir, appLabel;
|
||||
try {
|
||||
PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
|
||||
sourceDir = packageInfo.applicationInfo.sourceDir;
|
||||
appLabel = packageManager.getApplicationLabel(packageInfo.applicationInfo)
|
||||
.toString() + APP_EXSTENSION;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Could not find info for package \"" + packageName + "\"");
|
||||
return;
|
||||
}
|
||||
Uri uri = getShareableUri(view.getContext(), sourceDir, appLabel);
|
||||
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||
sendIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
|
||||
|
||||
sendIntent.setType(APP_MIME_TYPE);
|
||||
sendIntent.setComponent(ComponentName.unflattenFromString(mSharingComponent));
|
||||
|
||||
mTarget.startActivitySafely(view, sendIntent, mItemInfo);
|
||||
|
||||
AbstractFloatingView.closeAllOpenViews(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut factory for generating the Share App button
|
||||
*/
|
||||
public static final SystemShortcut.Factory<Launcher> SHORTCUT_FACTORY = (launcher, itemInfo) ->
|
||||
(new AppSharing(launcher)).getShortcut(launcher, itemInfo);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
import com.android.launcher3.uioverrides.QuickstepLauncher;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The Launcher variant used for Android Go Edition
|
||||
*/
|
||||
public class Launcher3QuickStepGo extends QuickstepLauncher {
|
||||
private static final String TAG = "Launcher3QuickStepGo";
|
||||
|
||||
@Override
|
||||
public Stream<SystemShortcut.Factory> getSupportedShortcuts() {
|
||||
Stream<SystemShortcut.Factory> shortcuts = super.getSupportedShortcuts();
|
||||
|
||||
if (AppSharing.ENABLE_APP_SHARING) {
|
||||
shortcuts = Stream.concat(shortcuts, Stream.of(AppSharing.SHORTCUT_FACTORY));
|
||||
}
|
||||
|
||||
return shortcuts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.quickstep;
|
||||
|
||||
import static android.view.Surface.ROTATION_0;
|
||||
|
||||
import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBNAIL;
|
||||
import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.assist.AssistContent;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.quickstep.util.AssistContentRequester;
|
||||
import com.android.quickstep.util.RecentsOrientedState;
|
||||
import com.android.quickstep.views.GoOverviewActionsView;
|
||||
import com.android.quickstep.views.TaskThumbnailView;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
/**
|
||||
* Go-specific extension of the factory class that adds an overlay to TaskView
|
||||
*/
|
||||
public final class TaskOverlayFactoryGo extends TaskOverlayFactory {
|
||||
public static final String ACTION_LISTEN = "com.android.quickstep.ACTION_LISTEN";
|
||||
public static final String ACTION_TRANSLATE = "com.android.quickstep.ACTION_TRANSLATE";
|
||||
public static final String ACTION_SEARCH = "com.android.quickstep.ACTION_SEARCH";
|
||||
public static final String ELAPSED_NANOS = "niu_actions_elapsed_realtime_nanos";
|
||||
public static final String ACTIONS_URL = "niu_actions_app_url";
|
||||
public static final String ACTIONS_APP_PACKAGE = "niu_actions_app_package";
|
||||
public static final String ACTIONS_ERROR_CODE = "niu_actions_app_error_code";
|
||||
public static final int ERROR_PERMISSIONS_STRUCTURE = 1;
|
||||
public static final int ERROR_PERMISSIONS_SCREENSHOT = 2;
|
||||
private static final String NIU_ACTIONS_CONFIRMED = "launcher_go.niu_actions_confirmed";
|
||||
private static final String ASSIST_SETTINGS_ARGS_BUNDLE = ":settings:show_fragment_args";
|
||||
private static final String ASSIST_SETTINGS_ARGS_KEY = ":settings:fragment_args_key";
|
||||
private static final String ASSIST_SETTINGS_PREFERENCE_KEY = "default_assist";
|
||||
private static final String TAG = "TaskOverlayFactoryGo";
|
||||
|
||||
public static final String LISTEN_TOOL_TIP_SEEN = "launcher.go_listen_tip_seen";
|
||||
public static final String TRANSLATE_TOOL_TIP_SEEN = "launcher.go_translate_tip_seen";
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef({PRIVACY_CONFIRMATION, ASSISTANT_NOT_SELECTED, ASSISTANT_NOT_SUPPORTED})
|
||||
private @interface DialogType{}
|
||||
private static final int PRIVACY_CONFIRMATION = 0;
|
||||
private static final int ASSISTANT_NOT_SELECTED = 1;
|
||||
private static final int ASSISTANT_NOT_SUPPORTED = 2;
|
||||
|
||||
private AssistContentRequester mContentRequester;
|
||||
|
||||
public TaskOverlayFactoryGo(Context context) {
|
||||
mContentRequester = new AssistContentRequester(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new overlay instance for the given View
|
||||
*/
|
||||
public TaskOverlayGo createOverlay(TaskThumbnailView thumbnailView) {
|
||||
return new TaskOverlayGo(thumbnailView, mContentRequester);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overlay on each task handling Overview Action Buttons.
|
||||
* @param <T> The type of View in which the overlay will be placed
|
||||
*/
|
||||
public static final class TaskOverlayGo<T extends GoOverviewActionsView> extends TaskOverlay {
|
||||
private String mNIUPackageName;
|
||||
private String mTaskPackageName;
|
||||
private String mWebUrl;
|
||||
private boolean mAssistStructurePermitted;
|
||||
private boolean mAssistScreenshotPermitted;
|
||||
private AssistContentRequester mFactoryContentRequester;
|
||||
private SharedPreferences mSharedPreferences;
|
||||
private OverlayDialogGo mDialog;
|
||||
|
||||
private TaskOverlayGo(TaskThumbnailView taskThumbnailView,
|
||||
AssistContentRequester assistContentRequester) {
|
||||
super(taskThumbnailView);
|
||||
mFactoryContentRequester = assistContentRequester;
|
||||
mSharedPreferences = Utilities.getPrefs(mApplicationContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current task is interactive for the user
|
||||
*/
|
||||
@Override
|
||||
public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix,
|
||||
boolean rotated) {
|
||||
if (mDialog != null && mDialog.isShowing()) {
|
||||
// Redraw the dialog in case the layout changed
|
||||
mDialog.dismiss();
|
||||
showDialog(mDialog.getAction(), mDialog.getType());
|
||||
}
|
||||
|
||||
getActionsView().updateDisabledFlags(DISABLED_NO_THUMBNAIL, thumbnail == null);
|
||||
if (thumbnail == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated);
|
||||
// Disable Overview Actions for Work Profile apps
|
||||
boolean isManagedProfileTask =
|
||||
UserManager.get(mApplicationContext).isManagedProfile(task.key.userId);
|
||||
boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot() && !isManagedProfileTask;
|
||||
getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task));
|
||||
mTaskPackageName = task.key.getPackageName();
|
||||
mSharedPreferences = Utilities.getPrefs(mApplicationContext);
|
||||
checkSettings();
|
||||
|
||||
if (!mAssistStructurePermitted || !mAssistScreenshotPermitted
|
||||
|| TextUtils.isEmpty(mNIUPackageName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int taskId = task.key.id;
|
||||
mFactoryContentRequester.requestAssistContent(taskId, this::onAssistContentReceived);
|
||||
|
||||
RecentsOrientedState orientedState =
|
||||
mThumbnailView.getTaskView().getRecentsView().getPagedViewOrientedState();
|
||||
boolean isInLandscape = orientedState.getDisplayRotation() != ROTATION_0;
|
||||
|
||||
// show tooltips in portrait mode only
|
||||
// TODO: remove If check once b/183714277 is fixed
|
||||
if (!isInLandscape) {
|
||||
new Handler().post(() -> {
|
||||
showTooltipsIfUnseen();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Provide Assist Content to the overlay. */
|
||||
@VisibleForTesting
|
||||
public void onAssistContentReceived(AssistContent assistContent) {
|
||||
mWebUrl = assistContent.getWebUri() != null
|
||||
? assistContent.getWebUri().toString() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
mWebUrl = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateOrientationState(RecentsOrientedState state) {
|
||||
super.updateOrientationState(state);
|
||||
((GoOverviewActionsView) getActionsView()).updateOrientationState(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and sends an Intent corresponding to the button that was clicked
|
||||
*/
|
||||
private void sendNIUIntent(String actionType) {
|
||||
if (TextUtils.isEmpty(mNIUPackageName)) {
|
||||
showDialog(actionType, ASSISTANT_NOT_SELECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mSharedPreferences.getBoolean(NIU_ACTIONS_CONFIRMED, false)) {
|
||||
showDialog(actionType, PRIVACY_CONFIRMATION);
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = createNIUIntent(actionType);
|
||||
// Only add and send the image if the appropriate permissions are held
|
||||
if (mAssistStructurePermitted && mAssistScreenshotPermitted) {
|
||||
mImageApi.shareAsDataWithExplicitIntent(/* crop */ null, intent);
|
||||
} else {
|
||||
// If both permissions are disabled, the structure error code takes priority
|
||||
// The user must enable that one before they can enable screenshots
|
||||
int code = mAssistStructurePermitted ? ERROR_PERMISSIONS_SCREENSHOT
|
||||
: ERROR_PERMISSIONS_STRUCTURE;
|
||||
intent.putExtra(ACTIONS_ERROR_CODE, code);
|
||||
try {
|
||||
mApplicationContext.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.e(TAG, "No activity found to receive permission error intent");
|
||||
showDialog(actionType, ASSISTANT_NOT_SUPPORTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Intent createNIUIntent(String actionType) {
|
||||
Intent intent = new Intent(actionType)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
|
||||
.setPackage(mNIUPackageName)
|
||||
.putExtra(ACTIONS_APP_PACKAGE, mTaskPackageName)
|
||||
.putExtra(ELAPSED_NANOS, SystemClock.elapsedRealtimeNanos());
|
||||
|
||||
if (mWebUrl != null) {
|
||||
intent.putExtra(ACTIONS_URL, mWebUrl);
|
||||
}
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the Assistant has screen context permissions
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public void checkSettings() {
|
||||
ContentResolver contentResolver = mApplicationContext.getContentResolver();
|
||||
mAssistStructurePermitted = Settings.Secure.getInt(contentResolver,
|
||||
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1) != 0;
|
||||
mAssistScreenshotPermitted = Settings.Secure.getInt(contentResolver,
|
||||
Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 1) != 0;
|
||||
|
||||
String assistantPackage =
|
||||
Settings.Secure.getString(contentResolver, Settings.Secure.ASSISTANT);
|
||||
mNIUPackageName = assistantPackage.split("/", 2)[0];
|
||||
}
|
||||
|
||||
protected class OverlayUICallbacksGoImpl extends OverlayUICallbacksImpl
|
||||
implements OverlayUICallbacksGo {
|
||||
public OverlayUICallbacksGoImpl(boolean isAllowedByPolicy, Task task) {
|
||||
super(isAllowedByPolicy, task);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public void onListen() {
|
||||
if (mIsAllowedByPolicy) {
|
||||
endLiveTileMode(() -> sendNIUIntent(ACTION_LISTEN));
|
||||
} else {
|
||||
showBlockedByPolicyMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public void onTranslate() {
|
||||
if (mIsAllowedByPolicy) {
|
||||
endLiveTileMode(() -> sendNIUIntent(ACTION_TRANSLATE));
|
||||
} else {
|
||||
showBlockedByPolicyMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public void onSearch() {
|
||||
if (mIsAllowedByPolicy) {
|
||||
endLiveTileMode(() -> sendNIUIntent(ACTION_SEARCH));
|
||||
} else {
|
||||
showBlockedByPolicyMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setImageActionsAPI(ImageActionsApi imageActionsApi) {
|
||||
mImageApi = imageActionsApi;
|
||||
}
|
||||
|
||||
// TODO (b/192406446): Test that these dialogs are shown at the appropriate times
|
||||
private void showDialog(String action, @DialogType int type) {
|
||||
switch (type) {
|
||||
case PRIVACY_CONFIRMATION:
|
||||
showDialog(action, PRIVACY_CONFIRMATION,
|
||||
R.string.niu_actions_confirmation_title,
|
||||
R.string.niu_actions_confirmation_text, R.string.dialog_cancel,
|
||||
this::onDialogClickCancel, R.string.dialog_acknowledge,
|
||||
this::onNiuActionsConfirmationAccept);
|
||||
break;
|
||||
case ASSISTANT_NOT_SELECTED:
|
||||
showDialog(action, ASSISTANT_NOT_SELECTED,
|
||||
R.string.assistant_not_selected_title,
|
||||
R.string.assistant_not_selected_text, R.string.dialog_cancel,
|
||||
this::onDialogClickCancel, R.string.dialog_settings,
|
||||
this::onDialogClickSettings);
|
||||
break;
|
||||
case ASSISTANT_NOT_SUPPORTED:
|
||||
showDialog(action, ASSISTANT_NOT_SUPPORTED,
|
||||
R.string.assistant_not_supported_title,
|
||||
R.string.assistant_not_supported_text, R.string.dialog_cancel,
|
||||
this::onDialogClickCancel, R.string.dialog_settings,
|
||||
this::onDialogClickSettings);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unexpected dialog type");
|
||||
}
|
||||
}
|
||||
|
||||
private void showDialog(String action, @DialogType int type, int titleTextID,
|
||||
int bodyTextID, int button1TextID,
|
||||
View.OnClickListener button1Callback, int button2TextID,
|
||||
View.OnClickListener button2Callback) {
|
||||
BaseDraggingActivity activity = BaseActivity.fromContext(getActionsView().getContext());
|
||||
LayoutInflater inflater = LayoutInflater.from(activity);
|
||||
View view = inflater.inflate(R.layout.niu_actions_dialog, /* root */ null);
|
||||
|
||||
TextView dialogTitle = view.findViewById(R.id.niu_actions_dialog_header);
|
||||
dialogTitle.setText(titleTextID);
|
||||
|
||||
TextView dialogBody = view.findViewById(R.id.niu_actions_dialog_description);
|
||||
dialogBody.setText(bodyTextID);
|
||||
|
||||
Button button1 = view.findViewById(R.id.niu_actions_dialog_button_1);
|
||||
button1.setText(button1TextID);
|
||||
button1.setOnClickListener(button1Callback);
|
||||
|
||||
Button button2 = view.findViewById(R.id.niu_actions_dialog_button_2);
|
||||
button2.setText(button2TextID);
|
||||
button2.setOnClickListener(button2Callback);
|
||||
|
||||
mDialog = new OverlayDialogGo(activity, type, action);
|
||||
mDialog.setView(view);
|
||||
mDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
mDialog.show();
|
||||
}
|
||||
|
||||
private void onNiuActionsConfirmationAccept(View v) {
|
||||
mDialog.dismiss();
|
||||
mSharedPreferences.edit().putBoolean(NIU_ACTIONS_CONFIRMED, true).apply();
|
||||
sendNIUIntent(mDialog.getAction());
|
||||
}
|
||||
|
||||
private void onDialogClickCancel(View v) {
|
||||
mDialog.cancel();
|
||||
}
|
||||
|
||||
private void onDialogClickSettings(View v) {
|
||||
mDialog.dismiss();
|
||||
|
||||
Bundle fragmentArgs = new Bundle();
|
||||
fragmentArgs.putString(ASSIST_SETTINGS_ARGS_KEY, ASSIST_SETTINGS_PREFERENCE_KEY);
|
||||
Intent intent = new Intent(Settings.ACTION_VOICE_INPUT_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
.putExtra(ASSIST_SETTINGS_ARGS_BUNDLE, fragmentArgs);
|
||||
try {
|
||||
mApplicationContext.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.e(TAG, "No activity found to receive assistant settings intent");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks and Shows the tooltip if they are not seen by user
|
||||
* Order of tooltips are translate and then listen
|
||||
*/
|
||||
private void showTooltipsIfUnseen() {
|
||||
if (!mSharedPreferences.getBoolean(TRANSLATE_TOOL_TIP_SEEN, false)) {
|
||||
((GoOverviewActionsView) getActionsView()).showTranslateToolTip();
|
||||
mSharedPreferences.edit().putBoolean(TRANSLATE_TOOL_TIP_SEEN, true).apply();
|
||||
} else if (!mSharedPreferences.getBoolean(LISTEN_TOOL_TIP_SEEN, false)) {
|
||||
((GoOverviewActionsView) getActionsView()).showListenToolTip();
|
||||
mSharedPreferences.edit().putBoolean(LISTEN_TOOL_TIP_SEEN, true).apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class OverlayDialogGo extends AlertDialog {
|
||||
private final String mAction;
|
||||
private final @DialogType int mType;
|
||||
|
||||
OverlayDialogGo(Context context, @DialogType int type, String action) {
|
||||
super(context);
|
||||
mType = type;
|
||||
mAction = action;
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return mAction;
|
||||
}
|
||||
public @DialogType int getType() {
|
||||
return mType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callbacks the Ui can generate. This is the only way for a Ui to call methods on the
|
||||
* controller.
|
||||
*/
|
||||
public interface OverlayUICallbacksGo extends OverlayUICallbacks {
|
||||
/** User has requested to listen to the current content read aloud */
|
||||
void onListen();
|
||||
|
||||
/** User has requested a translation of the current content */
|
||||
void onTranslate();
|
||||
|
||||
/** User has requested a visual search of the current content */
|
||||
void onSearch();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.quickstep.views;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.Px;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.views.ArrowTipView;
|
||||
import com.android.quickstep.TaskOverlayFactoryGo.OverlayUICallbacksGo;
|
||||
import com.android.quickstep.util.RecentsOrientedState;
|
||||
|
||||
/**
|
||||
* View for showing Go-specific action buttons in Overview
|
||||
*/
|
||||
public class GoOverviewActionsView extends OverviewActionsView<OverlayUICallbacksGo> {
|
||||
|
||||
private ArrowTipView mArrowTipView;
|
||||
|
||||
public GoOverviewActionsView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public GoOverviewActionsView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public GoOverviewActionsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
if (getResources().getBoolean(R.bool.enable_niu_actions)) {
|
||||
findViewById(R.id.action_listen).setOnClickListener(this);
|
||||
findViewById(R.id.action_translate).setOnClickListener(this);
|
||||
} else {
|
||||
findViewById(R.id.layout_listen).setVisibility(GONE);
|
||||
findViewById(R.id.spacer_listen).setVisibility(GONE);
|
||||
findViewById(R.id.layout_translate).setVisibility(GONE);
|
||||
findViewById(R.id.spacer_translate).setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
super.onClick(view);
|
||||
|
||||
if (mCallbacks == null) {
|
||||
return;
|
||||
}
|
||||
int id = view.getId();
|
||||
if (id == R.id.action_listen) {
|
||||
mCallbacks.onListen();
|
||||
} else if (id == R.id.action_translate) {
|
||||
mCallbacks.onTranslate();
|
||||
} else if (id == R.id.action_search) {
|
||||
mCallbacks.onSearch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows Tooltip for action icons
|
||||
*/
|
||||
private void showToolTip(int viewId, int textResourceId) {
|
||||
int[] location = new int[2];
|
||||
@Px int topMargin = getResources().getDimensionPixelSize(R.dimen.tooltip_top_margin);
|
||||
findViewById(viewId).getLocationOnScreen(location);
|
||||
mArrowTipView = new ArrowTipView(getContext(), /* isPointingUp= */ false)
|
||||
.showAtLocation(getResources().getString(textResourceId),
|
||||
/* arrowXCoord= */ location[0] + findViewById(viewId).getWidth() / 2,
|
||||
/* yCoord= */ location[1] - topMargin);
|
||||
|
||||
mArrowTipView.bringToFront();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows Tooltip for listen action icon
|
||||
*/
|
||||
public void showListenToolTip() {
|
||||
showToolTip(/* viewId= */ R.id.action_listen,
|
||||
/* textResourceId= */ R.string.tooltip_listen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows Tooltip for translate action icon
|
||||
*/
|
||||
public void showTranslateToolTip() {
|
||||
showToolTip(/* viewId= */ R.id.action_translate,
|
||||
/* textResourceId= */ R.string.tooltip_translate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when device orientation is changed
|
||||
*/
|
||||
public void updateOrientationState(RecentsOrientedState orientedState) {
|
||||
// dismiss tooltip
|
||||
boolean canLauncherRotate = orientedState.canRecentsActivityRotate();
|
||||
if (mArrowTipView != null && !canLauncherRotate) {
|
||||
mArrowTipView.close(/* animate= */ false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.model.BgDataModel.Callbacks;
|
||||
import com.android.launcher3.util.LooperExecutor;
|
||||
|
||||
/**
|
||||
* Helper class to handle results of {@link com.android.launcher3.model.LoaderTask}.
|
||||
@@ -29,12 +28,7 @@ public class LoaderResults extends BaseLoaderResults {
|
||||
|
||||
public LoaderResults(LauncherAppState app, BgDataModel dataModel,
|
||||
AllAppsList allAppsList, Callbacks[] callbacks) {
|
||||
this(app, dataModel, allAppsList, callbacks, MAIN_EXECUTOR);
|
||||
}
|
||||
|
||||
public LoaderResults(LauncherAppState app, BgDataModel dataModel,
|
||||
AllAppsList allAppsList, Callbacks[] callbacks, LooperExecutor executor) {
|
||||
super(app, dataModel, allAppsList, callbacks, executor);
|
||||
super(app, dataModel, allAppsList, callbacks, MAIN_EXECUTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,12 +24,14 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.icons.ComponentWithLabelAndIcon;
|
||||
import com.android.launcher3.model.data.PackageItemInfo;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
import com.android.launcher3.widget.WidgetListRowEntry;
|
||||
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -41,21 +43,27 @@ public class WidgetsModel {
|
||||
|
||||
// True is the widget support is disabled.
|
||||
public static final boolean GO_DISABLE_WIDGETS = true;
|
||||
public static final boolean GO_DISABLE_NOTIFICATION_DOTS = true;
|
||||
|
||||
private static final ArrayList<WidgetListRowEntry> EMPTY_WIDGET_LIST = new ArrayList<>();
|
||||
private static final ArrayList<WidgetsListBaseEntry> EMPTY_WIDGET_LIST = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns a list of {@link WidgetListRowEntry}. All {@link WidgetItem} in a single row
|
||||
* are sorted (based on label and user), but the overall list of {@link WidgetListRowEntry}s
|
||||
* is not sorted. This list is sorted at the UI when using
|
||||
* {@link com.android.launcher3.widget.WidgetsDiffReporter}
|
||||
* Returns a list of {@link WidgetsListBaseEntry}. All {@link WidgetItem} in a single row are
|
||||
* sorted (based on label and user), but the overall list of {@link WidgetsListBaseEntry}s is
|
||||
* not sorted. This list is sorted at the UI when using
|
||||
* {@link com.android.launcher3.widget.picker.WidgetsDiffReporter}
|
||||
*
|
||||
* @see com.android.launcher3.widget.WidgetsListAdapter#setWidgets(ArrayList)
|
||||
* @see com.android.launcher3.widget.picker.WidgetsListAdapter#setWidgets(List)
|
||||
*/
|
||||
public synchronized ArrayList<WidgetListRowEntry> getWidgetsList(Context context) {
|
||||
public synchronized ArrayList<WidgetsListBaseEntry> getWidgetsListForPicker(Context context) {
|
||||
return EMPTY_WIDGET_LIST;
|
||||
}
|
||||
|
||||
/** Returns a mapping of packages to their widgets without static shortcuts. */
|
||||
public synchronized Map<PackageUserKey, List<WidgetItem>> getAllWidgetsWithoutShortcuts() {
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise
|
||||
* only widgets and shortcuts associated with the package/user are.
|
||||
@@ -74,4 +82,9 @@ public class WidgetsModel {
|
||||
ComponentName providerName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Returns {@link PackageItemInfo} of a pending widget. */
|
||||
public static PackageItemInfo newPendingItemInfo(ComponentName provider) {
|
||||
return new PackageItemInfo(provider.getPackageName());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -10,4 +10,4 @@ PROTOBUF_CLASS_PATH=com.google.protobuf:protobuf-gradle-plugin:0.8.8
|
||||
PROTOBUF_DEPENDENCY=com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7
|
||||
|
||||
BUILD_TOOLS_VERSION=28.0.3
|
||||
COMPILE_SDK=android-R
|
||||
COMPILE_SDK=android-S
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
|
||||
errorLine1=" android:topLeftRadius="?android:attr/dialogCornerRadius""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
|
||||
line="6"
|
||||
column="9"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
|
||||
errorLine1=" android:topRightRadius="?android:attr/dialogCornerRadius" />"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
|
||||
line="7"
|
||||
column="9"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="`@android:style/Widget.DeviceDefault.Button.Colored` requires API level 28 (current min is 26)"
|
||||
errorLine1=" <style name="Widget.DeviceDefault.Button.Rounded.Colored" parent="@android:style/Widget.DeviceDefault.Button.Colored">"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/res/values/styles.xml"
|
||||
line="287"
|
||||
column="63"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="`@android:dimen/system_app_widget_background_radius` requires API level 31 (current min is 26)"
|
||||
errorLine1=" <corners android:radius="@android:dimen/system_app_widget_background_radius" />"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
|
||||
line="20"
|
||||
column="14"/>
|
||||
</issue>
|
||||
|
||||
</issues>
|
||||
@@ -0,0 +1,576 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.View#getWindowInsetsController`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
|
||||
line="203"
|
||||
column="9"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.WindowInsets.Type#ime`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
|
||||
line="203"
|
||||
column="60"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.WindowInsetsController#hide`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
|
||||
line="203"
|
||||
column="37"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.View#getWindowInsetsController`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
|
||||
line="193"
|
||||
column="17"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.WindowInsets.Type#ime`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
|
||||
line="193"
|
||||
column="68"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.WindowInsetsController#hide`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
|
||||
line="193"
|
||||
column="45"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 29): `android.appwidget.AppWidgetHostView#updateAppWidgetSize`"
|
||||
errorLine1=" widgetView.updateAppWidgetSize(new Bundle(), sizes);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/AppWidgetResizeFrame.java"
|
||||
line="399"
|
||||
column="24"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 29): `android.graphics.Rect#inset`"
|
||||
errorLine1=" potentialTaskRect.inset(insets.left, insets.top, insets.right, insets.bottom);"
|
||||
errorLine2=" ~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/BaseActivityInterface.java"
|
||||
line="248"
|
||||
column="27"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 29): `android.graphics.Rect#inset`"
|
||||
errorLine1=" potentialTaskRect.inset("
|
||||
errorLine2=" ~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/BaseActivityInterface.java"
|
||||
line="249"
|
||||
column="27"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 29): `android.graphics.Rect#inset`"
|
||||
errorLine1=" outRect.inset(Math.max(insets.left, sideMargin), Math.max(insets.top, topMargin),"
|
||||
errorLine2=" ~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/BaseActivityInterface.java"
|
||||
line="291"
|
||||
column="17"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 29): `android.graphics.Rect#inset`"
|
||||
errorLine1=" gridRect.inset(0, dp.overviewTaskThumbnailTopMarginPx, 0, 0);"
|
||||
errorLine2=" ~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/BaseActivityInterface.java"
|
||||
line="315"
|
||||
column="18"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.WindowManager#getCurrentWindowMetrics`"
|
||||
errorLine1=" .getCurrentWindowMetrics().getWindowInsets();"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
|
||||
line="236"
|
||||
column="22"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.WindowMetrics#getWindowInsets`"
|
||||
errorLine1=" .getCurrentWindowMetrics().getWindowInsets();"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
|
||||
line="236"
|
||||
column="48"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.content.Context#getDisplay`"
|
||||
errorLine1=" if (mContext.getDisplay() != null) {"
|
||||
errorLine2=" ~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java"
|
||||
line="115"
|
||||
column="26"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.content.Context#getDisplay`"
|
||||
errorLine1=" mContext.getDisplay().getRealSize(mDisplaySize);"
|
||||
errorLine2=" ~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java"
|
||||
line="116"
|
||||
column="26"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.content.ContextWrapper#getDisplay`"
|
||||
errorLine1=" Display display = getDisplay();"
|
||||
errorLine2=" ~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java"
|
||||
line="153"
|
||||
column="27"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `java.util.List#of`"
|
||||
errorLine1=" List.of(new Rect(0, 0, metrics.widthPixels, metrics.heightPixels)));"
|
||||
errorLine2=" ~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java"
|
||||
line="158"
|
||||
column="26"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 29): `android.appwidget.AppWidgetHostView#resetColorResources`"
|
||||
errorLine1=" resetColorResources();"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
|
||||
line="137"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `java.util.List#of`"
|
||||
errorLine1=" mColorExtractor.addLocation(List.of(mLastLocationRegistered));"
|
||||
errorLine2=" ~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
|
||||
line="367"
|
||||
column="46"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `java.util.List#of`"
|
||||
errorLine1=" mColorExtractor.addLocation(List.of(mLastLocationRegistered));"
|
||||
errorLine2=" ~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
|
||||
line="390"
|
||||
column="50"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#maxResizeWidth`"
|
||||
errorLine1=" (ATLEAST_S && maxResizeWidth > 0)"
|
||||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="91"
|
||||
column="31"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#maxResizeWidth`"
|
||||
errorLine1=" ? getSpanX(widgetPadding, maxResizeWidth, smallestCellWidth)"
|
||||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="92"
|
||||
column="51"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#maxResizeHeight`"
|
||||
errorLine1=" (ATLEAST_S && maxResizeHeight > 0)"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="95"
|
||||
column="31"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#maxResizeHeight`"
|
||||
errorLine1=" ? getSpanY(widgetPadding, maxResizeHeight, smallestCellHeight)"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="96"
|
||||
column="51"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
|
||||
errorLine1=" if (ATLEAST_S && targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="101"
|
||||
column="26"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
|
||||
errorLine1=" if (ATLEAST_S && targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="101"
|
||||
column="57"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
|
||||
errorLine1=" && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="102"
|
||||
column="20"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
|
||||
errorLine1=" && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="102"
|
||||
column="52"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
|
||||
errorLine1=" spanX = targetCellWidth;"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="103"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
|
||||
errorLine1=" spanY = targetCellHeight;"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="104"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.content.Context#getDisplay`"
|
||||
errorLine1=" final Display display = mContext.getDisplay();"
|
||||
errorLine2=" ~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java"
|
||||
line="94"
|
||||
column="42"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 29): `android.content.pm.LauncherActivityInfo#getLoadingProgress`"
|
||||
errorLine1=" return (int) (100 * info.getLoadingProgress());"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/util/PackageManagerHelper.java"
|
||||
line="338"
|
||||
column="38"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `java.util.List#of`"
|
||||
errorLine1=" private List<WidgetsListBaseEntry> mAllWidgets = List.of();"
|
||||
errorLine2=" ~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/popup/PopupDataProvider.java"
|
||||
line="64"
|
||||
column="59"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `java.util.List#of`"
|
||||
errorLine1=" private List<ItemInfo> mRecommendedWidgets = List.of();"
|
||||
errorLine2=" ~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/popup/PopupDataProvider.java"
|
||||
line="66"
|
||||
column="55"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `new android.view.SurfaceControlViewHost`"
|
||||
errorLine1=" .submit(() -> new SurfaceControlViewHost(mContext, mDisplay, mHostToken))"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
|
||||
line="91"
|
||||
column="35"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.SurfaceControlViewHost#getSurfacePackage`"
|
||||
errorLine1=" surfacePackage = mSurfaceControlViewHost.getSurfacePackage();"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
|
||||
line="93"
|
||||
column="54"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.SurfaceControlViewHost#setView`"
|
||||
errorLine1=" host.setView(view, view.getMeasuredWidth(), view.getMeasuredHeight());"
|
||||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
|
||||
line="127"
|
||||
column="22"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Cast from `SurfacePackage` to `Parcelable` requires API level 30 (current min is 29)"
|
||||
errorLine1=" result.putParcelable(KEY_SURFACE_PACKAGE, surfacePackage);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
|
||||
line="132"
|
||||
column="51"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.SurfaceControlViewHost#release`"
|
||||
errorLine1=" mSurfaceControlViewHost.release();"
|
||||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
|
||||
line="149"
|
||||
column="41"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.graphics.Outline#setPath`"
|
||||
errorLine1=" outline.setPath(mPath);"
|
||||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/popup/RoundedArrowDrawable.java"
|
||||
line="88"
|
||||
column="17"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 29): `new android.widget.EdgeEffect`"
|
||||
errorLine1=" ? new EdgeEffect(context, attrs) : new EdgeEffect(context);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/views/SpringRelativeLayout.java"
|
||||
line="49"
|
||||
column="19"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 29): `new android.widget.EdgeEffect`"
|
||||
errorLine1=" ? new EdgeEffect(context, attrs) : new EdgeEffect(context);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/views/SpringRelativeLayout.java"
|
||||
line="51"
|
||||
column="19"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.WindowManager.LayoutParams#setFitInsetsTypes`"
|
||||
errorLine1=" mWindowLayoutParams.setFitInsetsTypes(0);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java"
|
||||
line="316"
|
||||
column="29"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.WindowInsets#getInsets`"
|
||||
errorLine1=" Insets systemInsets = insets.getInsets(WindowInsets.Type.systemBars());"
|
||||
errorLine2=" ~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java"
|
||||
line="118"
|
||||
column="42"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.WindowInsets.Type#systemBars`"
|
||||
errorLine1=" Insets systemInsets = insets.getInsets(WindowInsets.Type.systemBars());"
|
||||
errorLine2=" ~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java"
|
||||
line="118"
|
||||
column="70"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#loadDescription`"
|
||||
errorLine1=" CharSequence description = mItem.widgetInfo.loadDescription(getContext());"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
|
||||
line="193"
|
||||
column="57"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#previewLayout`"
|
||||
errorLine1=" && item.widgetInfo.previewLayout != Resources.ID_NULL) {"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
|
||||
line="214"
|
||||
column="20"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#previewLayout`"
|
||||
errorLine1=" launcherAppWidgetProviderInfo.initialLayout = item.widgetInfo.previewLayout;"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
|
||||
line="222"
|
||||
column="59"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.View#getWindowInsetsController`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
|
||||
line="558"
|
||||
column="9"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.WindowInsets.Type#ime`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
|
||||
line="558"
|
||||
column="60"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `android.view.WindowInsetsController#hide`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
|
||||
line="558"
|
||||
column="37"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 29): `java.util.List#of`"
|
||||
errorLine1=" return new RecommendationTableData(List.of(), previewScale);"
|
||||
errorLine2=" ~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java"
|
||||
line="139"
|
||||
column="53"/>
|
||||
</issue>
|
||||
|
||||
</issues>
|
||||
@@ -0,0 +1,598 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.View#getWindowInsetsController`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
|
||||
line="203"
|
||||
column="9"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.WindowInsets.Type#ime`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
|
||||
line="203"
|
||||
column="60"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.WindowInsetsController#hide`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
|
||||
line="203"
|
||||
column="37"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.View#getWindowInsetsController`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
|
||||
line="193"
|
||||
column="17"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.WindowInsets.Type#ime`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
|
||||
line="193"
|
||||
column="68"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.WindowInsetsController#hide`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
|
||||
line="193"
|
||||
column="45"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#updateAppWidgetSize`"
|
||||
errorLine1=" widgetView.updateAppWidgetSize(new Bundle(), sizes);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/AppWidgetResizeFrame.java"
|
||||
line="399"
|
||||
column="24"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.WindowManager#getCurrentWindowMetrics`"
|
||||
errorLine1=" .getCurrentWindowMetrics().getWindowInsets();"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
|
||||
line="236"
|
||||
column="22"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.WindowMetrics#getWindowInsets`"
|
||||
errorLine1=" .getCurrentWindowMetrics().getWindowInsets();"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
|
||||
line="236"
|
||||
column="48"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 29 (current min is 26): `android.content.res.Resources#getFloat`"
|
||||
errorLine1=" folderLabelTextScale = res.getFloat(R.dimen.folder_label_text_scale);"
|
||||
errorLine2=" ~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
|
||||
line="256"
|
||||
column="36"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 29 (current min is 26): `android.content.res.Resources#getFloat`"
|
||||
errorLine1=" return mContext.getResources().getFloat(resId);"
|
||||
errorLine2=" ~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/util/DynamicResource.java"
|
||||
line="73"
|
||||
column="40"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#resetColorResources`"
|
||||
errorLine1=" resetColorResources();"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
|
||||
line="137"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `java.util.List#of`"
|
||||
errorLine1=" mColorExtractor.addLocation(List.of(mLastLocationRegistered));"
|
||||
errorLine2=" ~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
|
||||
line="367"
|
||||
column="46"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `java.util.List#of`"
|
||||
errorLine1=" mColorExtractor.addLocation(List.of(mLastLocationRegistered));"
|
||||
errorLine2=" ~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
|
||||
line="390"
|
||||
column="50"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#maxResizeWidth`"
|
||||
errorLine1=" (ATLEAST_S && maxResizeWidth > 0)"
|
||||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="91"
|
||||
column="31"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#maxResizeWidth`"
|
||||
errorLine1=" ? getSpanX(widgetPadding, maxResizeWidth, smallestCellWidth)"
|
||||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="92"
|
||||
column="51"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#maxResizeHeight`"
|
||||
errorLine1=" (ATLEAST_S && maxResizeHeight > 0)"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="95"
|
||||
column="31"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#maxResizeHeight`"
|
||||
errorLine1=" ? getSpanY(widgetPadding, maxResizeHeight, smallestCellHeight)"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="96"
|
||||
column="51"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
|
||||
errorLine1=" if (ATLEAST_S && targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="101"
|
||||
column="26"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
|
||||
errorLine1=" if (ATLEAST_S && targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="101"
|
||||
column="57"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
|
||||
errorLine1=" && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="102"
|
||||
column="20"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
|
||||
errorLine1=" && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="102"
|
||||
column="52"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
|
||||
errorLine1=" spanX = targetCellWidth;"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="103"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
|
||||
errorLine1=" spanY = targetCellHeight;"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
|
||||
line="104"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 28 (current min is 26): `android.app.Person#getKey`"
|
||||
errorLine1=" return people.stream().filter(person -> person.getKey() != null)"
|
||||
errorLine2=" ~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/notification/NotificationKeyData.java"
|
||||
line="72"
|
||||
column="56"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Method reference requires API level 28 (current min is 26): `Person::getKey`"
|
||||
errorLine1=" .map(Person::getKey).sorted().toArray(String[]::new);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/notification/NotificationKeyData.java"
|
||||
line="73"
|
||||
column="22"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 26): `android.content.pm.LauncherActivityInfo#getLoadingProgress`"
|
||||
errorLine1=" return (int) (100 * info.getLoadingProgress());"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/util/PackageManagerHelper.java"
|
||||
line="338"
|
||||
column="38"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`"
|
||||
errorLine1=" AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
|
||||
line="1752"
|
||||
column="17"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`"
|
||||
errorLine1=" : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
|
||||
line="1753"
|
||||
column="19"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`"
|
||||
errorLine1=" AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
|
||||
line="1760"
|
||||
column="17"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`"
|
||||
errorLine1=" : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
|
||||
line="1761"
|
||||
column="19"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `java.util.List#of`"
|
||||
errorLine1=" private List<WidgetsListBaseEntry> mAllWidgets = List.of();"
|
||||
errorLine2=" ~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/popup/PopupDataProvider.java"
|
||||
line="64"
|
||||
column="59"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `java.util.List#of`"
|
||||
errorLine1=" private List<ItemInfo> mRecommendedWidgets = List.of();"
|
||||
errorLine2=" ~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/popup/PopupDataProvider.java"
|
||||
line="66"
|
||||
column="55"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `new android.view.SurfaceControlViewHost`"
|
||||
errorLine1=" .submit(() -> new SurfaceControlViewHost(mContext, mDisplay, mHostToken))"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
|
||||
line="91"
|
||||
column="35"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.SurfaceControlViewHost#getSurfacePackage`"
|
||||
errorLine1=" surfacePackage = mSurfaceControlViewHost.getSurfacePackage();"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
|
||||
line="93"
|
||||
column="54"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.SurfaceControlViewHost#setView`"
|
||||
errorLine1=" host.setView(view, view.getMeasuredWidth(), view.getMeasuredHeight());"
|
||||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
|
||||
line="127"
|
||||
column="22"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Cast from `SurfacePackage` to `Parcelable` requires API level 30 (current min is 26)"
|
||||
errorLine1=" result.putParcelable(KEY_SURFACE_PACKAGE, surfacePackage);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
|
||||
line="132"
|
||||
column="51"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.SurfaceControlViewHost#release`"
|
||||
errorLine1=" mSurfaceControlViewHost.release();"
|
||||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
|
||||
line="149"
|
||||
column="41"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.graphics.Outline#setPath`"
|
||||
errorLine1=" outline.setPath(mPath);"
|
||||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/popup/RoundedArrowDrawable.java"
|
||||
line="88"
|
||||
column="17"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 26): `new android.widget.EdgeEffect`"
|
||||
errorLine1=" ? new EdgeEffect(context, attrs) : new EdgeEffect(context);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/views/SpringRelativeLayout.java"
|
||||
line="49"
|
||||
column="19"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 26): `new android.widget.EdgeEffect`"
|
||||
errorLine1=" ? new EdgeEffect(context, attrs) : new EdgeEffect(context);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/views/SpringRelativeLayout.java"
|
||||
line="51"
|
||||
column="19"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 29 (current min is 26): `android.view.WindowInsets#getTappableElementInsets`"
|
||||
errorLine1=" return windowInsets.getTappableElementInsets().bottom > 0;"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/SysUiScrim.java"
|
||||
line="190"
|
||||
column="33"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 29 (current min is 26): `android.graphics.Insets#bottom`"
|
||||
errorLine1=" return windowInsets.getTappableElementInsets().bottom > 0;"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/SysUiScrim.java"
|
||||
line="190"
|
||||
column="20"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 28 (current min is 26): `android.appwidget.AppWidgetProviderInfo#widgetFeatures`"
|
||||
errorLine1=" int featureFlags = mProviderInfo.widgetFeatures;"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetAddFlowHandler.java"
|
||||
line="93"
|
||||
column="28"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#loadDescription`"
|
||||
errorLine1=" CharSequence description = mItem.widgetInfo.loadDescription(getContext());"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
|
||||
line="193"
|
||||
column="57"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#previewLayout`"
|
||||
errorLine1=" && item.widgetInfo.previewLayout != Resources.ID_NULL) {"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
|
||||
line="214"
|
||||
column="20"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#previewLayout`"
|
||||
errorLine1=" launcherAppWidgetProviderInfo.initialLayout = item.widgetInfo.previewLayout;"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
|
||||
line="222"
|
||||
column="59"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.View#getWindowInsetsController`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
|
||||
line="558"
|
||||
column="9"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.WindowInsets.Type#ime`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
|
||||
line="558"
|
||||
column="60"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `android.view.WindowInsetsController#hide`"
|
||||
errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
|
||||
errorLine2=" ~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
|
||||
line="558"
|
||||
column="37"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level R (current min is 26): `java.util.List#of`"
|
||||
errorLine1=" return new RecommendationTableData(List.of(), previewScale);"
|
||||
errorLine2=" ~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java"
|
||||
line="139"
|
||||
column="53"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Method reference requires API level 28 (current min is 26): `Person::getKey`"
|
||||
errorLine1=" : Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/model/data/WorkspaceItemInfo.java"
|
||||
line="178"
|
||||
column="42"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#setColorResources`"
|
||||
errorLine1=" view.setColorResources(mWallpaperColorResources);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java"
|
||||
line="381"
|
||||
column="18"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 27 (current min is 26): `android.app.WallpaperManager#getWallpaperColors`"
|
||||
errorLine1=" : WallpaperManager.getInstance(context).getWallpaperColors(FLAG_SYSTEM);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java"
|
||||
line="270"
|
||||
column="61"/>
|
||||
</issue>
|
||||
|
||||
</issues>
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
|
||||
errorLine1=" android:topLeftRadius="?android:attr/dialogCornerRadius""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
|
||||
line="6"
|
||||
column="9"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
|
||||
errorLine1=" android:topRightRadius="?android:attr/dialogCornerRadius" />"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
|
||||
line="7"
|
||||
column="9"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="`@android:style/Widget.DeviceDefault.Button.Colored` requires API level 28 (current min is 26)"
|
||||
errorLine1=" <style name="Widget.DeviceDefault.Button.Rounded.Colored" parent="@android:style/Widget.DeviceDefault.Button.Colored">"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/res/values/styles.xml"
|
||||
line="287"
|
||||
column="63"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="`@android:dimen/system_app_widget_background_radius` requires API level 31 (current min is 26)"
|
||||
errorLine1=" <corners android:radius="@android:dimen/system_app_widget_background_radius" />"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
|
||||
line="20"
|
||||
column="14"/>
|
||||
</issue>
|
||||
|
||||
</issues>
|
||||
+3
-2
@@ -45,9 +45,10 @@
|
||||
|
||||
# BUG(70852369): Surpress additional warnings after changing from Proguard to R8
|
||||
-dontwarn android.app.**
|
||||
-dontwarn android.view.**
|
||||
-dontwarn android.os.**
|
||||
-dontwarn android.graphics.**
|
||||
-dontwarn android.os.**
|
||||
-dontwarn android.view.**
|
||||
-dontwarn android.window.**
|
||||
|
||||
# Ignore warnings for hidden utility classes referenced from the shared lib
|
||||
-dontwarn com.android.internal.util.**
|
||||
|
||||
@@ -18,6 +18,8 @@ syntax = "proto2";
|
||||
option java_package = "com.android.launcher3.logger";
|
||||
option java_outer_classname = "LauncherAtom";
|
||||
|
||||
import "launcher_atom_extension.proto";
|
||||
|
||||
//
|
||||
// ItemInfos
|
||||
message ItemInfo {
|
||||
@@ -27,6 +29,8 @@ message ItemInfo {
|
||||
Shortcut shortcut = 3;
|
||||
Widget widget = 4;
|
||||
FolderIcon folder_icon = 9;
|
||||
Slice slice = 10;
|
||||
SearchActionItem search_action_item = 11;
|
||||
}
|
||||
// When used for launch event, stores the global predictive rank
|
||||
optional int32 rank = 5;
|
||||
@@ -55,7 +59,7 @@ message ContainerInfo {
|
||||
SettingsContainer settings_container = 9;
|
||||
PredictedHotseatContainer predicted_hotseat_container = 10;
|
||||
TaskSwitcherContainer task_switcher_container = 11;
|
||||
TaskForegroundContainer task_foreground_container = 12;
|
||||
ExtendedContainers extended_containers = 20;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,14 +97,8 @@ message ShortcutsContainer {
|
||||
message SettingsContainer {
|
||||
}
|
||||
|
||||
// Container for tasks in the Overview UI.
|
||||
// Typically entered using either the overview gesture or overview button.
|
||||
message TaskSwitcherContainer {}
|
||||
|
||||
// Container for tasks from another foreground app, when not on launcher screen.
|
||||
// Typically home gesture or overview gesture can be triggered from
|
||||
// this container.
|
||||
message TaskForegroundContainer {}
|
||||
message TaskSwitcherContainer {
|
||||
}
|
||||
|
||||
enum Attribute {
|
||||
UNKNOWN = 0;
|
||||
@@ -127,6 +125,25 @@ enum Attribute {
|
||||
// Folder's label is empty(i.e., title == "").
|
||||
// Not eligible for auto-labeling.
|
||||
EMPTY_LABEL = 12;
|
||||
|
||||
ALL_APPS_SEARCH_RESULT_APPLICATION = 13;
|
||||
ALL_APPS_SEARCH_RESULT_SHORTCUT = 14;
|
||||
ALL_APPS_SEARCH_RESULT_PEOPLE = 15;
|
||||
ALL_APPS_SEARCH_RESULT_ACTION = 16;
|
||||
ALL_APPS_SEARCH_RESULT_SETTING = 17;
|
||||
ALL_APPS_SEARCH_RESULT_SCREENSHOT = 18;
|
||||
ALL_APPS_SEARCH_RESULT_SLICE = 19;
|
||||
ALL_APPS_SEARCH_RESULT_WIDGETS = 20;
|
||||
ALL_APPS_SEARCH_RESULT_PLAY = 21;
|
||||
ALL_APPS_SEARCH_RESULT_SUGGEST = 22;
|
||||
ALL_APPS_SEARCH_RESULT_ASSISTANT = 23;
|
||||
ALL_APPS_SEARCH_RESULT_CHROMETAB = 24;
|
||||
ALL_APPS_SEARCH_RESULT_NAVVYSITE = 25;
|
||||
ALL_APPS_SEARCH_RESULT_TIPS = 26;
|
||||
ALL_APPS_SEARCH_RESULT_PEOPLE_TILE = 27;
|
||||
|
||||
WIDGETS_BOTTOM_TRAY = 28;
|
||||
WIDGETS_TRAY_PREDICTION = 29;
|
||||
}
|
||||
|
||||
// Main app icons
|
||||
@@ -138,6 +155,7 @@ message Application {
|
||||
// Legacy shortcuts and shortcuts handled by ShortcutManager
|
||||
message Shortcut {
|
||||
optional string shortcut_name = 1;
|
||||
optional string shortcut_id = 2;
|
||||
}
|
||||
|
||||
// AppWidgets handled by AppWidgetManager
|
||||
@@ -147,6 +165,7 @@ message Widget {
|
||||
optional int32 app_widget_id = 3;
|
||||
optional string package_name = 4; // only populated during snapshot if from workspace
|
||||
optional string component_name = 5; // only populated during snapshot if from workspace
|
||||
optional int32 widget_features = 6;
|
||||
}
|
||||
|
||||
// Tasks handled by PackageManager
|
||||
@@ -172,6 +191,17 @@ message FolderIcon {
|
||||
optional string label_info = 4;
|
||||
}
|
||||
|
||||
// Contains Slice details for logging.
|
||||
message Slice{
|
||||
optional string uri = 1;
|
||||
}
|
||||
|
||||
// Represents SearchAction with in launcher
|
||||
message SearchActionItem{
|
||||
optional string package_name = 1;
|
||||
optional string title = 2;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Containers
|
||||
|
||||
|
||||
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
syntax = "proto2";
|
||||
|
||||
import "launcher_log_extension.proto";
|
||||
|
||||
option java_package = "com.android.launcher3.userevent";
|
||||
option java_outer_classname = "LauncherLogProto";
|
||||
|
||||
package userevent;
|
||||
|
||||
message Target {
|
||||
enum Type {
|
||||
NONE = 0;
|
||||
ITEM = 1;
|
||||
CONTROL = 2;
|
||||
CONTAINER = 3;
|
||||
}
|
||||
|
||||
optional Type type = 1;
|
||||
|
||||
// For container type and item type
|
||||
// Used mainly for ContainerType.FOLDER, ItemType.*
|
||||
optional int32 page_index = 2;
|
||||
optional int32 rank = 3;
|
||||
optional int32 grid_x = 4;
|
||||
optional int32 grid_y = 5;
|
||||
|
||||
// For container types only
|
||||
optional ContainerType container_type = 6;
|
||||
optional int32 cardinality = 7;
|
||||
|
||||
// For control types only
|
||||
optional ControlType control_type = 8;
|
||||
|
||||
// For item types only
|
||||
optional ItemType item_type = 9;
|
||||
optional int32 package_name_hash = 10;
|
||||
optional int32 component_hash = 11; // Used for ItemType.WIDGET
|
||||
optional int32 intent_hash = 12; // Used for ItemType.SHORTCUT
|
||||
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;
|
||||
optional TipType tip_type = 17;
|
||||
optional int32 search_query_length = 18;
|
||||
optional bool is_work_app = 19;
|
||||
optional FromFolderLabelState from_folder_label_state = 20;
|
||||
optional ToFolderLabelState to_folder_label_state = 21;
|
||||
|
||||
// Note: proto does not support duplicate enum values, even if they belong to different enum type.
|
||||
// Hence "FROM" and "TO" prefix added.
|
||||
enum FromFolderLabelState {
|
||||
FROM_FOLDER_LABEL_STATE_UNSPECIFIED = 0;
|
||||
FROM_EMPTY = 1;
|
||||
FROM_CUSTOM = 2;
|
||||
FROM_SUGGESTED = 3;
|
||||
}
|
||||
|
||||
enum ToFolderLabelState {
|
||||
TO_FOLDER_LABEL_STATE_UNSPECIFIED = 0;
|
||||
TO_SUGGESTION0_WITH_VALID_PRIMARY = 1;
|
||||
TO_SUGGESTION1_WITH_VALID_PRIMARY = 2;
|
||||
TO_SUGGESTION1_WITH_EMPTY_PRIMARY = 3;
|
||||
TO_SUGGESTION2_WITH_VALID_PRIMARY = 4;
|
||||
TO_SUGGESTION2_WITH_EMPTY_PRIMARY = 5;
|
||||
TO_SUGGESTION3_WITH_VALID_PRIMARY = 6;
|
||||
TO_SUGGESTION3_WITH_EMPTY_PRIMARY = 7;
|
||||
TO_EMPTY_WITH_VALID_SUGGESTIONS = 8 [deprecated = true];
|
||||
TO_EMPTY_WITH_VALID_PRIMARY = 15;
|
||||
TO_EMPTY_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY = 16;
|
||||
TO_EMPTY_WITH_EMPTY_SUGGESTIONS = 9;
|
||||
TO_EMPTY_WITH_SUGGESTIONS_DISABLED = 10;
|
||||
TO_CUSTOM_WITH_VALID_SUGGESTIONS = 11 [deprecated = true];
|
||||
TO_CUSTOM_WITH_VALID_PRIMARY = 17;
|
||||
TO_CUSTOM_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY = 18;
|
||||
TO_CUSTOM_WITH_EMPTY_SUGGESTIONS = 12;
|
||||
TO_CUSTOM_WITH_SUGGESTIONS_DISABLED = 13;
|
||||
UNCHANGED = 14;
|
||||
}
|
||||
}
|
||||
|
||||
// Used to define what type of item a Target would represent.
|
||||
enum ItemType {
|
||||
DEFAULT_ITEMTYPE = 0;
|
||||
APP_ICON = 1;
|
||||
SHORTCUT = 2;
|
||||
WIDGET = 3;
|
||||
FOLDER_ICON = 4;
|
||||
DEEPSHORTCUT = 5;
|
||||
SEARCHBOX = 6;
|
||||
EDITTEXT = 7;
|
||||
NOTIFICATION = 8;
|
||||
TASK = 9; // Each page of Recents UI (QuickStep)
|
||||
WEB_APP = 10;
|
||||
TASK_ICON = 11;
|
||||
}
|
||||
|
||||
// Used to define what type of container a Target would represent.
|
||||
enum ContainerType {
|
||||
DEFAULT_CONTAINERTYPE = 0;
|
||||
WORKSPACE = 1;
|
||||
HOTSEAT = 2;
|
||||
FOLDER = 3;
|
||||
ALLAPPS = 4;
|
||||
WIDGETS = 5;
|
||||
OVERVIEW = 6; // Zoomed out workspace (without QuickStep)
|
||||
PREDICTION = 7;
|
||||
SEARCHRESULT = 8;
|
||||
DEEPSHORTCUTS = 9;
|
||||
PINITEM = 10; // confirmation screen
|
||||
NAVBAR = 11;
|
||||
TASKSWITCHER = 12; // Recents UI Container (QuickStep)
|
||||
APP = 13; // Foreground activity is another app (QuickStep)
|
||||
TIP = 14; // Onboarding texts (QuickStep)
|
||||
OTHER_LAUNCHER_APP = 15;
|
||||
}
|
||||
|
||||
// Used to define what type of control a Target would represent.
|
||||
enum ControlType {
|
||||
DEFAULT_CONTROLTYPE = 0;
|
||||
ALL_APPS_BUTTON = 1;
|
||||
WIDGETS_BUTTON = 2;
|
||||
WALLPAPER_BUTTON = 3;
|
||||
SETTINGS_BUTTON = 4;
|
||||
REMOVE_TARGET = 5;
|
||||
UNINSTALL_TARGET = 6;
|
||||
APPINFO_TARGET = 7;
|
||||
RESIZE_HANDLE = 8;
|
||||
VERTICAL_SCROLL = 9;
|
||||
HOME_INTENT = 10; // Deprecated, use enum Command instead
|
||||
BACK_BUTTON = 11;
|
||||
QUICK_SCRUB_BUTTON = 12;
|
||||
CLEAR_ALL_BUTTON = 13;
|
||||
CANCEL_TARGET = 14;
|
||||
TASK_PREVIEW = 15;
|
||||
SPLIT_SCREEN_TARGET = 16;
|
||||
REMOTE_ACTION_SHORTCUT = 17;
|
||||
APP_USAGE_SETTINGS = 18;
|
||||
BACK_GESTURE = 19;
|
||||
UNDO = 20;
|
||||
DISMISS_PREDICTION = 21;
|
||||
HYBRID_HOTSEAT_ACCEPTED = 22;
|
||||
HYBRID_HOTSEAT_CANCELED = 23;
|
||||
OVERVIEW_ACTIONS_SHARE_BUTTON = 24;
|
||||
OVERVIEW_ACTIONS_SCREENSHOT_BUTTON = 25;
|
||||
OVERVIEW_ACTIONS_SELECT_BUTTON = 26;
|
||||
SELECT_MODE_CLOSE_BUTTON = 27;
|
||||
SELECT_MODE_ITEM = 28;
|
||||
}
|
||||
|
||||
enum TipType {
|
||||
DEFAULT_NONE = 0;
|
||||
BOUNCE = 1;
|
||||
SWIPE_UP_TEXT = 2;
|
||||
QUICK_SCRUB_TEXT = 3;
|
||||
PREDICTION_TEXT = 4;
|
||||
DWB_TOAST = 5;
|
||||
HYBRID_HOTSEAT = 6;
|
||||
}
|
||||
|
||||
// Used to define the action component of the LauncherEvent.
|
||||
message Action {
|
||||
enum Type {
|
||||
TOUCH = 0;
|
||||
AUTOMATED = 1;
|
||||
COMMAND = 2;
|
||||
TIP = 3;
|
||||
SOFT_KEYBOARD = 4;
|
||||
// HARD_KEYBOARD, ASSIST
|
||||
}
|
||||
|
||||
enum Touch {
|
||||
TAP = 0;
|
||||
LONGPRESS = 1;
|
||||
DRAGDROP = 2;
|
||||
SWIPE = 3;
|
||||
FLING = 4;
|
||||
PINCH = 5;
|
||||
SWIPE_NOOP = 6;
|
||||
}
|
||||
|
||||
enum Direction {
|
||||
NONE = 0;
|
||||
UP = 1;
|
||||
DOWN = 2;
|
||||
LEFT = 3;
|
||||
RIGHT = 4;
|
||||
UPRIGHT = 5;
|
||||
UPLEFT = 6;
|
||||
}
|
||||
enum Command {
|
||||
HOME_INTENT = 0;
|
||||
BACK = 1;
|
||||
ENTRY = 2; // Indicates entry to one of Launcher container type target
|
||||
// not using the HOME_INTENT
|
||||
CANCEL = 3; // Indicates that a confirmation screen was cancelled
|
||||
CONFIRM = 4; // Indicates thata confirmation screen was accepted
|
||||
STOP = 5; // Indicates onStop() was called (screen time out, power off)
|
||||
RECENTS_BUTTON = 6; // Indicates that Recents button was pressed
|
||||
RESUME = 7; // Indicates onResume() was called
|
||||
}
|
||||
|
||||
optional Type type = 1;
|
||||
optional Touch touch = 2;
|
||||
optional Direction dir = 3;
|
||||
optional Command command = 4;
|
||||
// Log if the action was performed on outside of the container
|
||||
optional bool is_outside = 5;
|
||||
optional bool is_state_change = 6;
|
||||
}
|
||||
|
||||
//
|
||||
// Context free grammar of typical user interaction:
|
||||
// Action (Touch) + Target
|
||||
// Action (Touch) + Target + Target
|
||||
//
|
||||
message LauncherEvent {
|
||||
required Action action = 1;
|
||||
// List of targets that touch actions can be operated on.
|
||||
repeated Target src_target = 2;
|
||||
repeated Target dest_target = 3;
|
||||
|
||||
optional int64 action_duration_millis = 4;
|
||||
optional int64 elapsed_container_millis = 5;
|
||||
optional int64 elapsed_session_millis = 6;
|
||||
|
||||
optional bool is_in_multi_window_mode = 7 [deprecated = true];
|
||||
optional bool is_in_landscape_mode = 8 [deprecated = true];
|
||||
|
||||
optional LauncherEventExtension extension = 9;
|
||||
}
|
||||
@@ -28,4 +28,40 @@ message LauncherTraceProto {
|
||||
message TouchInteractionServiceProto {
|
||||
|
||||
optional bool service_connected = 1;
|
||||
optional OverviewComponentObserverProto overview_component_obvserver = 2;
|
||||
optional InputConsumerProto input_consumer = 3;
|
||||
}
|
||||
|
||||
message OverviewComponentObserverProto {
|
||||
|
||||
optional bool overview_activity_started = 1;
|
||||
optional bool overview_activity_resumed = 2;
|
||||
}
|
||||
|
||||
message InputConsumerProto {
|
||||
|
||||
optional string name = 1;
|
||||
optional SwipeHandlerProto swipe_handler = 2;
|
||||
}
|
||||
|
||||
message SwipeHandlerProto {
|
||||
|
||||
optional GestureStateProto gesture_state = 1;
|
||||
optional bool is_recents_attached_to_app_window = 2;
|
||||
optional int32 scroll_offset = 3;
|
||||
// Swipe up progress from 0 (app) to 1 (overview); can be > 1 if swiping past overview.
|
||||
optional float app_to_overview_progress = 4;
|
||||
}
|
||||
|
||||
message GestureStateProto {
|
||||
|
||||
optional GestureEndTarget endTarget = 1 [default = UNSET];
|
||||
|
||||
enum GestureEndTarget {
|
||||
UNSET = 0;
|
||||
HOME = 1;
|
||||
RECENTS = 2;
|
||||
NEW_TASK = 3;
|
||||
LAST_TASK = 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
syntax = "proto2";
|
||||
|
||||
option java_package = "com.android.launcher3.logger";
|
||||
option java_outer_classname = "LauncherAtomExtensions";
|
||||
|
||||
|
||||
// This proto file contains placeholder messages that can be overridden by
|
||||
// other Launcher variants.
|
||||
// Variants could have its own launcher_atom_extension.proto file(should have
|
||||
// same messages declared here but with different implementation); when building
|
||||
// variant's apk launcher_atom.proto will reference variant's extension file,
|
||||
// essentially overriding this file.
|
||||
|
||||
|
||||
// Wrapper message for additional containers used in variants.
|
||||
message ExtendedContainers {}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2021 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package {
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "packages_apps_Launcher3_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["packages_apps_Launcher3_license"],
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "launcher3-quickstep-robolectric-src",
|
||||
path: "robolectric_tests",
|
||||
srcs: ["robolectric_tests/src/**/*.java"],
|
||||
}
|
||||
@@ -49,10 +49,11 @@
|
||||
android:stateNotNeeded="true"
|
||||
android:windowSoftInputMode="adjustPan"
|
||||
android:screenOrientation="unspecified"
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density"
|
||||
android:resizeableActivity="true"
|
||||
android:resumeWhilePausing="true"
|
||||
android:taskAffinity=""
|
||||
android:exported="true"
|
||||
android:enabled="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
@@ -17,106 +17,130 @@
|
||||
** 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" >
|
||||
|
||||
<permission
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.android.launcher3">
|
||||
|
||||
<permission
|
||||
android:name="${packageName}.permission.HOTSEAT_EDU"
|
||||
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
|
||||
android:protectionLevel="signatureOrSystem" />
|
||||
|
||||
<uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
|
||||
<uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
|
||||
<uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS"/>
|
||||
<uses-permission android:name="android.permission.REMOVE_TASKS"/>
|
||||
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>
|
||||
<uses-permission android:name="android.permission.STATUS_BAR"/>
|
||||
<uses-permission android:name="android.permission.STOP_APP_SWITCHES"/>
|
||||
<uses-permission android:name="android.permission.SET_ORIENTATION"/>
|
||||
<uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY"/>
|
||||
<uses-permission android:name="android.permission.MONITOR_INPUT"/>
|
||||
|
||||
<uses-permission android:name="${packageName}.permission.HOTSEAT_EDU" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" />
|
||||
|
||||
<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/AppTheme"
|
||||
android:largeHeap="@bool/config_largeHeap"
|
||||
android:restoreAnyVersion="true"
|
||||
android:supportsRtl="true" >
|
||||
<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/AppTheme"
|
||||
android:largeHeap="@bool/config_largeHeap"
|
||||
android:restoreAnyVersion="true"
|
||||
android:supportsRtl="true">
|
||||
|
||||
<service
|
||||
android:name="com.android.quickstep.TouchInteractionService"
|
||||
android:permission="android.permission.STATUS_BAR_SERVICE"
|
||||
android:directBootAware="true" >
|
||||
<service android:name="com.android.quickstep.TouchInteractionService"
|
||||
android:permission="android.permission.STATUS_BAR_SERVICE"
|
||||
android:directBootAware="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.QUICKSTEP_SERVICE" />
|
||||
<action android:name="android.intent.action.QUICKSTEP_SERVICE"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<activity android:name="com.android.quickstep.RecentsActivity"
|
||||
android:excludeFromRecents="true"
|
||||
android:launchMode="singleTask"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:stateNotNeeded="true"
|
||||
android:theme="@style/LauncherTheme"
|
||||
android:screenOrientation="unspecified"
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
|
||||
android:resizeableActivity="true"
|
||||
android:resumeWhilePausing="true"
|
||||
android:taskAffinity="" />
|
||||
android:excludeFromRecents="true"
|
||||
android:launchMode="singleTask"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:stateNotNeeded="true"
|
||||
android:theme="@style/LauncherTheme"
|
||||
android:screenOrientation="unspecified"
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density"
|
||||
android:resizeableActivity="true"
|
||||
android:resumeWhilePausing="true"
|
||||
android:taskAffinity=""/>
|
||||
|
||||
<!-- Content provider to settings search. The autority should be same as the packageName -->
|
||||
<provider
|
||||
android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
|
||||
android:authorities="${packageName}"
|
||||
android:grantUriPermissions="true"
|
||||
android:multiprocess="true"
|
||||
android:permission="android.permission.READ_SEARCH_INDEXABLES"
|
||||
android:exported="true">
|
||||
<provider android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
|
||||
android:authorities="${packageName}"
|
||||
android:grantUriPermissions="true"
|
||||
android:multiprocess="true"
|
||||
android:permission="android.permission.READ_SEARCH_INDEXABLES"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" />
|
||||
<action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER"/>
|
||||
</intent-filter>
|
||||
</provider>
|
||||
|
||||
<!-- FileProvider used for sharing images. -->
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${packageName}.overview.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/overview_file_provider_paths" />
|
||||
<provider android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${packageName}.overview.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/overview_file_provider_paths"/>
|
||||
</provider>
|
||||
|
||||
<service
|
||||
android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
|
||||
tools:node="remove" />
|
||||
<activity android:name="com.android.launcher3.proxy.ProxyActivityStarter"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
|
||||
android:launchMode="singleTask"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity
|
||||
android:name="com.android.launcher3.proxy.ProxyActivityStarter"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
|
||||
android:launchMode="singleTask"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:exported="false" />
|
||||
|
||||
<activity
|
||||
android:name="com.android.quickstep.interaction.GestureSandboxActivity"
|
||||
<activity android:name="com.android.quickstep.interaction.GestureSandboxActivity"
|
||||
android:autoRemoveFromRecents="true"
|
||||
android:excludeFromRecents="true"
|
||||
android:screenOrientation="portrait">
|
||||
android:screenOrientation="portrait"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.quickstep.action.GESTURE_SANDBOX" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<action android:name="com.android.quickstep.action.GESTURE_SANDBOX"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!--
|
||||
Activity following gesture nav onboarding.
|
||||
It's protected by android.permission.REBOOT to ensure that only system apps can start it
|
||||
(setup wizard already has this permission)
|
||||
-->
|
||||
<activity android:name="com.android.quickstep.interaction.AllSetActivity"
|
||||
android:autoRemoveFromRecents="true"
|
||||
android:excludeFromRecents="true"
|
||||
android:screenOrientation="portrait"
|
||||
android:permission="android.permission.REBOOT"
|
||||
android:theme="@style/AllSetTheme"
|
||||
android:label="@string/allset_title"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.quickstep.action.GESTURE_ONBOARDING_ALL_SET"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".hybridhotseat.HotseatEduActivity"
|
||||
android:theme="@android:style/Theme.NoDisplay"
|
||||
android:noHistory="true"
|
||||
android:launchMode="singleTask"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:permission="${packageName}.permission.HOTSEAT_EDU">
|
||||
android:permission="${packageName}.permission.HOTSEAT_EDU"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.launcher3.action.SHOW_HYBRID_HOTSEAT_EDU"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
syntax = "proto2";
|
||||
|
||||
option java_package = "com.android.launcher3.logger";
|
||||
option java_outer_classname = "LauncherAtomExtensions";
|
||||
|
||||
|
||||
// Wrapper message for containers used at the quickstep level.
|
||||
// Message name should match with launcher_atom_extension.proto message at
|
||||
// the AOSP level.
|
||||
message ExtendedContainers {
|
||||
|
||||
oneof Container{
|
||||
DeviceSearchResultContainer device_search_result_container = 1;
|
||||
CorrectedDeviceSearchResultContainer corrected_device_search_result_container = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Represents on-device search result container.
|
||||
message DeviceSearchResultContainer{
|
||||
optional int32 query_length = 1;
|
||||
}
|
||||
|
||||
// Represents on-device search result container with results from spell-corrected query.
|
||||
message CorrectedDeviceSearchResultContainer{
|
||||
optional int32 query_length = 1;
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<gradient
|
||||
android:angle="90"
|
||||
android:endColor="@android:color/transparent"
|
||||
android:startColor="@color/chip_scrim_start_color"
|
||||
android:type="linear" />
|
||||
</shape>
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<color name="chip_hint_foreground_color">#fff</color>
|
||||
<color name="chip_scrim_start_color">#39000000</color>
|
||||
|
||||
<color name="all_apps_label_text">#61000000</color>
|
||||
<color name="all_apps_label_text_dark">#61FFFFFF</color>
|
||||
<color name="all_apps_prediction_row_separator">#3c000000</color>
|
||||
<color name="all_apps_prediction_row_separator_dark">#3cffffff</color>
|
||||
</resources>
|
||||
@@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<dimen name="chip_hint_border_width">1dp</dimen>
|
||||
<dimen name="chip_hint_corner_radius">20dp</dimen>
|
||||
<dimen name="chip_hint_outer_padding">20dp</dimen>
|
||||
<dimen name="chip_hint_start_padding">10dp</dimen>
|
||||
<dimen name="chip_hint_end_padding">12dp</dimen>
|
||||
<dimen name="chip_hint_horizontal_margin">20dp</dimen>
|
||||
<dimen name="chip_hint_vertical_offset">16dp</dimen>
|
||||
<dimen name="chip_hint_elevation">2dp</dimen>
|
||||
<dimen name="chip_icon_size">16dp</dimen>
|
||||
<dimen name="chip_text_height">26dp</dimen>
|
||||
<dimen name="chip_text_top_padding">4dp</dimen>
|
||||
<dimen name="chip_text_start_padding">10dp</dimen>
|
||||
<dimen name="chip_text_size">14sp</dimen>
|
||||
|
||||
<dimen name="all_apps_prediction_row_divider_height">17dp</dimen>
|
||||
<dimen name="all_apps_label_top_padding">16dp</dimen>
|
||||
<dimen name="all_apps_label_bottom_padding">8dp</dimen>
|
||||
<dimen name="all_apps_label_text_size">14sp</dimen>
|
||||
|
||||
<!-- Minimum distance to swipe to trigger accessibility gesture -->
|
||||
<dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
|
||||
</resources>
|
||||
-134
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
|
||||
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
|
||||
/**
|
||||
* A {@link QuickstepAppTransitionManagerImpl} that also implements recents transitions from
|
||||
* {@link RecentsView}.
|
||||
*/
|
||||
public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransitionManagerImpl {
|
||||
|
||||
public LauncherAppTransitionManagerImpl(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLaunchingFromRecents(@NonNull View v,
|
||||
@Nullable RemoteAnimationTargetCompat[] targets) {
|
||||
return mLauncher.getStateManager().getState().overviewUi
|
||||
&& findTaskViewToLaunch(mLauncher, v, targets) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
|
||||
@NonNull RemoteAnimationTargetCompat[] appTargets,
|
||||
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing) {
|
||||
RecentsView recentsView = mLauncher.getOverviewPanel();
|
||||
boolean skipLauncherChanges = !launcherClosing;
|
||||
|
||||
TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets);
|
||||
PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
|
||||
createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets,
|
||||
mLauncher.getDepthController(), pa);
|
||||
anim.play(pa.buildAnim());
|
||||
|
||||
Animator childStateAnimation = null;
|
||||
// Found a visible recents task that matches the opening app, lets launch the app from there
|
||||
Animator launcherAnim;
|
||||
final AnimatorListenerAdapter windowAnimEndListener;
|
||||
if (launcherClosing) {
|
||||
launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView);
|
||||
launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
|
||||
launcherAnim.setDuration(RECENTS_LAUNCH_DURATION);
|
||||
|
||||
// Make sure recents gets fixed up by resetting task alphas and scales, etc.
|
||||
windowAnimEndListener = new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mLauncher.getStateManager().moveToRestState();
|
||||
mLauncher.getStateManager().reapplyState();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
AnimatorPlaybackController controller =
|
||||
mLauncher.getStateManager().createAnimationToNewWorkspace(NORMAL,
|
||||
RECENTS_LAUNCH_DURATION);
|
||||
controller.dispatchOnStart();
|
||||
childStateAnimation = controller.getTarget();
|
||||
launcherAnim = controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION);
|
||||
windowAnimEndListener = new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mLauncher.getStateManager().goToState(NORMAL, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
anim.play(launcherAnim);
|
||||
|
||||
// Set the current animation first, before adding windowAnimEndListener. Setting current
|
||||
// animation adds some listeners which need to be called before windowAnimEndListener
|
||||
// (the ordering of listeners matter in this case).
|
||||
mLauncher.getStateManager().setCurrentAnimation(anim, childStateAnimation);
|
||||
anim.addListener(windowAnimEndListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Runnable composeViewContentAnimator(@NonNull AnimatorSet anim, float[] alphas,
|
||||
float[] trans) {
|
||||
RecentsView overview = mLauncher.getOverviewPanel();
|
||||
ObjectAnimator alpha = ObjectAnimator.ofFloat(overview,
|
||||
RecentsView.CONTENT_ALPHA, alphas);
|
||||
alpha.setDuration(CONTENT_ALPHA_DURATION);
|
||||
alpha.setInterpolator(LINEAR);
|
||||
anim.play(alpha);
|
||||
overview.setFreezeViewVisibility(true);
|
||||
|
||||
ObjectAnimator transY = ObjectAnimator.ofFloat(overview, View.TRANSLATION_Y, trans);
|
||||
transY.setInterpolator(AGGRESSIVE_EASE);
|
||||
transY.setDuration(CONTENT_TRANSLATION_DURATION);
|
||||
anim.play(transY);
|
||||
|
||||
return () -> {
|
||||
overview.setFreezeViewVisibility(false);
|
||||
overview.setTranslationY(0);
|
||||
mLauncher.getStateManager().reapplyState();
|
||||
};
|
||||
}
|
||||
}
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.appprediction;
|
||||
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_ON_BOARD_POPUP;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.quickstep.logging.UserEventDispatcherExtension.ALL_APPS_PREDICTION_TIPS;
|
||||
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.FloatingHeaderView;
|
||||
import com.android.launcher3.statemanager.StateManager.StateListener;
|
||||
import com.android.launcher3.views.ArrowTipView;
|
||||
import com.android.systemui.shared.system.LauncherEventUtil;
|
||||
|
||||
/**
|
||||
* ArrowTip helper aligned just above prediction apps, shown to users that enter all apps for the
|
||||
* first time.
|
||||
*/
|
||||
public class AllAppsTipView {
|
||||
|
||||
private static final String ALL_APPS_TIP_SEEN = "launcher.all_apps_tip_seen";
|
||||
|
||||
private static boolean showAllAppsTipIfNecessary(Launcher launcher) {
|
||||
FloatingHeaderView floatingHeaderView = launcher.getAppsView().getFloatingHeaderView();
|
||||
if (!floatingHeaderView.hasVisibleContent()
|
||||
|| AbstractFloatingView.getOpenView(launcher,
|
||||
TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE) != null
|
||||
|| !launcher.isInState(ALL_APPS)
|
||||
|| hasSeenAllAppsTip(launcher)
|
||||
|| launcher.getSystemService(UserManager.class).isDemoUser()
|
||||
|| Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int[] coords = new int[2];
|
||||
floatingHeaderView.findFixedRowByType(PredictionRowView.class).getLocationOnScreen(coords);
|
||||
ArrowTipView arrowTipView = new ArrowTipView(launcher).setOnClosedCallback(() -> {
|
||||
launcher.getSharedPrefs().edit().putBoolean(ALL_APPS_TIP_SEEN, true).apply();
|
||||
launcher.getUserEventDispatcher().logActionTip(LauncherEventUtil.DISMISS,
|
||||
ALL_APPS_PREDICTION_TIPS);
|
||||
});
|
||||
arrowTipView.show(launcher.getString(R.string.all_apps_prediction_tip), coords[1]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean hasSeenAllAppsTip(Launcher launcher) {
|
||||
return launcher.getSharedPrefs().getBoolean(ALL_APPS_TIP_SEEN, false);
|
||||
}
|
||||
|
||||
public static void scheduleShowIfNeeded(Launcher launcher) {
|
||||
if (!hasSeenAllAppsTip(launcher)) {
|
||||
launcher.getStateManager().addStateListener(new StateListener<LauncherState>() {
|
||||
@Override
|
||||
public void onStateTransitionComplete(LauncherState finalState) {
|
||||
if (finalState == ALL_APPS) {
|
||||
if (showAllAppsTipIfNecessary(launcher)) {
|
||||
launcher.getStateManager().removeStateListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.appprediction;
|
||||
|
||||
import static com.android.quickstep.InstantAppResolverImpl.COMPONENT_CLASS_MARKER;
|
||||
|
||||
import com.android.launcher3.allapps.AllAppsStore;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
|
||||
public class ComponentKeyMapper {
|
||||
|
||||
protected final ComponentKey componentKey;
|
||||
private final DynamicItemCache mCache;
|
||||
|
||||
public ComponentKeyMapper(ComponentKey key, DynamicItemCache cache) {
|
||||
componentKey = key;
|
||||
mCache = cache;
|
||||
}
|
||||
|
||||
public String getPackage() {
|
||||
return componentKey.componentName.getPackageName();
|
||||
}
|
||||
|
||||
public String getComponentClass() {
|
||||
return componentKey.componentName.getClassName();
|
||||
}
|
||||
|
||||
public ComponentKey getComponentKey() {
|
||||
return componentKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return componentKey.toString();
|
||||
}
|
||||
|
||||
public ItemInfoWithIcon getApp(AllAppsStore store) {
|
||||
AppInfo item = store.getApp(componentKey);
|
||||
if (item != null) {
|
||||
return item;
|
||||
} else if (getComponentClass().equals(COMPONENT_CLASS_MARKER)) {
|
||||
return mCache.getInstantApp(componentKey.componentName.getPackageName());
|
||||
} else {
|
||||
return mCache.getShortcutInfo(componentKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
-268
@@ -1,268 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.appprediction;
|
||||
|
||||
import static android.content.pm.PackageManager.MATCH_INSTANT;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
import static com.android.quickstep.InstantAppResolverImpl.COMPONENT_CLASS_MARKER;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.allapps.AllAppsStore;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
import com.android.launcher3.shortcuts.ShortcutRequest;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.InstantAppResolver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utility class which loads and caches predicted items like instant apps and shortcuts, before
|
||||
* they can be displayed on the UI
|
||||
*/
|
||||
public class DynamicItemCache {
|
||||
|
||||
private static final String TAG = "DynamicItemCache";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String DEFAULT_URL = "default-url";
|
||||
|
||||
private static final int BG_MSG_LOAD_SHORTCUTS = 1;
|
||||
private static final int BG_MSG_LOAD_INSTANT_APPS = 2;
|
||||
|
||||
private static final int UI_MSG_UPDATE_SHORTCUTS = 1;
|
||||
private static final int UI_MSG_UPDATE_INSTANT_APPS = 2;
|
||||
|
||||
private final Context mContext;
|
||||
private final Handler mWorker;
|
||||
private final Handler mUiHandler;
|
||||
private final InstantAppResolver mInstantAppResolver;
|
||||
private final Runnable mOnUpdateCallback;
|
||||
private final IconCache mIconCache;
|
||||
|
||||
private final Map<ComponentKey, WorkspaceItemInfo> mShortcuts;
|
||||
private final Map<String, InstantAppItemInfo> mInstantApps;
|
||||
|
||||
public DynamicItemCache(Context context, Runnable onUpdateCallback) {
|
||||
mContext = context;
|
||||
mWorker = new Handler(MODEL_EXECUTOR.getLooper(), this::handleWorkerMessage);
|
||||
mUiHandler = new Handler(Looper.getMainLooper(), this::handleUiMessage);
|
||||
mInstantAppResolver = InstantAppResolver.newInstance(context);
|
||||
mOnUpdateCallback = onUpdateCallback;
|
||||
mIconCache = LauncherAppState.getInstance(mContext).getIconCache();
|
||||
|
||||
mShortcuts = new HashMap<>();
|
||||
mInstantApps = new HashMap<>();
|
||||
}
|
||||
|
||||
public void cacheItems(List<ShortcutKey> shortcutKeys, List<String> pkgNames) {
|
||||
if (!shortcutKeys.isEmpty()) {
|
||||
mWorker.removeMessages(BG_MSG_LOAD_SHORTCUTS);
|
||||
Message.obtain(mWorker, BG_MSG_LOAD_SHORTCUTS, shortcutKeys).sendToTarget();
|
||||
}
|
||||
if (!pkgNames.isEmpty()) {
|
||||
mWorker.removeMessages(BG_MSG_LOAD_INSTANT_APPS);
|
||||
Message.obtain(mWorker, BG_MSG_LOAD_INSTANT_APPS, pkgNames).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleWorkerMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case BG_MSG_LOAD_SHORTCUTS: {
|
||||
List<ShortcutKey> shortcutKeys = msg.obj != null ?
|
||||
(List<ShortcutKey>) msg.obj : Collections.EMPTY_LIST;
|
||||
Map<ShortcutKey, WorkspaceItemInfo> shortcutKeyAndInfos = new ArrayMap<>();
|
||||
for (ShortcutKey shortcutKey : shortcutKeys) {
|
||||
WorkspaceItemInfo workspaceItemInfo = loadShortcutWorker(shortcutKey);
|
||||
if (workspaceItemInfo != null) {
|
||||
shortcutKeyAndInfos.put(shortcutKey, workspaceItemInfo);
|
||||
}
|
||||
}
|
||||
Message.obtain(mUiHandler, UI_MSG_UPDATE_SHORTCUTS, shortcutKeyAndInfos)
|
||||
.sendToTarget();
|
||||
return true;
|
||||
}
|
||||
case BG_MSG_LOAD_INSTANT_APPS: {
|
||||
List<String> pkgNames = msg.obj != null ?
|
||||
(List<String>) msg.obj : Collections.EMPTY_LIST;
|
||||
List<InstantAppItemInfo> instantAppItemInfos = new ArrayList<>();
|
||||
for (String pkgName : pkgNames) {
|
||||
InstantAppItemInfo instantAppItemInfo = loadInstantApp(pkgName);
|
||||
if (instantAppItemInfo != null) {
|
||||
instantAppItemInfos.add(instantAppItemInfo);
|
||||
}
|
||||
}
|
||||
Message.obtain(mUiHandler, UI_MSG_UPDATE_INSTANT_APPS, instantAppItemInfos)
|
||||
.sendToTarget();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean handleUiMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case UI_MSG_UPDATE_SHORTCUTS: {
|
||||
mShortcuts.clear();
|
||||
mShortcuts.putAll((Map<ShortcutKey, WorkspaceItemInfo>) msg.obj);
|
||||
mOnUpdateCallback.run();
|
||||
return true;
|
||||
}
|
||||
case UI_MSG_UPDATE_INSTANT_APPS: {
|
||||
List<InstantAppItemInfo> instantAppItemInfos = (List<InstantAppItemInfo>) msg.obj;
|
||||
mInstantApps.clear();
|
||||
for (InstantAppItemInfo instantAppItemInfo : instantAppItemInfos) {
|
||||
mInstantApps.put(instantAppItemInfo.getTargetComponent().getPackageName(),
|
||||
instantAppItemInfo);
|
||||
}
|
||||
mOnUpdateCallback.run();
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, String.format("Cache size: %d, Cache: %s",
|
||||
mInstantApps.size(), mInstantApps.toString()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private WorkspaceItemInfo loadShortcutWorker(ShortcutKey shortcutKey) {
|
||||
List<ShortcutInfo> details = shortcutKey.buildRequest(mContext).query(ShortcutRequest.ALL);
|
||||
if (!details.isEmpty()) {
|
||||
WorkspaceItemInfo si = new WorkspaceItemInfo(details.get(0), mContext);
|
||||
mIconCache.getShortcutIcon(si, details.get(0));
|
||||
return si;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "No shortcut found: " + shortcutKey.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private InstantAppItemInfo loadInstantApp(String pkgName) {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
|
||||
try {
|
||||
ApplicationInfo ai = pm.getApplicationInfo(pkgName, 0);
|
||||
if (!mInstantAppResolver.isInstantApp(ai)) {
|
||||
return null;
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String url = retrieveDefaultUrl(pkgName, pm);
|
||||
if (url == null) {
|
||||
Log.w(TAG, "no default-url available for pkg " + pkgName);
|
||||
return null;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW)
|
||||
.addCategory(Intent.CATEGORY_BROWSABLE)
|
||||
.setData(Uri.parse(url));
|
||||
InstantAppItemInfo info = new InstantAppItemInfo(intent, pkgName);
|
||||
IconCache iconCache = LauncherAppState.getInstance(mContext).getIconCache();
|
||||
iconCache.getTitleAndIcon(info, false);
|
||||
if (info.bitmap.icon == null || iconCache.isDefaultIcon(info.bitmap, info.user)) {
|
||||
return null;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String retrieveDefaultUrl(String pkgName, PackageManager pm) {
|
||||
Intent mainIntent = new Intent().setAction(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_LAUNCHER).setPackage(pkgName);
|
||||
List<ResolveInfo> resolveInfos = pm.queryIntentActivities(
|
||||
mainIntent, MATCH_INSTANT | PackageManager.GET_META_DATA);
|
||||
String url = null;
|
||||
for (ResolveInfo resolveInfo : resolveInfos) {
|
||||
if (resolveInfo.activityInfo.metaData != null
|
||||
&& resolveInfo.activityInfo.metaData.containsKey(DEFAULT_URL)) {
|
||||
url = resolveInfo.activityInfo.metaData.getString(DEFAULT_URL);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public InstantAppItemInfo getInstantApp(String pkgName) {
|
||||
return mInstantApps.get(pkgName);
|
||||
}
|
||||
|
||||
@MainThread
|
||||
public WorkspaceItemInfo getShortcutInfo(ComponentKey key) {
|
||||
return mShortcuts.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* requests and caches icons for app targets
|
||||
*/
|
||||
public void updateDependencies(List<ComponentKeyMapper> componentKeyMappers,
|
||||
AllAppsStore appsStore, IconCache.ItemInfoUpdateReceiver callback, int itemCount) {
|
||||
List<String> instantAppsToLoad = new ArrayList<>();
|
||||
List<ShortcutKey> shortcutsToLoad = new ArrayList<>();
|
||||
int total = componentKeyMappers.size();
|
||||
for (int i = 0, count = 0; i < total && count < itemCount; i++) {
|
||||
ComponentKeyMapper mapper = componentKeyMappers.get(i);
|
||||
// Update instant apps
|
||||
if (COMPONENT_CLASS_MARKER.equals(mapper.getComponentClass())) {
|
||||
instantAppsToLoad.add(mapper.getPackage());
|
||||
count++;
|
||||
} else if (mapper.getComponentKey() instanceof ShortcutKey) {
|
||||
shortcutsToLoad.add((ShortcutKey) mapper.getComponentKey());
|
||||
count++;
|
||||
} else {
|
||||
// Reload high res icon
|
||||
AppInfo info = (AppInfo) mapper.getApp(appsStore);
|
||||
if (info != null) {
|
||||
if (info.usingLowResIcon()) {
|
||||
mIconCache.updateIconInBackground(callback, info);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
cacheItems(shortcutsToLoad, instantAppsToLoad);
|
||||
}
|
||||
}
|
||||
-276
@@ -1,276 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.appprediction;
|
||||
|
||||
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.prediction.AppPredictionContext;
|
||||
import android.app.prediction.AppPredictionManager;
|
||||
import android.app.prediction.AppPredictor;
|
||||
import android.app.prediction.AppTarget;
|
||||
import android.app.prediction.AppTargetEvent;
|
||||
import android.app.prediction.AppTargetId;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
|
||||
import com.android.launcher3.model.AppLaunchTracker;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.systemui.plugins.AppLaunchEventsPlugin;
|
||||
import com.android.systemui.plugins.PluginListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Subclass of app tracker which publishes the data to the prediction engine and gets back results.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.Q)
|
||||
public class PredictionAppTracker extends AppLaunchTracker
|
||||
implements PluginListener<AppLaunchEventsPlugin> {
|
||||
|
||||
private static final String TAG = "PredictionAppTracker";
|
||||
private static final boolean DBG = false;
|
||||
|
||||
private static final int MSG_INIT = 0;
|
||||
private static final int MSG_DESTROY = 1;
|
||||
private static final int MSG_LAUNCH = 2;
|
||||
private static final int MSG_PREDICT = 3;
|
||||
|
||||
protected final Context mContext;
|
||||
private final Handler mMessageHandler;
|
||||
private final List<AppLaunchEventsPlugin> mAppLaunchEventsPluginsList;
|
||||
|
||||
// Accessed only on worker thread
|
||||
private AppPredictor mHomeAppPredictor;
|
||||
private AppPredictor mRecentsOverviewPredictor;
|
||||
|
||||
public PredictionAppTracker(Context context) {
|
||||
mContext = context;
|
||||
mMessageHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::handleMessage);
|
||||
InvariantDeviceProfile.INSTANCE.get(mContext).addOnChangeListener(this::onIdpChanged);
|
||||
|
||||
mMessageHandler.sendEmptyMessage(MSG_INIT);
|
||||
|
||||
mAppLaunchEventsPluginsList = new ArrayList<>();
|
||||
PluginManagerWrapper.INSTANCE.get(context)
|
||||
.addPluginListener(this, AppLaunchEventsPlugin.class, true);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void onIdpChanged(int changeFlags, InvariantDeviceProfile profile) {
|
||||
if ((changeFlags & CHANGE_FLAG_GRID) != 0) {
|
||||
// Reinitialize everything
|
||||
mMessageHandler.sendEmptyMessage(MSG_INIT);
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void destroy() {
|
||||
if (mHomeAppPredictor != null) {
|
||||
mHomeAppPredictor.destroy();
|
||||
mHomeAppPredictor = null;
|
||||
}
|
||||
if (mRecentsOverviewPredictor != null) {
|
||||
mRecentsOverviewPredictor.destroy();
|
||||
mRecentsOverviewPredictor = null;
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private AppPredictor createPredictor(Client client, int count) {
|
||||
AppPredictionManager apm = mContext.getSystemService(AppPredictionManager.class);
|
||||
|
||||
if (apm == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AppPredictor predictor = apm.createAppPredictionSession(
|
||||
new AppPredictionContext.Builder(mContext)
|
||||
.setUiSurface(client.id)
|
||||
.setPredictedTargetCount(count)
|
||||
.setExtras(getAppPredictionContextExtras(client))
|
||||
.build());
|
||||
predictor.registerPredictionUpdates(mContext.getMainExecutor(),
|
||||
PredictionUiStateManager.INSTANCE.get(mContext).appPredictorCallback(client));
|
||||
predictor.requestPredictionUpdate();
|
||||
return predictor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to add custom extras.
|
||||
*/
|
||||
@WorkerThread
|
||||
@Nullable
|
||||
public Bundle getAppPredictionContextExtras(Client client) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private boolean handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_INIT: {
|
||||
// Destroy any existing clients
|
||||
destroy();
|
||||
|
||||
// Initialize the clients
|
||||
int count = InvariantDeviceProfile.INSTANCE.get(mContext).numAllAppsColumns;
|
||||
mHomeAppPredictor = createPredictor(Client.HOME, count);
|
||||
mRecentsOverviewPredictor = createPredictor(Client.OVERVIEW, count);
|
||||
return true;
|
||||
}
|
||||
case MSG_DESTROY: {
|
||||
destroy();
|
||||
return true;
|
||||
}
|
||||
case MSG_LAUNCH: {
|
||||
if (mHomeAppPredictor != null) {
|
||||
mHomeAppPredictor.notifyAppTargetEvent((AppTargetEvent) msg.obj);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case MSG_PREDICT: {
|
||||
if (mHomeAppPredictor != null) {
|
||||
String client = (String) msg.obj;
|
||||
if (Client.HOME.id.equals(client)) {
|
||||
mHomeAppPredictor.requestPredictionUpdate();
|
||||
} else {
|
||||
mRecentsOverviewPredictor.requestPredictionUpdate();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void onReturnedToHome() {
|
||||
String client = Client.HOME.id;
|
||||
mMessageHandler.removeMessages(MSG_PREDICT, client);
|
||||
Message.obtain(mMessageHandler, MSG_PREDICT, client).sendToTarget();
|
||||
if (DBG) {
|
||||
Log.d(TAG, String.format("Sent immediate message to update %s", client));
|
||||
}
|
||||
|
||||
// Relay onReturnedToHome to every plugin.
|
||||
mAppLaunchEventsPluginsList.forEach(AppLaunchEventsPlugin::onReturnedToHome);
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void onStartShortcut(String packageName, String shortcutId, UserHandle user,
|
||||
String container) {
|
||||
// TODO: Use the full shortcut info
|
||||
AppTarget target = new AppTarget.Builder(
|
||||
new AppTargetId("shortcut:" + shortcutId), packageName, user)
|
||||
.setClassName(shortcutId)
|
||||
.build();
|
||||
|
||||
sendLaunch(target, container);
|
||||
|
||||
// Relay onStartShortcut info to every connected plugin.
|
||||
mAppLaunchEventsPluginsList
|
||||
.forEach(plugin -> plugin.onStartShortcut(
|
||||
packageName,
|
||||
shortcutId,
|
||||
user,
|
||||
container != null ? container : CONTAINER_DEFAULT)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void onStartApp(ComponentName cn, UserHandle user, String container) {
|
||||
if (cn != null) {
|
||||
AppTarget target = new AppTarget.Builder(
|
||||
new AppTargetId("app:" + cn), cn.getPackageName(), user)
|
||||
.setClassName(cn.getClassName())
|
||||
.build();
|
||||
sendLaunch(target, container);
|
||||
|
||||
// Relay onStartApp to every connected plugin.
|
||||
mAppLaunchEventsPluginsList
|
||||
.forEach(plugin -> plugin.onStartApp(
|
||||
cn,
|
||||
user,
|
||||
container != null ? container : CONTAINER_DEFAULT)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void onDismissApp(ComponentName cn, UserHandle user, String container) {
|
||||
if (cn == null) return;
|
||||
AppTarget target = new AppTarget.Builder(
|
||||
new AppTargetId("app: " + cn), cn.getPackageName(), user)
|
||||
.setClassName(cn.getClassName())
|
||||
.build();
|
||||
sendDismiss(target, container);
|
||||
|
||||
// Relay onDismissApp to every connected plugin.
|
||||
mAppLaunchEventsPluginsList
|
||||
.forEach(plugin -> plugin.onDismissApp(
|
||||
cn,
|
||||
user,
|
||||
container != null ? container : CONTAINER_DEFAULT)
|
||||
);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void sendEvent(AppTarget target, String container, int eventId) {
|
||||
AppTargetEvent event = new AppTargetEvent.Builder(target, eventId)
|
||||
.setLaunchLocation(container == null ? CONTAINER_DEFAULT : container)
|
||||
.build();
|
||||
Message.obtain(mMessageHandler, MSG_LAUNCH, event).sendToTarget();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void sendLaunch(AppTarget target, String container) {
|
||||
sendEvent(target, container, AppTargetEvent.ACTION_LAUNCH);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void sendDismiss(AppTarget target, String container) {
|
||||
sendEvent(target, container, AppTargetEvent.ACTION_DISMISS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginConnected(AppLaunchEventsPlugin appLaunchEventsPlugin, Context context) {
|
||||
mAppLaunchEventsPluginsList.add(appLaunchEventsPlugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginDisconnected(AppLaunchEventsPlugin appLaunchEventsPlugin) {
|
||||
mAppLaunchEventsPluginsList.remove(appLaunchEventsPlugin);
|
||||
}
|
||||
}
|
||||
-412
@@ -1,412 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT 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.appprediction;
|
||||
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
|
||||
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
|
||||
import static com.android.launcher3.logging.LoggerUtils.newTarget;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.IntProperty;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.allapps.AllAppsStore;
|
||||
import com.android.launcher3.allapps.FloatingHeaderRow;
|
||||
import com.android.launcher3.allapps.FloatingHeaderView;
|
||||
import com.android.launcher3.anim.AlphaUpdateListener;
|
||||
import com.android.launcher3.anim.PropertySetter;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.keyboard.FocusIndicatorHelper;
|
||||
import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
|
||||
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
|
||||
import com.android.launcher3.model.AppLaunchTracker;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.touch.ItemClickHandler;
|
||||
import com.android.launcher3.touch.ItemLongClickListener;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.quickstep.AnimatedFloat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
public class PredictionRowView extends LinearLayout implements
|
||||
LogContainerProvider, OnDeviceProfileChangeListener, FloatingHeaderRow {
|
||||
|
||||
private static final String TAG = "PredictionRowView";
|
||||
|
||||
private static final IntProperty<PredictionRowView> TEXT_ALPHA =
|
||||
new IntProperty<PredictionRowView>("textAlpha") {
|
||||
@Override
|
||||
public void setValue(PredictionRowView view, int alpha) {
|
||||
view.setTextAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get(PredictionRowView view) {
|
||||
return view.mIconLastSetTextAlpha;
|
||||
}
|
||||
};
|
||||
|
||||
private static final Interpolator ALPHA_FACTOR_INTERPOLATOR =
|
||||
(t) -> (t < 0.8f) ? 0 : (t - 0.8f) / 0.2f;
|
||||
|
||||
private static final OnClickListener PREDICTION_CLICK_LISTENER =
|
||||
ItemClickHandler.getInstance(AppLaunchTracker.CONTAINER_PREDICTIONS);
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final PredictionUiStateManager mPredictionUiStateManager;
|
||||
private int mNumPredictedAppsPerRow;
|
||||
|
||||
// The set of predicted app component names
|
||||
private final List<ComponentKeyMapper> mPredictedAppComponents = new ArrayList<>();
|
||||
// The set of predicted apps resolved from the component names and the current set of apps
|
||||
private final ArrayList<ItemInfoWithIcon> mPredictedApps = new ArrayList<>();
|
||||
// Helper to drawing the focus indicator.
|
||||
private final FocusIndicatorHelper mFocusHelper;
|
||||
|
||||
private final int mIconTextColor;
|
||||
private final int mIconFullTextAlpha;
|
||||
private int mIconLastSetTextAlpha;
|
||||
// Might use mIconFullTextAlpha instead of mIconLastSetTextAlpha if we are translucent.
|
||||
private int mIconCurrentTextAlpha;
|
||||
|
||||
private FloatingHeaderView mParent;
|
||||
private boolean mScrolledOut;
|
||||
|
||||
private float mScrollTranslation = 0;
|
||||
private final AnimatedFloat mContentAlphaFactor =
|
||||
new AnimatedFloat(this::updateTranslationAndAlpha);
|
||||
private final AnimatedFloat mOverviewScrollFactor =
|
||||
new AnimatedFloat(this::updateTranslationAndAlpha);
|
||||
|
||||
private boolean mPredictionsEnabled = false;
|
||||
|
||||
public PredictionRowView(@NonNull Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public PredictionRowView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setOrientation(LinearLayout.HORIZONTAL);
|
||||
|
||||
mFocusHelper = new SimpleFocusIndicatorHelper(this);
|
||||
|
||||
mNumPredictedAppsPerRow = LauncherAppState.getIDP(context).numAllAppsColumns;
|
||||
mLauncher = Launcher.getLauncher(context);
|
||||
mLauncher.addOnDeviceProfileChangeListener(this);
|
||||
|
||||
mPredictionUiStateManager = PredictionUiStateManager.INSTANCE.get(context);
|
||||
|
||||
mIconTextColor = Themes.getAttrColor(context, android.R.attr.textColorSecondary);
|
||||
mIconFullTextAlpha = Color.alpha(mIconTextColor);
|
||||
mIconCurrentTextAlpha = mIconFullTextAlpha;
|
||||
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
|
||||
mPredictionUiStateManager.setTargetAppsView(mLauncher.getAppsView());
|
||||
getAppsStore().registerIconContainer(this);
|
||||
AllAppsTipView.scheduleShowIfNeeded(mLauncher);
|
||||
}
|
||||
|
||||
private AllAppsStore getAppsStore() {
|
||||
return mLauncher.getAppsView().getAppsStore();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
|
||||
mPredictionUiStateManager.setTargetAppsView(null);
|
||||
getAppsStore().unregisterIconContainer(this);
|
||||
}
|
||||
|
||||
public void setup(FloatingHeaderView parent, FloatingHeaderRow[] rows, boolean tabsHidden) {
|
||||
mParent = parent;
|
||||
}
|
||||
|
||||
private void updateVisibility() {
|
||||
setVisibility(mPredictionsEnabled ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(getExpectedHeight(),
|
||||
MeasureSpec.EXACTLY));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
mFocusHelper.draw(canvas);
|
||||
super.dispatchDraw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getExpectedHeight() {
|
||||
return getVisibility() == GONE ? 0 :
|
||||
Launcher.getLauncher(getContext()).getDeviceProfile().allAppsCellHeightPx
|
||||
+ getPaddingTop() + getPaddingBottom();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDraw() {
|
||||
return getVisibility() != GONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasVisibleContent() {
|
||||
return mPredictionsEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the predicted apps.
|
||||
*/
|
||||
public List<ItemInfoWithIcon> getPredictedApps() {
|
||||
return mPredictedApps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current set of predicted apps.
|
||||
*
|
||||
* This can be called before we get the full set of applications, we should merge the results
|
||||
* only in onPredictionsUpdated() which is idempotent.
|
||||
*
|
||||
* If the number of predicted apps is the same as the previous list of predicted apps,
|
||||
* we can optimize by swapping them in place.
|
||||
*/
|
||||
public void setPredictedApps(List<ComponentKeyMapper> apps) {
|
||||
mPredictedAppComponents.clear();
|
||||
mPredictedAppComponents.addAll(apps);
|
||||
|
||||
mPredictedApps.clear();
|
||||
mPredictedApps.addAll(processPredictedAppComponents(mPredictedAppComponents));
|
||||
applyPredictionApps();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceProfileChanged(DeviceProfile dp) {
|
||||
mNumPredictedAppsPerRow = dp.inv.numAllAppsColumns;
|
||||
removeAllViews();
|
||||
applyPredictionApps();
|
||||
}
|
||||
|
||||
private void applyPredictionApps() {
|
||||
if (getChildCount() != mNumPredictedAppsPerRow) {
|
||||
while (getChildCount() > mNumPredictedAppsPerRow) {
|
||||
removeViewAt(0);
|
||||
}
|
||||
LayoutInflater inflater = mLauncher.getAppsView().getLayoutInflater();
|
||||
while (getChildCount() < mNumPredictedAppsPerRow) {
|
||||
BubbleTextView icon = (BubbleTextView) inflater.inflate(
|
||||
R.layout.all_apps_icon, this, false);
|
||||
icon.setOnClickListener(PREDICTION_CLICK_LISTENER);
|
||||
icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS);
|
||||
icon.setLongPressTimeoutFactor(1f);
|
||||
icon.setOnFocusChangeListener(mFocusHelper);
|
||||
|
||||
LayoutParams lp = (LayoutParams) icon.getLayoutParams();
|
||||
// Ensure the all apps icon height matches the workspace icons in portrait mode.
|
||||
lp.height = mLauncher.getDeviceProfile().allAppsCellHeightPx;
|
||||
lp.width = 0;
|
||||
lp.weight = 1;
|
||||
addView(icon);
|
||||
}
|
||||
}
|
||||
|
||||
int predictionCount = mPredictedApps.size();
|
||||
int iconColor = setColorAlphaBound(mIconTextColor, mIconCurrentTextAlpha);
|
||||
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
BubbleTextView icon = (BubbleTextView) getChildAt(i);
|
||||
icon.reset();
|
||||
if (predictionCount > i) {
|
||||
icon.setVisibility(View.VISIBLE);
|
||||
if (mPredictedApps.get(i) instanceof AppInfo) {
|
||||
icon.applyFromApplicationInfo((AppInfo) mPredictedApps.get(i));
|
||||
} else if (mPredictedApps.get(i) instanceof WorkspaceItemInfo) {
|
||||
icon.applyFromWorkspaceItem((WorkspaceItemInfo) mPredictedApps.get(i));
|
||||
}
|
||||
icon.setTextColor(iconColor);
|
||||
} else {
|
||||
icon.setVisibility(predictionCount == 0 ? GONE : INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
boolean predictionsEnabled = predictionCount > 0;
|
||||
if (predictionsEnabled != mPredictionsEnabled) {
|
||||
mPredictionsEnabled = predictionsEnabled;
|
||||
mLauncher.reapplyUi(false /* cancelCurrentAnimation */);
|
||||
updateVisibility();
|
||||
}
|
||||
mParent.onHeightUpdated();
|
||||
}
|
||||
|
||||
private List<ItemInfoWithIcon> processPredictedAppComponents(
|
||||
List<ComponentKeyMapper> components) {
|
||||
if (getAppsStore().getApps().length == 0) {
|
||||
// Apps have not been bound yet.
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<ItemInfoWithIcon> predictedApps = new ArrayList<>();
|
||||
for (ComponentKeyMapper mapper : components) {
|
||||
ItemInfoWithIcon info = mapper.getApp(getAppsStore());
|
||||
if (info != null) {
|
||||
ItemInfoWithIcon predictedApp = info.clone();
|
||||
predictedApp.container = LauncherSettings.Favorites.CONTAINER_PREDICTION;
|
||||
predictedApps.add(predictedApp);
|
||||
} else {
|
||||
if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
Log.e(TAG, "Predicted app not found: " + mapper);
|
||||
}
|
||||
}
|
||||
// Stop at the number of predicted apps
|
||||
if (predictedApps.size() == mNumPredictedAppsPerRow) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return predictedApps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillInLogContainerData(ItemInfo childInfo, LauncherLogProto.Target child,
|
||||
ArrayList<LauncherLogProto.Target> parents) {
|
||||
for (int i = 0; i < mPredictedApps.size(); i++) {
|
||||
ItemInfoWithIcon appInfo = mPredictedApps.get(i);
|
||||
if (appInfo == childInfo) {
|
||||
child.predictedRank = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
parents.add(newContainerTarget(LauncherLogProto.ContainerType.PREDICTION));
|
||||
|
||||
// include where the prediction is coming this used to be Launcher#modifyUserEvent
|
||||
LauncherLogProto.Target parent = newTarget(LauncherLogProto.Target.Type.CONTAINER);
|
||||
LauncherState state = mLauncher.getStateManager().getState();
|
||||
if (state == LauncherState.ALL_APPS) {
|
||||
parent.containerType = LauncherLogProto.ContainerType.ALLAPPS;
|
||||
} else if (state == OVERVIEW) {
|
||||
parent.containerType = LauncherLogProto.ContainerType.TASKSWITCHER;
|
||||
}
|
||||
parents.add(parent);
|
||||
}
|
||||
|
||||
public void setTextAlpha(int textAlpha) {
|
||||
mIconLastSetTextAlpha = textAlpha;
|
||||
if (getAlpha() < 1 && textAlpha > 0) {
|
||||
// If the entire header is translucent, make sure the text is at full opacity so it's
|
||||
// not double-translucent. However, we support keeping the text invisible (alpha == 0).
|
||||
textAlpha = mIconFullTextAlpha;
|
||||
}
|
||||
mIconCurrentTextAlpha = textAlpha;
|
||||
int iconColor = setColorAlphaBound(mIconTextColor, mIconCurrentTextAlpha);
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
((BubbleTextView) getChildAt(i)).setTextColor(iconColor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(float alpha) {
|
||||
super.setAlpha(alpha);
|
||||
// Reapply text alpha so that we update it to be full alpha if the row is now translucent.
|
||||
setTextAlpha(mIconLastSetTextAlpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOverlappingRendering() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setVerticalScroll(int scroll, boolean isScrolledOut) {
|
||||
mScrolledOut = isScrolledOut;
|
||||
updateTranslationAndAlpha();
|
||||
if (!isScrolledOut) {
|
||||
mScrollTranslation = scroll;
|
||||
updateTranslationAndAlpha();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTranslationAndAlpha() {
|
||||
if (mPredictionsEnabled) {
|
||||
setTranslationY((1 - mOverviewScrollFactor.value) * mScrollTranslation);
|
||||
|
||||
float factor = ALPHA_FACTOR_INTERPOLATOR.getInterpolation(mOverviewScrollFactor.value);
|
||||
float endAlpha = factor + (1 - factor) * (mScrolledOut ? 0 : 1);
|
||||
setAlpha(mContentAlphaFactor.value * endAlpha);
|
||||
AlphaUpdateListener.updateVisibility(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentVisibility(boolean hasHeaderExtra, boolean hasAllAppsContent,
|
||||
PropertySetter setter, Interpolator headerFade, Interpolator allAppsFade) {
|
||||
// Text follows all apps visibility
|
||||
int textAlpha = hasHeaderExtra && hasAllAppsContent ? mIconFullTextAlpha : 0;
|
||||
setter.setInt(this, TEXT_ALPHA, textAlpha, allAppsFade);
|
||||
setter.setFloat(mOverviewScrollFactor, AnimatedFloat.VALUE,
|
||||
(hasHeaderExtra && !hasAllAppsContent) ? 1 : 0, LINEAR);
|
||||
setter.setFloat(mContentAlphaFactor, AnimatedFloat.VALUE, hasHeaderExtra ? 1 : 0,
|
||||
headerFade);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets, DeviceProfile grid) {
|
||||
int leftRightPadding = grid.desiredWorkspaceLeftRightMarginPx
|
||||
+ grid.cellLayoutPaddingLeftRightPx;
|
||||
setPadding(leftRightPadding, getPaddingTop(), leftRightPadding, getPaddingBottom());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<PredictionRowView> getTypeClass() {
|
||||
return PredictionRowView.class;
|
||||
}
|
||||
}
|
||||
-370
@@ -1,370 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.appprediction;
|
||||
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
|
||||
import android.app.prediction.AppPredictor;
|
||||
import android.app.prediction.AppTarget;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.AllAppsContainerView;
|
||||
import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener;
|
||||
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
|
||||
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
import com.android.launcher3.statemanager.StateManager.StateListener;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* Handler responsible to updating the UI due to predicted apps changes. Operations:
|
||||
* 1) Pushes the predicted apps to all-apps. If all-apps is visible, waits until it becomes
|
||||
* invisible again before applying the changes. This ensures that the UI does not change abruptly
|
||||
* in front of the user, even if an app launched and user pressed back button to return to the
|
||||
* all-apps UI again.
|
||||
* 2) Prefetch high-res icons for predicted apps. This ensures that we have the icons in memory
|
||||
* even if all-apps is not opened as they are shown in search UI as well
|
||||
* 3) Load instant app if it is not already in memory. As predictions are persisted on disk,
|
||||
* instant app will not be in memory when launcher starts.
|
||||
* 4) Maintains the current active client id (for the predictions) and all updates are performed on
|
||||
* that client id.
|
||||
*/
|
||||
public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||
ItemInfoUpdateReceiver, OnIDPChangeListener, OnUpdateListener {
|
||||
|
||||
public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state";
|
||||
|
||||
// TODO (b/129421797): Update the client constants
|
||||
public enum Client {
|
||||
HOME("home"),
|
||||
OVERVIEW("overview");
|
||||
|
||||
public final String id;
|
||||
|
||||
Client(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
public static final MainThreadInitializedObject<PredictionUiStateManager> INSTANCE =
|
||||
new MainThreadInitializedObject<>(PredictionUiStateManager::new);
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
private final DynamicItemCache mDynamicItemCache;
|
||||
private final List[] mPredictionServicePredictions;
|
||||
|
||||
private int mMaxIconsPerRow;
|
||||
private Client mActiveClient;
|
||||
|
||||
private AllAppsContainerView mAppsView;
|
||||
|
||||
private PredictionState mPendingState;
|
||||
private PredictionState mCurrentState;
|
||||
|
||||
private boolean mGettingValidPredictionResults;
|
||||
|
||||
private PredictionUiStateManager(Context context) {
|
||||
mContext = context;
|
||||
|
||||
mDynamicItemCache = new DynamicItemCache(context, this::onAppsUpdated);
|
||||
|
||||
mActiveClient = Client.HOME;
|
||||
|
||||
InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
|
||||
mMaxIconsPerRow = idp.numColumns;
|
||||
|
||||
idp.addOnChangeListener(this);
|
||||
mPredictionServicePredictions = new List[Client.values().length];
|
||||
for (int i = 0; i < mPredictionServicePredictions.length; i++) {
|
||||
mPredictionServicePredictions[i] = Collections.emptyList();
|
||||
}
|
||||
mGettingValidPredictionResults = Utilities.getDevicePrefs(context)
|
||||
.getBoolean(LAST_PREDICTION_ENABLED_STATE, true);
|
||||
|
||||
// Call this last
|
||||
mCurrentState = parseLastState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIdpChanged(int changeFlags, InvariantDeviceProfile profile) {
|
||||
mMaxIconsPerRow = profile.numColumns;
|
||||
}
|
||||
|
||||
public Client getClient() {
|
||||
return mActiveClient;
|
||||
}
|
||||
|
||||
public void switchClient(Client client) {
|
||||
if (client == mActiveClient) {
|
||||
return;
|
||||
}
|
||||
mActiveClient = client;
|
||||
dispatchOnChange(true);
|
||||
}
|
||||
|
||||
public void setTargetAppsView(AllAppsContainerView appsView) {
|
||||
if (mAppsView != null) {
|
||||
mAppsView.getAppsStore().removeUpdateListener(this);
|
||||
}
|
||||
mAppsView = appsView;
|
||||
if (mAppsView != null) {
|
||||
mAppsView.getAppsStore().addUpdateListener(this);
|
||||
}
|
||||
if (mPendingState != null) {
|
||||
applyState(mPendingState);
|
||||
mPendingState = null;
|
||||
} else {
|
||||
applyState(mCurrentState);
|
||||
}
|
||||
updateDependencies(mCurrentState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reapplyItemInfo(ItemInfoWithIcon info) { }
|
||||
|
||||
@Override
|
||||
public void onStateTransitionComplete(LauncherState state) {
|
||||
if (mAppsView == null) {
|
||||
return;
|
||||
}
|
||||
if (mPendingState != null && canApplyPredictions(mPendingState)) {
|
||||
applyState(mPendingState);
|
||||
mPendingState = null;
|
||||
}
|
||||
if (mPendingState == null) {
|
||||
Launcher.getLauncher(mAppsView.getContext()).getStateManager()
|
||||
.removeStateListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleApplyPredictedApps(PredictionState state) {
|
||||
boolean registerListener = mPendingState == null;
|
||||
mPendingState = state;
|
||||
if (registerListener) {
|
||||
// Add a listener and wait until appsView is invisible again.
|
||||
Launcher.getLauncher(mAppsView.getContext()).getStateManager().addStateListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyState(PredictionState state) {
|
||||
mCurrentState = state;
|
||||
if (mAppsView != null) {
|
||||
mAppsView.getFloatingHeaderView().findFixedRowByType(PredictionRowView.class)
|
||||
.setPredictedApps(mCurrentState.apps);
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePredictionStateAfterCallback() {
|
||||
boolean validResults = false;
|
||||
for (List l : mPredictionServicePredictions) {
|
||||
validResults |= l != null && !l.isEmpty();
|
||||
}
|
||||
if (validResults != mGettingValidPredictionResults) {
|
||||
mGettingValidPredictionResults = validResults;
|
||||
Utilities.getDevicePrefs(mContext).edit()
|
||||
.putBoolean(LAST_PREDICTION_ENABLED_STATE, true)
|
||||
.apply();
|
||||
}
|
||||
dispatchOnChange(true);
|
||||
}
|
||||
|
||||
public AppPredictor.Callback appPredictorCallback(Client client) {
|
||||
return targets -> {
|
||||
mPredictionServicePredictions[client.ordinal()] = targets;
|
||||
updatePredictionStateAfterCallback();
|
||||
};
|
||||
}
|
||||
|
||||
private void dispatchOnChange(boolean changed) {
|
||||
PredictionState newState = changed
|
||||
? parseLastState()
|
||||
: mPendingState != null && canApplyPredictions(mPendingState)
|
||||
? mPendingState
|
||||
: mCurrentState;
|
||||
if (changed && mAppsView != null && !canApplyPredictions(newState)) {
|
||||
scheduleApplyPredictedApps(newState);
|
||||
} else {
|
||||
applyState(newState);
|
||||
}
|
||||
}
|
||||
|
||||
private PredictionState parseLastState() {
|
||||
PredictionState state = new PredictionState();
|
||||
state.isEnabled = mGettingValidPredictionResults;
|
||||
if (!state.isEnabled) {
|
||||
state.apps = Collections.EMPTY_LIST;
|
||||
return state;
|
||||
}
|
||||
|
||||
state.apps = new ArrayList<>();
|
||||
|
||||
List<AppTarget> appTargets = mPredictionServicePredictions[mActiveClient.ordinal()];
|
||||
if (!appTargets.isEmpty()) {
|
||||
for (AppTarget appTarget : appTargets) {
|
||||
ComponentKey key;
|
||||
if (appTarget.getShortcutInfo() != null) {
|
||||
key = ShortcutKey.fromInfo(appTarget.getShortcutInfo());
|
||||
} else {
|
||||
key = new ComponentKey(new ComponentName(appTarget.getPackageName(),
|
||||
appTarget.getClassName()), appTarget.getUser());
|
||||
}
|
||||
state.apps.add(new ComponentKeyMapper(key, mDynamicItemCache));
|
||||
}
|
||||
}
|
||||
updateDependencies(state);
|
||||
return state;
|
||||
}
|
||||
|
||||
private void updateDependencies(PredictionState state) {
|
||||
if (!state.isEnabled || mAppsView == null) {
|
||||
return;
|
||||
}
|
||||
mDynamicItemCache.updateDependencies(state.apps, mAppsView.getAppsStore(), this,
|
||||
mMaxIconsPerRow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppsUpdated() {
|
||||
dispatchOnChange(false);
|
||||
}
|
||||
|
||||
private boolean canApplyPredictions(PredictionState newState) {
|
||||
if (mAppsView == null) {
|
||||
// If there is no apps view, no need to schedule.
|
||||
return true;
|
||||
}
|
||||
Launcher launcher = Launcher.getLauncher(mAppsView.getContext());
|
||||
PredictionRowView predictionRow = mAppsView.getFloatingHeaderView().
|
||||
findFixedRowByType(PredictionRowView.class);
|
||||
if (!predictionRow.isShown() || predictionRow.getAlpha() == 0 ||
|
||||
launcher.isForceInvisible()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mCurrentState.isEnabled != newState.isEnabled
|
||||
|| mCurrentState.apps.isEmpty() != newState.apps.isEmpty()) {
|
||||
// If the visibility of the prediction row is changing, apply immediately.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
|
||||
// If we are here & mAppsView.isShown() = true, we are probably in all-apps or mid way
|
||||
return false;
|
||||
}
|
||||
if (!launcher.isInState(OVERVIEW) && !launcher.isInState(BACKGROUND_APP)) {
|
||||
// Just a fallback as we dont need to apply instantly, if we are not in the swipe-up UI
|
||||
return false;
|
||||
}
|
||||
|
||||
// Instead of checking against 1, we should check against (1 + delta), where delta accounts
|
||||
// for the nav-bar height (as app icon can still be visible under the nav-bar). Checking
|
||||
// against 1, keeps the logic simple :)
|
||||
return launcher.getAllAppsController().getProgress() > 1;
|
||||
}
|
||||
|
||||
public PredictionState getCurrentState() {
|
||||
return mCurrentState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ranking info for the app within all apps prediction.
|
||||
* Only applicable when {@link ItemInfo#itemType} is one of the followings:
|
||||
* {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION},
|
||||
* {@link LauncherSettings.Favorites#ITEM_TYPE_SHORTCUT},
|
||||
* {@link LauncherSettings.Favorites#ITEM_TYPE_DEEP_SHORTCUT}
|
||||
*/
|
||||
public OptionalInt getAllAppsRank(@Nullable ItemInfo itemInfo) {
|
||||
if (itemInfo == null || itemInfo.getTargetComponent() == null || itemInfo.user == null) {
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
|
||||
if (itemInfo.itemType == ITEM_TYPE_APPLICATION
|
||||
|| itemInfo.itemType == ITEM_TYPE_SHORTCUT
|
||||
|| itemInfo.itemType == ITEM_TYPE_DEEP_SHORTCUT) {
|
||||
ComponentKey key = new ComponentKey(itemInfo.getTargetComponent(),
|
||||
itemInfo.user);
|
||||
final List<ComponentKeyMapper> apps = getCurrentState().apps;
|
||||
return IntStream.range(0, apps.size())
|
||||
.filter(index -> key.equals(apps.get(index).getComponentKey()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in predicted_rank field based on app prediction.
|
||||
* Only applicable when {@link ItemInfo#itemType} is one of the followings:
|
||||
* {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION},
|
||||
* {@link LauncherSettings.Favorites#ITEM_TYPE_SHORTCUT},
|
||||
* {@link LauncherSettings.Favorites#ITEM_TYPE_DEEP_SHORTCUT}
|
||||
*/
|
||||
public static void fillInPredictedRank(
|
||||
@NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) {
|
||||
|
||||
final PredictionUiStateManager manager = PredictionUiStateManager.INSTANCE.getNoCreate();
|
||||
if (manager == null || itemInfo.getTargetComponent() == null || itemInfo.user == null
|
||||
|| (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
|
||||
&& itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
|
||||
&& itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)) {
|
||||
return;
|
||||
}
|
||||
if (itemInfo.container != LauncherSettings.Favorites.CONTAINER_PREDICTION) {
|
||||
HotseatPredictionController.encodeHotseatLayoutIntoPredictionRank(itemInfo, target);
|
||||
return;
|
||||
}
|
||||
|
||||
final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user);
|
||||
final List<ComponentKeyMapper> predictedApps = manager.getCurrentState().apps;
|
||||
IntStream.range(0, predictedApps.size())
|
||||
.filter((i) -> k.equals(predictedApps.get(i).getComponentKey()))
|
||||
.findFirst()
|
||||
.ifPresent((rank) -> target.predictedRank = 0 - rank);
|
||||
}
|
||||
|
||||
public static class PredictionState {
|
||||
|
||||
public boolean isEnabled;
|
||||
public List<ComponentKeyMapper> apps;
|
||||
}
|
||||
}
|
||||
-128
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.hybridhotseat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.logging.FileLog;
|
||||
import com.android.launcher3.util.Executors;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Helper class to allow hot seat file logging
|
||||
*/
|
||||
public class HotseatFileLog {
|
||||
|
||||
public static final int LOG_DAYS = 10;
|
||||
private static final String FILE_NAME_PREFIX = "hotseat-log-";
|
||||
private static final DateFormat DATE_FORMAT =
|
||||
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
|
||||
public static final MainThreadInitializedObject<HotseatFileLog> INSTANCE =
|
||||
new MainThreadInitializedObject<>(HotseatFileLog::new);
|
||||
|
||||
|
||||
private final Handler mHandler = new Handler(
|
||||
Executors.createAndStartNewLooper("hotseat-logger"));
|
||||
private final File mLogsDir;
|
||||
private PrintWriter mCurrentWriter;
|
||||
private String mFileName;
|
||||
|
||||
private HotseatFileLog(Context context) {
|
||||
mLogsDir = context.getFilesDir();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints log values to disk
|
||||
*/
|
||||
public void log(String tag, String msg) {
|
||||
String out = String.format("%s %s %s", DATE_FORMAT.format(new Date()), tag, msg);
|
||||
|
||||
mHandler.post(() -> {
|
||||
synchronized (this) {
|
||||
PrintWriter writer = getWriter();
|
||||
if (writer != null) {
|
||||
writer.println(out);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private PrintWriter getWriter() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
String fName = FILE_NAME_PREFIX + (cal.get(Calendar.DAY_OF_YEAR) % 10);
|
||||
if (fName.equals(mFileName)) return mCurrentWriter;
|
||||
|
||||
boolean append = false;
|
||||
File logFile = new File(mLogsDir, fName);
|
||||
if (logFile.exists()) {
|
||||
Calendar modifiedTime = Calendar.getInstance();
|
||||
modifiedTime.setTimeInMillis(logFile.lastModified());
|
||||
|
||||
// If the file was modified more that 36 hours ago, purge the file.
|
||||
// We use instead of 24 to account for day-365 followed by day-1
|
||||
modifiedTime.add(Calendar.HOUR, 36);
|
||||
append = cal.before(modifiedTime);
|
||||
}
|
||||
|
||||
|
||||
if (mCurrentWriter != null) {
|
||||
mCurrentWriter.close();
|
||||
}
|
||||
try {
|
||||
mCurrentWriter = new PrintWriter(new FileWriter(logFile, append));
|
||||
mFileName = fName;
|
||||
} catch (Exception ex) {
|
||||
Log.e("HotseatLogs", "Error writing logs to file", ex);
|
||||
closeWriter();
|
||||
}
|
||||
return mCurrentWriter;
|
||||
}
|
||||
|
||||
|
||||
private synchronized void closeWriter() {
|
||||
mFileName = null;
|
||||
if (mCurrentWriter != null) {
|
||||
mCurrentWriter.close();
|
||||
}
|
||||
mCurrentWriter = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of all log files
|
||||
*/
|
||||
public synchronized File[] getLogFiles() {
|
||||
File[] files = new File[LOG_DAYS + FileLog.LOG_DAYS];
|
||||
//include file log files here
|
||||
System.arraycopy(FileLog.getLogFiles(), 0, files, 0, FileLog.LOG_DAYS);
|
||||
|
||||
closeWriter();
|
||||
for (int i = 0; i < LOG_DAYS; i++) {
|
||||
files[FileLog.LOG_DAYS + i] = new File(mLogsDir, FILE_NAME_PREFIX + i);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
}
|
||||
-723
@@ -1,723 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.hybridhotseat;
|
||||
|
||||
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.hybridhotseat.HotseatEduController.getSettingsIntent;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_RANKED;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.app.prediction.AppPredictionContext;
|
||||
import android.app.prediction.AppPredictionManager;
|
||||
import android.app.prediction.AppPredictor;
|
||||
import android.app.prediction.AppTarget;
|
||||
import android.app.prediction.AppTargetEvent;
|
||||
import android.content.ComponentName;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.DragSource;
|
||||
import com.android.launcher3.DropTarget;
|
||||
import com.android.launcher3.Hotseat;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.AllAppsStore;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.appprediction.ComponentKeyMapper;
|
||||
import com.android.launcher3.appprediction.DynamicItemCache;
|
||||
import com.android.launcher3.dragndrop.DragController;
|
||||
import com.android.launcher3.dragndrop.DragOptions;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
|
||||
import com.android.launcher3.logger.LauncherAtom.PredictedHotseatContainer;
|
||||
import com.android.launcher3.logging.InstanceId;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.model.data.FolderInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
import com.android.launcher3.touch.ItemLongClickListener;
|
||||
import com.android.launcher3.uioverrides.PredictedAppIcon;
|
||||
import com.android.launcher3.uioverrides.QuickstepLauncher;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.OnboardingPrefs;
|
||||
import com.android.launcher3.views.ArrowTipView;
|
||||
import com.android.launcher3.views.Snackbar;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* Provides prediction ability for the hotseat. Fills gaps in hotseat with predicted items, allows
|
||||
* pinning of predicted apps and manages replacement of predicted apps with user drag.
|
||||
*/
|
||||
public class HotseatPredictionController implements DragController.DragListener,
|
||||
View.OnAttachStateChangeListener, SystemShortcut.Factory<QuickstepLauncher>,
|
||||
InvariantDeviceProfile.OnIDPChangeListener, AllAppsStore.OnUpdateListener,
|
||||
IconCache.ItemInfoUpdateReceiver, DragSource {
|
||||
|
||||
private static final String TAG = "PredictiveHotseat";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final String PREDICTION_CLIENT = "hotseat";
|
||||
private DropTarget.DragObject mDragObject;
|
||||
private int mHotSeatItemsCount;
|
||||
private int mPredictedSpotsCount = 0;
|
||||
|
||||
private Launcher mLauncher;
|
||||
private final Hotseat mHotseat;
|
||||
|
||||
private final HotseatRestoreHelper mRestoreHelper;
|
||||
|
||||
private List<ComponentKeyMapper> mComponentKeyMappers = new ArrayList<>();
|
||||
|
||||
private DynamicItemCache mDynamicItemCache;
|
||||
|
||||
private final HotseatPredictionModel mPredictionModel;
|
||||
private AppPredictor mAppPredictor;
|
||||
private AllAppsStore mAllAppsStore;
|
||||
private AnimatorSet mIconRemoveAnimators;
|
||||
private boolean mUIUpdatePaused = false;
|
||||
private boolean mIsDestroyed = false;
|
||||
|
||||
|
||||
private List<PredictedAppIcon.PredictedIconOutlineDrawing> mOutlineDrawings = new ArrayList<>();
|
||||
|
||||
private final View.OnLongClickListener mPredictionLongClickListener = v -> {
|
||||
if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
|
||||
if (mLauncher.getWorkspace().isSwitchingState()) return false;
|
||||
if (!mLauncher.getOnboardingPrefs().getBoolean(
|
||||
OnboardingPrefs.HOTSEAT_LONGPRESS_TIP_SEEN)) {
|
||||
Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled,
|
||||
R.string.hotseat_prediction_settings, null,
|
||||
() -> mLauncher.startActivity(getSettingsIntent()));
|
||||
mLauncher.getOnboardingPrefs().markChecked(OnboardingPrefs.HOTSEAT_LONGPRESS_TIP_SEEN);
|
||||
mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
return true;
|
||||
}
|
||||
// Start the drag
|
||||
mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions());
|
||||
return true;
|
||||
};
|
||||
|
||||
public HotseatPredictionController(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
mHotseat = launcher.getHotseat();
|
||||
mAllAppsStore = mLauncher.getAppsView().getAppsStore();
|
||||
LauncherAppState appState = LauncherAppState.getInstance(launcher);
|
||||
mPredictionModel = (HotseatPredictionModel) appState.getPredictionModel();
|
||||
mAllAppsStore.addUpdateListener(this);
|
||||
mDynamicItemCache = new DynamicItemCache(mLauncher, this::fillGapsWithPrediction);
|
||||
mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons;
|
||||
launcher.getDeviceProfile().inv.addOnChangeListener(this);
|
||||
mHotseat.addOnAttachStateChangeListener(this);
|
||||
mRestoreHelper = new HotseatRestoreHelper(mLauncher);
|
||||
if (mHotseat.isAttachedToWindow()) {
|
||||
onViewAttachedToWindow(mHotseat);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows appropriate hotseat education based on prediction enabled and migration states.
|
||||
*/
|
||||
public void showEdu() {
|
||||
mLauncher.getStateManager().goToState(NORMAL, true, () -> {
|
||||
if (mComponentKeyMappers.isEmpty()) {
|
||||
// launcher has empty predictions set
|
||||
Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_disabled,
|
||||
R.string.hotseat_prediction_settings, null,
|
||||
() -> mLauncher.startActivity(getSettingsIntent()));
|
||||
} else if (getPredictedIcons().size() >= (mHotSeatItemsCount + 1) / 2) {
|
||||
showDiscoveryTip();
|
||||
} else {
|
||||
HotseatEduController eduController = new HotseatEduController(mLauncher,
|
||||
mRestoreHelper,
|
||||
this::createPredictor);
|
||||
eduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers));
|
||||
eduController.showEdu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows educational tip for hotseat if user does not go through Tips app.
|
||||
*/
|
||||
private void showDiscoveryTip() {
|
||||
if (getPredictedIcons().isEmpty()) {
|
||||
new ArrowTipView(mLauncher).show(
|
||||
mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop());
|
||||
} else {
|
||||
Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled,
|
||||
R.string.hotseat_prediction_settings, null,
|
||||
() -> mLauncher.startActivity(getSettingsIntent()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if hotseat client has predictions
|
||||
*/
|
||||
public boolean hasPredictions() {
|
||||
return !mComponentKeyMappers.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View view) {
|
||||
mLauncher.getDragController().addDragListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View view) {
|
||||
mLauncher.getDragController().removeDragListener(this);
|
||||
}
|
||||
|
||||
private void fillGapsWithPrediction() {
|
||||
fillGapsWithPrediction(false, null);
|
||||
}
|
||||
|
||||
private void fillGapsWithPrediction(boolean animate, Runnable callback) {
|
||||
if (mUIUpdatePaused || mDragObject != null) {
|
||||
return;
|
||||
}
|
||||
List<WorkspaceItemInfo> predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers);
|
||||
if (mComponentKeyMappers.isEmpty() != predictedApps.isEmpty()) {
|
||||
// Safely ignore update as AppsList is not ready yet. This will called again once
|
||||
// apps are ready (HotseatPredictionController#onAppsUpdated)
|
||||
return;
|
||||
}
|
||||
int predictionIndex = 0;
|
||||
ArrayList<WorkspaceItemInfo> newItems = new ArrayList<>();
|
||||
// make sure predicted icon removal and filling predictions don't step on each other
|
||||
if (mIconRemoveAnimators != null && mIconRemoveAnimators.isRunning()) {
|
||||
mIconRemoveAnimators.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
fillGapsWithPrediction(animate, callback);
|
||||
mIconRemoveAnimators.removeListener(this);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
for (int rank = 0; rank < mHotSeatItemsCount; rank++) {
|
||||
View child = mHotseat.getChildAt(
|
||||
mHotseat.getCellXFromOrder(rank),
|
||||
mHotseat.getCellYFromOrder(rank));
|
||||
|
||||
if (child != null && !isPredictedIcon(child)) {
|
||||
continue;
|
||||
}
|
||||
if (predictedApps.size() <= predictionIndex) {
|
||||
// Remove predicted apps from the past
|
||||
if (isPredictedIcon(child)) {
|
||||
mHotseat.removeView(child);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
WorkspaceItemInfo predictedItem = predictedApps.get(predictionIndex++);
|
||||
if (isPredictedIcon(child) && child.isEnabled()) {
|
||||
PredictedAppIcon icon = (PredictedAppIcon) child;
|
||||
icon.applyFromWorkspaceItem(predictedItem);
|
||||
icon.finishBinding(mPredictionLongClickListener);
|
||||
} else {
|
||||
newItems.add(predictedItem);
|
||||
}
|
||||
preparePredictionInfo(predictedItem, rank);
|
||||
}
|
||||
mPredictedSpotsCount = predictionIndex;
|
||||
bindItems(newItems, animate, callback);
|
||||
}
|
||||
|
||||
private void bindItems(List<WorkspaceItemInfo> itemsToAdd, boolean animate, Runnable callback) {
|
||||
AnimatorSet animationSet = new AnimatorSet();
|
||||
for (WorkspaceItemInfo item : itemsToAdd) {
|
||||
PredictedAppIcon icon = PredictedAppIcon.createIcon(mHotseat, item);
|
||||
mLauncher.getWorkspace().addInScreenFromBind(icon, item);
|
||||
icon.finishBinding(mPredictionLongClickListener);
|
||||
if (animate) {
|
||||
animationSet.play(ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0.2f, 1));
|
||||
}
|
||||
}
|
||||
if (animate) {
|
||||
if (callback != null) {
|
||||
animationSet.addListener(AnimationSuccessListener.forRunnable(callback));
|
||||
}
|
||||
animationSet.start();
|
||||
} else {
|
||||
if (callback != null) callback.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters callbacks and frees resources
|
||||
*/
|
||||
public void destroy() {
|
||||
mIsDestroyed = true;
|
||||
mAllAppsStore.removeUpdateListener(this);
|
||||
mLauncher.getDeviceProfile().inv.removeOnChangeListener(this);
|
||||
mHotseat.removeOnAttachStateChangeListener(this);
|
||||
if (mAppPredictor != null) {
|
||||
mAppPredictor.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* start and pauses predicted apps update on the hotseat
|
||||
*/
|
||||
public void setPauseUIUpdate(boolean paused) {
|
||||
mUIUpdatePaused = paused;
|
||||
if (!paused) {
|
||||
fillGapsWithPrediction();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates App Predictor with all the current apps pinned on the hotseat
|
||||
*/
|
||||
public void createPredictor() {
|
||||
AppPredictionManager apm = mLauncher.getSystemService(AppPredictionManager.class);
|
||||
if (apm == null) {
|
||||
return;
|
||||
}
|
||||
if (mAppPredictor != null) {
|
||||
mAppPredictor.destroy();
|
||||
mAppPredictor = null;
|
||||
}
|
||||
WeakReference<HotseatPredictionController> controllerRef = new WeakReference<>(this);
|
||||
|
||||
|
||||
mPredictionModel.createBundle(bundle -> {
|
||||
if (mIsDestroyed) return;
|
||||
mAppPredictor = apm.createAppPredictionSession(
|
||||
new AppPredictionContext.Builder(mLauncher)
|
||||
.setUiSurface(PREDICTION_CLIENT)
|
||||
.setPredictedTargetCount(mHotSeatItemsCount)
|
||||
.setExtras(bundle)
|
||||
.build());
|
||||
mAppPredictor.registerPredictionUpdates(
|
||||
mLauncher.getApplicationContext().getMainExecutor(),
|
||||
list -> {
|
||||
if (controllerRef.get() != null) {
|
||||
controllerRef.get().setPredictedApps(list);
|
||||
}
|
||||
});
|
||||
mAppPredictor.requestPredictionUpdate();
|
||||
});
|
||||
setPauseUIUpdate(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create WorkspaceItemInfo objects and binds PredictedAppIcon views for cached predicted items.
|
||||
*/
|
||||
public void showCachedItems(List<AppInfo> apps, IntArray ranks) {
|
||||
if (hasPredictions() && mAppPredictor != null) {
|
||||
mAppPredictor.requestPredictionUpdate();
|
||||
fillGapsWithPrediction();
|
||||
return;
|
||||
}
|
||||
int count = Math.min(ranks.size(), apps.size());
|
||||
List<WorkspaceItemInfo> items = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
WorkspaceItemInfo item = new WorkspaceItemInfo(apps.get(i));
|
||||
ComponentKey componentKey = new ComponentKey(item.getTargetComponent(), item.user);
|
||||
preparePredictionInfo(item, ranks.get(i));
|
||||
items.add(item);
|
||||
|
||||
mComponentKeyMappers.add(new ComponentKeyMapper(componentKey, mDynamicItemCache));
|
||||
}
|
||||
updateDependencies();
|
||||
bindItems(items, false, null);
|
||||
}
|
||||
|
||||
private void setPredictedApps(List<AppTarget> appTargets) {
|
||||
mComponentKeyMappers.clear();
|
||||
if (appTargets.isEmpty()) {
|
||||
mRestoreHelper.restoreBackup();
|
||||
}
|
||||
StringBuilder predictionLog = new StringBuilder("predictedApps: [\n");
|
||||
ArrayList<ComponentKey> componentKeys = new ArrayList<>();
|
||||
for (AppTarget appTarget : appTargets) {
|
||||
ComponentKey key;
|
||||
if (appTarget.getShortcutInfo() != null) {
|
||||
key = ShortcutKey.fromInfo(appTarget.getShortcutInfo());
|
||||
} else {
|
||||
key = new ComponentKey(new ComponentName(appTarget.getPackageName(),
|
||||
appTarget.getClassName()), appTarget.getUser());
|
||||
}
|
||||
componentKeys.add(key);
|
||||
predictionLog.append(key.toString());
|
||||
predictionLog.append(",rank:");
|
||||
predictionLog.append(appTarget.getRank());
|
||||
predictionLog.append("\n");
|
||||
mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache));
|
||||
}
|
||||
predictionLog.append("]");
|
||||
if (Utilities.IS_DEBUG_DEVICE) {
|
||||
HotseatFileLog.INSTANCE.get(mLauncher).log(TAG, predictionLog.toString());
|
||||
}
|
||||
updateDependencies();
|
||||
fillGapsWithPrediction();
|
||||
mPredictionModel.cachePredictionComponentKeys(componentKeys);
|
||||
}
|
||||
|
||||
private void updateDependencies() {
|
||||
mDynamicItemCache.updateDependencies(mComponentKeyMappers, mAllAppsStore, this,
|
||||
mHotSeatItemsCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins a predicted app icon into place.
|
||||
*/
|
||||
public void pinPrediction(ItemInfo info) {
|
||||
PredictedAppIcon icon = (PredictedAppIcon) mHotseat.getChildAt(
|
||||
mHotseat.getCellXFromOrder(info.rank),
|
||||
mHotseat.getCellYFromOrder(info.rank));
|
||||
if (icon == null) {
|
||||
return;
|
||||
}
|
||||
WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo((WorkspaceItemInfo) info);
|
||||
mLauncher.getModelWriter().addItemToDatabase(workspaceItemInfo,
|
||||
LauncherSettings.Favorites.CONTAINER_HOTSEAT, workspaceItemInfo.screenId,
|
||||
workspaceItemInfo.cellX, workspaceItemInfo.cellY);
|
||||
ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 1, 0.8f, 1).start();
|
||||
icon.pin(workspaceItemInfo);
|
||||
AppTarget appTarget = mPredictionModel.getAppTargetFromInfo(workspaceItemInfo);
|
||||
if (appTarget != null) {
|
||||
notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(appTarget,
|
||||
AppTargetEvent.ACTION_PIN, workspaceItemInfo));
|
||||
}
|
||||
}
|
||||
|
||||
private List<WorkspaceItemInfo> mapToWorkspaceItemInfo(
|
||||
List<ComponentKeyMapper> components) {
|
||||
AllAppsStore allAppsStore = mLauncher.getAppsView().getAppsStore();
|
||||
if (allAppsStore.getApps().length == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<WorkspaceItemInfo> predictedApps = new ArrayList<>();
|
||||
for (ComponentKeyMapper mapper : components) {
|
||||
ItemInfoWithIcon info = mapper.getApp(allAppsStore);
|
||||
if (info instanceof AppInfo) {
|
||||
WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((AppInfo) info);
|
||||
predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
|
||||
predictedApps.add(predictedApp);
|
||||
} else if (info instanceof WorkspaceItemInfo) {
|
||||
WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((WorkspaceItemInfo) info);
|
||||
predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
|
||||
predictedApps.add(predictedApp);
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
Log.e(TAG, "Predicted app not found: " + mapper);
|
||||
}
|
||||
}
|
||||
// Stop at the number of hotseat items
|
||||
if (predictedApps.size() == mHotSeatItemsCount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return predictedApps;
|
||||
}
|
||||
|
||||
private List<PredictedAppIcon> getPredictedIcons() {
|
||||
List<PredictedAppIcon> icons = new ArrayList<>();
|
||||
ViewGroup vg = mHotseat.getShortcutsAndWidgets();
|
||||
for (int i = 0; i < vg.getChildCount(); i++) {
|
||||
View child = vg.getChildAt(i);
|
||||
if (isPredictedIcon(child)) {
|
||||
icons.add((PredictedAppIcon) child);
|
||||
}
|
||||
}
|
||||
return icons;
|
||||
}
|
||||
|
||||
private void removePredictedApps(List<PredictedAppIcon.PredictedIconOutlineDrawing> outlines,
|
||||
ItemInfo draggedInfo) {
|
||||
if (mIconRemoveAnimators != null) {
|
||||
mIconRemoveAnimators.end();
|
||||
}
|
||||
mIconRemoveAnimators = new AnimatorSet();
|
||||
removeOutlineDrawings();
|
||||
for (PredictedAppIcon icon : getPredictedIcons()) {
|
||||
if (!icon.isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
if (icon.getTag().equals(draggedInfo)) {
|
||||
mHotseat.removeView(icon);
|
||||
continue;
|
||||
}
|
||||
int rank = ((WorkspaceItemInfo) icon.getTag()).rank;
|
||||
outlines.add(new PredictedAppIcon.PredictedIconOutlineDrawing(
|
||||
mHotseat.getCellXFromOrder(rank), mHotseat.getCellYFromOrder(rank), icon));
|
||||
icon.setEnabled(false);
|
||||
ObjectAnimator animator = ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0);
|
||||
animator.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
if (icon.getParent() != null) {
|
||||
mHotseat.removeView(icon);
|
||||
}
|
||||
}
|
||||
});
|
||||
mIconRemoveAnimators.play(animator);
|
||||
}
|
||||
mIconRemoveAnimators.start();
|
||||
}
|
||||
|
||||
private void notifyItemAction(AppTargetEvent event) {
|
||||
if (mAppPredictor != null) {
|
||||
mAppPredictor.notifyAppTargetEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
|
||||
removePredictedApps(mOutlineDrawings, dragObject.dragInfo);
|
||||
mDragObject = dragObject;
|
||||
if (mOutlineDrawings.isEmpty()) return;
|
||||
for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) {
|
||||
mHotseat.addDelegatedCellDrawing(outlineDrawing);
|
||||
}
|
||||
mHotseat.invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpins pinned app when it's converted into a folder
|
||||
*/
|
||||
public void folderCreatedFromWorkspaceItem(ItemInfo itemInfo, FolderInfo folderInfo) {
|
||||
AppTarget folderTarget = mPredictionModel.getAppTargetFromInfo(folderInfo);
|
||||
AppTarget itemTarget = mPredictionModel.getAppTargetFromInfo(itemInfo);
|
||||
if (folderTarget != null && HotseatPredictionModel.isTrackedForPrediction(folderInfo)) {
|
||||
notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(folderTarget,
|
||||
AppTargetEvent.ACTION_PIN, folderInfo));
|
||||
}
|
||||
// using folder info with isTrackedForPrediction as itemInfo.container is already changed
|
||||
// to folder by this point
|
||||
if (itemTarget != null && HotseatPredictionModel.isTrackedForPrediction(folderInfo)) {
|
||||
notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(itemTarget,
|
||||
AppTargetEvent.ACTION_UNPIN, folderInfo
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins workspace item created when all folder items are removed but one
|
||||
*/
|
||||
public void folderConvertedToWorkspaceItem(ItemInfo itemInfo, FolderInfo folderInfo) {
|
||||
AppTarget folderTarget = mPredictionModel.getAppTargetFromInfo(folderInfo);
|
||||
AppTarget itemTarget = mPredictionModel.getAppTargetFromInfo(itemInfo);
|
||||
if (folderTarget != null && HotseatPredictionModel.isTrackedForPrediction(folderInfo)) {
|
||||
notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(folderTarget,
|
||||
AppTargetEvent.ACTION_UNPIN, folderInfo));
|
||||
}
|
||||
if (itemTarget != null && HotseatPredictionModel.isTrackedForPrediction(itemInfo)) {
|
||||
notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(itemTarget,
|
||||
AppTargetEvent.ACTION_PIN, itemInfo));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragEnd() {
|
||||
if (mDragObject == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemInfo dragInfo = mDragObject.dragInfo;
|
||||
if (mDragObject.isMoved()) {
|
||||
AppTarget appTarget = mPredictionModel.getAppTargetFromInfo(dragInfo);
|
||||
//always send pin event first to prevent AiAi from predicting an item moved within
|
||||
// the same page
|
||||
if (appTarget != null && HotseatPredictionModel.isTrackedForPrediction(dragInfo)) {
|
||||
notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(appTarget,
|
||||
AppTargetEvent.ACTION_PIN, dragInfo));
|
||||
}
|
||||
if (appTarget != null && HotseatPredictionModel.isTrackedForPrediction(
|
||||
mDragObject.originalDragInfo)) {
|
||||
notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(appTarget,
|
||||
AppTargetEvent.ACTION_UNPIN, mDragObject.originalDragInfo));
|
||||
}
|
||||
}
|
||||
mDragObject = null;
|
||||
fillGapsWithPrediction(true, this::removeOutlineDrawings);
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public SystemShortcut<QuickstepLauncher> getShortcut(QuickstepLauncher activity,
|
||||
ItemInfo itemInfo) {
|
||||
if (itemInfo.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) {
|
||||
return null;
|
||||
}
|
||||
return new PinPrediction(activity, itemInfo);
|
||||
}
|
||||
|
||||
private void preparePredictionInfo(WorkspaceItemInfo itemInfo, int rank) {
|
||||
itemInfo.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
|
||||
itemInfo.rank = rank;
|
||||
itemInfo.cellX = mHotseat.getCellXFromOrder(rank);
|
||||
itemInfo.cellY = mHotseat.getCellYFromOrder(rank);
|
||||
itemInfo.screenId = rank;
|
||||
}
|
||||
|
||||
private void removeOutlineDrawings() {
|
||||
if (mOutlineDrawings.isEmpty()) return;
|
||||
for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) {
|
||||
mHotseat.removeDelegatedCellDrawing(outlineDrawing);
|
||||
}
|
||||
mHotseat.invalidate();
|
||||
mOutlineDrawings.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIdpChanged(int changeFlags, InvariantDeviceProfile profile) {
|
||||
if ((changeFlags & CHANGE_FLAG_GRID) != 0) {
|
||||
this.mHotSeatItemsCount = profile.numHotseatIcons;
|
||||
createPredictor();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppsUpdated() {
|
||||
fillGapsWithPrediction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reapplyItemInfo(ItemInfoWithIcon info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDropCompleted(View target, DropTarget.DragObject d, boolean success) {
|
||||
//Does nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillInLogContainerData(ItemInfo childInfo, LauncherLogProto.Target child,
|
||||
ArrayList<LauncherLogProto.Target> parents) {
|
||||
mHotseat.fillInLogContainerData(childInfo, child, parents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs rank info based on current list of predicted items
|
||||
*/
|
||||
public void logLaunchedAppRankingInfo(@NonNull ItemInfo itemInfo, InstanceId instanceId) {
|
||||
if (Utilities.IS_DEBUG_DEVICE) {
|
||||
final String pkg = itemInfo.getTargetComponent() != null
|
||||
? itemInfo.getTargetComponent().getPackageName() : "unknown";
|
||||
HotseatFileLog.INSTANCE.get(mLauncher).log("UserEvent",
|
||||
"appLaunch: packageName:" + pkg + ",isWorkApp:" + (itemInfo.user != null
|
||||
&& !Process.myUserHandle().equals(itemInfo.user))
|
||||
+ ",launchLocation:" + itemInfo.container);
|
||||
}
|
||||
|
||||
if (itemInfo.getTargetComponent() == null || itemInfo.user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ComponentKey key = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user);
|
||||
|
||||
final List<ComponentKeyMapper> predictedApps = new ArrayList<>(mComponentKeyMappers);
|
||||
OptionalInt rank = IntStream.range(0, predictedApps.size())
|
||||
.filter(index -> key.equals(predictedApps.get(index).getComponentKey()))
|
||||
.findFirst();
|
||||
if (!rank.isPresent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int cardinality = 0;
|
||||
for (PredictedAppIcon icon : getPredictedIcons()) {
|
||||
ItemInfo info = (ItemInfo) icon.getTag();
|
||||
cardinality |= 1 << info.screenId;
|
||||
}
|
||||
|
||||
PredictedHotseatContainer.Builder containerBuilder = PredictedHotseatContainer.newBuilder();
|
||||
containerBuilder.setCardinality(cardinality);
|
||||
if (itemInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) {
|
||||
containerBuilder.setIndex(rank.getAsInt());
|
||||
}
|
||||
mLauncher.getStatsLogManager().logger()
|
||||
.withInstanceId(instanceId)
|
||||
.withRank(rank.getAsInt())
|
||||
.withContainerInfo(ContainerInfo.newBuilder()
|
||||
.setPredictedHotseatContainer(containerBuilder)
|
||||
.build())
|
||||
.log(LAUNCHER_HOTSEAT_RANKED);
|
||||
}
|
||||
|
||||
private class PinPrediction extends SystemShortcut<QuickstepLauncher> {
|
||||
|
||||
private PinPrediction(QuickstepLauncher target, ItemInfo itemInfo) {
|
||||
super(R.drawable.ic_pin, R.string.pin_prediction, target,
|
||||
itemInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
dismissTaskMenuView(mTarget);
|
||||
pinPrediction(mItemInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in predicted_rank field based on app prediction.
|
||||
* Only applicable when {@link ItemInfo#itemType} is PREDICTED_HOTSEAT
|
||||
*/
|
||||
public static void encodeHotseatLayoutIntoPredictionRank(
|
||||
@NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) {
|
||||
QuickstepLauncher launcher = QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
|
||||
if (launcher == null || launcher.getHotseatPredictionController() == null
|
||||
|| itemInfo.getTargetComponent() == null) {
|
||||
return;
|
||||
}
|
||||
HotseatPredictionController controller = launcher.getHotseatPredictionController();
|
||||
|
||||
final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user);
|
||||
|
||||
final List<ComponentKeyMapper> predictedApps = controller.mComponentKeyMappers;
|
||||
OptionalInt rank = IntStream.range(0, predictedApps.size())
|
||||
.filter((i) -> k.equals(predictedApps.get(i).getComponentKey()))
|
||||
.findFirst();
|
||||
|
||||
target.predictedRank = 10000 + (controller.mPredictedSpotsCount * 100)
|
||||
+ (rank.isPresent() ? rank.getAsInt() + 1 : 0);
|
||||
}
|
||||
|
||||
private static boolean isPredictedIcon(View view) {
|
||||
return view instanceof PredictedAppIcon && view.getTag() instanceof WorkspaceItemInfo
|
||||
&& ((WorkspaceItemInfo) view.getTag()).container
|
||||
== LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
|
||||
}
|
||||
}
|
||||
-279
@@ -1,279 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.uioverrides.touchcontrollers;
|
||||
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_HEADER_FADE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
|
||||
import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_PAUSE_TO_OVERVIEW_ANIM;
|
||||
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.util.VibratorWrapper;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.util.MotionPauseDetector;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
/**
|
||||
* Touch controller which handles swipe and hold to go to Overview
|
||||
*/
|
||||
public class FlingAndHoldTouchController extends PortraitStatesTouchController {
|
||||
|
||||
private static final long PEEK_IN_ANIM_DURATION = 240;
|
||||
private static final long PEEK_OUT_ANIM_DURATION = 100;
|
||||
private static final float MAX_DISPLACEMENT_PERCENT = 0.75f;
|
||||
|
||||
protected final MotionPauseDetector mMotionPauseDetector;
|
||||
private final float mMotionPauseMinDisplacement;
|
||||
private final float mMotionPauseMaxDisplacement;
|
||||
|
||||
private AnimatorSet mPeekAnim;
|
||||
|
||||
public FlingAndHoldTouchController(Launcher l) {
|
||||
super(l, false /* allowDragToOverview */);
|
||||
mMotionPauseDetector = new MotionPauseDetector(l);
|
||||
mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop();
|
||||
mMotionPauseMaxDisplacement = getMotionPauseMaxDisplacement();
|
||||
}
|
||||
|
||||
protected float getMotionPauseMaxDisplacement() {
|
||||
return getShiftRange() * MAX_DISPLACEMENT_PERCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getAtomicDuration() {
|
||||
return QuickstepAtomicAnimationFactory.ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start, float startDisplacement) {
|
||||
mMotionPauseDetector.clear();
|
||||
|
||||
super.onDragStart(start, startDisplacement);
|
||||
|
||||
if (handlingOverviewAnim()) {
|
||||
mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseChanged);
|
||||
}
|
||||
|
||||
if (mAtomicAnim != null) {
|
||||
mAtomicAnim.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onMotionPauseChanged(boolean isPaused) {
|
||||
RecentsView recentsView = mLauncher.getOverviewPanel();
|
||||
recentsView.setOverviewStateEnabled(isPaused);
|
||||
if (mPeekAnim != null) {
|
||||
mPeekAnim.cancel();
|
||||
}
|
||||
LauncherState fromState = isPaused ? NORMAL : OVERVIEW_PEEK;
|
||||
LauncherState toState = isPaused ? OVERVIEW_PEEK : NORMAL;
|
||||
long peekDuration = isPaused ? PEEK_IN_ANIM_DURATION : PEEK_OUT_ANIM_DURATION;
|
||||
|
||||
StateAnimationConfig config = new StateAnimationConfig();
|
||||
config.duration = peekDuration;
|
||||
config.animFlags = PLAY_ATOMIC_OVERVIEW_PEEK;
|
||||
mPeekAnim = mLauncher.getStateManager().createAtomicAnimation(
|
||||
fromState, toState, config);
|
||||
mPeekAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mPeekAnim = null;
|
||||
}
|
||||
});
|
||||
mPeekAnim.start();
|
||||
VibratorWrapper.INSTANCE.get(mLauncher).vibrate(OVERVIEW_HAPTIC);
|
||||
|
||||
mLauncher.getDragLayer().getScrim().createSysuiMultiplierAnim(isPaused ? 0 : 1)
|
||||
.setDuration(peekDuration).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether we are handling the overview animation, rather than
|
||||
* having it as part of the existing animation to the target state.
|
||||
*/
|
||||
protected boolean handlingOverviewAnim() {
|
||||
int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags();
|
||||
return mStartState == NORMAL && (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StateAnimationConfig getConfigForStates(
|
||||
LauncherState fromState, LauncherState toState) {
|
||||
if (fromState == NORMAL && toState == ALL_APPS) {
|
||||
StateAnimationConfig builder = new StateAnimationConfig();
|
||||
// Fade in prediction icons quickly, then rest of all apps after reaching overview.
|
||||
float progressToReachOverview = NORMAL.getVerticalProgress(mLauncher)
|
||||
- OVERVIEW.getVerticalProgress(mLauncher);
|
||||
builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(
|
||||
ACCEL,
|
||||
0,
|
||||
ALL_APPS_CONTENT_FADE_THRESHOLD));
|
||||
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
|
||||
ACCEL,
|
||||
progressToReachOverview,
|
||||
progressToReachOverview + ALL_APPS_CONTENT_FADE_THRESHOLD));
|
||||
|
||||
// Get workspace out of the way quickly, to prepare for potential pause.
|
||||
builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL_3);
|
||||
builder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, DEACCEL_3);
|
||||
builder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_3);
|
||||
return builder;
|
||||
} else if (fromState == ALL_APPS && toState == NORMAL) {
|
||||
StateAnimationConfig builder = new StateAnimationConfig();
|
||||
// Keep all apps/predictions opaque until the very end of the transition.
|
||||
float progressToReachOverview = OVERVIEW.getVerticalProgress(mLauncher);
|
||||
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
|
||||
DEACCEL,
|
||||
progressToReachOverview - ALL_APPS_CONTENT_FADE_THRESHOLD,
|
||||
progressToReachOverview));
|
||||
builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(
|
||||
DEACCEL,
|
||||
1 - ALL_APPS_CONTENT_FADE_THRESHOLD,
|
||||
1));
|
||||
return builder;
|
||||
}
|
||||
return super.getConfigForStates(fromState, toState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDrag(float displacement, MotionEvent event) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "FlingAndHoldTouchController");
|
||||
}
|
||||
float upDisplacement = -displacement;
|
||||
mMotionPauseDetector.setDisallowPause(!handlingOverviewAnim()
|
||||
|| upDisplacement < mMotionPauseMinDisplacement
|
||||
|| upDisplacement > mMotionPauseMaxDisplacement);
|
||||
mMotionPauseDetector.addPosition(event);
|
||||
return super.onDrag(displacement, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragEnd(float velocity) {
|
||||
if (mMotionPauseDetector.isPaused() && handlingOverviewAnim()) {
|
||||
goToOverviewOnDragEnd(velocity);
|
||||
} else {
|
||||
super.onDragEnd(velocity);
|
||||
}
|
||||
|
||||
View searchView = mLauncher.getAppsView().getSearchView();
|
||||
if (searchView instanceof FeedbackHandler) {
|
||||
((FeedbackHandler) searchView).resetFeedback();
|
||||
}
|
||||
mMotionPauseDetector.clear();
|
||||
}
|
||||
|
||||
protected void goToOverviewOnDragEnd(float velocity) {
|
||||
if (mPeekAnim != null) {
|
||||
mPeekAnim.cancel();
|
||||
}
|
||||
|
||||
Animator overviewAnim = mLauncher.createAtomicAnimationFactory()
|
||||
.createStateElementAnimation(INDEX_PAUSE_TO_OVERVIEW_ANIM);
|
||||
mAtomicAnim = new AnimatorSet();
|
||||
mAtomicAnim.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
onSwipeInteractionCompleted(OVERVIEW, Touch.SWIPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
if (mCancelled) {
|
||||
StateAnimationConfig config = new StateAnimationConfig();
|
||||
config.animFlags = PLAY_ATOMIC_OVERVIEW_PEEK;
|
||||
config.duration = PEEK_OUT_ANIM_DURATION;
|
||||
mPeekAnim = mLauncher.getStateManager().createAtomicAnimation(
|
||||
mFromState, mToState, config);
|
||||
mPeekAnim.start();
|
||||
}
|
||||
mAtomicAnim = null;
|
||||
}
|
||||
});
|
||||
mAtomicAnim.play(overviewAnim);
|
||||
mAtomicAnim.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void goToTargetState(LauncherState targetState, int logAction) {
|
||||
if (mPeekAnim != null && mPeekAnim.isStarted()) {
|
||||
// Don't jump to the target state until overview is no longer peeking.
|
||||
mPeekAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
FlingAndHoldTouchController.super.goToTargetState(targetState, logAction);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
super.goToTargetState(targetState, logAction);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@AnimationFlags
|
||||
protected int updateAnimComponentsOnReinit(@AnimationFlags int animComponents) {
|
||||
if (handlingOverviewAnim()) {
|
||||
// We don't want the state transition to all apps to animate overview,
|
||||
// as that will cause a jump after our atomic animation.
|
||||
return animComponents | SKIP_OVERVIEW;
|
||||
} else {
|
||||
return animComponents;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for views with feedback animation requiring reset
|
||||
*/
|
||||
public interface FeedbackHandler {
|
||||
|
||||
/**
|
||||
* reset searchWidget feedback
|
||||
*/
|
||||
void resetFeedback();
|
||||
}
|
||||
|
||||
}
|
||||
-81
@@ -1,81 +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.uioverrides.touchcontrollers;
|
||||
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.quickstep.TouchInteractionService;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
/**
|
||||
* Touch controller from going from OVERVIEW to ALL_APPS.
|
||||
*
|
||||
* This is used in landscape mode. It is also used in portrait mode for the fallback recents.
|
||||
*/
|
||||
public class OverviewToAllAppsTouchController extends PortraitStatesTouchController {
|
||||
|
||||
public OverviewToAllAppsTouchController(Launcher l) {
|
||||
super(l, true /* allowDragToOverview */);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canInterceptTouch(MotionEvent ev) {
|
||||
if (mCurrentAnimation != null) {
|
||||
// If we are already animating from a previous state, we can intercept.
|
||||
return true;
|
||||
}
|
||||
if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
|
||||
return false;
|
||||
}
|
||||
if (mLauncher.isInState(ALL_APPS)) {
|
||||
// In all-apps only listen if the container cannot scroll itself
|
||||
return mLauncher.getAppsView().shouldContainerScroll(ev);
|
||||
} else if (mLauncher.isInState(NORMAL)) {
|
||||
return (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0;
|
||||
} else if (mLauncher.isInState(OVERVIEW)) {
|
||||
RecentsView rv = mLauncher.getOverviewPanel();
|
||||
return ev.getY() > (rv.getBottom() - rv.getPaddingBottom());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
|
||||
if (fromState == ALL_APPS && !isDragTowardPositive) {
|
||||
// Should swipe down go to OVERVIEW instead?
|
||||
return TouchInteractionService.isConnected() ?
|
||||
mLauncher.getStateManager().getLastState() : NORMAL;
|
||||
} else if (isDragTowardPositive) {
|
||||
return ALL_APPS;
|
||||
}
|
||||
return fromState;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLogContainerTypeForNormalState(MotionEvent ev) {
|
||||
return LauncherLogProto.ContainerType.WORKSPACE;
|
||||
}
|
||||
}
|
||||
-175
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
||||
import static com.android.launcher3.anim.Interpolators.clampToProgress;
|
||||
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.util.Log;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.launcher3.statemanager.StatefulActivity;
|
||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||
import com.android.quickstep.util.SurfaceTransactionApplier;
|
||||
import com.android.quickstep.util.TaskViewSimulator;
|
||||
import com.android.quickstep.util.TransformParams;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
|
||||
/**
|
||||
* Provider for the atomic (for 3-button mode) remote window animation from the app to the overview.
|
||||
*
|
||||
* @param <T> activity that contains the overview
|
||||
*/
|
||||
final class AppToOverviewAnimationProvider<T extends StatefulActivity<?>> extends
|
||||
RemoteAnimationProvider {
|
||||
|
||||
private static final long RECENTS_LAUNCH_DURATION = 250;
|
||||
private static final String TAG = "AppToOverviewAnimationProvider";
|
||||
|
||||
private final BaseActivityInterface<?, T> mActivityInterface;
|
||||
// The id of the currently running task that is transitioning to overview.
|
||||
private final RunningTaskInfo mTargetTask;
|
||||
private final RecentsAnimationDeviceState mDeviceState;
|
||||
|
||||
private T mActivity;
|
||||
private RecentsView mRecentsView;
|
||||
|
||||
AppToOverviewAnimationProvider(
|
||||
BaseActivityInterface<?, T> activityInterface, RunningTaskInfo targetTask,
|
||||
RecentsAnimationDeviceState deviceState) {
|
||||
mActivityInterface = activityInterface;
|
||||
mTargetTask = targetTask;
|
||||
mDeviceState = deviceState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when the activity is ready/initialized.
|
||||
*
|
||||
* @param activity the activity that is ready
|
||||
* @param wasVisible true if it was visible before
|
||||
*/
|
||||
boolean onActivityReady(T activity, Boolean wasVisible) {
|
||||
activity.<RecentsView>getOverviewPanel().showCurrentTask(mTargetTask);
|
||||
AbstractFloatingView.closeAllOpenViews(activity, wasVisible);
|
||||
BaseActivityInterface.AnimationFactory factory = mActivityInterface.prepareRecentsUI(
|
||||
mDeviceState,
|
||||
wasVisible, (controller) -> {
|
||||
controller.getNormalController().dispatchOnStart();
|
||||
controller.getNormalController().getAnimationPlayer().end();
|
||||
});
|
||||
factory.createActivityInterface(RECENTS_LAUNCH_DURATION);
|
||||
factory.setRecentsAttachedToAppWindow(true, false);
|
||||
mActivity = activity;
|
||||
mRecentsView = mActivity.getOverviewPanel();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create remote window animation from the currently running app to the overview panel.
|
||||
*
|
||||
* @param appTargets the target apps
|
||||
* @return animation from app to overview
|
||||
*/
|
||||
@Override
|
||||
public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
|
||||
RemoteAnimationTargetCompat[] wallpaperTargets) {
|
||||
PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
|
||||
if (mActivity == null) {
|
||||
Log.e(TAG, "Animation created, before activity");
|
||||
return pa.buildAnim();
|
||||
}
|
||||
|
||||
mRecentsView.setRunningTaskIconScaledDown(true);
|
||||
pa.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
mActivityInterface.onSwipeUpToRecentsComplete();
|
||||
mRecentsView.animateUpRunningTaskIconScale();
|
||||
}
|
||||
});
|
||||
|
||||
DepthController depthController = mActivityInterface.getDepthController();
|
||||
if (depthController != null) {
|
||||
pa.addFloat(depthController, DEPTH, BACKGROUND_APP.getDepth(mActivity),
|
||||
OVERVIEW.getDepth(mActivity), TOUCH_RESPONSE_INTERPOLATOR);
|
||||
}
|
||||
|
||||
RemoteAnimationTargets targets = new RemoteAnimationTargets(appTargets,
|
||||
wallpaperTargets, MODE_CLOSING);
|
||||
|
||||
// Use the top closing app to determine the insets for the animation
|
||||
RemoteAnimationTargetCompat runningTaskTarget = mTargetTask == null ? null
|
||||
: targets.findTask(mTargetTask.taskId);
|
||||
if (runningTaskTarget == null) {
|
||||
Log.e(TAG, "No closing app");
|
||||
return pa.buildAnim();
|
||||
}
|
||||
|
||||
TaskViewSimulator tsv = new TaskViewSimulator(mActivity, mRecentsView.getSizeStrategy());
|
||||
tsv.setDp(mActivity.getDeviceProfile());
|
||||
tsv.setPreview(runningTaskTarget);
|
||||
tsv.setLayoutRotation(mRecentsView.getPagedViewOrientedState().getTouchRotation(),
|
||||
mRecentsView.getPagedViewOrientedState().getDisplayRotation());
|
||||
|
||||
TransformParams params = new TransformParams()
|
||||
.setTargetSet(targets)
|
||||
.setSyncTransactionApplier(new SurfaceTransactionApplier(mActivity.getRootView()));
|
||||
|
||||
AnimatedFloat recentsAlpha = new AnimatedFloat(() -> { });
|
||||
params.setBaseBuilderProxy((builder, app, p)
|
||||
-> builder.withAlpha(recentsAlpha.value));
|
||||
|
||||
Interpolator taskInterpolator;
|
||||
if (targets.isAnimatingHome()) {
|
||||
params.setHomeBuilderProxy((builder, app, p) -> builder.withAlpha(1 - p.getProgress()));
|
||||
|
||||
taskInterpolator = TOUCH_RESPONSE_INTERPOLATOR;
|
||||
pa.addFloat(recentsAlpha, AnimatedFloat.VALUE, 0, 1, TOUCH_RESPONSE_INTERPOLATOR);
|
||||
} else {
|
||||
// When animation from app to recents, the recents layer is drawn on top of the app. To
|
||||
// prevent the overlap, we animate the task first and then quickly fade in the recents.
|
||||
taskInterpolator = clampToProgress(TOUCH_RESPONSE_INTERPOLATOR, 0, 0.8f);
|
||||
pa.addFloat(recentsAlpha, AnimatedFloat.VALUE, 0, 1,
|
||||
clampToProgress(TOUCH_RESPONSE_INTERPOLATOR, 0.8f, 1));
|
||||
}
|
||||
|
||||
pa.addFloat(params, TransformParams.PROGRESS, 0, 1, taskInterpolator);
|
||||
tsv.addAppToOverviewAnim(pa, taskInterpolator);
|
||||
pa.addOnFrameCallback(() -> tsv.apply(params));
|
||||
return pa.buildAnim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get duration of animation from app to overview.
|
||||
*
|
||||
* @return duration of animation
|
||||
*/
|
||||
long getRecentsLaunchDuration() {
|
||||
return RECENTS_LAUNCH_DURATION;
|
||||
}
|
||||
}
|
||||
@@ -1,394 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.statemanager.StatefulActivity;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.util.VibratorWrapper;
|
||||
import com.android.launcher3.util.WindowBounds;
|
||||
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.ActivityInitListener;
|
||||
import com.android.quickstep.util.InputConsumerProxy;
|
||||
import com.android.quickstep.util.RectFSpringAnim;
|
||||
import com.android.quickstep.util.SurfaceTransactionApplier;
|
||||
import com.android.quickstep.util.TransformParams;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.InputConsumerController;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Base class for swipe up handler with some utility methods
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.Q)
|
||||
public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extends RecentsView>
|
||||
extends SwipeUpAnimationLogic implements RecentsAnimationListener {
|
||||
|
||||
private static final String TAG = "BaseSwipeUpHandler";
|
||||
|
||||
protected final BaseActivityInterface<?, T> mActivityInterface;
|
||||
protected final InputConsumerProxy mInputConsumerProxy;
|
||||
|
||||
protected final ActivityInitListener mActivityInitListener;
|
||||
|
||||
protected RecentsAnimationController mRecentsAnimationController;
|
||||
protected RecentsAnimationTargets mRecentsAnimationTargets;
|
||||
|
||||
// Callbacks to be made once the recents animation starts
|
||||
private final ArrayList<Runnable> mRecentsAnimationStartCallbacks = new ArrayList<>();
|
||||
|
||||
protected T mActivity;
|
||||
protected Q mRecentsView;
|
||||
|
||||
protected Runnable mGestureEndCallback;
|
||||
|
||||
protected MultiStateCallback mStateCallback;
|
||||
|
||||
protected boolean mCanceled;
|
||||
|
||||
private boolean mRecentsViewScrollLinked = false;
|
||||
|
||||
protected BaseSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
|
||||
GestureState gestureState, InputConsumerController inputConsumer) {
|
||||
super(context, deviceState, gestureState, new TransformParams());
|
||||
mActivityInterface = gestureState.getActivityInterface();
|
||||
mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
|
||||
mInputConsumerProxy =
|
||||
new InputConsumerProxy(inputConsumer, this::createNewInputProxyHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called at the end of constructor of subclasses. This calls various methods which can
|
||||
* depend on proper class initialization.
|
||||
*/
|
||||
protected void initAfterSubclassConstructor() {
|
||||
initTransitionEndpoints(
|
||||
mTaskViewSimulator.getOrientationState().getLauncherDeviceProfile());
|
||||
}
|
||||
|
||||
protected void performHapticFeedback() {
|
||||
VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
|
||||
}
|
||||
|
||||
public Consumer<MotionEvent> getRecentsViewDispatcher(float navbarRotation) {
|
||||
return mRecentsView != null ? mRecentsView.getEventDispatcher(navbarRotation) : null;
|
||||
}
|
||||
|
||||
public void setGestureEndCallback(Runnable gestureEndCallback) {
|
||||
mGestureEndCallback = gestureEndCallback;
|
||||
}
|
||||
|
||||
public abstract Intent getLaunchIntent();
|
||||
|
||||
protected void linkRecentsViewScroll() {
|
||||
SurfaceTransactionApplier.create(mRecentsView, applier -> {
|
||||
mTransformParams.setSyncTransactionApplier(applier);
|
||||
runOnRecentsAnimationStart(() ->
|
||||
mRecentsAnimationTargets.addReleaseCheck(applier));
|
||||
});
|
||||
|
||||
mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
|
||||
if (moveWindowWithRecentsScroll()) {
|
||||
updateFinalShift();
|
||||
}
|
||||
});
|
||||
runOnRecentsAnimationStart(() ->
|
||||
mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController,
|
||||
mRecentsAnimationTargets));
|
||||
mRecentsViewScrollLinked = true;
|
||||
}
|
||||
|
||||
protected void startNewTask(Consumer<Boolean> resultCallback) {
|
||||
// Launch the task user scrolled to (mRecentsView.getNextPage()).
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
// We finish recents animation inside launchTask() when live tile is enabled.
|
||||
mRecentsView.getNextPageTaskView().launchTask(false /* animate */,
|
||||
true /* freezeTaskList */);
|
||||
} else {
|
||||
if (!mCanceled) {
|
||||
TaskView nextTask = mRecentsView.getNextPageTaskView();
|
||||
if (nextTask != null) {
|
||||
int taskId = nextTask.getTask().key.id;
|
||||
mGestureState.updateLastStartedTaskId(taskId);
|
||||
boolean hasTaskPreviouslyAppeared = mGestureState.getPreviouslyAppearedTaskIds()
|
||||
.contains(taskId);
|
||||
nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
|
||||
success -> {
|
||||
resultCallback.accept(success);
|
||||
if (success) {
|
||||
if (hasTaskPreviouslyAppeared) {
|
||||
onRestartPreviouslyAppearedTask();
|
||||
}
|
||||
} else {
|
||||
mActivityInterface.onLaunchTaskFailed();
|
||||
nextTask.notifyTaskLaunchFailed(TAG);
|
||||
mRecentsAnimationController.finish(true /* toRecents */, null);
|
||||
}
|
||||
}, MAIN_EXECUTOR.getHandler());
|
||||
} else {
|
||||
mActivityInterface.onLaunchTaskFailed();
|
||||
Toast.makeText(mContext, R.string.activity_not_available, LENGTH_SHORT).show();
|
||||
mRecentsAnimationController.finish(true /* toRecents */, null);
|
||||
}
|
||||
}
|
||||
mCanceled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when we successfully startNewTask() on the task that was previously running. Normally
|
||||
* we call resumeLastTask() when returning to the previously running task, but this handles a
|
||||
* specific edge case: if we switch from A to B, and back to A before B appears, we need to
|
||||
* start A again to ensure it stays on top.
|
||||
*/
|
||||
@CallSuper
|
||||
protected void onRestartPreviouslyAppearedTask() {
|
||||
// Finish the controller here, since we won't get onTaskAppeared() for a task that already
|
||||
// appeared.
|
||||
if (mRecentsAnimationController != null) {
|
||||
mRecentsAnimationController.finish(false, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given {@param action} if the recents animation has already started, or queues it to
|
||||
* be run when it is next started.
|
||||
*/
|
||||
protected void runOnRecentsAnimationStart(Runnable action) {
|
||||
if (mRecentsAnimationTargets == null) {
|
||||
mRecentsAnimationStartCallbacks.add(action);
|
||||
} else {
|
||||
action.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO can we remove this now that we don't finish the controller until onTaskAppeared()?
|
||||
* @return whether the recents animation has started and there are valid app targets.
|
||||
*/
|
||||
protected boolean hasTargets() {
|
||||
return mRecentsAnimationTargets != null && mRecentsAnimationTargets.hasTargets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecentsAnimationStart(RecentsAnimationController recentsAnimationController,
|
||||
RecentsAnimationTargets targets) {
|
||||
mRecentsAnimationController = recentsAnimationController;
|
||||
mRecentsAnimationTargets = targets;
|
||||
mTransformParams.setTargetSet(mRecentsAnimationTargets);
|
||||
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(
|
||||
mGestureState.getRunningTaskId());
|
||||
|
||||
if (runningTaskTarget != null) {
|
||||
mTaskViewSimulator.setPreview(runningTaskTarget);
|
||||
}
|
||||
|
||||
// Only initialize the device profile, if it has not been initialized before, as in some
|
||||
// configurations targets.homeContentInsets may not be correct.
|
||||
if (mActivity == null) {
|
||||
DeviceProfile dp = mTaskViewSimulator.getOrientationState().getLauncherDeviceProfile();
|
||||
if (targets.minimizedHomeBounds != null && runningTaskTarget != null) {
|
||||
Rect overviewStackBounds = mActivityInterface
|
||||
.getOverviewWindowBounds(targets.minimizedHomeBounds, runningTaskTarget);
|
||||
dp = dp.getMultiWindowProfile(mContext,
|
||||
new WindowBounds(overviewStackBounds, targets.homeContentInsets));
|
||||
} else {
|
||||
// If we are not in multi-window mode, home insets should be same as system insets.
|
||||
dp = dp.copy(mContext);
|
||||
}
|
||||
dp.updateInsets(targets.homeContentInsets);
|
||||
dp.updateIsSeascape(mContext);
|
||||
initTransitionEndpoints(dp);
|
||||
}
|
||||
|
||||
// Notify when the animation starts
|
||||
if (!mRecentsAnimationStartCallbacks.isEmpty()) {
|
||||
for (Runnable action : new ArrayList<>(mRecentsAnimationStartCallbacks)) {
|
||||
action.run();
|
||||
}
|
||||
mRecentsAnimationStartCallbacks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
|
||||
mRecentsAnimationController = null;
|
||||
mRecentsAnimationTargets = null;
|
||||
if (mRecentsView != null) {
|
||||
mRecentsView.setRecentsAnimationTargets(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
|
||||
mRecentsAnimationController = null;
|
||||
mRecentsAnimationTargets = null;
|
||||
if (mRecentsView != null) {
|
||||
mRecentsView.setRecentsAnimationTargets(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
|
||||
if (mRecentsAnimationController != null) {
|
||||
if (handleTaskAppeared(appearedTaskTarget)) {
|
||||
mRecentsAnimationController.finish(false /* toRecents */,
|
||||
null /* onFinishComplete */);
|
||||
mActivityInterface.onLaunchTaskSuccess();
|
||||
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return Whether this was the task we were waiting to appear, and thus handled it. */
|
||||
protected abstract boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget);
|
||||
|
||||
/**
|
||||
* @return The index of the TaskView in RecentsView whose taskId matches the task that will
|
||||
* resume if we finish the controller.
|
||||
*/
|
||||
protected int getLastAppearedTaskIndex() {
|
||||
return mGestureState.getLastAppearedTaskId() != -1
|
||||
? mRecentsView.getTaskIndexForId(mGestureState.getLastAppearedTaskId())
|
||||
: mRecentsView.getRunningTaskIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether we are continuing a gesture that already landed on a new task,
|
||||
* but before that task appeared.
|
||||
*/
|
||||
protected boolean hasStartedNewTask() {
|
||||
return mGestureState.getLastStartedTaskId() != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the window should be translated horizontally if the recents view scrolls
|
||||
*/
|
||||
protected abstract boolean moveWindowWithRecentsScroll();
|
||||
|
||||
protected boolean onActivityInit(Boolean alreadyOnHome) {
|
||||
T createdActivity = mActivityInterface.getCreatedActivity();
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "BaseSwipeUpHandler.1");
|
||||
}
|
||||
if (createdActivity != null) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "BaseSwipeUpHandler.2");
|
||||
}
|
||||
initTransitionEndpoints(createdActivity.getDeviceProfile());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to create a input proxy for the running task
|
||||
*/
|
||||
@UiThread
|
||||
protected abstract InputConsumer createNewInputProxyHandler();
|
||||
|
||||
/**
|
||||
* Called when the value of {@link #mCurrentShift} changes
|
||||
*/
|
||||
@UiThread
|
||||
public abstract void updateFinalShift();
|
||||
|
||||
/**
|
||||
* Called when motion pause is detected
|
||||
*/
|
||||
public abstract void onMotionPauseChanged(boolean isPaused);
|
||||
|
||||
@UiThread
|
||||
public void onGestureStarted(boolean isLikelyToStartNewTask) { }
|
||||
|
||||
@UiThread
|
||||
public abstract void onGestureCancelled();
|
||||
|
||||
@UiThread
|
||||
public abstract void onGestureEnded(float endVelocity, PointF velocity, PointF downPos);
|
||||
|
||||
public abstract void onConsumerAboutToBeSwitched();
|
||||
|
||||
public void setIsLikelyToStartNewTask(boolean isLikelyToStartNewTask) { }
|
||||
|
||||
/**
|
||||
* Registers a callback to run when the activity is ready.
|
||||
* @param intent The intent that will be used to start the activity if it doesn't exist already.
|
||||
*/
|
||||
public void initWhenReady(Intent intent) {
|
||||
// Preload the plan
|
||||
RecentsModel.INSTANCE.get(mContext).getTasks(null);
|
||||
|
||||
mActivityInitListener.register(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the transform on the recents animation
|
||||
*/
|
||||
protected void applyWindowTransform() {
|
||||
if (mWindowTransitionController != null) {
|
||||
mWindowTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
|
||||
}
|
||||
if (mRecentsAnimationTargets != null) {
|
||||
if (mRecentsViewScrollLinked) {
|
||||
mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
|
||||
}
|
||||
mTaskViewSimulator.apply(mTransformParams);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
|
||||
HomeAnimationFactory homeAnimationFactory) {
|
||||
RectFSpringAnim anim =
|
||||
super.createWindowAnimationToHome(startProgress, homeAnimationFactory);
|
||||
if (mRecentsAnimationTargets != null) {
|
||||
mRecentsAnimationTargets.addReleaseCheck(anim);
|
||||
}
|
||||
return anim;
|
||||
}
|
||||
|
||||
public interface Factory {
|
||||
|
||||
BaseSwipeUpHandler newHandler(
|
||||
GestureState gestureState, long touchTimeMs, boolean continuingLastGesture);
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.content.Context;
|
||||
import android.graphics.RectF;
|
||||
import android.os.UserHandle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.BaseQuickstepLauncher;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.util.RectFSpringAnim;
|
||||
import com.android.quickstep.util.StaggeredWorkspaceAnim;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.system.InputConsumerController;
|
||||
|
||||
/**
|
||||
* Temporary class to allow easier refactoring
|
||||
*/
|
||||
public class LauncherSwipeHandlerV2 extends
|
||||
BaseSwipeUpHandlerV2<BaseQuickstepLauncher, RecentsView> {
|
||||
|
||||
public LauncherSwipeHandlerV2(Context context, RecentsAnimationDeviceState deviceState,
|
||||
TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
|
||||
boolean continuingLastGesture, InputConsumerController inputConsumer) {
|
||||
super(context, deviceState, taskAnimationManager, gestureState, touchTimeMs,
|
||||
continuingLastGesture, inputConsumer);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected HomeAnimationFactory createHomeAnimationFactory(long duration) {
|
||||
HomeAnimationFactory homeAnimFactory;
|
||||
if (mActivity != null) {
|
||||
final TaskView runningTaskView = mRecentsView.getRunningTaskView();
|
||||
final View workspaceView;
|
||||
if (runningTaskView != null
|
||||
&& runningTaskView.getTask().key.getComponent() != null) {
|
||||
workspaceView = mActivity.getWorkspace().getFirstMatchForAppClose(
|
||||
runningTaskView.getTask().key.getComponent().getPackageName(),
|
||||
UserHandle.of(runningTaskView.getTask().key.userId));
|
||||
} else {
|
||||
workspaceView = null;
|
||||
}
|
||||
final RectF iconLocation = new RectF();
|
||||
boolean canUseWorkspaceView =
|
||||
workspaceView != null && workspaceView.isAttachedToWindow();
|
||||
FloatingIconView floatingIconView = canUseWorkspaceView
|
||||
? FloatingIconView.getFloatingIconView(mActivity, workspaceView,
|
||||
true /* hideOriginal */, iconLocation, false /* isOpening */)
|
||||
: null;
|
||||
|
||||
mActivity.getRootView().setForceHideBackArrow(true);
|
||||
mActivity.setHintUserWillBeActive();
|
||||
|
||||
if (canUseWorkspaceView) {
|
||||
// We want the window alpha to be 0 once this threshold is met, so that the
|
||||
// FolderIconView can be seen morphing into the icon shape.
|
||||
float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION;
|
||||
homeAnimFactory = new LauncherHomeAnimationFactory() {
|
||||
@Override
|
||||
public RectF getWindowTargetRect() {
|
||||
return iconLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnimation(RectFSpringAnim anim) {
|
||||
anim.addAnimatorListener(floatingIconView);
|
||||
floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged);
|
||||
floatingIconView.setFastFinishRunnable(anim::end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(RectF currentRect, float progress, float radius) {
|
||||
floatingIconView.update(currentRect, 1f, progress, windowAlphaThreshold,
|
||||
radius, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
floatingIconView.fastFinish();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
homeAnimFactory = new LauncherHomeAnimationFactory();
|
||||
}
|
||||
} else {
|
||||
homeAnimFactory = new HomeAnimationFactory() {
|
||||
@Override
|
||||
public AnimatorPlaybackController createActivityAnimationToHome() {
|
||||
return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
|
||||
}
|
||||
};
|
||||
mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
|
||||
isPresent -> mRecentsView.startHome());
|
||||
}
|
||||
return homeAnimFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finishRecentsControllerToHome(Runnable callback) {
|
||||
mRecentsAnimationController.finish(
|
||||
true /* toRecents */, callback, true /* sendUserLeaveHint */);
|
||||
}
|
||||
|
||||
private class LauncherHomeAnimationFactory extends HomeAnimationFactory {
|
||||
@NonNull
|
||||
@Override
|
||||
public AnimatorPlaybackController createActivityAnimationToHome() {
|
||||
// Return an empty APC here since we have an non-user controlled animation
|
||||
// to home.
|
||||
long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
|
||||
return mActivity.getStateManager().createAnimationToNewWorkspace(
|
||||
NORMAL, accuracy, 0 /* animComponents */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playAtomicAnimation(float velocity) {
|
||||
new StaggeredWorkspaceAnim(mActivity, velocity,
|
||||
true /* animateOverviewScrim */).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,259 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import androidx.annotation.BinderThread;
|
||||
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.statemanager.StatefulActivity;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.quickstep.util.ActivityInitListener;
|
||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.LatencyTrackerCompat;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
|
||||
/**
|
||||
* Helper class to handle various atomic commands for switching between Overview.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
public class OverviewCommandHelper {
|
||||
|
||||
private final Context mContext;
|
||||
private final RecentsAnimationDeviceState mDeviceState;
|
||||
private final RecentsModel mRecentsModel;
|
||||
private final OverviewComponentObserver mOverviewComponentObserver;
|
||||
|
||||
private long mLastToggleTime;
|
||||
|
||||
public OverviewCommandHelper(Context context, RecentsAnimationDeviceState deviceState,
|
||||
OverviewComponentObserver observer) {
|
||||
mContext = context;
|
||||
mDeviceState = deviceState;
|
||||
mRecentsModel = RecentsModel.INSTANCE.get(mContext);
|
||||
mOverviewComponentObserver = observer;
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
public void onOverviewToggle() {
|
||||
// If currently screen pinning, do not enter overview
|
||||
if (mDeviceState.isScreenPinningActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ActivityManagerWrapper.getInstance()
|
||||
.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
|
||||
MAIN_EXECUTOR.execute(new RecentsActivityCommand<>());
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
public void onOverviewShown(boolean triggeredFromAltTab) {
|
||||
if (triggeredFromAltTab) {
|
||||
ActivityManagerWrapper.getInstance()
|
||||
.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
|
||||
}
|
||||
MAIN_EXECUTOR.execute(new ShowRecentsCommand(triggeredFromAltTab));
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
public void onOverviewHidden() {
|
||||
MAIN_EXECUTOR.execute(new HideRecentsCommand());
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
public void onTip(int actionType, int viewType) {
|
||||
MAIN_EXECUTOR.execute(() ->
|
||||
UserEventDispatcher.newInstance(mContext).logActionTip(actionType, viewType));
|
||||
}
|
||||
|
||||
private class ShowRecentsCommand extends RecentsActivityCommand {
|
||||
|
||||
private final boolean mTriggeredFromAltTab;
|
||||
|
||||
ShowRecentsCommand(boolean triggeredFromAltTab) {
|
||||
mTriggeredFromAltTab = triggeredFromAltTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handleCommand(long elapsedTime) {
|
||||
// TODO: Go to the next page if started from alt-tab.
|
||||
return mActivityInterface.getVisibleRecentsView() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTransitionComplete() {
|
||||
// TODO(b/138729100) This doesn't execute first time launcher is run
|
||||
if (mTriggeredFromAltTab) {
|
||||
RecentsView rv = mActivityInterface.getVisibleRecentsView();
|
||||
if (rv == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure that recents view has focus so that it receives the followup key inputs
|
||||
TaskView taskView = rv.getNextTaskView();
|
||||
if (taskView == null) {
|
||||
if (rv.getTaskViewCount() > 0) {
|
||||
taskView = rv.getTaskViewAt(0);
|
||||
taskView.requestFocus();
|
||||
} else {
|
||||
rv.requestFocus();
|
||||
}
|
||||
} else {
|
||||
taskView.requestFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class HideRecentsCommand extends RecentsActivityCommand {
|
||||
|
||||
@Override
|
||||
protected boolean handleCommand(long elapsedTime) {
|
||||
RecentsView recents = mActivityInterface.getVisibleRecentsView();
|
||||
if (recents == null) {
|
||||
return false;
|
||||
}
|
||||
int currentPage = recents.getNextPage();
|
||||
if (currentPage >= 0 && currentPage < recents.getTaskViewCount()) {
|
||||
((TaskView) recents.getPageAt(currentPage)).launchTask(true);
|
||||
} else {
|
||||
recents.startHome();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class RecentsActivityCommand<T extends StatefulActivity<?>> implements Runnable {
|
||||
|
||||
protected final BaseActivityInterface<?, T> mActivityInterface;
|
||||
private final long mCreateTime;
|
||||
private final AppToOverviewAnimationProvider<T> mAnimationProvider;
|
||||
|
||||
private final long mToggleClickedTime = SystemClock.uptimeMillis();
|
||||
private boolean mUserEventLogged;
|
||||
private ActivityInitListener mListener;
|
||||
|
||||
public RecentsActivityCommand() {
|
||||
mActivityInterface = mOverviewComponentObserver.getActivityInterface();
|
||||
mCreateTime = SystemClock.elapsedRealtime();
|
||||
mAnimationProvider = new AppToOverviewAnimationProvider<>(mActivityInterface,
|
||||
ActivityManagerWrapper.getInstance().getRunningTask(), mDeviceState);
|
||||
|
||||
// Preload the plan
|
||||
mRecentsModel.getTasks(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long elapsedTime = mCreateTime - mLastToggleTime;
|
||||
mLastToggleTime = mCreateTime;
|
||||
|
||||
if (handleCommand(elapsedTime)) {
|
||||
// Command already handled.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mActivityInterface.switchToRecentsIfVisible(this::onTransitionComplete)) {
|
||||
// If successfully switched, then return
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, start overview.
|
||||
mListener = mActivityInterface.createActivityInitListener(this::onActivityReady);
|
||||
mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(),
|
||||
new RemoteAnimationProvider() {
|
||||
@Override
|
||||
public AnimatorSet createWindowAnimation(
|
||||
RemoteAnimationTargetCompat[] appTargets,
|
||||
RemoteAnimationTargetCompat[] wallpaperTargets) {
|
||||
return RecentsActivityCommand.this.createWindowAnimation(appTargets,
|
||||
wallpaperTargets);
|
||||
}
|
||||
}, mContext, MAIN_EXECUTOR.getHandler(),
|
||||
mAnimationProvider.getRecentsLaunchDuration());
|
||||
}
|
||||
|
||||
protected boolean handleCommand(long elapsedTime) {
|
||||
// TODO: We need to fix this case with PIP, when an activity first enters PIP, it shows
|
||||
// the menu activity which takes window focus, preventing the right condition from
|
||||
// being run below
|
||||
RecentsView recents = mActivityInterface.getVisibleRecentsView();
|
||||
if (recents != null) {
|
||||
// Launch the next task
|
||||
recents.showNextTask();
|
||||
return true;
|
||||
} else if (elapsedTime < ViewConfiguration.getDoubleTapTimeout()) {
|
||||
// The user tried to launch back into overview too quickly, either after
|
||||
// launching an app, or before overview has actually shown, just ignore for now
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean onActivityReady(Boolean wasVisible) {
|
||||
final T activity = mActivityInterface.getCreatedActivity();
|
||||
if (!mUserEventLogged) {
|
||||
activity.getUserEventDispatcher().logActionCommand(
|
||||
LauncherLogProto.Action.Command.RECENTS_BUTTON,
|
||||
mActivityInterface.getContainerType(),
|
||||
LauncherLogProto.ContainerType.TASKSWITCHER);
|
||||
mUserEventLogged = true;
|
||||
}
|
||||
|
||||
// Switch prediction client to overview
|
||||
PredictionUiStateManager.INSTANCE.get(activity).switchClient(
|
||||
PredictionUiStateManager.Client.OVERVIEW);
|
||||
return mAnimationProvider.onActivityReady(activity, wasVisible);
|
||||
}
|
||||
|
||||
private AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
|
||||
RemoteAnimationTargetCompat[] wallpaperTargets) {
|
||||
if (LatencyTrackerCompat.isEnabled(mContext)) {
|
||||
LatencyTrackerCompat.logToggleRecents(
|
||||
(int) (SystemClock.uptimeMillis() - mToggleClickedTime));
|
||||
}
|
||||
|
||||
mListener.unregister();
|
||||
|
||||
AnimatorSet animatorSet = mAnimationProvider.createWindowAnimation(appTargets,
|
||||
wallpaperTargets);
|
||||
animatorSet.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
onTransitionComplete();
|
||||
}
|
||||
});
|
||||
return animatorSet;
|
||||
}
|
||||
|
||||
protected void onTransitionComplete() { }
|
||||
}
|
||||
}
|
||||
@@ -1,238 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
||||
import static com.android.launcher3.anim.Interpolators.clampToProgress;
|
||||
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Matrix.ScaleToFit;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.launcher3.util.DefaultDisplay;
|
||||
import com.android.quickstep.util.SurfaceTransactionApplier;
|
||||
import com.android.quickstep.util.TaskViewSimulator;
|
||||
import com.android.quickstep.util.TransformParams;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskThumbnailView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
|
||||
/**
|
||||
* Utility class for helpful methods related to {@link TaskView} objects and their tasks.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.R)
|
||||
public final class TaskViewUtils {
|
||||
|
||||
private TaskViewUtils() {}
|
||||
|
||||
/**
|
||||
* Try to find a TaskView that corresponds with the component of the launched view.
|
||||
*
|
||||
* If this method returns a non-null TaskView, it will be used in composeRecentsLaunchAnimation.
|
||||
* Otherwise, we will assume we are using a normal app transition, but it's possible that the
|
||||
* opening remote target (which we don't get until onAnimationStart) will resolve to a TaskView.
|
||||
*/
|
||||
public static TaskView findTaskViewToLaunch(
|
||||
BaseDraggingActivity activity, View v, RemoteAnimationTargetCompat[] targets) {
|
||||
RecentsView recentsView = activity.getOverviewPanel();
|
||||
if (v instanceof TaskView) {
|
||||
TaskView taskView = (TaskView) v;
|
||||
return recentsView.isTaskViewVisible(taskView) ? taskView : null;
|
||||
}
|
||||
|
||||
// It's possible that the launched view can still be resolved to a visible task view, check
|
||||
// the task id of the opening task and see if we can find a match.
|
||||
if (v.getTag() instanceof ItemInfo) {
|
||||
ItemInfo itemInfo = (ItemInfo) v.getTag();
|
||||
ComponentName componentName = itemInfo.getTargetComponent();
|
||||
int userId = itemInfo.user.getIdentifier();
|
||||
if (componentName != null) {
|
||||
for (int i = 0; i < recentsView.getTaskViewCount(); i++) {
|
||||
TaskView taskView = recentsView.getTaskViewAt(i);
|
||||
if (recentsView.isTaskViewVisible(taskView)) {
|
||||
Task.TaskKey key = taskView.getTask().key;
|
||||
if (componentName.equals(key.getComponent()) && userId == key.userId) {
|
||||
return taskView;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targets == null) {
|
||||
return null;
|
||||
}
|
||||
// Resolve the opening task id
|
||||
int openingTaskId = -1;
|
||||
for (RemoteAnimationTargetCompat target : targets) {
|
||||
if (target.mode == MODE_OPENING) {
|
||||
openingTaskId = target.taskId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no opening task id, fall back to the normal app icon launch animation
|
||||
if (openingTaskId == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the opening task id is not currently visible in overview, then fall back to normal app
|
||||
// icon launch animation
|
||||
TaskView taskView = recentsView.getTaskView(openingTaskId);
|
||||
if (taskView == null || !recentsView.isTaskViewVisible(taskView)) {
|
||||
return null;
|
||||
}
|
||||
return taskView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an animation that controls the window of the opening targets for the recents launch
|
||||
* animation.
|
||||
*/
|
||||
public static void createRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
|
||||
RemoteAnimationTargetCompat[] appTargets,
|
||||
RemoteAnimationTargetCompat[] wallpaperTargets, DepthController depthController,
|
||||
PendingAnimation out) {
|
||||
|
||||
SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
|
||||
final RemoteAnimationTargets targets =
|
||||
new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING);
|
||||
targets.addReleaseCheck(applier);
|
||||
|
||||
TransformParams params = new TransformParams()
|
||||
.setSyncTransactionApplier(applier)
|
||||
.setTargetSet(targets);
|
||||
|
||||
final RecentsView recentsView = v.getRecentsView();
|
||||
int taskIndex = recentsView.indexOfChild(v);
|
||||
boolean parallaxCenterAndAdjacentTask = taskIndex != recentsView.getCurrentPage();
|
||||
int startScroll = recentsView.getScrollOffset(taskIndex);
|
||||
|
||||
Context context = v.getContext();
|
||||
DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
|
||||
// RecentsView never updates the display rotation until swipe-up so the value may be stale.
|
||||
// Use the display value instead.
|
||||
int displayRotation = DefaultDisplay.INSTANCE.get(context).getInfo().rotation;
|
||||
|
||||
TaskViewSimulator topMostSimulator = null;
|
||||
if (targets.apps.length > 0) {
|
||||
TaskViewSimulator tsv = new TaskViewSimulator(context, recentsView.getSizeStrategy());
|
||||
tsv.setDp(dp);
|
||||
tsv.setLayoutRotation(displayRotation, displayRotation);
|
||||
tsv.setPreview(targets.apps[targets.apps.length - 1]);
|
||||
tsv.fullScreenProgress.value = 0;
|
||||
tsv.recentsViewScale.value = 1;
|
||||
tsv.setScroll(startScroll);
|
||||
|
||||
out.setFloat(tsv.fullScreenProgress,
|
||||
AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
|
||||
out.setFloat(tsv.recentsViewScale,
|
||||
AnimatedFloat.VALUE, tsv.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
|
||||
out.setInt(tsv, TaskViewSimulator.SCROLL, 0, TOUCH_RESPONSE_INTERPOLATOR);
|
||||
|
||||
out.addOnFrameCallback(() -> tsv.apply(params));
|
||||
topMostSimulator = tsv;
|
||||
}
|
||||
|
||||
// Fade in the task during the initial 20% of the animation
|
||||
out.addFloat(params, TransformParams.TARGET_ALPHA, 0, 1, clampToProgress(LINEAR, 0, 0.2f));
|
||||
|
||||
if (!skipViewChanges && parallaxCenterAndAdjacentTask && topMostSimulator != null) {
|
||||
out.addFloat(v, VIEW_ALPHA, 1, 0, clampToProgress(LINEAR, 0.2f, 0.4f));
|
||||
|
||||
TaskViewSimulator simulatorToCopy = topMostSimulator;
|
||||
simulatorToCopy.apply(params);
|
||||
|
||||
// Mt represents the overall transformation on the thumbnailView relative to the
|
||||
// Launcher's rootView
|
||||
// K(t) represents transformation on the running window by the taskViewSimulator at
|
||||
// any time t.
|
||||
// at t = 0, we know that the simulator matches the thumbnailView. So if we apply K(0)`
|
||||
// on the Launcher's rootView, the thumbnailView would match the full running task
|
||||
// window. If we apply "K(0)` K(t)" thumbnailView will match the final transformed
|
||||
// window at any time t. This gives the overall matrix on thumbnailView to be:
|
||||
// Mt K(0)` K(t)
|
||||
// During animation we apply transformation on the thumbnailView (and not the rootView)
|
||||
// to follow the TaskViewSimulator. So the final matrix applied on the thumbnailView is:
|
||||
// Mt K(0)` K(t) Mt`
|
||||
TaskThumbnailView ttv = v.getThumbnail();
|
||||
RectF tvBounds = new RectF(0, 0, ttv.getWidth(), ttv.getHeight());
|
||||
float[] tvBoundsMapped = new float[]{0, 0, ttv.getWidth(), ttv.getHeight()};
|
||||
getDescendantCoordRelativeToAncestor(ttv, ttv.getRootView(), tvBoundsMapped, false);
|
||||
RectF tvBoundsInRoot = new RectF(
|
||||
tvBoundsMapped[0], tvBoundsMapped[1],
|
||||
tvBoundsMapped[2], tvBoundsMapped[3]);
|
||||
|
||||
Matrix mt = new Matrix();
|
||||
mt.setRectToRect(tvBounds, tvBoundsInRoot, ScaleToFit.FILL);
|
||||
|
||||
Matrix mti = new Matrix();
|
||||
mt.invert(mti);
|
||||
|
||||
Matrix k0i = new Matrix();
|
||||
simulatorToCopy.getCurrentMatrix().invert(k0i);
|
||||
|
||||
Matrix animationMatrix = new Matrix();
|
||||
out.addOnFrameCallback(() -> {
|
||||
animationMatrix.set(mt);
|
||||
animationMatrix.postConcat(k0i);
|
||||
animationMatrix.postConcat(simulatorToCopy.getCurrentMatrix());
|
||||
animationMatrix.postConcat(mti);
|
||||
ttv.setAnimationMatrix(animationMatrix);
|
||||
});
|
||||
|
||||
out.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
ttv.setAnimationMatrix(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
out.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
targets.release();
|
||||
}
|
||||
});
|
||||
|
||||
if (depthController != null) {
|
||||
out.setFloat(depthController, DEPTH, BACKGROUND_APP.getDepth(context),
|
||||
TOUCH_RESPONSE_INTERPOLATOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.systemui.shared.system.WindowCallbacksCompat;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
/**
|
||||
* Utility class for helpful methods related to {@link View} objects.
|
||||
*/
|
||||
public class ViewUtils {
|
||||
|
||||
/** See {@link #postDraw(View, Runnable, BooleanSupplier)}} */
|
||||
public static boolean postDraw(View view, Runnable onFinishRunnable) {
|
||||
return postDraw(view, onFinishRunnable, () -> false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject some addition logic in order to make sure that the view is updated smoothly post
|
||||
* draw, and allow addition task to be run after view update.
|
||||
*
|
||||
* @param onFinishRunnable runnable to be run right after the view finishes drawing.
|
||||
*/
|
||||
public static boolean postDraw(View view, Runnable onFinishRunnable, BooleanSupplier canceled) {
|
||||
// Defer finishing the animation until the next launcher frame with the
|
||||
// new thumbnail
|
||||
return new WindowCallbacksCompat(view) {
|
||||
// The number of frames to defer until we actually finish the animation
|
||||
private int mDeferFrameCount = 2;
|
||||
|
||||
@Override
|
||||
public void onPostDraw(Canvas canvas) {
|
||||
// If we were cancelled after this was attached, do not update
|
||||
// the state.
|
||||
if (canceled.getAsBoolean()) {
|
||||
detach();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDeferFrameCount > 0) {
|
||||
mDeferFrameCount--;
|
||||
// Workaround, detach and reattach to invalidate the root node for
|
||||
// another draw
|
||||
detach();
|
||||
attach();
|
||||
view.invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (onFinishRunnable != null) {
|
||||
onFinishRunnable.run();
|
||||
}
|
||||
detach();
|
||||
}
|
||||
}.attach();
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep.logging;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This class handles AOSP MetricsLogger function calls and logging around
|
||||
* quickstep interactions and app launches.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class UserEventDispatcherAppPredictionExtension extends UserEventDispatcherExtension {
|
||||
|
||||
public static final int ALL_APPS_PREDICTION_TIPS = 2;
|
||||
|
||||
private static final String TAG = "UserEventDispatcher";
|
||||
|
||||
public UserEventDispatcherAppPredictionExtension(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFillInLogContainerData(
|
||||
@NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target,
|
||||
@NonNull ArrayList<LauncherLogProto.Target> targets) {
|
||||
PredictionUiStateManager.fillInPredictedRank(itemInfo, target);
|
||||
}
|
||||
}
|
||||
-155
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
|
||||
import static com.android.launcher3.anim.Interpolators.INSTANT;
|
||||
import static com.android.launcher3.anim.Interpolators.clampToProgress;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.util.Log;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.statemanager.StateManager;
|
||||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
/**
|
||||
* Runs an animation from overview to home. Currently, this animation is just a wrapper around the
|
||||
* normal state transition, in order to keep RecentsView at the same scale and translationY that
|
||||
* it started out at as it translates offscreen. It also scrolls RecentsView to page 0 and may play
|
||||
* a {@link StaggeredWorkspaceAnim} if we're starting from an upward fling.
|
||||
*/
|
||||
public class OverviewToHomeAnim {
|
||||
|
||||
private static final String TAG = "OverviewToHomeAnim";
|
||||
|
||||
// Constants to specify how to scroll RecentsView to the default page if it's not already there.
|
||||
private static final int DEFAULT_PAGE = 0;
|
||||
private static final int PER_PAGE_SCROLL_DURATION = 150;
|
||||
private static final int MAX_PAGE_SCROLL_DURATION = 750;
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final Runnable mOnReachedHome;
|
||||
|
||||
// Only run mOnReachedHome when both of these are true.
|
||||
private boolean mIsHomeStaggeredAnimFinished;
|
||||
private boolean mIsOverviewHidden;
|
||||
|
||||
public OverviewToHomeAnim(Launcher launcher, Runnable onReachedHome) {
|
||||
mLauncher = launcher;
|
||||
mOnReachedHome = onReachedHome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the animation. If velocity < 0 (i.e. upwards), also plays a
|
||||
* {@link StaggeredWorkspaceAnim}.
|
||||
*/
|
||||
public void animateWithVelocity(float velocity) {
|
||||
StateManager<LauncherState> stateManager = mLauncher.getStateManager();
|
||||
LauncherState startState = stateManager.getState();
|
||||
if (startState != OVERVIEW) {
|
||||
Log.e(TAG, "animateFromOverviewToHome: unexpected start state " + startState);
|
||||
}
|
||||
AnimatorSet anim = new AnimatorSet();
|
||||
|
||||
boolean playStaggeredWorkspaceAnim = velocity < 0;
|
||||
if (playStaggeredWorkspaceAnim) {
|
||||
StaggeredWorkspaceAnim staggeredWorkspaceAnim = new StaggeredWorkspaceAnim(
|
||||
mLauncher, velocity, false /* animateOverviewScrim */);
|
||||
staggeredWorkspaceAnim.addAnimatorListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
mIsHomeStaggeredAnimFinished = true;
|
||||
maybeOverviewToHomeAnimComplete();
|
||||
}
|
||||
});
|
||||
anim.play(staggeredWorkspaceAnim.getAnimators());
|
||||
} else {
|
||||
mIsHomeStaggeredAnimFinished = true;
|
||||
}
|
||||
|
||||
RecentsView recentsView = mLauncher.getOverviewPanel();
|
||||
int numPagesToScroll = recentsView.getNextPage() - DEFAULT_PAGE;
|
||||
int scrollDuration = Math.min(MAX_PAGE_SCROLL_DURATION,
|
||||
numPagesToScroll * PER_PAGE_SCROLL_DURATION);
|
||||
int duration = Math.max(scrollDuration, startState.getTransitionDuration(mLauncher));
|
||||
|
||||
StateAnimationConfig config = new UseFirstInterpolatorStateAnimConfig();
|
||||
config.duration = duration;
|
||||
config.animFlags = playStaggeredWorkspaceAnim
|
||||
// StaggeredWorkspaceAnim doesn't animate overview, so we handle it here.
|
||||
? PLAY_ATOMIC_OVERVIEW_PEEK
|
||||
: ANIM_ALL_COMPONENTS;
|
||||
boolean isLayoutNaturalToLauncher = recentsView.getPagedOrientationHandler()
|
||||
.isLayoutNaturalToLauncher();
|
||||
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, isLayoutNaturalToLauncher
|
||||
? clampToProgress(FAST_OUT_SLOW_IN, 0, 0.75f) : FINAL_FRAME);
|
||||
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, FINAL_FRAME);
|
||||
config.setInterpolator(ANIM_OVERVIEW_SCALE, FINAL_FRAME);
|
||||
config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, INSTANT);
|
||||
if (!isLayoutNaturalToLauncher) {
|
||||
config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL);
|
||||
}
|
||||
AnimatorSet stateAnim = stateManager.createAtomicAnimation(
|
||||
startState, NORMAL, config);
|
||||
stateAnim.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
mIsOverviewHidden = true;
|
||||
maybeOverviewToHomeAnimComplete();
|
||||
}
|
||||
});
|
||||
anim.play(stateAnim);
|
||||
stateManager.setCurrentAnimation(anim, NORMAL);
|
||||
anim.start();
|
||||
recentsView.snapToPage(DEFAULT_PAGE, duration);
|
||||
}
|
||||
|
||||
private void maybeOverviewToHomeAnimComplete() {
|
||||
if (mIsHomeStaggeredAnimFinished && mIsOverviewHidden) {
|
||||
mOnReachedHome.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around StateAnimationConfig that doesn't allow interpolators to be set if they are
|
||||
* already set. This ensures they aren't overridden before being used.
|
||||
*/
|
||||
private static class UseFirstInterpolatorStateAnimConfig extends StateAnimationConfig {
|
||||
@Override
|
||||
public void setInterpolator(int animId, Interpolator interpolator) {
|
||||
if (mInterpolators[animId] == null || interpolator == null) {
|
||||
super.setInterpolator(animId, interpolator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static com.android.launcher3.tracing.nano.LauncherTraceFileProto.MagicNumber.MAGIC_NUMBER_H;
|
||||
import static com.android.launcher3.tracing.nano.LauncherTraceFileProto.MagicNumber.MAGIC_NUMBER_L;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import com.android.launcher3.tracing.nano.LauncherTraceProto;
|
||||
import com.android.launcher3.tracing.nano.LauncherTraceEntryProto;
|
||||
import com.android.launcher3.tracing.nano.LauncherTraceFileProto;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.systemui.shared.tracing.FrameProtoTracer;
|
||||
import com.android.systemui.shared.tracing.FrameProtoTracer.ProtoTraceParams;
|
||||
import com.android.systemui.shared.tracing.ProtoTraceable;
|
||||
import com.google.protobuf.nano.MessageNano;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Queue;
|
||||
|
||||
|
||||
/**
|
||||
* Controller for coordinating winscope proto tracing.
|
||||
*/
|
||||
public class ProtoTracer implements ProtoTraceParams<MessageNano,
|
||||
LauncherTraceFileProto, LauncherTraceEntryProto, LauncherTraceProto> {
|
||||
|
||||
public static final MainThreadInitializedObject<ProtoTracer> INSTANCE =
|
||||
new MainThreadInitializedObject<>(ProtoTracer::new);
|
||||
|
||||
private static final String TAG = "ProtoTracer";
|
||||
private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
|
||||
|
||||
private final Context mContext;
|
||||
private final FrameProtoTracer<MessageNano,
|
||||
LauncherTraceFileProto, LauncherTraceEntryProto, LauncherTraceProto> mProtoTracer;
|
||||
|
||||
public ProtoTracer(Context context) {
|
||||
mContext = context;
|
||||
mProtoTracer = new FrameProtoTracer<>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getTraceFile() {
|
||||
return new File(mContext.getFilesDir(), "launcher_trace.pb");
|
||||
}
|
||||
|
||||
@Override
|
||||
public LauncherTraceFileProto getEncapsulatingTraceProto() {
|
||||
return new LauncherTraceFileProto();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LauncherTraceEntryProto updateBufferProto(LauncherTraceEntryProto reuseObj,
|
||||
ArrayList<ProtoTraceable<LauncherTraceProto>> traceables) {
|
||||
LauncherTraceEntryProto proto = reuseObj != null
|
||||
? reuseObj
|
||||
: new LauncherTraceEntryProto();
|
||||
proto.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
|
||||
proto.launcher = proto.launcher != null ? proto.launcher : new LauncherTraceProto();
|
||||
for (ProtoTraceable t : traceables) {
|
||||
t.writeToProto(proto.launcher);
|
||||
}
|
||||
return proto;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serializeEncapsulatingProto(LauncherTraceFileProto encapsulatingProto,
|
||||
Queue<LauncherTraceEntryProto> buffer) {
|
||||
encapsulatingProto.magicNumber = MAGIC_NUMBER_VALUE;
|
||||
encapsulatingProto.entry = buffer.toArray(new LauncherTraceEntryProto[0]);
|
||||
return MessageNano.toByteArray(encapsulatingProto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getProtoBytes(MessageNano proto) {
|
||||
return MessageNano.toByteArray(proto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtoSize(MessageNano proto) {
|
||||
return proto.getCachedSize();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
mProtoTracer.start();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
mProtoTracer.stop();
|
||||
}
|
||||
|
||||
public void add(ProtoTraceable<LauncherTraceProto> traceable) {
|
||||
mProtoTracer.add(traceable);
|
||||
}
|
||||
|
||||
public void remove(ProtoTraceable<LauncherTraceProto> traceable) {
|
||||
mProtoTracer.remove(traceable);
|
||||
}
|
||||
|
||||
public void scheduleFrameUpdate() {
|
||||
mProtoTracer.scheduleFrameUpdate();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
mProtoTracer.update();
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
|
||||
import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_SHELF_ANIM;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.uioverrides.states.OverviewState;
|
||||
|
||||
/**
|
||||
* Animates the shelf between states HIDE, PEEK, and OVERVIEW.
|
||||
*/
|
||||
public class ShelfPeekAnim {
|
||||
|
||||
public static final Interpolator INTERPOLATOR = OVERSHOOT_1_2;
|
||||
public static final long DURATION = 240;
|
||||
|
||||
private final Launcher mLauncher;
|
||||
|
||||
private ShelfAnimState mShelfState;
|
||||
private boolean mIsPeeking;
|
||||
|
||||
public ShelfPeekAnim(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates to the given state, canceling the previous animation if it was still running.
|
||||
*/
|
||||
public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator, long duration) {
|
||||
if (mShelfState == shelfState || FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
|
||||
return;
|
||||
}
|
||||
mLauncher.getStateManager().cancelStateElementAnimation(INDEX_SHELF_ANIM);
|
||||
mShelfState = shelfState;
|
||||
mIsPeeking = mShelfState == ShelfAnimState.PEEK || mShelfState == ShelfAnimState.HIDE;
|
||||
if (mShelfState == ShelfAnimState.CANCEL) {
|
||||
return;
|
||||
}
|
||||
float shelfHiddenProgress = BACKGROUND_APP.getVerticalProgress(mLauncher);
|
||||
float shelfOverviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
|
||||
// Peek based on default overview progress so we can see hotseat if we're showing
|
||||
// that instead of predictions in overview.
|
||||
float defaultOverviewProgress = OverviewState.getDefaultVerticalProgress(mLauncher);
|
||||
float shelfPeekingProgress = shelfHiddenProgress
|
||||
- (shelfHiddenProgress - defaultOverviewProgress) * 0.25f;
|
||||
float toProgress = mShelfState == ShelfAnimState.HIDE
|
||||
? shelfHiddenProgress
|
||||
: mShelfState == ShelfAnimState.PEEK
|
||||
? shelfPeekingProgress
|
||||
: shelfOverviewProgress;
|
||||
Animator shelfAnim = mLauncher.getStateManager()
|
||||
.createStateElementAnimation(INDEX_SHELF_ANIM, toProgress);
|
||||
shelfAnim.setInterpolator(interpolator);
|
||||
shelfAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
mShelfState = ShelfAnimState.CANCEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animator) {
|
||||
mIsPeeking = mShelfState == ShelfAnimState.PEEK;
|
||||
}
|
||||
});
|
||||
shelfAnim.setDuration(duration).start();
|
||||
}
|
||||
|
||||
/** @return Whether the shelf is currently peeking or animating to or from peeking. */
|
||||
public boolean isPeeking() {
|
||||
return mIsPeeking;
|
||||
}
|
||||
|
||||
/** The various shelf states we can animate to. */
|
||||
public enum ShelfAnimState {
|
||||
HIDE(true), PEEK(true), OVERVIEW(false), CANCEL(false);
|
||||
|
||||
ShelfAnimState(boolean shouldPreformHaptic) {
|
||||
this.shouldPreformHaptic = shouldPreformHaptic;
|
||||
}
|
||||
|
||||
public final boolean shouldPreformHaptic;
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.quickstep.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.widget.Button;
|
||||
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.quickstep.views.RecentsView.PageCallbacks;
|
||||
import com.android.quickstep.views.RecentsView.ScrollState;
|
||||
|
||||
public class ClearAllButton extends Button implements PageCallbacks {
|
||||
|
||||
public static final FloatProperty<ClearAllButton> VISIBILITY_ALPHA =
|
||||
new FloatProperty<ClearAllButton>("visibilityAlpha") {
|
||||
@Override
|
||||
public Float get(ClearAllButton view) {
|
||||
return view.mVisibilityAlpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(ClearAllButton view, float v) {
|
||||
view.setVisibilityAlpha(v);
|
||||
}
|
||||
};
|
||||
|
||||
private float mScrollAlpha = 1;
|
||||
private float mContentAlpha = 1;
|
||||
private float mVisibilityAlpha = 1;
|
||||
|
||||
private boolean mIsRtl;
|
||||
|
||||
private int mScrollOffset;
|
||||
|
||||
public ClearAllButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
|
||||
mScrollOffset = orientationHandler.getClearAllScrollOffset(getRecentsView(), mIsRtl);
|
||||
}
|
||||
|
||||
private RecentsView getRecentsView() {
|
||||
return (RecentsView) getParent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRtlPropertiesChanged(int layoutDirection) {
|
||||
super.onRtlPropertiesChanged(layoutDirection);
|
||||
mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOverlappingRendering() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setContentAlpha(float alpha) {
|
||||
if (mContentAlpha != alpha) {
|
||||
mContentAlpha = alpha;
|
||||
updateAlpha();
|
||||
}
|
||||
}
|
||||
|
||||
public void setVisibilityAlpha(float alpha) {
|
||||
if (mVisibilityAlpha != alpha) {
|
||||
mVisibilityAlpha = alpha;
|
||||
updateAlpha();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScroll(ScrollState scrollState) {
|
||||
PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
|
||||
float orientationSize = orientationHandler.getPrimaryValue(getWidth(), getHeight());
|
||||
if (orientationSize == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
float shift = Math.min(scrollState.scrollFromEdge, orientationSize);
|
||||
float translation = mIsRtl ? (mScrollOffset - shift) : (mScrollOffset + shift);
|
||||
orientationHandler.setPrimaryAndResetSecondaryTranslate(this, translation);
|
||||
mScrollAlpha = 1 - shift / orientationSize;
|
||||
updateAlpha();
|
||||
}
|
||||
|
||||
private void updateAlpha() {
|
||||
final float alpha = mScrollAlpha * mContentAlpha * mVisibilityAlpha;
|
||||
setAlpha(alpha);
|
||||
setClickable(alpha == 1);
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
package com.android.quickstep.views;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.ViewOverlay;
|
||||
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
|
||||
public class LiveTileOverlay extends Drawable {
|
||||
|
||||
private static final long ICON_ANIM_DURATION = 120;
|
||||
|
||||
private static final FloatProperty<LiveTileOverlay> PROGRESS =
|
||||
new FloatProperty<LiveTileOverlay>("progress") {
|
||||
@Override
|
||||
public void setValue(LiveTileOverlay liveTileOverlay, float progress) {
|
||||
liveTileOverlay.setIconAnimationProgress(progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(LiveTileOverlay liveTileOverlay) {
|
||||
return liveTileOverlay.mIconAnimationProgress;
|
||||
}
|
||||
};
|
||||
|
||||
public static final LiveTileOverlay INSTANCE = new LiveTileOverlay();
|
||||
|
||||
private final Paint mPaint = new Paint();
|
||||
private final Rect mBoundsRect = new Rect();
|
||||
|
||||
private RectF mCurrentRect;
|
||||
private float mCornerRadius;
|
||||
private Drawable mIcon;
|
||||
private Animator mIconAnimator;
|
||||
|
||||
private boolean mDrawEnabled = true;
|
||||
private float mIconAnimationProgress = 0f;
|
||||
private boolean mIsAttached;
|
||||
|
||||
private LiveTileOverlay() {
|
||||
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
||||
}
|
||||
|
||||
public void update(RectF currentRect, float cornerRadius) {
|
||||
invalidateSelf();
|
||||
|
||||
mCurrentRect = currentRect;
|
||||
mCornerRadius = cornerRadius;
|
||||
|
||||
mCurrentRect.roundOut(mBoundsRect);
|
||||
setBounds(mBoundsRect);
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
public void setIcon(Drawable icon) {
|
||||
mIcon = icon;
|
||||
}
|
||||
|
||||
public void startIconAnimation() {
|
||||
if (mIconAnimator != null) {
|
||||
mIconAnimator.cancel();
|
||||
}
|
||||
// This animator must match the icon part of {@link TaskView#FOCUS_TRANSITION} animation.
|
||||
mIconAnimator = ObjectAnimator.ofFloat(this, PROGRESS, 1);
|
||||
mIconAnimator.setDuration(ICON_ANIM_DURATION).setInterpolator(LINEAR);
|
||||
mIconAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mIconAnimator = null;
|
||||
}
|
||||
});
|
||||
mIconAnimator.start();
|
||||
}
|
||||
|
||||
public float cancelIconAnimation() {
|
||||
if (mIconAnimator != null) {
|
||||
mIconAnimator.cancel();
|
||||
}
|
||||
return mIconAnimationProgress;
|
||||
}
|
||||
|
||||
public void setDrawEnabled(boolean drawEnabled) {
|
||||
if (mDrawEnabled != drawEnabled) {
|
||||
mDrawEnabled = drawEnabled;
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
if (mCurrentRect != null && mDrawEnabled) {
|
||||
canvas.drawRoundRect(mCurrentRect, mCornerRadius, mCornerRadius, mPaint);
|
||||
if (mIcon != null && mIconAnimationProgress > 0f) {
|
||||
canvas.save();
|
||||
float scale = Interpolators.clampToProgress(FAST_OUT_SLOW_IN, 0f,
|
||||
1f).getInterpolation(mIconAnimationProgress);
|
||||
canvas.translate(mCurrentRect.centerX() - mIcon.getBounds().width() / 2 * scale,
|
||||
mCurrentRect.top - mIcon.getBounds().height() / 2 * scale);
|
||||
canvas.scale(scale, scale);
|
||||
mIcon.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int i) { }
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) { }
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
public boolean attach(ViewOverlay overlay) {
|
||||
if (overlay != null && !mIsAttached) {
|
||||
overlay.add(this);
|
||||
mIsAttached = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void detach(ViewOverlay overlay) {
|
||||
if (overlay != null) {
|
||||
overlay.remove(this);
|
||||
mIsAttached = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setIconAnimationProgress(float progress) {
|
||||
mIconAnimationProgress = progress;
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="#303030"/>
|
||||
</shape>
|
||||
@@ -0,0 +1,20 @@
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="28dp"/>
|
||||
<solid android:color="?android:attr/colorBackgroundFloating"/>
|
||||
</shape>
|
||||
@@ -13,7 +13,9 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<solid android:color="#E61A73E8" />
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:priv-android="http://schemas.android.com/apk/prv/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="?priv-android:attr/colorAccentPrimary" />
|
||||
<corners android:radius="?android:attr/dialogCornerRadius" />
|
||||
</shape>
|
||||
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#909090"
|
||||
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The Android Open Source Project
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/gesture_tutorial_fake_task_view_color" />
|
||||
</shape>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The Android Open Source Project
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/gesture_tutorial_fake_previous_task_view_color" />
|
||||
</shape>
|
||||
@@ -0,0 +1,247 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The Android Open Source Project
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="412dp"
|
||||
android:height="892dp"
|
||||
android:viewportWidth="412"
|
||||
android:viewportHeight="892">
|
||||
<path
|
||||
android:pathData="M0,101h412v791h-412z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M28,222L282,222A4,4 0,0 1,286 226L286,254A4,4 0,0 1,282 258L28,258A4,4 0,0 1,24 254L24,226A4,4 0,0 1,28 222z"
|
||||
android:fillColor="#BDC1C6"/>
|
||||
<path
|
||||
android:pathData="M28,266L344,266A4,4 0,0 1,348 270L348,298A4,4 0,0 1,344 302L28,302A4,4 0,0 1,24 298L24,270A4,4 0,0 1,28 266z"
|
||||
android:fillColor="#BDC1C6"/>
|
||||
<path
|
||||
android:pathData="M28,310L257,310A4,4 0,0 1,261 314L261,342A4,4 0,0 1,257 346L28,346A4,4 0,0 1,24 342L24,314A4,4 0,0 1,28 310z"
|
||||
android:fillColor="#BDC1C6"/>
|
||||
<path
|
||||
android:pathData="M28,354L67,354A4,4 0,0 1,71 358L71,362A4,4 0,0 1,67 366L28,366A4,4 0,0 1,24 362L24,358A4,4 0,0 1,28 354z"
|
||||
android:fillColor="#BDC1C6"/>
|
||||
<path
|
||||
android:pathData="M86,354L125,354A4,4 0,0 1,129 358L129,362A4,4 0,0 1,125 366L86,366A4,4 0,0 1,82 362L82,358A4,4 0,0 1,86 354z"
|
||||
android:fillColor="#BDC1C6"/>
|
||||
<path
|
||||
android:pathData="M28,390L384,390A4,4 0,0 1,388 394L388,626A4,4 0,0 1,384 630L28,630A4,4 0,0 1,24 626L24,394A4,4 0,0 1,28 390z"
|
||||
android:fillColor="#5F6368"/>
|
||||
<path
|
||||
android:pathData="M101.322,469.362L71.101,577.73H131.543L101.322,469.362Z"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#5F6368"
|
||||
android:strokeColor="#9ADCB2"/>
|
||||
<path
|
||||
android:pathData="M101.322,522.516V543.644V611.743"
|
||||
android:fillColor="#5F6368"/>
|
||||
<path
|
||||
android:pathData="M101.322,522.516V543.644V611.743"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9ADCB2"/>
|
||||
<path
|
||||
android:pathData="M109.577,532.822L101.322,548.135"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9ADCB2"/>
|
||||
<path
|
||||
android:pathData="M109.577,558.221L101.322,574.196"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9ADCB2"/>
|
||||
<path
|
||||
android:pathData="M94.54,524.945L101.322,534.442"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9ADCB2"/>
|
||||
<path
|
||||
android:pathData="M90.929,549.239L101.322,561.166"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9ADCB2"/>
|
||||
<path
|
||||
android:pathData="M62.772,412.307L30.855,563.669H94.688L62.772,412.307Z"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#5F6368"
|
||||
android:strokeColor="#9ADCB2"/>
|
||||
<path
|
||||
android:pathData="M62.772,486.516V516.037V611.154"
|
||||
android:fillColor="#5F6368"/>
|
||||
<path
|
||||
android:pathData="M62.772,486.516V516.037V611.154"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9ADCB2"/>
|
||||
<path
|
||||
android:pathData="M74.344,500.944L62.772,522.368"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9ADCB2"/>
|
||||
<path
|
||||
android:pathData="M74.344,536.43L62.772,558.736"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9ADCB2"/>
|
||||
<path
|
||||
android:pathData="M53.263,489.976L62.772,503.154"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9ADCB2"/>
|
||||
<path
|
||||
android:pathData="M48.251,523.914L62.772,540.552"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9ADCB2"/>
|
||||
<path
|
||||
android:pathData="M37,612H377"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#9AA0A6"/>
|
||||
<path
|
||||
android:pathData="M81.24,441.187L84.066,443.127L87.333,441.98L86.273,445.244L88.393,447.978H84.949L83.006,450.8L81.947,447.537L78.679,446.655L81.417,444.626L81.24,441.187Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M172.561,469L175.387,471.029L178.654,469.794L177.594,473.057L179.714,475.791H176.27L174.327,478.702L173.267,475.438L170,474.468L172.737,472.44L172.561,469Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M278.073,481.229L280.81,483.257L284.078,482.022L283.018,485.286L285.137,488.02H281.693L279.839,490.93L278.691,487.667L275.424,486.697L278.161,484.668L278.073,481.229Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M325.561,459L328.387,460.94L331.654,459.794L330.594,463.057L332.714,465.791H329.27L327.327,468.613L326.267,465.35L323,464.468L325.737,462.44L325.561,459Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M209.649,517L212.475,519.029L215.654,517.794L214.682,521.057L216.802,523.791H213.358L211.415,526.702L210.356,523.438L207,522.468L209.737,520.44L209.649,517Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M128.836,482.816L129.455,485.11L131.662,485.815L129.808,487.314L129.896,489.784L128.042,488.285L125.922,489.078L126.629,486.785L125.304,484.757L127.512,484.845L128.836,482.816Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M37.532,450L38.239,452.381L40.358,453.087L38.504,454.498L38.592,456.968L36.737,455.556L34.618,456.35L35.325,453.969L34,452.029H36.208L37.532,450Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M284.077,516.947L284.784,519.329L286.903,520.034L285.048,521.445L285.137,523.915L283.282,522.415L281.163,523.297L281.869,520.916L280.545,518.976H282.753L284.077,516.947Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M232.771,444.893L233.478,447.274L235.597,447.979L233.743,449.391L233.831,451.86L231.977,450.449L229.857,451.243L230.564,448.861L229.239,446.921H231.447L232.771,444.893Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M152.384,521L152.914,522.676L154.415,523.117L153.091,524.175L153.179,525.851L151.854,524.881L150.442,525.41L150.883,523.734L150,522.411H151.501L152.384,521Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M136.473,515L136.914,516.676L138.415,517.117L137.179,518.175V519.851L135.943,518.881L134.442,519.41L134.971,517.822L134,516.411H135.589L136.473,515Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M314.454,410.406L314.896,412.082L316.397,412.523L315.16,413.493V415.257L313.924,414.199L312.423,414.816L312.953,413.14L311.981,411.817H313.571L314.454,410.406Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M344.212,488.195L344.742,489.871L346.243,490.4L344.919,491.37L345.007,493.046L343.683,492.076L342.27,492.605L342.711,491.018L341.828,489.606H343.329L344.212,488.195Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M47.067,420.814L47.508,422.402L49.009,422.931L47.773,423.901V425.665L46.537,424.607L45.036,425.136L45.566,423.549L44.594,422.137L46.184,422.226L47.067,420.814Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M265.887,448.42L266.328,450.007L267.829,450.537L266.593,451.507V453.271L265.357,452.212L263.856,452.83L264.385,451.154L263.414,449.831H265.004L265.887,448.42Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M110.912,413.759L111.441,415.435L112.854,415.876L111.618,416.934V418.61L110.382,417.551L108.969,418.169L109.41,416.493L108.439,415.17H110.028L110.912,413.759Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M149.412,418.344L152.238,420.372L155.505,419.138L154.445,422.489L156.565,425.135L153.121,425.223L151.178,428.045L150.118,424.782L146.851,423.812L149.589,421.783L149.412,418.344Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M37.532,450L38.239,452.381L40.358,453.087L38.504,454.498L38.592,456.968L36.737,455.556L34.618,456.35L35.325,453.969L34,452.029H36.208L37.532,450Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M141.906,455.74L142.612,458.122L144.731,458.827L142.877,460.238L142.965,462.708L141.111,461.208L139.08,462.09L139.786,459.709L138.374,457.769H140.669L141.906,455.74Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M201.777,459.267L202.395,461.56L204.603,462.265L202.748,463.765L202.836,466.146L200.982,464.735L198.863,465.529L199.569,463.235L198.245,461.207H200.452L201.777,459.267Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M370.175,504.248L370.793,506.629L373.001,507.335L371.146,508.746L371.234,511.216L369.38,509.716L367.261,510.598L367.967,508.217L366.643,506.277H368.85L370.175,504.248Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M300.532,437L301.239,439.381L303.358,440.087L301.592,441.498V443.968L299.826,442.468L297.706,443.35L298.413,440.969L297,439.029H299.296L300.532,437Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M193.384,420L193.914,421.676L195.415,422.117L194.091,423.087L194.179,424.851L192.854,423.792L191.442,424.41L191.883,422.734L191,421.411H192.501L193.384,420Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M248.313,469.323L248.843,470.911L250.256,471.44L249.02,472.41V474.174L247.784,473.116L246.371,473.645L246.812,472.057L245.841,470.646L247.43,470.734L248.313,469.323Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M169.988,496.751L170.518,498.427L172.019,498.956L170.694,499.926L170.782,501.602L169.458,500.632L168.045,501.161L168.487,499.573L167.604,498.162H169.105L169.988,496.751Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M222.441,400L222.882,401.676L224.384,402.117L223.059,403.175L223.147,404.851L221.911,403.792L220.41,404.41L220.851,402.734L219.968,401.411H221.469L222.441,400Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M211.754,492.341L212.284,493.928L213.785,494.458L212.461,495.428L212.549,497.192L211.225,496.133L209.812,496.662L210.253,495.075L209.37,493.664L210.871,493.752L211.754,492.341Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M254.054,420.814L254.584,422.402L256.085,422.931L254.761,423.901L254.849,425.665L253.524,424.607L252.111,425.136L252.553,423.549L251.67,422.137L253.171,422.226L254.054,420.814Z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
<path
|
||||
android:pathData="M307.162,602.392H205L255.565,502.27H322.273L374.238,602.392H307.162L255.565,502.785L307.162,602.392Z"
|
||||
android:fillColor="#5F6368"/>
|
||||
<path
|
||||
android:pathData="M307.162,602.392H205L255.565,502.27H322.273L374.238,602.392H307.162ZM307.162,602.392L255.565,502.785"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#A8CBFE"/>
|
||||
<path
|
||||
android:pathData="M255.565,503.079V602.392"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#A8CBFE"/>
|
||||
<path
|
||||
android:pathData="M356.686,430.931C358.218,423.774 353.2,416.635 345.477,414.986C337.754,413.337 330.251,417.801 328.719,424.958C327.186,432.115 332.205,439.254 339.928,440.903C347.651,442.553 355.154,438.088 356.686,430.931Z"
|
||||
android:fillColor="#FEEFC3"/>
|
||||
<path
|
||||
android:pathData="M344.708,427.026C345.789,421.976 342.244,416.939 336.79,415.774C331.336,414.609 326.038,417.759 324.957,422.808C323.876,427.858 327.421,432.895 332.875,434.06C338.329,435.225 343.627,432.076 344.708,427.026Z"
|
||||
android:fillColor="#5F6368"/>
|
||||
<path
|
||||
android:pathData="M2,101L410,101A2,2 0,0 1,412 103L412,187A2,2 0,0 1,410 189L2,189A2,2 0,0 1,0 187L0,103A2,2 0,0 1,2 101z"
|
||||
android:fillColor="#E8EAED"/>
|
||||
<path
|
||||
android:pathData="M99,129L313,129A2,2 0,0 1,315 131L315,159A2,2 0,0 1,313 161L99,161A2,2 0,0 1,97 159L97,131A2,2 0,0 1,99 129z"
|
||||
android:fillColor="#80868B"/>
|
||||
<path
|
||||
android:pathData="M32,123L60,123A8,8 0,0 1,68 131L68,159A8,8 0,0 1,60 167L32,167A8,8 0,0 1,24 159L24,131A8,8 0,0 1,32 123z"
|
||||
android:fillColor="#80868B"/>
|
||||
<path
|
||||
android:pathData="M0,0h412v101h-412z"
|
||||
android:fillColor="#202124"/>
|
||||
<path
|
||||
android:pathData="M34.5,48L377.5,48A18.5,18.5 0,0 1,396 66.5L396,66.5A18.5,18.5 0,0 1,377.5 85L34.5,85A18.5,18.5 0,0 1,16 66.5L16,66.5A18.5,18.5 0,0 1,34.5 48z"
|
||||
android:fillColor="#3C4043"/>
|
||||
<path
|
||||
android:pathData="M28,654L356,654A4,4 0,0 1,360 658L360,672A4,4 0,0 1,356 676L28,676A4,4 0,0 1,24 672L24,658A4,4 0,0 1,28 654z"
|
||||
android:fillColor="#BDC1C6"/>
|
||||
<path
|
||||
android:pathData="M28,684L367,684A4,4 0,0 1,371 688L371,702A4,4 0,0 1,367 706L28,706A4,4 0,0 1,24 702L24,688A4,4 0,0 1,28 684z"
|
||||
android:fillColor="#BDC1C6"/>
|
||||
<path
|
||||
android:pathData="M28,714L337,714A4,4 0,0 1,341 718L341,732A4,4 0,0 1,337 736L28,736A4,4 0,0 1,24 732L24,718A4,4 0,0 1,28 714z"
|
||||
android:fillColor="#BDC1C6"/>
|
||||
<path
|
||||
android:pathData="M28,744L210,744A4,4 0,0 1,214 748L214,762A4,4 0,0 1,210 766L28,766A4,4 0,0 1,24 762L24,748A4,4 0,0 1,28 744z"
|
||||
android:fillColor="#BDC1C6"/>
|
||||
<path
|
||||
android:pathData="M28,790L344,790A4,4 0,0 1,348 794L348,808A4,4 0,0 1,344 812L28,812A4,4 0,0 1,24 808L24,794A4,4 0,0 1,28 790z"
|
||||
android:fillColor="#BDC1C6"/>
|
||||
<path
|
||||
android:pathData="M28,820L337,820A4,4 0,0 1,341 824L341,838A4,4 0,0 1,337 842L28,842A4,4 0,0 1,24 838L24,824A4,4 0,0 1,28 820z"
|
||||
android:fillColor="#BDC1C6"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,21 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="360dp"
|
||||
android:height="146dp"
|
||||
android:viewportWidth="360"
|
||||
android:viewportHeight="146">
|
||||
<path
|
||||
android:pathData="M25,96L335,96A25,25 0,0 1,360 121L360,121A25,25 0,0 1,335 146L25,146A25,25 0,0 1,0 121L0,121A25,25 0,0 1,25 96z"
|
||||
android:fillColor="#3C4043"/>
|
||||
<path
|
||||
android:pathData="M30,30m-30,0a30,30 0,1 1,60 0a30,30 0,1 1,-60 0"
|
||||
android:fillColor="#8AB4F8"/>
|
||||
<path
|
||||
android:pathData="M130,30m-30,0a30,30 0,1 1,60 0a30,30 0,1 1,-60 0"
|
||||
android:fillColor="#F28B82"/>
|
||||
<path
|
||||
android:pathData="M230,30m-30,0a30,30 0,1 1,60 0a30,30 0,1 1,-60 0"
|
||||
android:fillColor="#FDD663"/>
|
||||
<path
|
||||
android:pathData="M330,30m-30,0a30,30 0,1 1,60 0a30,30 0,1 1,-60 0"
|
||||
android:fillColor="#81C995"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The Android Open Source Project
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="?android:attr/colorBackground" />
|
||||
</shape>
|
||||
@@ -13,8 +13,19 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="@dimen/default_dialog_corner_radius"/>
|
||||
<solid android:color="@color/gesture_tutorial_primary_color"/>
|
||||
</shape>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape
|
||||
android:id="@android:id/mask"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="50dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="50dp"/>
|
||||
<solid android:color="@color/gesture_tutorial_primary_color"/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="50dp"/>
|
||||
<solid android:color="@android:color/transparent"/>
|
||||
<stroke android:width="1dp" android:color="@color/gesture_tutorial_primary_color"/>
|
||||
</shape>
|
||||
@@ -0,0 +1,96 @@
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<target android:name="_R_G_L_1_G">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="0"
|
||||
android:propertyName="scaleY"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="1"
|
||||
android:valueType="floatType" />
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="_R_G_L_1_G">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="0"
|
||||
android:propertyName="scaleY"
|
||||
android:startOffset="783"
|
||||
android:valueFrom="1"
|
||||
android:valueTo="0"
|
||||
android:valueType="floatType" />
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="_R_G_L_0_G_D_0_P_0">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="1000"
|
||||
android:propertyName="fillAlpha"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="0.25"
|
||||
android:valueTo="0.75"
|
||||
android:valueType="floatType">
|
||||
<aapt:attr name="android:interpolator">
|
||||
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
|
||||
</aapt:attr>
|
||||
</objectAnimator>
|
||||
<objectAnimator
|
||||
android:duration="1000"
|
||||
android:propertyName="fillAlpha"
|
||||
android:startOffset="1000"
|
||||
android:valueFrom="0.75"
|
||||
android:valueTo="0.25"
|
||||
android:valueType="floatType">
|
||||
<aapt:attr name="android:interpolator">
|
||||
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
|
||||
</aapt:attr>
|
||||
</objectAnimator>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="time_group">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="2000"
|
||||
android:propertyName="translateX"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="1"
|
||||
android:valueType="floatType" />
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector
|
||||
android:width="412dp"
|
||||
android:height="892dp"
|
||||
android:viewportHeight="892"
|
||||
android:viewportWidth="412">
|
||||
<group android:name="_R_G">
|
||||
<group
|
||||
android:name="_R_G_L_1_G"
|
||||
android:translateX="206"
|
||||
android:translateY="446" />
|
||||
<group
|
||||
android:name="_R_G_L_0_G"
|
||||
android:translateX="12.5"
|
||||
android:translateY="446">
|
||||
<path
|
||||
android:name="_R_G_L_0_G_D_0_P_0"
|
||||
android:fillAlpha="0.25"
|
||||
android:fillColor="@color/gesture_tutorial_primary_color"
|
||||
android:fillType="nonZero"
|
||||
android:pathData=" M12.5 -446 C12.5,-446 12.5,446 12.5,446 C12.5,446 -12.5,446 -12.5,446 C-12.5,446 -12.5,-446 -12.5,-446 C-12.5,-446 12.5,-446 12.5,-446c " />
|
||||
</group>
|
||||
</group>
|
||||
<group android:name="time_group" />
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
</animated-vector>
|
||||
@@ -0,0 +1,96 @@
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<target android:name="_R_G_L_1_G_D_0_P_0">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="1000"
|
||||
android:propertyName="fillAlpha"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="0.25"
|
||||
android:valueTo="0.75"
|
||||
android:valueType="floatType">
|
||||
<aapt:attr name="android:interpolator">
|
||||
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
|
||||
</aapt:attr>
|
||||
</objectAnimator>
|
||||
<objectAnimator
|
||||
android:duration="1000"
|
||||
android:propertyName="fillAlpha"
|
||||
android:startOffset="1000"
|
||||
android:valueFrom="0.75"
|
||||
android:valueTo="0.25"
|
||||
android:valueType="floatType">
|
||||
<aapt:attr name="android:interpolator">
|
||||
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
|
||||
</aapt:attr>
|
||||
</objectAnimator>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="_R_G_L_0_G">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="0"
|
||||
android:propertyName="scaleY"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="1"
|
||||
android:valueType="floatType" />
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="_R_G_L_0_G">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="0"
|
||||
android:propertyName="scaleY"
|
||||
android:startOffset="850"
|
||||
android:valueFrom="1"
|
||||
android:valueTo="0"
|
||||
android:valueType="floatType" />
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="time_group">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="2000"
|
||||
android:propertyName="translateX"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="1"
|
||||
android:valueType="floatType" />
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector
|
||||
android:width="412dp"
|
||||
android:height="892dp"
|
||||
android:viewportHeight="892"
|
||||
android:viewportWidth="412">
|
||||
<group android:name="_R_G">
|
||||
<group
|
||||
android:name="_R_G_L_1_G"
|
||||
android:translateX="206"
|
||||
android:translateY="879.5">
|
||||
<path
|
||||
android:name="_R_G_L_1_G_D_0_P_0"
|
||||
android:fillAlpha="0.25"
|
||||
android:fillColor="@color/gesture_tutorial_primary_color"
|
||||
android:fillType="nonZero"
|
||||
android:pathData=" M206 -12.5 C206,-12.5 206,12.5 206,12.5 C206,12.5 -206,12.5 -206,12.5 C-206,12.5 -206,-12.5 -206,-12.5 C-206,-12.5 206,-12.5 206,-12.5c " />
|
||||
</group>
|
||||
<group
|
||||
android:name="_R_G_L_0_G"
|
||||
android:translateX="206"
|
||||
android:translateY="446" />
|
||||
</group>
|
||||
<group android:name="time_group" />
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
</animated-vector>
|
||||
@@ -0,0 +1,96 @@
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<target android:name="_R_G_L_1_G_D_0_P_0">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="1000"
|
||||
android:propertyName="fillAlpha"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="0.25"
|
||||
android:valueTo="0.75"
|
||||
android:valueType="floatType">
|
||||
<aapt:attr name="android:interpolator">
|
||||
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
|
||||
</aapt:attr>
|
||||
</objectAnimator>
|
||||
<objectAnimator
|
||||
android:duration="1000"
|
||||
android:propertyName="fillAlpha"
|
||||
android:startOffset="1000"
|
||||
android:valueFrom="0.75"
|
||||
android:valueTo="0.25"
|
||||
android:valueType="floatType">
|
||||
<aapt:attr name="android:interpolator">
|
||||
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
|
||||
</aapt:attr>
|
||||
</objectAnimator>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="_R_G_L_0_G">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="0"
|
||||
android:propertyName="scaleY"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="1"
|
||||
android:valueType="floatType" />
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="_R_G_L_0_G">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="0"
|
||||
android:propertyName="scaleY"
|
||||
android:startOffset="1500"
|
||||
android:valueFrom="1"
|
||||
android:valueTo="0"
|
||||
android:valueType="floatType" />
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="time_group">
|
||||
<aapt:attr name="android:animation">
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="2000"
|
||||
android:propertyName="translateX"
|
||||
android:startOffset="0"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="1"
|
||||
android:valueType="floatType" />
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector
|
||||
android:width="412dp"
|
||||
android:height="892dp"
|
||||
android:viewportHeight="892"
|
||||
android:viewportWidth="412">
|
||||
<group android:name="_R_G">
|
||||
<group
|
||||
android:name="_R_G_L_1_G"
|
||||
android:translateX="206"
|
||||
android:translateY="879.5">
|
||||
<path
|
||||
android:name="_R_G_L_1_G_D_0_P_0"
|
||||
android:fillAlpha="0.25"
|
||||
android:fillColor="@color/gesture_tutorial_primary_color"
|
||||
android:fillType="nonZero"
|
||||
android:pathData=" M206 -12.5 C206,-12.5 206,12.5 206,12.5 C206,12.5 -206,12.5 -206,12.5 C-206,12.5 -206,-12.5 -206,-12.5 C-206,-12.5 206,-12.5 206,-12.5c " />
|
||||
</group>
|
||||
<group
|
||||
android:name="_R_G_L_0_G"
|
||||
android:translateX="206"
|
||||
android:translateY="446" />
|
||||
</group>
|
||||
<group android:name="time_group" />
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
</animated-vector>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,24 @@
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
~ Copyright (C) 2021 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M19,7h2v2h-2V7zM15,7h2v2h-2V7zM3,7h2v2H3V7zM7,7h2v2H7V7zM11,7h2v2h-2V7zM19,11h2v2h-2V11zM15,11h2v2h-2V11zM3,11h2v2H3V11zM7,11h2v2H7V11zM11,11h2v2h-2V11zM7,15h10v2H7V15z"
|
||||
android:fillColor="@android:color/white" />
|
||||
</vector>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user