Merge "Merge Android 12"

This commit is contained in:
Xin Li
2021-10-07 23:50:25 +00:00
committed by Gerrit Code Review
1143 changed files with 74441 additions and 37601 deletions
+181 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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" />
+1
View File
@@ -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
-17
View File
@@ -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
View File
@@ -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
+39
View File
@@ -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
+24
View File
@@ -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
View File
@@ -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
View File
@@ -0,0 +1,934 @@
COMMAND>> git log f99351888c3e5a128559678304fefd647472bc7f..4c3952dc60fc78d3816012a86d7e71747ef34c74
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));
+71
View File
@@ -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>
+8
View File
@@ -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>
+24
View File
@@ -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>
+36
View File
@@ -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>
@@ -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>
@@ -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>
+22
View File
@@ -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>
+30
View File
@@ -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>
@@ -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>
+43
View File
@@ -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>
+44
View File
@@ -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>
+90
View File
@@ -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
View File
@@ -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
+48
View File
@@ -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=&quot;?android:attr/dialogCornerRadius&quot;"
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=&quot;?android:attr/dialogCornerRadius&quot; />"
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=" &lt;style name=&quot;Widget.DeviceDefault.Button.Rounded.Colored&quot; parent=&quot;@android:style/Widget.DeviceDefault.Button.Colored&quot;>"
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=" &lt;corners android:radius=&quot;@android:dimen/system_app_widget_background_radius&quot; />"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
line="20"
column="14"/>
</issue>
</issues>
+576
View File
@@ -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 &amp;&amp; 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 &amp;&amp; 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 &amp;&amp; targetCellWidth >= minSpanX &amp;&amp; targetCellWidth &lt;= 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 &amp;&amp; targetCellWidth >= minSpanX &amp;&amp; targetCellWidth &lt;= 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=" &amp;&amp; targetCellHeight >= minSpanY &amp;&amp; targetCellHeight &lt;= 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=" &amp;&amp; targetCellHeight >= minSpanY &amp;&amp; targetCellHeight &lt;= 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&lt;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&lt;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=" &amp;&amp; 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>
+598
View File
@@ -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 &amp;&amp; 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 &amp;&amp; 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 &amp;&amp; targetCellWidth >= minSpanX &amp;&amp; targetCellWidth &lt;= 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 &amp;&amp; targetCellWidth >= minSpanX &amp;&amp; targetCellWidth &lt;= 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=" &amp;&amp; targetCellHeight >= minSpanY &amp;&amp; targetCellHeight &lt;= 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=" &amp;&amp; targetCellHeight >= minSpanY &amp;&amp; targetCellHeight &lt;= 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&lt;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&lt;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=" &amp;&amp; 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>
+48
View File
@@ -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=&quot;?android:attr/dialogCornerRadius&quot;"
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=&quot;?android:attr/dialogCornerRadius&quot; />"
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=" &lt;style name=&quot;Widget.DeviceDefault.Button.Rounded.Colored&quot; parent=&quot;@android:style/Widget.DeviceDefault.Button.Colored&quot;>"
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=" &lt;corners android:radius=&quot;@android:dimen/system_app_widget_background_radius&quot; />"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
line="20"
column="14"/>
</issue>
</issues>
+3 -2
View File
@@ -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.**
+39 -9
View File
@@ -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
-245
View File
@@ -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;
}
+36
View File
@@ -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 {}
+28
View File
@@ -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"],
}
+2 -1
View File
@@ -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" />
+90 -66
View File
@@ -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>
@@ -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();
};
}
}
@@ -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);
}
}
}
});
}
}
}
@@ -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);
}
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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);
}
}
@@ -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>
+10
View File
@@ -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
+24
View File
@@ -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