From a40a239df1a831b120a319e09ce7b82f563f1e01 Mon Sep 17 00:00:00 2001 From: Alistair Delva Date: Mon, 5 Oct 2020 14:46:26 +0000 Subject: [PATCH 01/17] Revert "Merge commit '8d14dbe041199d611839140f1c9285fd4174e9f4' ..." Revert "Merging from ub-launcher3-master @ build 6877130" Revert "Merging from ub-launcher3-master @ build 6877130" Revert "Merging from ub-launcher3-master @ build 6877130" Revert submission 12738409-merge_ub-launcher3-master_6877130 Reason for revert: Introduced crashes to global presubmit Reverted Changes: I624658ce6:Merge commit '8d14dbe041199d611839140f1c9285fd4174... Iccd2f1e3a:Merging from ub-launcher3-master @ build 6877130 I791d64951:Merging from ub-launcher3-master @ build 6877130 Icdd32ab01:Merging from ub-launcher3-master @ build 6877130 Bug: 169963211 Change-Id: I77a4ae59e823147beae8dd7cb9b54ccdace2c7f4 (cherry picked from commit 087a9e39b663dade90d8dfd74300e42575649b87) --- Android.mk | 8 + build.gradle | 24 +- protos/launcher_log.proto | 245 ++++++++++++ .../res/layout/gesture_tutorial_fragment.xml | 9 +- quickstep/res/values/strings.xml | 15 - .../launcher3/BaseQuickstepLauncher.java | 8 - .../launcher3/LauncherAnimationRunner.java | 3 +- .../QuickstepAppTransitionManagerImpl.java | 75 ++-- .../appprediction/PredictionRowView.java | 31 +- .../HotseatPredictionController.java | 1 + .../uioverrides/states/AllAppsState.java | 4 +- .../states/BackgroundAppState.java | 5 +- .../states/OverviewModalTaskState.java | 5 +- .../uioverrides/states/OverviewState.java | 4 +- .../uioverrides/states/QuickSwitchState.java | 5 +- .../LandscapeEdgeSwipeController.java | 16 +- .../NavBarToHomeTouchController.java | 19 +- ...ButtonNavbarToOverviewTouchController.java | 5 +- .../NoButtonQuickSwitchTouchController.java | 25 +- .../OverviewToAllAppsTouchController.java | 6 + .../PortraitStatesTouchController.java | 13 +- .../QuickSwitchTouchController.java | 19 +- .../StatusBarTouchController.java | 14 +- .../TaskViewTouchController.java | 14 +- .../android/quickstep/AbsSwipeUpHandler.java | 49 +-- .../quickstep/BaseActivityInterface.java | 5 + .../quickstep/FallbackActivityInterface.java | 10 + .../com/android/quickstep/GestureState.java | 12 +- .../quickstep/LauncherActivityInterface.java | 12 + .../quickstep/OverviewCommandHelper.java | 13 +- .../android/quickstep/RecentsActivity.java | 19 +- .../com/android/quickstep/RecentsModel.java | 14 +- .../com/android/quickstep/TaskIconCache.java | 50 ++- .../quickstep/TaskShortcutFactory.java | 4 + .../android/quickstep/TaskThumbnailCache.java | 52 ++- .../quickstep/TouchInteractionService.java | 11 +- .../fallback/FallbackRecentsView.java | 10 +- .../AssistantInputConsumer.java | 20 +- .../OtherActivityInputConsumer.java | 12 +- .../OverviewWithoutFocusInputConsumer.java | 17 +- .../AssistantGestureTutorialFragment.java | 2 +- .../BackGestureTutorialFragment.java | 2 +- .../interaction/EdgeBackGestureHandler.java | 4 - .../HomeGestureTutorialFragment.java | 2 +- .../interaction/NavBarGestureHandler.java | 6 - .../OverviewGestureTutorialFragment.java | 2 +- .../interaction/RootSandboxLayout.java | 44 --- .../interaction/SandboxLauncherRenderer.java | 44 --- .../SandboxModeTutorialController.java | 102 ----- .../SandboxModeTutorialFragment.java | 43 -- .../interaction/TutorialController.java | 17 +- .../interaction/TutorialFragment.java | 39 +- .../quickstep/util/CancellableTask.java | 68 ---- .../quickstep/util/OverviewToHomeAnim.java | 4 +- .../quickstep/util/RecentsOrientedState.java | 11 +- .../util/RemoteAnimationProvider.java | 12 +- .../quickstep/util/TaskViewSimulator.java | 5 +- .../views/DigitalWellBeingToast.java | 5 +- .../quickstep/views/LauncherRecentsView.java | 11 +- .../quickstep/views/OverviewActionsView.java | 4 +- .../android/quickstep/views/RecentsView.java | 35 +- .../android/quickstep/views/TaskMenuView.java | 12 +- .../com/android/quickstep/views/TaskView.java | 37 +- .../quickstep/DigitalWellBeingToastTest.java | 7 +- res/layout/search_result_icon_row.xml | 31 -- res/layout/search_result_shortcut.xml | 42 ++ res/layout/search_result_suggest.xml | 38 -- res/layout/search_result_thumbnail.xml | 19 - res/values/config.xml | 1 + .../secondarydisplay/SDWorkModeTest.java | 5 + .../launcher3/ui/LauncherUIScrollTest.java | 5 + src/com/android/launcher3/BaseActivity.java | 12 + src/com/android/launcher3/BubbleTextView.java | 59 +-- .../android/launcher3/ButtonDropTarget.java | 3 + src/com/android/launcher3/CellLayout.java | 7 +- .../android/launcher3/DeleteDropTarget.java | 24 +- .../android/launcher3/FastBitmapDrawable.java | 9 +- src/com/android/launcher3/Hotseat.java | 23 +- src/com/android/launcher3/Launcher.java | 92 ++--- .../android/launcher3/LauncherAppState.java | 2 +- src/com/android/launcher3/LauncherState.java | 12 +- .../launcher3/SecondaryDropTarget.java | 16 + .../launcher3/SessionCommitReceiver.java | 8 - src/com/android/launcher3/Utilities.java | 4 - src/com/android/launcher3/Workspace.java | 40 +- .../launcher3/WorkspaceLayoutManager.java | 6 +- .../launcher3/allapps/AllAppsGridAdapter.java | 94 ++--- .../allapps/AllAppsRecyclerView.java | 15 +- .../launcher3/allapps/DiscoveryBounce.java | 10 +- .../search/AllAppsSearchBarController.java | 40 -- .../launcher3/anim/PendingAnimation.java | 10 +- .../launcher3/dragndrop/AddItemActivity.java | 30 +- .../launcher3/dragndrop/DragController.java | 2 + src/com/android/launcher3/folder/Folder.java | 34 +- .../android/launcher3/folder/FolderIcon.java | 1 + .../graphics/LauncherPreviewRenderer.java | 3 +- .../launcher3/logging/LoggerUtils.java | 190 +++++++++ .../launcher3/logging/StatsLogManager.java | 74 ++-- .../launcher3/logging/StatsLogUtils.java | 49 +++ .../logging/UserEventDispatcher.java | 373 ++++++++++++++++++ .../launcher3/model/data/FolderInfo.java | 119 ++++++ .../model/data/RemoteActionItemInfo.java | 64 --- .../notification/NotificationMainView.java | 7 +- .../launcher3/pm/InstallSessionHelper.java | 51 +-- .../launcher3/pm/InstallSessionTracker.java | 3 - src/com/android/launcher3/pm/UserCache.java | 6 +- .../android/launcher3/popup/ArrowPopup.java | 58 +-- .../popup/PopupContainerWithArrow.java | 9 +- .../launcher3/popup/RemoteActionShortcut.java | 4 + .../launcher3/popup/SystemShortcut.java | 6 + .../settings/DeveloperOptionsFragment.java | 9 - .../android/launcher3/states/HintState.java | 5 +- .../launcher3/states/SpringLoadedState.java | 5 +- .../AbstractStateChangeTouchController.java | 50 ++- .../touch/AllAppsSwipeController.java | 7 + .../launcher3/touch/ItemClickHandler.java | 24 -- .../touch/LandscapePagedViewHandler.java | 1 + .../touch/PagedOrientationHandler.java | 1 + .../touch/PortraitPagedViewHandler.java | 1 + src/com/android/launcher3/util/Executors.java | 27 -- .../launcher3/views/FloatingIconView.java | 88 +++-- .../launcher3/views/HeroSearchResultView.java | 41 +- .../launcher3/views/OptionsPopupView.java | 6 +- .../launcher3/views/SearchResultIconRow.java | 155 -------- .../views/SearchResultPeopleView.java | 65 +-- .../launcher3/views/SearchResultPlayItem.java | 9 +- .../launcher3/views/SearchResultShortcut.java | 110 ++++++ .../views/SearchResultSuggestRow.java | 131 ------ .../views/SearchSectionHeaderView.java | 5 - .../views/SearchSettingsRowView.java | 9 +- .../views/ThumbnailSearchResultView.java | 114 ------ .../systemui/plugins/AllAppsSearchPlugin.java | 8 +- .../systemui/plugins/shared/SearchTarget.java | 69 +--- .../plugins/shared/SearchTargetEvent.java | 10 +- .../uioverrides/states/AllAppsState.java | 4 +- .../uioverrides/states/OverviewState.java | 5 +- .../launcher3/ui/AbstractLauncherUiTest.java | 2 - .../com/android/launcher3/ui/WorkTabTest.java | 7 +- 138 files changed, 2135 insertions(+), 1944 deletions(-) create mode 100644 protos/launcher_log.proto delete mode 100644 quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java delete mode 100644 quickstep/src/com/android/quickstep/interaction/SandboxLauncherRenderer.java delete mode 100644 quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java delete mode 100644 quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java delete mode 100644 quickstep/src/com/android/quickstep/util/CancellableTask.java delete mode 100644 res/layout/search_result_icon_row.xml create mode 100644 res/layout/search_result_shortcut.xml delete mode 100644 res/layout/search_result_suggest.xml delete mode 100644 res/layout/search_result_thumbnail.xml create mode 100644 src/com/android/launcher3/logging/LoggerUtils.java create mode 100644 src/com/android/launcher3/logging/StatsLogUtils.java create mode 100644 src/com/android/launcher3/logging/UserEventDispatcher.java delete mode 100644 src/com/android/launcher3/model/data/RemoteActionItemInfo.java delete mode 100644 src/com/android/launcher3/views/SearchResultIconRow.java create mode 100644 src/com/android/launcher3/views/SearchResultShortcut.java delete mode 100644 src/com/android/launcher3/views/SearchResultSuggestRow.java delete mode 100644 src/com/android/launcher3/views/ThumbnailSearchResultView.java diff --git a/Android.mk b/Android.mk index 349a134d75..25f5412d21 100644 --- a/Android.mk +++ b/Android.mk @@ -36,12 +36,18 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ 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 := 26 LOCAL_MODULE := Launcher3CommonDepsLib @@ -129,6 +135,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_STATIC_JAVA_LIBRARIES := \ SystemUI-statsd \ SystemUISharedLib \ + launcherprotosnano \ launcher_log_protos_lite ifneq (,$(wildcard frameworks/base)) LOCAL_PRIVATE_PLATFORM_APIS := true @@ -196,6 +203,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_STATIC_JAVA_LIBRARIES := \ SystemUI-statsd \ SystemUISharedLib \ + launcherprotosnano \ launcher_log_protos_lite ifneq (,$(wildcard frameworks/base)) LOCAL_PRIVATE_PLATFORM_APIS := true diff --git a/build.gradle b/build.gradle index 28a05d569c..534ca65115 100644 --- a/build.gradle +++ b/build.gradle @@ -82,6 +82,7 @@ android { manifest.srcFile 'AndroidManifest-common.xml' proto { srcDir 'protos/' + srcDir 'proto_overrides/' } } @@ -149,6 +150,7 @@ 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') @@ -169,16 +171,20 @@ dependencies { protobuf { // Configure the protoc executable protoc { - artifact = "com.google.protobuf:protoc:${protocVersion}" - } - generateProtoTasks { - all().each { task -> - task.builtins { - remove java - java { - option "lite" + 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" + } } } } } -} \ No newline at end of file +} diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto new file mode 100644 index 0000000000..9423cb2642 --- /dev/null +++ b/protos/launcher_log.proto @@ -0,0 +1,245 @@ +/* + * 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; +} diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml index 52475dfc8a..43bf0ea966 100644 --- a/quickstep/res/layout/gesture_tutorial_fragment.xml +++ b/quickstep/res/layout/gesture_tutorial_fragment.xml @@ -13,8 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. --> - @@ -94,11 +93,11 @@ style="@style/TextAppearance.GestureTutorial.Feedback" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_below="@id/gesture_tutorial_fragment_titles_container" + android:layout_above="@id/gesture_tutorial_fragment_action_button" android:layout_centerHorizontal="true" android:layout_marginStart="@dimen/gesture_tutorial_feedback_margin_start_end" android:layout_marginEnd="@dimen/gesture_tutorial_feedback_margin_start_end" - android:layout_marginTop="40dp"/> + android:layout_marginBottom="10dp"/> @@ -127,4 +126,4 @@ android:background="@null" android:foreground="?android:attr/selectableItemBackgroundBorderless" android:stateListAnimator="@null"/> - \ No newline at end of file + \ No newline at end of file diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index 4b45b10d4d..86120e3b97 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -149,21 +149,6 @@ Try swiping further - - Sandbox Mode - - Try any navigation gesture - - Back gesture successful - - Assistant gesture successful - - Home gesture successful - - Overview gesture successful - - Make sure you swipe from the left/right edge of the screen - All set diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index 44d43c6784..bc3b4ab0ef 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -22,8 +22,6 @@ import static com.android.launcher3.LauncherState.NORMAL; import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY; -import com.android.systemui.shared.system.InteractionJankMonitorWrapper; - import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.app.ActivityOptions; @@ -321,10 +319,4 @@ public abstract class BaseQuickstepLauncher extends Launcher public void setHintUserWillBeActive() { addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE); } - - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - InteractionJankMonitorWrapper.init(getWindow().getDecorView()); - } } diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java index 5c8463c2a7..b35b33c418 100644 --- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java +++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java @@ -34,7 +34,8 @@ import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @TargetApi(Build.VERSION_CODES.P) -public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat { +public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat, + WrappedAnimationRunnerImpl { private static final String TAG = "LauncherAnimationRunner"; diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java index 057c0f4aaa..b53e834db4 100644 --- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java @@ -66,7 +66,6 @@ import androidx.annotation.Nullable; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.allapps.AllAppsTransitionController; -import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.shortcuts.DeepShortcutView; @@ -82,7 +81,6 @@ import com.android.quickstep.util.StaggeredWorkspaceAnim; import com.android.quickstep.util.SurfaceTransactionApplier; import com.android.systemui.shared.system.ActivityCompat; import com.android.systemui.shared.system.ActivityOptionsCompat; -import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat; @@ -797,36 +795,6 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans == PackageManager.PERMISSION_GRANTED; } - private void addCujInstrumentation(Animator anim, int cuj, String transition) { - if (Trace.isEnabled()) { - anim.addListener(new AnimationSuccessListener() { - @Override - public void onAnimationStart(Animator animation) { - Trace.beginAsyncSection(transition, 0); - InteractionJankMonitorWrapper.begin(cuj); - super.onAnimationStart(animation); - } - - @Override - public void onAnimationCancel(Animator animation) { - super.onAnimationCancel(animation); - InteractionJankMonitorWrapper.cancel(cuj); - } - - @Override - public void onAnimationSuccess(Animator animator) { - InteractionJankMonitorWrapper.end(cuj); - } - - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - Trace.endAsyncSection(TRANSITION_OPEN_LAUNCHER, 0); - } - }); - } - } - /** * Remote animation runner for animation from the app to Launcher, including recents. */ @@ -891,9 +859,21 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans // is initialized. if (launcherIsATargetWithMode(appTargets, MODE_OPENING) || mLauncher.isForceInvisible()) { - addCujInstrumentation( - anim, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME, - TRANSITION_OPEN_LAUNCHER); + if (Trace.isEnabled()) { + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + Trace.beginAsyncSection(TRANSITION_OPEN_LAUNCHER, 0); + super.onAnimationStart(animation); + } + + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + Trace.endAsyncSection(TRANSITION_OPEN_LAUNCHER, 0); + } + }); + } // Only register the content animation for cancellation when state changes mLauncher.getStateManager().setCurrentAnimation(anim); @@ -962,12 +942,25 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans launcherClosing); } - addCujInstrumentation(anim, - launchingFromRecents - ? InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_RECENTS - : InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_ICON, - launchingFromRecents - ? TRANSITION_LAUNCH_FROM_RECENTS : TRANSITION_LAUNCH_FROM_ICON); + if (Trace.isEnabled()) { + final String section = + launchingFromRecents + ? TRANSITION_LAUNCH_FROM_RECENTS : TRANSITION_LAUNCH_FROM_ICON; + + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + Trace.beginAsyncSection(section, 0); + super.onAnimationStart(animation); + } + + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + Trace.endAsyncSection(section, 0); + } + }); + } if (launcherClosing) { anim.addListener(mForceInvisibleListener); diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java index 5b066c6be6..d3c4c3d62d 100644 --- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java +++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java @@ -16,8 +16,11 @@ 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; @@ -40,6 +43,7 @@ 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.LauncherState; import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsSectionDecorator; import com.android.launcher3.allapps.FloatingHeaderRow; @@ -49,11 +53,13 @@ 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.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; @@ -62,7 +68,7 @@ import java.util.List; @TargetApi(Build.VERSION_CODES.P) public class PredictionRowView extends LinearLayout implements - OnDeviceProfileChangeListener, FloatingHeaderRow { + LogContainerProvider, OnDeviceProfileChangeListener, FloatingHeaderRow { private static final IntProperty TEXT_ALPHA = new IntProperty("textAlpha") { @@ -265,6 +271,29 @@ public class PredictionRowView extends LinearLayout implements mParent.onHeightUpdated(); } + @Override + public void fillInLogContainerData(ItemInfo childInfo, LauncherLogProto.Target child, + ArrayList 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) { diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index 380735044d..151a113d1e 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -55,6 +55,7 @@ import com.android.launcher3.popup.SystemShortcut; 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.OnboardingPrefs; import com.android.launcher3.views.ArrowTipView; import com.android.launcher3.views.Snackbar; diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java index a2e3bdf8a0..bce73cd4e4 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java @@ -16,7 +16,6 @@ package com.android.launcher3.uioverrides.states; import static com.android.launcher3.anim.Interpolators.DEACCEL_2; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS; import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview; import android.content.Context; @@ -24,6 +23,7 @@ import android.content.Context; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.allapps.AllAppsContainerView; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; /** * Definition for AllApps state @@ -40,7 +40,7 @@ public class AllAppsState extends LauncherState { }; public AllAppsState(int id) { - super(id, LAUNCHER_STATE_ALLAPPS, STATE_FLAGS); + super(id, ContainerType.ALLAPPS, STATE_FLAGS); } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java index 4b4f955204..8ff05f2aaa 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java @@ -15,13 +15,12 @@ */ package com.android.launcher3.uioverrides.states; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND; - import android.content.Context; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Launcher; import com.android.launcher3.allapps.AllAppsTransitionController; +import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.views.RecentsView; @@ -34,7 +33,7 @@ public class BackgroundAppState extends OverviewState { | FLAG_WORKSPACE_INACCESSIBLE | FLAG_NON_INTERACTIVE | FLAG_CLOSE_POPUPS; public BackgroundAppState(int id) { - this(id, LAUNCHER_STATE_BACKGROUND); + this(id, LauncherLogProto.ContainerType.TASKSWITCHER); } protected BackgroundAppState(int id, int logContainer) { diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java index 41c689d16d..fc0dcd5119 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java @@ -15,14 +15,13 @@ */ package com.android.launcher3.uioverrides.states; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW; - import android.content.Context; import android.graphics.Rect; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.quickstep.views.RecentsView; /** @@ -35,7 +34,7 @@ public class OverviewModalTaskState extends OverviewState { FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_WORKSPACE_INACCESSIBLE; public OverviewModalTaskState(int id) { - super(id, LAUNCHER_STATE_OVERVIEW, STATE_FLAGS); + super(id, ContainerType.OVERVIEW, STATE_FLAGS); } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java index 525ff5816d..bbe7821864 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -16,7 +16,6 @@ package com.android.launcher3.uioverrides.states; import static com.android.launcher3.anim.Interpolators.DEACCEL_2; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW; import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import static com.android.quickstep.SysUINavigationMode.hideShelfInTwoButtonLandscape; import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview; @@ -30,6 +29,7 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Workspace; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.views.RecentsView; @@ -51,7 +51,7 @@ public class OverviewState extends LauncherState { } protected OverviewState(int id, int stateFlags) { - this(id, LAUNCHER_STATE_OVERVIEW, stateFlags); + this(id, ContainerType.TASKSWITCHER, stateFlags); } protected OverviewState(int id, int logContainer, int stateFlags) { diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java index 51e72dacdc..2c7373e206 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java @@ -15,9 +15,8 @@ */ package com.android.launcher3.uioverrides.states; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND; - import com.android.launcher3.Launcher; +import com.android.launcher3.userevent.nano.LauncherLogProto; /** * State to indicate we are about to launch a recent task. Note that this state is only used when @@ -27,7 +26,7 @@ import com.android.launcher3.Launcher; public class QuickSwitchState extends BackgroundAppState { public QuickSwitchState(int id) { - super(id, LAUNCHER_STATE_BACKGROUND); + super(id, LauncherLogProto.ContainerType.APP); } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java index 7a0f634b45..bef191ef8f 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java @@ -12,6 +12,8 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.states.StateAnimationConfig.AnimationFlags; import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SingleAxisSwipeDetector; +import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.quickstep.SystemUiProxy; /** @@ -43,6 +45,11 @@ public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchContro return draggingFromNav ? OVERVIEW : NORMAL; } + @Override + protected int getLogContainerTypeForNormalState(MotionEvent ev) { + return LauncherLogProto.ContainerType.NAVBAR; + } + @Override protected float getShiftRange() { return mLauncher.getDragLayer().getWidth(); @@ -58,8 +65,13 @@ public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchContro } @Override - protected void onSwipeInteractionCompleted(LauncherState targetState) { - super.onSwipeInteractionCompleted(targetState); + protected int getDirectionForLog() { + return mLauncher.getDeviceProfile().isSeascape() ? Direction.RIGHT : Direction.LEFT; + } + + @Override + protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) { + super.onSwipeInteractionCompleted(targetState, logAction); if (mStartState == NORMAL && targetState == OVERVIEW) { SystemUiProxy.INSTANCE.get(mLauncher).onOverviewShown(true, TAG); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java index d210bc6851..76168440a8 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java @@ -45,9 +45,12 @@ import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.graphics.OverviewScrim; +import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.SingleAxisSwipeDetector; +import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.TouchController; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.util.AssistantUtilities; @@ -208,6 +211,7 @@ public class NavBarToHomeTouchController implements TouchController, @Override public void onDragEnd(float velocity) { boolean fling = mSwipeDetector.isFling(velocity); + final int logAction = fling ? Touch.FLING : Touch.SWIPE; float progress = mCurrentAnimation.getProgressFraction(); float interpolatedProgress = PULLBACK_INTERPOLATOR.getInterpolation(progress); boolean success = interpolatedProgress >= SUCCESS_TRANSITION_PROGRESS @@ -226,7 +230,7 @@ public class NavBarToHomeTouchController implements TouchController, () -> onSwipeInteractionCompleted(mEndState)); } if (mStartState != mEndState) { - logHomeGesture(); + // TODO: add to WW log } AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(mLauncher); if (topOpenView != null) { @@ -251,10 +255,17 @@ public class NavBarToHomeTouchController implements TouchController, AccessibilityManagerCompat.sendStateEventToTest(mLauncher, targetState.ordinal); } - private void logHomeGesture() { + private void logStateChange(int startContainerType, int logAction) { + mLauncher.getUserEventDispatcher().logStateChangeAction(logAction, + LauncherLogProto.Action.Direction.UP, + mSwipeDetector.getDownX(), mSwipeDetector.getDownY(), + LauncherLogProto.ContainerType.NAVBAR, + startContainerType, + mEndState.containerType, + mLauncher.getWorkspace().getCurrentPage()); mLauncher.getStatsLogManager().logger() - .withSrcState(mStartState.statsLogOrdinal) - .withDstState(mEndState.statsLogOrdinal) + .withSrcState(StatsLogManager.containerTypeToAtomState(mStartState.containerType)) + .withDstState(StatsLogManager.containerTypeToAtomState(mEndState.containerType)) .log(LAUNCHER_HOME_GESTURE); } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java index 2a3bdbfcb8..c78d4741d8 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java @@ -49,6 +49,7 @@ import com.android.launcher3.anim.Interpolators; import com.android.launcher3.graphics.OverviewScrim; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.testing.TestProtocol; +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.AnimatorControllerWithResistance; @@ -206,7 +207,7 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch private void maybeSwipeInteractionToOverviewComplete() { if (mReachedOverview && mDetector.isSettlingState()) { - onSwipeInteractionCompleted(OVERVIEW); + onSwipeInteractionCompleted(OVERVIEW, Touch.SWIPE); } } @@ -250,7 +251,7 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch private void goToOverviewOrHomeOnDragEnd(float velocity) { boolean goToHomeInsteadOfOverview = !mMotionPauseDetector.isPaused(); if (goToHomeInsteadOfOverview) { - new OverviewToHomeAnim(mLauncher, ()-> onSwipeInteractionCompleted(NORMAL)) + new OverviewToHomeAnim(mLauncher, ()-> onSwipeInteractionCompleted(NORMAL, Touch.FLING)) .animateWithVelocity(velocity); } if (mReachedOverview) { diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java index f378848a71..a6a3497f04 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java @@ -57,9 +57,13 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.graphics.OverviewScrim; +import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.BaseSwipeDetector; import com.android.launcher3.touch.BothAxesSwipeDetector; +import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.TouchController; import com.android.launcher3.util.VibratorWrapper; import com.android.quickstep.AnimatedFloat; @@ -283,6 +287,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController, boolean horizontalFling = mSwipeDetector.isFling(velocity.x); boolean verticalFling = mSwipeDetector.isFling(velocity.y); boolean noFling = !horizontalFling && !verticalFling; + int logAction = noFling ? Touch.SWIPE : Touch.FLING; if (mMotionPauseDetector.isPaused() && noFling) { cancelAnimations(); @@ -293,7 +298,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController, overviewAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - onAnimationToStateCompleted(OVERVIEW); + onAnimationToStateCompleted(OVERVIEW, logAction); } }); overviewAnim.start(); @@ -388,7 +393,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController, } nonOverviewAnim.setDuration(Math.max(xDuration, yDuration)); - mNonOverviewAnim.setEndAction(() -> onAnimationToStateCompleted(targetState)); + mNonOverviewAnim.setEndAction(() -> onAnimationToStateCompleted(targetState, logAction)); cancelAnimations(); xOverviewAnim.start(); @@ -396,17 +401,27 @@ public class NoButtonQuickSwitchTouchController implements TouchController, nonOverviewAnim.start(); } - private void onAnimationToStateCompleted(LauncherState targetState) { + private void onAnimationToStateCompleted(LauncherState targetState, int logAction) { + mLauncher.getUserEventDispatcher().logStateChangeAction(logAction, + getDirectionForLog(), mSwipeDetector.getDownX(), mSwipeDetector.getDownY(), + LauncherLogProto.ContainerType.NAVBAR, + mStartState.containerType, + targetState.containerType, + mLauncher.getWorkspace().getCurrentPage()); mLauncher.getStatsLogManager().logger() .withSrcState(LAUNCHER_STATE_HOME) - .withDstState(targetState.statsLogOrdinal) - .log(getLauncherAtomEvent(mStartState.statsLogOrdinal, targetState.statsLogOrdinal, + .withDstState(StatsLogManager.containerTypeToAtomState(targetState.containerType)) + .log(getLauncherAtomEvent(mStartState.containerType, targetState.containerType, targetState.ordinal > mStartState.ordinal ? LAUNCHER_UNKNOWN_SWIPEUP : LAUNCHER_UNKNOWN_SWIPEDOWN)); mLauncher.getStateManager().goToState(targetState, false, this::clearState); } + private int getDirectionForLog() { + return Utilities.isRtl(mLauncher.getResources()) ? Direction.LEFT : Direction.RIGHT; + } + private void cancelAnimations() { if (mNonOverviewAnim != null) { mNonOverviewAnim.getAnimationPlayer().cancel(); diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java index 45e5e2fb7c..90911684ec 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java @@ -25,6 +25,7 @@ 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; @@ -72,4 +73,9 @@ public class OverviewToAllAppsTouchController extends PortraitStatesTouchControl } return fromState; } + + @Override + protected int getLogContainerTypeForNormalState(MotionEvent ev) { + return LauncherLogProto.ContainerType.WORKSPACE; + } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java index 037d9889fd..059a703075 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java @@ -48,6 +48,8 @@ import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SingleAxisSwipeDetector; import com.android.launcher3.uioverrides.states.OverviewState; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TouchInteractionService; import com.android.quickstep.util.LayoutUtils; @@ -170,6 +172,11 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr return fromState; } + @Override + protected int getLogContainerTypeForNormalState(MotionEvent ev) { + return isTouchOverHotseat(mLauncher, ev) ? ContainerType.HOTSEAT : ContainerType.WORKSPACE; + } + private StateAnimationConfig getNormalToOverviewAnimation() { mAllAppsInterpolatorWrapper.baseInterpolator = LINEAR; @@ -278,7 +285,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr private void cancelPendingAnim() { if (mPendingAnimation != null) { - mPendingAnimation.finish(false); + mPendingAnimation.finish(false, Touch.SWIPE); mPendingAnimation = null; } } @@ -313,8 +320,8 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr } @Override - protected void onSwipeInteractionCompleted(LauncherState targetState) { - super.onSwipeInteractionCompleted(targetState); + protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) { + super.onSwipeInteractionCompleted(targetState, logAction); if (mStartState == NORMAL && targetState == OVERVIEW) { SystemUiProxy.INSTANCE.get(mLauncher).onOverviewShown(true, TAG); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java index b8c2030852..c643858e5c 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java @@ -21,7 +21,6 @@ import static com.android.launcher3.anim.Interpolators.ACCEL_2; import static com.android.launcher3.anim.Interpolators.DEACCEL_2; import static com.android.launcher3.anim.Interpolators.INSTANT; import static com.android.launcher3.anim.Interpolators.LINEAR; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; @@ -42,6 +41,8 @@ import com.android.launcher3.Utilities; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SingleAxisSwipeDetector; +import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.SystemUiProxy; @@ -91,14 +92,14 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll @Override public void onDragStart(boolean start, float startDisplacement) { super.onDragStart(start, startDisplacement); - mStartContainerType = LAUNCHER_STATE_BACKGROUND; + mStartContainerType = LauncherLogProto.ContainerType.NAVBAR; ActivityManagerWrapper.getInstance() .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); } @Override - protected void onSwipeInteractionCompleted(LauncherState targetState) { - super.onSwipeInteractionCompleted(targetState); + protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) { + super.onSwipeInteractionCompleted(targetState, logAction); } @Override @@ -152,4 +153,14 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll protected float getShiftRange() { return mLauncher.getDeviceProfile().widthPx / 2f; } + + @Override + protected int getLogContainerTypeForNormalState(MotionEvent ev) { + return LauncherLogProto.ContainerType.NAVBAR; + } + + @Override + protected int getDirectionForLog() { + return Utilities.isRtl(mLauncher.getResources()) ? Direction.LEFT : Direction.RIGHT; + } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java index fe69c9b87d..16bd9ed384 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java @@ -15,12 +15,10 @@ */ package com.android.launcher3.uioverrides.touchcontrollers; -import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_UP; - -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN; +import static android.view.MotionEvent.ACTION_CANCEL; import android.graphics.PointF; import android.util.SparseArray; @@ -33,9 +31,12 @@ import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.TouchController; -import com.android.quickstep.SystemUiProxy; +import com.android.quickstep.SystemUiProxy; import java.io.PrintWriter; /** @@ -132,8 +133,9 @@ public class StatusBarTouchController implements TouchController { int action = ev.getAction(); if (action == ACTION_UP || action == ACTION_CANCEL) { dispatchTouchEvent(ev); - mLauncher.getStatsLogManager().logger() - .log(LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN); + mLauncher.getUserEventDispatcher().logActionOnContainer(action == ACTION_UP ? + Touch.FLING : Touch.SWIPE, Direction.DOWN, ContainerType.WORKSPACE, + mLauncher.getWorkspace().getCurrentPage()); setWindowSlippery(false); return true; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java index 186caf6dc1..df6194d4b2 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java @@ -36,6 +36,7 @@ import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.touch.BaseSwipeDetector; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.touch.SingleAxisSwipeDetector; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.FlingBlockCheck; import com.android.launcher3.util.TouchController; import com.android.launcher3.views.BaseDragLayer; @@ -202,7 +203,7 @@ public abstract class TaskViewTouchController mCurrentAnimation.setPlayFraction(0); } if (mPendingAnimation != null) { - mPendingAnimation.finish(false); + mPendingAnimation.finish(false, Touch.SWIPE); mPendingAnimation = null; } @@ -284,6 +285,7 @@ public abstract class TaskViewTouchController public void onDragEnd(float velocity) { boolean fling = mDetector.isFling(velocity); final boolean goingToEnd; + final int logAction; boolean blockedFling = fling && mFlingBlockCheck.isBlocked(); if (blockedFling) { fling = false; @@ -292,9 +294,11 @@ public abstract class TaskViewTouchController float progress = mCurrentAnimation.getProgressFraction(); float interpolatedProgress = mCurrentAnimation.getInterpolatedProgress(); if (fling) { + logAction = Touch.FLING; boolean goingUp = orientationHandler.isGoingUp(velocity, mIsRtl); goingToEnd = goingUp == mCurrentAnimationIsGoingUp; } else { + logAction = Touch.SWIPE; goingToEnd = interpolatedProgress > SUCCESS_TRANSITION_PROGRESS; } long animationDuration = BaseSwipeDetector.calculateDuration( @@ -303,14 +307,14 @@ public abstract class TaskViewTouchController animationDuration *= LauncherAnimUtils.blockedFlingDurationFactor(velocity); } - mCurrentAnimation.setEndAction(() -> onCurrentAnimationEnd(goingToEnd)); + mCurrentAnimation.setEndAction(() -> onCurrentAnimationEnd(goingToEnd, logAction)); mCurrentAnimation.startWithVelocity(mActivity, goingToEnd, velocity, mEndDisplacement, animationDuration); } - private void onCurrentAnimationEnd(boolean wasSuccess) { + private void onCurrentAnimationEnd(boolean wasSuccess, int logAction) { if (mPendingAnimation != null) { - mPendingAnimation.finish(wasSuccess); + mPendingAnimation.finish(wasSuccess, logAction); mPendingAnimation = null; } clearState(); @@ -322,7 +326,7 @@ public abstract class TaskViewTouchController mTaskBeingDragged = null; mCurrentAnimation = null; if (mPendingAnimation != null) { - mPendingAnimation.finish(false); + mPendingAnimation.finish(false, Touch.SWIPE); mPendingAnimation = null; } } diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 5e05a7dbe1..26ad3778a7 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -75,8 +75,12 @@ import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.StatsLogManager.StatsLogger; +import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.testing.TestProtocol; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.TraceHelper; import com.android.launcher3.util.VibratorWrapper; import com.android.launcher3.util.WindowBounds; @@ -97,7 +101,6 @@ import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputConsumerController; -import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.systemui.shared.system.LatencyTrackerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.TaskInfoCompat; @@ -216,7 +219,8 @@ public abstract class AbsSwipeUpHandler, Q extends private boolean mPassedOverviewThreshold; private boolean mGestureStarted; - private boolean mLogDirectionUpOrLeft = true; + private int mLogAction = Touch.SWIPE; + private int mLogDirection = Direction.UP; private PointF mDownPos; private boolean mIsLikelyToStartNewTask; @@ -430,13 +434,9 @@ public abstract class AbsSwipeUpHandler, Q extends mOnDeferredActivityLaunch); mGestureState.runOnceAtState(STATE_END_TARGET_SET, - () -> { - mDeviceState.getRotationTouchHelper() - .onEndTargetCalculated(mGestureState.getEndTarget(), - mActivityInterface); - - mRecentsView.onGestureEndTargetCalculated(mGestureState.getEndTarget()); - }); + () -> mDeviceState.getRotationTouchHelper(). + onEndTargetCalculated(mGestureState.getEndTarget(), + mActivityInterface)); notifyGestureStartedAsync(); } @@ -741,6 +741,7 @@ public abstract class AbsSwipeUpHandler, Q extends public void onGestureCancelled() { updateDisplacement(0); mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED); + mLogAction = Touch.SWIPE_NOOP; handleNormalGestureEnd(0, false, new PointF(), true /* isCancel */); } @@ -756,11 +757,13 @@ public abstract class AbsSwipeUpHandler, Q extends boolean isFling = mGestureStarted && !mIsMotionPaused && Math.abs(endVelocity) > flingThreshold; mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED); + + mLogAction = isFling ? Touch.FLING : Touch.SWIPE; boolean isVelocityVertical = Math.abs(velocity.y) > Math.abs(velocity.x); if (isVelocityVertical) { - mLogDirectionUpOrLeft = velocity.y < 0; + mLogDirection = velocity.y < 0 ? Direction.UP : Direction.DOWN; } else { - mLogDirectionUpOrLeft = velocity.x < 0; + mLogDirection = velocity.x < 0 ? Direction.LEFT : Direction.RIGHT; } mDownPos = downPos; handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */); @@ -972,7 +975,8 @@ public abstract class AbsSwipeUpHandler, Q extends break; case LAST_TASK: case NEW_TASK: - event = mLogDirectionUpOrLeft ? LAUNCHER_QUICKSWITCH_LEFT + event = (mLogDirection == Direction.LEFT) + ? LAUNCHER_QUICKSWITCH_LEFT : LAUNCHER_QUICKSWITCH_RIGHT; break; default: @@ -980,10 +984,12 @@ public abstract class AbsSwipeUpHandler, Q extends } StatsLogger logger = StatsLogManager.newInstance(mContext).logger() .withSrcState(LAUNCHER_STATE_BACKGROUND) - .withDstState(endTarget.containerType); + .withDstState(StatsLogManager.containerTypeToAtomState(endTarget.containerType)); if (targetTask != null) { logger.withItemInfo(targetTask.getItemInfo()); } + logger.log(event); + DeviceProfile dp = mDp; if (dp == null || mDownPos == null) { @@ -993,8 +999,12 @@ public abstract class AbsSwipeUpHandler, Q extends int pageIndex = endTarget == LAST_TASK ? LOG_NO_OP_PAGE_INDEX : mRecentsView.getNextPage(); - // TODO: set correct container using the pageIndex - logger.log(event); + UserEventDispatcher.newInstance(mContext).logStateChangeAction( + mLogAction, mLogDirection, + (int) mDownPos.x, (int) mDownPos.y, + ContainerType.NAVBAR, ContainerType.APP, + endTarget.containerType, + pageIndex); } /** Animates to the given progress, where 0 is the current app and 1 is overview. */ @@ -1131,12 +1141,10 @@ public abstract class AbsSwipeUpHandler, Q extends anim.addOnUpdateListener((r, p) -> { updateSysUiFlags(Math.max(p, mCurrentShift.value)); }); - final int cuj = InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME; anim.addAnimatorListener(new AnimationSuccessListener() { @Override public void onAnimationStart(Animator animation) { Trace.beginAsyncSection(TRANSITION_OPEN_LAUNCHER, 0); - InteractionJankMonitorWrapper.begin(cuj); if (mActivity != null) { removeLiveTileOverlay(); } @@ -1150,13 +1158,6 @@ public abstract class AbsSwipeUpHandler, Q extends // Make sure recents is in its final state maybeUpdateRecentsAttachedState(false); mActivityInterface.onSwipeUpToHomeComplete(mDeviceState); - InteractionJankMonitorWrapper.end(cuj); - } - - @Override - public void onAnimationCancel(Animator animation) { - super.onAnimationCancel(animation); - InteractionJankMonitorWrapper.cancel(cuj); } @Override diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index d35e270dd5..8b108ac299 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -152,6 +152,11 @@ public abstract class BaseActivityInterface mAnimationProvider; private final long mToggleClickedTime = SystemClock.uptimeMillis(); + private boolean mUserEventLogged; private ActivityInitListener mListener; public RecentsActivityCommand() { @@ -156,7 +160,7 @@ public class OverviewCommandHelper { ActivityManagerWrapper.getInstance().getRunningTask(), mDeviceState); // Preload the plan - RecentsModel.INSTANCE.get(mContext).getTasks(null); + mRecentsModel.getTasks(null); } @Override @@ -208,6 +212,13 @@ public class OverviewCommandHelper { 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; + } return mAnimationProvider.onActivityReady(activity, wasVisible); } diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java index 2f55f14a9b..6f2f9fb523 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -41,10 +41,7 @@ import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAnimationRunner; -import com.android.launcher3.LauncherAnimationRunner.AnimationResult; import com.android.launcher3.R; -import com.android.launcher3.WrappedAnimationRunnerImpl; -import com.android.launcher3.WrappedLauncherAnimationRunner; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.compat.AccessibilityManagerCompat; @@ -90,9 +87,6 @@ public final class RecentsActivity extends StatefulActivity { private StateManager mStateManager; - // Strong refs to runners which are cleared when the activity is destroyed - private WrappedAnimationRunnerImpl mActivityLaunchAnimationRunner; - /** * Init drag layer and overview panel views. */ @@ -124,6 +118,7 @@ public final class RecentsActivity extends StatefulActivity { * etc.) */ protected void onHandleConfigChanged() { + mUserEventDispatcher = null; initDeviceProfile(); AbstractFloatingView.closeOpenViews(this, true, @@ -175,11 +170,8 @@ public final class RecentsActivity extends StatefulActivity { } final TaskView taskView = (TaskView) v; - mActivityLaunchAnimationRunner = new WrappedAnimationRunnerImpl() { - @Override - public Handler getHandler() { - return mUiHandler; - } + RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mUiHandler, + true /* startAtFrontOfQueue */) { @Override public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, @@ -190,10 +182,8 @@ public final class RecentsActivity extends StatefulActivity { result.setAnimation(anim, RecentsActivity.this); } }; - final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner<>( - mActivityLaunchAnimationRunner, true /* startAtFrontOfQueue */); return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat( - wrapper, RECENTS_LAUNCH_DURATION, + runner, RECENTS_LAUNCH_DURATION, RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION - STATUS_BAR_TRANSITION_PRE_DELAY)); } @@ -298,7 +288,6 @@ public final class RecentsActivity extends StatefulActivity { protected void onDestroy() { super.onDestroy(); ACTIVITY_TRACKER.onActivityDestroyed(this); - mActivityLaunchAnimationRunner = null; } @Override diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java index d47217b770..6c302ae5d7 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -18,6 +18,7 @@ package com.android.quickstep; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; +import static com.android.launcher3.util.Executors.createAndStartNewLooper; import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId; import android.annotation.TargetApi; @@ -25,11 +26,11 @@ import android.app.ActivityManager; import android.content.ComponentCallbacks2; import android.content.Context; import android.os.Build; +import android.os.Looper; import android.os.Process; import android.os.UserHandle; import com.android.launcher3.icons.IconProvider; -import com.android.launcher3.util.Executors.SimpleThreadFactory; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -39,8 +40,6 @@ import com.android.systemui.shared.system.TaskStackChangeListener; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; import java.util.function.Consumer; /** @@ -53,9 +52,6 @@ public class RecentsModel extends TaskStackChangeListener { public static final MainThreadInitializedObject INSTANCE = new MainThreadInitializedObject<>(RecentsModel::new); - private static final Executor RECENTS_MODEL_EXECUTOR = Executors.newSingleThreadExecutor( - new SimpleThreadFactory("TaskThumbnailIconCache-", THREAD_PRIORITY_BACKGROUND)); - private final List mThumbnailChangeListeners = new ArrayList<>(); private final Context mContext; @@ -65,10 +61,12 @@ public class RecentsModel extends TaskStackChangeListener { private RecentsModel(Context context) { mContext = context; + Looper looper = + createAndStartNewLooper("TaskThumbnailIconCache", THREAD_PRIORITY_BACKGROUND); mTaskList = new RecentTasksList(MAIN_EXECUTOR, new KeyguardManagerCompat(context), ActivityManagerWrapper.getInstance()); - mIconCache = new TaskIconCache(context, RECENTS_MODEL_EXECUTOR); - mThumbnailCache = new TaskThumbnailCache(context, RECENTS_MODEL_EXECUTOR); + mIconCache = new TaskIconCache(context, looper); + mThumbnailCache = new TaskThumbnailCache(context, looper); ActivityManagerWrapper.getInstance().registerTaskStackListener(this); IconProvider.registerIconChangeListener(context, diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java index 65e89cfa2f..7ff799ec55 100644 --- a/quickstep/src/com/android/quickstep/TaskIconCache.java +++ b/quickstep/src/com/android/quickstep/TaskIconCache.java @@ -17,6 +17,7 @@ package com.android.quickstep; import static com.android.launcher3.FastBitmapDrawable.newIcon; import static com.android.launcher3.uioverrides.QuickstepLauncher.GO_LOW_RAM_RECENTS_ENABLED; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.app.ActivityManager.TaskDescription; import android.content.Context; @@ -26,6 +27,8 @@ import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Build; +import android.os.Handler; +import android.os.Looper; import android.os.UserHandle; import android.util.SparseArray; import android.view.accessibility.AccessibilityManager; @@ -34,11 +37,12 @@ import androidx.annotation.WorkerThread; import com.android.launcher3.FastBitmapDrawable; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.IconProvider; import com.android.launcher3.icons.LauncherIcons; +import com.android.launcher3.icons.cache.HandlerRunnable; import com.android.launcher3.util.Preconditions; -import com.android.quickstep.util.CancellableTask; import com.android.quickstep.util.TaskKeyLruCache; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.Task.TaskKey; @@ -46,7 +50,6 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.PackageManagerWrapper; import com.android.systemui.shared.system.TaskDescriptionCompat; -import java.util.concurrent.Executor; import java.util.function.Consumer; /** @@ -54,7 +57,7 @@ import java.util.function.Consumer; */ public class TaskIconCache { - private final Executor mBgExecutor; + private final Handler mBackgroundHandler; private final AccessibilityManager mAccessibilityManager; private final Context mContext; @@ -62,9 +65,9 @@ public class TaskIconCache { private final SparseArray mDefaultIcons = new SparseArray<>(); private final IconProvider mIconProvider; - public TaskIconCache(Context context, Executor bgExecutor) { + public TaskIconCache(Context context, Looper backgroundLooper) { mContext = context; - mBgExecutor = bgExecutor; + mBackgroundHandler = new Handler(backgroundLooper); mAccessibilityManager = context.getSystemService(AccessibilityManager.class); Resources res = context.getResources(); @@ -80,27 +83,31 @@ public class TaskIconCache { * @param callback The callback to receive the task after its data has been populated. * @return A cancelable handle to the request */ - public CancellableTask updateIconInBackground(Task task, Consumer callback) { + public IconLoadRequest updateIconInBackground(Task task, Consumer callback) { Preconditions.assertUIThread(); if (task.icon != null) { // Nothing to load, the icon is already loaded callback.accept(task); return null; } - CancellableTask request = new CancellableTask() { - @Override - public TaskCacheEntry getResultOnBg() { - return getCacheEntry(task); - } + IconLoadRequest request = new IconLoadRequest(mBackgroundHandler) { @Override - public void handleResult(TaskCacheEntry result) { - task.icon = result.icon; - task.titleDescription = result.contentDescription; - callback.accept(task); + public void run() { + TaskCacheEntry entry = getCacheEntry(task); + if (isCanceled()) { + // We don't call back to the provided callback in this case + return; + } + MAIN_EXECUTOR.execute(() -> { + task.icon = entry.icon; + task.titleDescription = entry.contentDescription; + callback.accept(task); + onEnd(); + }); } }; - mBgExecutor.execute(request); + Utilities.postAsyncCallback(mBackgroundHandler, request); return request; } @@ -113,8 +120,9 @@ public class TaskIconCache { } void invalidateCacheEntries(String pkg, UserHandle handle) { - mBgExecutor.execute(() -> mIconCache.removeAll(key -> - pkg.equals(key.getPackageName()) && handle.getIdentifier() == key.userId)); + Utilities.postAsyncCallback(mBackgroundHandler, + () -> mIconCache.removeAll(key -> + pkg.equals(key.getPackageName()) && handle.getIdentifier() == key.userId)); } @WorkerThread @@ -200,6 +208,12 @@ public class TaskIconCache { } } + public static abstract class IconLoadRequest extends HandlerRunnable { + IconLoadRequest(Handler handler) { + super(handler, null); + } + } + private static class TaskCacheEntry { public Drawable icon; public String contentDescription = ""; diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java index 65bb0f35d1..2b55b805c6 100644 --- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java +++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java @@ -21,6 +21,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SELECTIONS; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP; +import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP; import android.app.Activity; import android.app.ActivityOptions; @@ -38,6 +39,7 @@ import com.android.launcher3.logging.StatsLogManager.LauncherEvent; import com.android.launcher3.model.WellbeingModel; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.popup.SystemShortcut.AppInfo; +import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.util.Executors; import com.android.launcher3.util.InstantAppResolver; import com.android.quickstep.views.RecentsView; @@ -226,6 +228,8 @@ public interface TaskShortcutFactory { @Override protected boolean onActivityStarted(BaseDraggingActivity activity) { + activity.getUserEventDispatcher().logActionOnControl(TAP, + LauncherLogProto.ControlType.SPLIT_SCREEN_TARGET); return true; } }; diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java index a8a0219594..2b7a8ec250 100644 --- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java +++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java @@ -15,12 +15,17 @@ */ package com.android.quickstep; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + import android.content.Context; import android.content.res.Resources; +import android.os.Handler; +import android.os.Looper; import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.icons.cache.HandlerRunnable; import com.android.launcher3.util.Preconditions; -import com.android.quickstep.util.CancellableTask; import com.android.quickstep.util.TaskKeyLruCache; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.Task.TaskKey; @@ -28,12 +33,11 @@ import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; import java.util.ArrayList; -import java.util.concurrent.Executor; import java.util.function.Consumer; public class TaskThumbnailCache { - private final Executor mBgExecutor; + private final Handler mBackgroundHandler; private final int mCacheSize; private final TaskKeyLruCache mCache; @@ -90,8 +94,8 @@ public class TaskThumbnailCache { } } - public TaskThumbnailCache(Context context, Executor bgExecutor) { - mBgExecutor = bgExecutor; + public TaskThumbnailCache(Context context, Looper backgroundLooper) { + mBackgroundHandler = new Handler(backgroundLooper); mHighResLoadingState = new HighResLoadingState(context); Resources res = context.getResources(); @@ -126,7 +130,7 @@ public class TaskThumbnailCache { * @param callback The callback to receive the task after its data has been populated. * @return A cancelable handle to the request */ - public CancellableTask updateThumbnailInBackground( + public ThumbnailLoadRequest updateThumbnailInBackground( Task task, Consumer callback) { Preconditions.assertUIThread(); @@ -138,13 +142,14 @@ public class TaskThumbnailCache { return null; } + return updateThumbnailInBackground(task.key, !mHighResLoadingState.isEnabled(), t -> { task.thumbnail = t; callback.accept(t); }); } - private CancellableTask updateThumbnailInBackground(TaskKey key, boolean lowResolution, + private ThumbnailLoadRequest updateThumbnailInBackground(TaskKey key, boolean lowResolution, Consumer callback) { Preconditions.assertUIThread(); @@ -155,20 +160,26 @@ public class TaskThumbnailCache { return null; } - CancellableTask request = new CancellableTask() { + ThumbnailLoadRequest request = new ThumbnailLoadRequest(mBackgroundHandler, + lowResolution) { @Override - public ThumbnailData getResultOnBg() { - return ActivityManagerWrapper.getInstance().getTaskThumbnail( + public void run() { + ThumbnailData thumbnail = ActivityManagerWrapper.getInstance().getTaskThumbnail( key.id, lowResolution); - } - @Override - public void handleResult(ThumbnailData result) { - mCache.put(key, result); - callback.accept(result); + MAIN_EXECUTOR.execute(() -> { + if (isCanceled()) { + // We don't call back to the provided callback in this case + return; + } + + mCache.put(key, thumbnail); + callback.accept(thumbnail); + onEnd(); + }); } }; - mBgExecutor.execute(request); + Utilities.postAsyncCallback(mBackgroundHandler, request); return request; } @@ -207,6 +218,15 @@ public class TaskThumbnailCache { return mEnableTaskSnapshotPreloading && mHighResLoadingState.mVisible; } + public static abstract class ThumbnailLoadRequest extends HandlerRunnable { + public final boolean mLowResolution; + + ThumbnailLoadRequest(Handler handler, boolean lowResolution) { + super(handler, null); + mLowResolution = lowResolution; + } + } + /** * @return Whether device supports low-res thumbnails. Low-res files are an optimization * for faster load times of snapshots. Devices can optionally disable low-res files so that diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 3e05b07074..df93e0b6a2 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -20,7 +20,6 @@ import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_UP; -import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.quickstep.GestureState.DEFAULT_STATE; @@ -688,7 +687,7 @@ public class TouchInteractionService extends Service implements PluginListener } /** - * When the gesture ends and we're going to recents view, we also remove the temporary + * When the gesture ends and recents view become interactive, we also remove the temporary * invisible tile added for the home task. This also pushes the remaining tiles back * to the center. */ @Override - public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) { - super.onGestureEndTargetCalculated(endTarget); - if (mHomeTaskInfo != null && endTarget == RECENTS) { + public void onGestureAnimationEnd() { + super.onGestureAnimationEnd(); + if (mHomeTaskInfo != null) { TaskView tv = getTaskView(mHomeTaskInfo.taskId); if (tv != null) { PendingAnimation pa = createTaskDismissAnimation(tv, true, false, 150); diff --git a/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java index 580e4ec807..89e6931ed9 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java @@ -25,6 +25,12 @@ import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.Utilities.squaredHypot; +import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPLEFT; +import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPRIGHT; +import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.FLING; +import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.SWIPE; +import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.SWIPE_NOOP; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.NAVBAR; import android.animation.ValueAnimator; import android.content.Context; @@ -41,6 +47,7 @@ import android.view.ViewConfiguration; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.logging.UserEventDispatcher; import com.android.quickstep.BaseActivityInterface; import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; @@ -73,6 +80,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer { private float mTimeFraction; private long mDragTime; private float mLastProgress; + private int mDirection; private BaseActivityInterface mActivityInterface; private final float mDragDistThreshold; @@ -189,6 +197,8 @@ public class AssistantInputConsumer extends DelegateInputConsumer { if (mState != STATE_DELEGATE_ACTIVE && !mLaunchedAssistant) { ValueAnimator animator = ValueAnimator.ofFloat(mLastProgress, 0) .setDuration(RETRACT_ANIMATION_DURATION_MS); + UserEventDispatcher.newInstance(mContext).logActionOnContainer( + SWIPE_NOOP, mDirection, NAVBAR); animator.addUpdateListener(valueAnimator -> { float progress = (float) valueAnimator.getAnimatedValue(); SystemUiProxy.INSTANCE.get(mContext).onAssistantProgress(progress); @@ -213,7 +223,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer { mLastProgress = Math.min(mDistance * 1f / mDragDistThreshold, 1) * mTimeFraction; if (mDistance >= mDragDistThreshold && mTimeFraction >= 1) { SystemUiProxy.INSTANCE.get(mContext).onAssistantGestureCompletion(0); - startAssistantInternal(); + startAssistantInternal(SWIPE); Bundle args = new Bundle(); args.putInt(OPA_BUNDLE_TRIGGER, OPA_BUNDLE_TRIGGER_DIAG_SWIPE_GESTURE); @@ -226,7 +236,10 @@ public class AssistantInputConsumer extends DelegateInputConsumer { } } - private void startAssistantInternal() { + private void startAssistantInternal(int gestureType) { + UserEventDispatcher.newInstance(mContext) + .logActionOnContainer(gestureType, mDirection, NAVBAR); + BaseDraggingActivity launcherActivity = mActivityInterface.getCreatedActivity(); if (launcherActivity != null) { launcherActivity.getRootView().performHapticFeedback( @@ -240,6 +253,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer { */ private boolean isValidAssistantGestureAngle(float deltaX, float deltaY) { float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX)); + mDirection = angle > 90 ? UPLEFT : UPRIGHT; // normalize so that angle is measured clockwise from horizontal in the bottom right corner // and counterclockwise from horizontal in the bottom left corner @@ -258,7 +272,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer { mLastProgress = 1; SystemUiProxy.INSTANCE.get(mContext).onAssistantGestureCompletion( (float) Math.sqrt(velocityX * velocityX + velocityY * velocityY)); - startAssistantInternal(); + startAssistantInternal(FLING); Bundle args = new Bundle(); args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE); diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 35dbee9490..b1a1133885 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -67,7 +67,6 @@ import com.android.quickstep.util.CachedEventDispatcher; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.util.NavBarPosition; import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver; import com.android.systemui.shared.system.InputMonitorCompat; import java.util.function.Consumer; @@ -93,7 +92,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC private RecentsAnimationCallbacks mActiveCallbacks; private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher(); private final InputMonitorCompat mInputMonitorCompat; - private final InputEventReceiver mInputEventReceiver; private final BaseActivityInterface mActivityInterface; private final AbsSwipeUpHandler.Factory mHandlerFactory; @@ -137,8 +135,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState, TaskAnimationManager taskAnimationManager, GestureState gestureState, boolean isDeferredDownTarget, Consumer onCompleteCallback, - InputMonitorCompat inputMonitorCompat, InputEventReceiver inputEventReceiver, - boolean disableHorizontalSwipe, Factory handlerFactory) { + InputMonitorCompat inputMonitorCompat, boolean disableHorizontalSwipe, + Factory handlerFactory) { super(base); mDeviceState = deviceState; mNavBarPosition = mDeviceState.getNavBarPosition(); @@ -156,7 +154,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mOnCompleteCallback = onCompleteCallback; mVelocityTracker = VelocityTracker.obtain(); mInputMonitorCompat = inputMonitorCompat; - mInputEventReceiver = inputEventReceiver; boolean continuingPreviousGesture = mTaskAnimationManager.isRecentsAnimationRunning(); mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget; @@ -218,9 +215,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC switch (ev.getActionMasked()) { case ACTION_DOWN: { - // Until we detect the gesture, handle events as we receive them - mInputEventReceiver.setBatchingEnabled(false); - Object traceToken = TraceHelper.INSTANCE.beginSection(DOWN_EVT, FLAG_CHECK_FOR_RACE_CONDITIONS); mActivePointerId = ev.getPointerId(0); @@ -357,8 +351,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers"); mInputMonitorCompat.pilferPointers(); - // Once we detect the gesture, we can enable batching to reduce further updates - mInputEventReceiver.setBatchingEnabled(true); mActivityInterface.closeOverlay(); ActivityManagerWrapper.getInstance().closeSystemWindows( diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java index 924b32c015..1c77a0593d 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java @@ -15,7 +15,6 @@ */ package com.android.quickstep.inputconsumers; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE; @@ -28,6 +27,9 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.TestProtocol; +import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.RecentsAnimationDeviceState; @@ -80,12 +82,17 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer, mContext.startActivity(mGestureState.getHomeIntent()); ActiveGestureLog.INSTANCE.addLog("startQuickstep"); BaseActivity activity = BaseDraggingActivity.fromContext(mContext); - int state = (mGestureState != null && mGestureState.getEndTarget() != null) + int pageIndex = -1; // This number doesn't reflect workspace page index. + // It only indicates that launcher client screen was shown. + int containerType = (mGestureState != null && mGestureState.getEndTarget() != null) ? mGestureState.getEndTarget().containerType - : LAUNCHER_STATE_HOME; + : LauncherLogProto.ContainerType.WORKSPACE; + activity.getUserEventDispatcher().logActionOnContainer( + wasFling ? Touch.FLING : Touch.SWIPE, Direction.UP, containerType, pageIndex); + activity.getUserEventDispatcher().setPreviousHomeGesture(true); activity.getStatsLogManager().logger() - .withSrcState(LAUNCHER_STATE_BACKGROUND) - .withDstState(state) + .withSrcState(LAUNCHER_STATE_HOME) + .withDstState(LAUNCHER_STATE_HOME) .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder() .setWorkspace( LauncherAtom.WorkspaceContainer.newBuilder() diff --git a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java index 16886ec177..70181fb9ca 100644 --- a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java +++ b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java @@ -24,7 +24,7 @@ import com.android.quickstep.interaction.TutorialController.TutorialType; /** Shows the Home gesture interactive tutorial. */ public class AssistantGestureTutorialFragment extends TutorialFragment { @Override - Integer getHandAnimationResId() { + int getHandAnimationResId() { return R.drawable.assistant_gesture; } diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java index 41db684d44..bef50ea8df 100644 --- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java +++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java @@ -24,7 +24,7 @@ import com.android.quickstep.interaction.TutorialController.TutorialType; /** Shows the Back gesture interactive tutorial. */ public class BackGestureTutorialFragment extends TutorialFragment { @Override - Integer getHandAnimationResId() { + int getHandAnimationResId() { return R.drawable.back_gesture; } diff --git a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java index 9489bac266..e4b348e51b 100644 --- a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java +++ b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java @@ -143,10 +143,6 @@ public class EdgeBackGestureHandler implements OnTouchListener { return false; } - boolean onInterceptTouch(MotionEvent motionEvent) { - return isWithinTouchRegion((int) motionEvent.getX(), (int) motionEvent.getY()); - } - private boolean isWithinTouchRegion(int x, int y) { // Disallow if too far from the edge if (x > mEdgeWidth + mLeftInset && x < (mDisplaySize.x - mEdgeWidth - mRightInset)) { diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java index 63595a5283..e2a9d1276c 100644 --- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java +++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java @@ -21,7 +21,7 @@ import com.android.quickstep.interaction.TutorialController.TutorialType; /** Shows the Home gesture interactive tutorial. */ public class HomeGestureTutorialFragment extends TutorialFragment { @Override - Integer getHandAnimationResId() { + int getHandAnimationResId() { return R.drawable.home_gesture; } diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java index d1b0a7088f..f897ecc01a 100644 --- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java +++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java @@ -250,12 +250,6 @@ public class NavBarGestureHandler implements OnTouchListener, return intercepted; } - boolean onInterceptTouch(MotionEvent event) { - return mAssistantLeftRegion.contains(event.getX(), event.getY()) - || mAssistantRightRegion.contains(event.getX(), event.getY()) - || event.getY() >= mDisplaySize.y - mBottomGestureHeight; - } - protected void onMotionPauseDetected() { VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC); } diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java index 93200bb21d..3357b70497 100644 --- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java +++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java @@ -21,7 +21,7 @@ import com.android.quickstep.interaction.TutorialController.TutorialType; /** Shows the Overview gesture interactive tutorial. */ public class OverviewGestureTutorialFragment extends TutorialFragment { @Override - Integer getHandAnimationResId() { + int getHandAnimationResId() { return R.drawable.overview_gesture; } diff --git a/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java b/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java deleted file mode 100644 index db1afc2012..0000000000 --- a/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java +++ /dev/null @@ -1,44 +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.interaction; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.widget.RelativeLayout; - -import androidx.fragment.app.FragmentManager; - -/** Root layout that TutorialFragment uses to intercept motion events. */ -public class RootSandboxLayout extends RelativeLayout { - public RootSandboxLayout(Context context) { - super(context); - } - - public RootSandboxLayout(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public RootSandboxLayout(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent motionEvent) { - return ((TutorialFragment) FragmentManager.findFragment(this)) - .onInterceptTouch(motionEvent); - } -} diff --git a/quickstep/src/com/android/quickstep/interaction/SandboxLauncherRenderer.java b/quickstep/src/com/android/quickstep/interaction/SandboxLauncherRenderer.java deleted file mode 100644 index 80ffe6609e..0000000000 --- a/quickstep/src/com/android/quickstep/interaction/SandboxLauncherRenderer.java +++ /dev/null @@ -1,44 +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.interaction; - -import android.content.Context; -import android.view.View; - -import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.graphics.LauncherPreviewRenderer; - -/** Renders a fake Launcher for use in the Sandbox. */ -class SandboxLauncherRenderer extends LauncherPreviewRenderer { - SandboxLauncherRenderer(Context context, InvariantDeviceProfile idp, boolean migrated) { - super(context, idp, migrated); - } - - @Override - public boolean shouldShowRealLauncherPreview() { - return false; - } - - @Override - public boolean shouldShowQsb() { - return false; - } - - @Override - public View.OnLongClickListener getWorkspaceChildOnLongClickListener() { - return null; - } -} diff --git a/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java deleted file mode 100644 index d54efc56e5..0000000000 --- a/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java +++ /dev/null @@ -1,102 +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.interaction; - -import android.graphics.PointF; -import android.view.View; - -import androidx.annotation.Nullable; - -import com.android.launcher3.R; -import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult; -import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult; - -/** A {@link TutorialController} for the Sandbox Mode. */ -public class SandboxModeTutorialController extends SwipeUpGestureTutorialController { - - SandboxModeTutorialController(SandboxModeTutorialFragment fragment, TutorialType tutorialType) { - super(fragment, tutorialType); - } - - @Nullable - @Override - Integer getTitleStringId() { - return R.string.sandbox_mode_title; - } - - @Nullable - @Override - Integer getSubtitleStringId() { - return R.string.sandbox_mode_subtitle; - } - - @Nullable - @Override - Integer getActionButtonStringId() { - return R.string.gesture_tutorial_action_button_label_done; - } - - @Override - void onActionButtonClicked(View button) { - mTutorialFragment.closeTutorial(); - } - - @Override - public void onBackGestureAttempted(BackGestureResult result) { - switch (result) { - case BACK_COMPLETED_FROM_LEFT: - case BACK_COMPLETED_FROM_RIGHT: - showRippleEffect(null); - showFeedback(R.string.sandbox_mode_back_gesture_feedback_successful); - break; - case BACK_CANCELLED_FROM_RIGHT: - showFeedback(R.string.back_gesture_feedback_cancelled_right_edge); - break; - case BACK_CANCELLED_FROM_LEFT: - showFeedback(R.string.back_gesture_feedback_cancelled_left_edge); - break; - case BACK_NOT_STARTED_TOO_FAR_FROM_EDGE: - showFeedback(R.string.sandbox_mode_back_gesture_feedback_swipe_too_far_from_edge); - break; - } - } - - @Override - public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) { - switch (result) { - case ASSISTANT_COMPLETED: - showRippleEffect(null); - showFeedback(R.string.sandbox_mode_assistant_gesture_feedback_successful); - break; - case HOME_GESTURE_COMPLETED: - animateFakeTaskViewHome(finalVelocity, () -> { - showFeedback(R.string.sandbox_mode_home_gesture_feedback_successful); - }); - break; - case OVERVIEW_GESTURE_COMPLETED: - fadeOutFakeTaskView(true, () -> { - showFeedback(R.string.sandbox_mode_overview_gesture_feedback_successful); - }); - break; - case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION: - case HOME_OR_OVERVIEW_CANCELLED: - case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE: - case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE: - showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge); - break; - } - } -} diff --git a/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java deleted file mode 100644 index 955a2f7d2e..0000000000 --- a/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java +++ /dev/null @@ -1,43 +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.interaction; - -import android.view.MotionEvent; -import android.view.View; - -import com.android.quickstep.interaction.TutorialController.TutorialType; - -/** Shows the general navigation gesture sandbox environment. */ -public class SandboxModeTutorialFragment extends TutorialFragment { - - @Override - TutorialController createController(TutorialType type) { - return new SandboxModeTutorialController(this, type); - } - - @Override - Class getControllerClass() { - return SandboxModeTutorialController.class; - } - - @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - if (motionEvent.getAction() == MotionEvent.ACTION_DOWN && mTutorialController != null) { - mTutorialController.setRippleHotspot(motionEvent.getX(), motionEvent.getY()); - } - return super.onTouch(view, motionEvent); - } -} diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java index 2198ade105..73f1f8cb8c 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java @@ -47,12 +47,11 @@ abstract class TutorialController implements BackGestureAttemptCallback, final TextView mTitleTextView; final TextView mSubtitleTextView; final TextView mFeedbackView; - final View mLauncherView; final ClipIconView mFakeIconView; final View mFakeTaskView; final View mRippleView; final RippleDrawable mRippleDrawable; - @Nullable final TutorialHandAnimation mHandCoachingAnimation; + final TutorialHandAnimation mHandCoachingAnimation; final ImageView mHandCoachingView; final Button mActionTextButton; final Button mActionButton; @@ -69,7 +68,6 @@ abstract class TutorialController implements BackGestureAttemptCallback, mTitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_title_view); mSubtitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_subtitle_view); mFeedbackView = rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_view); - mLauncherView = tutorialFragment.getLauncherView(); mFakeIconView = rootView.findViewById(R.id.gesture_tutorial_fake_icon_view); mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view); mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view); @@ -145,16 +143,13 @@ abstract class TutorialController implements BackGestureAttemptCallback, void onActionTextButtonClicked(View button) {} void showHandCoachingAnimation() { - if (isComplete() || mHandCoachingAnimation == null) { + if (isComplete()) { return; } mHandCoachingAnimation.startLoopedAnimation(mTutorialType); } void hideHandCoachingAnimation() { - if (mHandCoachingAnimation == null) { - return; - } mHandCoachingAnimation.stop(); mHandCoachingView.setVisibility(View.INVISIBLE); } @@ -167,10 +162,8 @@ abstract class TutorialController implements BackGestureAttemptCallback, if (isComplete()) { hideHandCoachingAnimation(); - mLauncherView.setVisibility(View.INVISIBLE); } else { showHandCoachingAnimation(); - mLauncherView.setVisibility(View.VISIBLE); } } @@ -213,8 +206,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, return mTutorialType == TutorialType.BACK_NAVIGATION_COMPLETE || mTutorialType == TutorialType.HOME_NAVIGATION_COMPLETE || mTutorialType == TutorialType.OVERVIEW_NAVIGATION_COMPLETE - || mTutorialType == TutorialType.ASSISTANT_COMPLETE - || mTutorialType == TutorialType.SANDBOX_MODE; + || mTutorialType == TutorialType.ASSISTANT_COMPLETE; } /** Denotes the type of the tutorial. */ @@ -227,7 +219,6 @@ abstract class TutorialController implements BackGestureAttemptCallback, OVERVIEW_NAVIGATION, OVERVIEW_NAVIGATION_COMPLETE, ASSISTANT, - ASSISTANT_COMPLETE, - SANDBOX_MODE + ASSISTANT_COMPLETE } } diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java index f297d5a835..9a8264d098 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java @@ -31,7 +31,6 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; -import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.R; import com.android.quickstep.interaction.TutorialController.TutorialType; @@ -43,10 +42,9 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { TutorialType mTutorialType; @Nullable TutorialController mTutorialController = null; View mRootView; - @Nullable TutorialHandAnimation mHandCoachingAnimation = null; + TutorialHandAnimation mHandCoachingAnimation; EdgeBackGestureHandler mEdgeBackGestureHandler; NavBarGestureHandler mNavBarGestureHandler; - private View mLauncherView; public static TutorialFragment newInstance(TutorialType tutorialType) { TutorialFragment fragment = getFragmentForTutorialType(tutorialType); @@ -76,17 +74,13 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { case ASSISTANT: case ASSISTANT_COMPLETE: return new AssistantGestureTutorialFragment(); - case SANDBOX_MODE: - return new SandboxModeTutorialFragment(); default: Log.e(LOG_TAG, "Failed to find an appropriate fragment for " + tutorialType.name()); } return null; } - @Nullable Integer getHandAnimationResId() { - return null; - } + abstract int getHandAnimationResId(); abstract TutorialController createController(TutorialType type); @@ -120,14 +114,8 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { return insets; }); mRootView.setOnTouchListener(this); - Integer handAnimationResId = getHandAnimationResId(); - if (handAnimationResId != null) { - mHandCoachingAnimation = - new TutorialHandAnimation(getContext(), mRootView, handAnimationResId); - } - InvariantDeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(getContext()); - mLauncherView = new SandboxLauncherRenderer(getContext(), dp, true).getRenderedView(); - ((ViewGroup) mRootView).addView(mLauncherView, 0); + mHandCoachingAnimation = new TutorialHandAnimation(getContext(), mRootView, + getHandAnimationResId()); return mRootView; } @@ -140,25 +128,16 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { @Override public void onPause() { super.onPause(); - - if (mHandCoachingAnimation != null) { - mHandCoachingAnimation.stop(); - } + mHandCoachingAnimation.stop(); } @Override public boolean onTouch(View view, MotionEvent motionEvent) { - // Note: Using logical-or to ensure both functions get called. + // Note: Using logical or to ensure both functions get called. return mEdgeBackGestureHandler.onTouch(view, motionEvent) | mNavBarGestureHandler.onTouch(view, motionEvent); } - boolean onInterceptTouch(MotionEvent motionEvent) { - // Note: Using logical-or to ensure both functions get called. - return mEdgeBackGestureHandler.onInterceptTouch(motionEvent) - | mNavBarGestureHandler.onInterceptTouch(motionEvent); - } - void onAttachedToWindow() { mEdgeBackGestureHandler.setViewGroupParent((ViewGroup) getRootView()); } @@ -189,11 +168,7 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { return mRootView; } - View getLauncherView() { - return mLauncherView; - } - - @Nullable TutorialHandAnimation getHandAnimation() { + TutorialHandAnimation getHandAnimation() { return mHandCoachingAnimation; } diff --git a/quickstep/src/com/android/quickstep/util/CancellableTask.java b/quickstep/src/com/android/quickstep/util/CancellableTask.java deleted file mode 100644 index a6e2e81589..0000000000 --- a/quickstep/src/com/android/quickstep/util/CancellableTask.java +++ /dev/null @@ -1,68 +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.util.Executors.MAIN_EXECUTOR; - -import androidx.annotation.UiThread; -import androidx.annotation.WorkerThread; - -/** - * Utility class to executore a task on background and post the result on UI thread - */ -public abstract class CancellableTask implements Runnable { - - private boolean mCancelled = false; - - @Override - public final void run() { - if (mCancelled) { - return; - } - T result = getResultOnBg(); - if (mCancelled) { - return; - } - MAIN_EXECUTOR.execute(() -> { - if (mCancelled) { - return; - } - handleResult(result); - }); - } - - /** - * Called on the worker thread to process the request. The return object is passed to - * {@link #handleResult(Object)} - */ - @WorkerThread - public abstract T getResultOnBg(); - - /** - * Called on the UI thread to handle the final result. - * @param result - */ - @UiThread - public abstract void handleResult(T result); - - /** - * Cancels the request. If it is called before {@link #handleResult(Object)}, that method - * will not be called - */ - public void cancel() { - mCancelled = true; - } -} diff --git a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java index 1031c5b080..4a298d3bad 100644 --- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java +++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java @@ -18,10 +18,8 @@ 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; @@ -112,7 +110,7 @@ public class OverviewToHomeAnim { boolean isLayoutNaturalToLauncher = recentsView.getPagedOrientationHandler() .isLayoutNaturalToLauncher(); config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, isLayoutNaturalToLauncher - ? clampToProgress(FAST_OUT_SLOW_IN, 0, 0.75f) : FINAL_FRAME); + ? DEACCEL : FINAL_FRAME); config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, FINAL_FRAME); config.setInterpolator(ANIM_OVERVIEW_SCALE, FINAL_FRAME); config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, INSTANT); diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java index de44e07bae..df9b0cf435 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java +++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java @@ -23,6 +23,7 @@ import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; +import static com.android.launcher3.logging.LoggerUtils.extractObjectNameAndAddress; import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS; @@ -71,7 +72,6 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre private static final String TAG = "RecentsOrientedState"; private static final boolean DEBUG = false; - private static final String DELIMITER_DOT = "\\."; private ContentObserver mSystemAutoRotateObserver = new ContentObserver(new Handler()) { @Override @@ -534,13 +534,4 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre ? idp.landscapeProfile : idp.portraitProfile; } - - /** - * String conversion for only the helpful parts of {@link Object#toString()} method - * @param stringToExtract "foo.bar.baz.MyObject@1234" - * @return "MyObject@1234" - */ - private static String extractObjectNameAndAddress(String stringToExtract) { - return stringToExtract.substring(stringToExtract.lastIndexOf(DELIMITER_DOT)); - } } diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java index 19c6588877..04308c80cb 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java +++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java @@ -21,8 +21,6 @@ import android.content.Context; import android.os.Handler; import com.android.launcher3.LauncherAnimationRunner; -import com.android.launcher3.LauncherAnimationRunner.AnimationResult; -import com.android.launcher3.WrappedAnimationRunnerImpl; import com.android.launcher3.WrappedLauncherAnimationRunner; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; @@ -30,17 +28,14 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; public abstract class RemoteAnimationProvider { - WrappedAnimationRunnerImpl mAnimationRunner; + LauncherAnimationRunner mAnimationRunner; public abstract AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, RemoteAnimationTargetCompat[] wallpaperTargets); ActivityOptions toActivityOptions(Handler handler, long duration, Context context) { - mAnimationRunner = new WrappedAnimationRunnerImpl() { - @Override - public Handler getHandler() { - return handler; - } + mAnimationRunner = new LauncherAnimationRunner(handler, + false /* startAtFrontOfQueue */) { @Override public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, @@ -50,6 +45,7 @@ public abstract class RemoteAnimationProvider { }; final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner( mAnimationRunner, false /* startAtFrontOfQueue */); + return ActivityOptionsCompat.makeRemoteAnimation( new RemoteAnimationAdapterCompat(wrapper, duration, 0)); } diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java index 3a54bd61aa..903e87a7f8 100644 --- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java +++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java @@ -278,6 +278,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { int start = mOrientationState.getOrientationHandler() .getPrimaryValue(mTaskRect.left, mTaskRect.top); mScrollState.screenCenter = start + mScrollState.scroll + mScrollState.halfPageSize; + mScrollState.pageParentScale = recentsViewScale.value; mScrollState.updateInterpolation(start); mCurveScale = TaskView.getCurveScaleForInterpolation(mScrollState.linearInterpolation); } @@ -296,9 +297,9 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { mMatrix.postTranslate(insets.left, insets.top); mMatrix.postScale(scale, scale); - // Apply TaskView matrix: scale, translate, scroll - mMatrix.postScale(mCurveScale, mCurveScale, taskWidth / 2, taskHeight / 2); + // Apply TaskView matrix: translate, scale, scroll mMatrix.postTranslate(mTaskRect.left, mTaskRect.top + mOffsetY); + mMatrix.postScale(mCurveScale, mCurveScale, taskWidth / 2, taskHeight / 2); mOrientationState.getOrientationHandler().set( mMatrix, MATRIX_POST_TRANSLATE, mScrollState.scroll); diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java index 95bde801bf..b06d4bc355 100644 --- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java +++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java @@ -42,6 +42,7 @@ import androidx.annotation.StringRes; import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; +import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.systemui.shared.recents.model.Task; import java.time.Duration; @@ -216,8 +217,8 @@ public final class DigitalWellBeingToast { view, 0, 0, view.getWidth(), view.getHeight()); activity.startActivity(intent, options.toBundle()); - - // TODO: add WW logging on the app usage settings click. + activity.getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.Touch.TAP, + LauncherLogProto.ControlType.APP_USAGE_SETTINGS, view); } catch (ActivityNotFoundException e) { Log.e(TAG, "Failed to open app usage settings for task " + mTask.getTopComponent().getPackageName(), e); diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index 52a7466429..b338bd07ee 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -36,6 +36,7 @@ import android.view.Surface; import android.widget.FrameLayout; import com.android.launcher3.BaseQuickstepLauncher; +import com.android.launcher3.Hotseat; import com.android.launcher3.LauncherState; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statemanager.StateManager.StateListener; @@ -176,8 +177,14 @@ public class LauncherRecentsView extends RecentsView @Override protected boolean shouldStealTouchFromSiblingsBelow(MotionEvent ev) { - return mActivity.getStateManager().getState().overviewUi - && super.shouldStealTouchFromSiblingsBelow(ev); + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + // Allow touches to go through to the hotseat. + Hotseat hotseat = mActivity.getHotseat(); + boolean touchingHotseat = hotseat.isShown() + && mActivity.getDragLayer().isEventOverView(hotseat, ev, this); + return !touchingHotseat; + } + return super.shouldStealTouchFromSiblingsBelow(ev); } @Override diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java index b8e07cb189..2a6c9e92db 100644 --- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java @@ -54,6 +54,7 @@ public class OverviewActionsView extends FrameLayo HIDDEN_UNSUPPORTED_NAVIGATION, HIDDEN_NON_ZERO_ROTATION, HIDDEN_NO_TASKS, + HIDDEN_GESTURE_RUNNING, HIDDEN_NO_RECENTS}) @Retention(RetentionPolicy.SOURCE) public @interface ActionsHiddenFlags { } @@ -61,7 +62,8 @@ public class OverviewActionsView extends FrameLayo public static final int HIDDEN_UNSUPPORTED_NAVIGATION = 1 << 0; public static final int HIDDEN_NON_ZERO_ROTATION = 1 << 1; public static final int HIDDEN_NO_TASKS = 1 << 2; - public static final int HIDDEN_NO_RECENTS = 1 << 3; + public static final int HIDDEN_GESTURE_RUNNING = 1 << 3; + public static final int HIDDEN_NO_RECENTS = 1 << 4; @IntDef(flag = true, value = { DISABLED_SCROLLING, diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 7a8e11df78..0362377399 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -35,14 +35,16 @@ import static com.android.launcher3.anim.Interpolators.ACCEL_2; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN; import static com.android.launcher3.statehandlers.DepthController.DEPTH; import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS; +import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.CLEAR_ALL_BUTTON; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW; import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId; +import static com.android.quickstep.views.OverviewActionsView.HIDDEN_GESTURE_RUNNING; import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION; import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_RECENTS; import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS; @@ -107,6 +109,7 @@ import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.touch.PagedOrientationHandler.CurveProperties; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.DynamicResource; import com.android.launcher3.util.MultiValueAlpha; @@ -115,7 +118,6 @@ import com.android.launcher3.util.ResourceBasedOverride.Overrides; import com.android.launcher3.util.Themes; import com.android.launcher3.util.ViewPool; import com.android.quickstep.BaseActivityInterface; -import com.android.quickstep.GestureState; import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.RecentsAnimationTargets; import com.android.quickstep.RecentsModel; @@ -1127,6 +1129,7 @@ public abstract class RecentsView extends PagedView setEnableDrawingLiveTile(false); setRunningTaskHidden(true); setRunningTaskIconScaledDown(true); + mActionsView.updateHiddenFlags(HIDDEN_GESTURE_RUNNING, true); } /** @@ -1180,14 +1183,7 @@ public abstract class RecentsView extends PagedView } /** - * Called when a gesture from an app has finished, and an end target has been determined. - */ - public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) { - - } - - /** - * Called when a gesture from an app has finished, and the animation to the target has ended. + * Called when a gesture from an app has finished. */ public void onGestureAnimationEnd() { if (mOrientationState.setGestureActive(false)) { @@ -1326,6 +1322,7 @@ public abstract class RecentsView extends PagedView } private void animateActionsViewIn() { + mActionsView.updateHiddenFlags(HIDDEN_GESTURE_RUNNING, false); ObjectAnimator anim = ObjectAnimator.ofFloat( mActionsView.getVisibilityAlpha(), MultiValueAlpha.VALUE, 0, 1); anim.setDuration(TaskView.SCALE_ICON_DURATION); @@ -1410,12 +1407,13 @@ public abstract class RecentsView extends PagedView * Updates linearInterpolation for the provided child position */ public void updateInterpolation(float childStart) { - float pageCenter = childStart + halfPageSize; + float scaledHalfPageSize = halfPageSize / pageParentScale; + float pageCenter = childStart + scaledHalfPageSize; float distanceFromScreenCenter = screenCenter - pageCenter; // How far the page has to move from the center to be offscreen, taking into account // the EDGE_SCALE_DOWN_FACTOR that will be applied at that position. float distanceToReachEdge = halfScreenSize - + halfPageSize * (1 - TaskView.EDGE_SCALE_DOWN_FACTOR); + + scaledHalfPageSize * (1 - TaskView.EDGE_SCALE_DOWN_FACTOR); linearInterpolation = Math.min(1, Math.abs(distanceFromScreenCenter) / distanceToReachEdge); } @@ -1461,7 +1459,7 @@ public abstract class RecentsView extends PagedView public PendingAnimation createTaskDismissAnimation(TaskView taskView, boolean animateTaskView, boolean shouldRemoveTask, long duration) { if (mPendingAnimation != null) { - mPendingAnimation.finish(false); + mPendingAnimation.finish(false, Touch.SWIPE); } PendingAnimation anim = new PendingAnimation(duration); @@ -1623,7 +1621,7 @@ public abstract class RecentsView extends PagedView protected void runDismissAnimation(PendingAnimation pendingAnim) { AnimatorPlaybackController controller = pendingAnim.createPlaybackController(); controller.dispatchOnStart(); - controller.setEndAction(() -> pendingAnim.finish(true)); + controller.setEndAction(() -> pendingAnim.finish(true, Touch.SWIPE)); controller.getAnimationPlayer().setInterpolator(FAST_OUT_SLOW_IN); controller.start(); } @@ -1636,7 +1634,7 @@ public abstract class RecentsView extends PagedView @SuppressWarnings("unused") private void dismissAllTasks(View view) { runDismissAnimation(createAllTasksDismissAnimation(DISMISS_TASK_DURATION)); - mActivity.getStatsLogManager().logger().log(LAUNCHER_TASK_CLEAR_ALL); + mActivity.getUserEventDispatcher().logActionOnControl(TAP, CLEAR_ALL_BUTTON); } private void dismissCurrentTask() { @@ -2161,12 +2159,7 @@ public abstract class RecentsView extends PagedView tv.notifyTaskLaunchFailed(TAG); } }; - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - finishRecentsAnimation(false /* toRecents */, null); - onLaunchResult.accept(true /* success */); - } else { - tv.launchTask(false, onLaunchResult, getHandler()); - } + tv.launchTask(false, onLaunchResult, getHandler()); Task task = tv.getTask(); if (task != null) { mActivity.getStatsLogManager().logger().withItemInfo(tv.getItemInfo()) diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java index 4aff7e3211..d47eba6408 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java @@ -16,7 +16,6 @@ package com.android.quickstep.views; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA; import android.animation.Animator; @@ -230,16 +229,7 @@ public class TaskMenuView extends AbstractFloatingView { menuOptionView.findViewById(R.id.icon), menuOptionView.findViewById(R.id.text)); LayoutParams lp = (LayoutParams) menuOptionView.getLayoutParams(); mTaskView.getPagedOrientationHandler().setLayoutParamsForTaskMenuOptionItem(lp); - menuOptionView.setOnClickListener(view -> { - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - RecentsView recentsView = mTaskView.getRecentsView(); - recentsView.switchToScreenshot(null, - () -> recentsView.finishRecentsAnimation(true /* toRecents */, - () -> menuOption.onClick(view))); - } else { - menuOption.onClick(view); - } - }); + menuOptionView.setOnClickListener(menuOption); mOptionLayout.addView(menuOptionView); } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 3d6d423077..321821b573 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -73,11 +73,15 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.PagedOrientationHandler; +import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.TransformingTouchDelegate; import com.android.launcher3.util.ViewPool.Reusable; @@ -86,7 +90,6 @@ import com.android.quickstep.TaskIconCache; import com.android.quickstep.TaskOverlayFactory; import com.android.quickstep.TaskThumbnailCache; import com.android.quickstep.TaskUtils; -import com.android.quickstep.util.CancellableTask; import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.util.TaskCornerRadius; import com.android.quickstep.views.RecentsView.PageCallbacks; @@ -186,8 +189,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private boolean mShowScreenshot; // The current background requests to load the task thumbnail and icon - private CancellableTask mThumbnailLoadRequest; - private CancellableTask mIconLoadRequest; + private TaskThumbnailCache.ThumbnailLoadRequest mThumbnailLoadRequest; + private TaskIconCache.IconLoadRequest mIconLoadRequest; // Order in which the footers appear. Lower order appear below higher order. public static final int INDEX_DIGITAL_WELLBEING_TOAST = 0; @@ -217,7 +220,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { if (isRunningTask()) { - // TODO: Replace this animation with createRecentsWindowAnimator createLaunchAnimationForRunningTask().start(); } else { launchTask(true /* animate */); @@ -363,7 +365,10 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { final PendingAnimation pendingAnimation = getRecentsView().createTaskLaunchAnimation( this, RECENTS_LAUNCH_DURATION, TOUCH_RESPONSE_INTERPOLATOR); AnimatorPlaybackController currentAnimation = pendingAnimation.createPlaybackController(); - currentAnimation.setEndAction(() -> pendingAnimation.finish(true)); + currentAnimation.setEndAction(() -> { + pendingAnimation.finish(true, Touch.SWIPE); + launchTask(false); + }); return currentAnimation; } @@ -386,6 +391,20 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { public void launchTask(boolean animate, boolean freezeTaskList, Consumer resultCallback, Handler resultCallbackHandler) { + if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { + if (isRunningTask()) { + getRecentsView().finishRecentsAnimation(false /* toRecents */, + () -> resultCallbackHandler.post(() -> resultCallback.accept(true))); + } else { + launchTaskInternal(animate, freezeTaskList, resultCallback, resultCallbackHandler); + } + } else { + launchTaskInternal(animate, freezeTaskList, resultCallback, resultCallbackHandler); + } + } + + private void launchTaskInternal(boolean animate, boolean freezeTaskList, + Consumer resultCallback, Handler resultCallbackHandler) { if (mTask != null) { final ActivityOptions opts; TestLogging.recordEvent( @@ -462,13 +481,15 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } } - private boolean showTaskMenu() { + private boolean showTaskMenu(int action) { if (!getRecentsView().isClearAllHidden()) { getRecentsView().snapToPage(getRecentsView().indexOfChild(this)); } else { mMenuView = TaskMenuView.showForTask(this); mActivity.getStatsLogManager().logger().withItemInfo(getItemInfo()) .log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS); + UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE, + LauncherLogProto.ItemType.TASK_ICON); if (mMenuView != null) { mMenuView.addOnAttachStateChangeListener(mTaskMenuStateListener); } @@ -479,10 +500,10 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private void setIcon(Drawable icon) { if (icon != null) { mIconView.setDrawable(icon); - mIconView.setOnClickListener(v -> showTaskMenu()); + mIconView.setOnClickListener(v -> showTaskMenu(Touch.TAP)); mIconView.setOnLongClickListener(v -> { requestDisallowInterceptTouchEvent(true); - return showTaskMenu(); + return showTaskMenu(Touch.LONGPRESS); }); } else { mIconView.setDrawable(null); diff --git a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java index 2a7da7eca8..ccfa3fc0fb 100644 --- a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java +++ b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java @@ -3,8 +3,6 @@ package com.android.quickstep; import static androidx.test.InstrumentationRegistry.getInstrumentation; import static com.android.launcher3.LauncherState.OVERVIEW; -import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT; -import static com.android.launcher3.util.rule.TestStabilityRule.UNBUNDLED_POSTSUBMIT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -13,12 +11,12 @@ import static org.junit.Assert.assertTrue; import android.app.PendingIntent; import android.app.usage.UsageStatsManager; import android.content.Intent; +import android.os.Build; import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; import com.android.launcher3.Launcher; -import com.android.launcher3.util.rule.TestStabilityRule; import com.android.quickstep.views.DigitalWellBeingToast; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; @@ -36,6 +34,9 @@ public class DigitalWellBeingToastTest extends AbstractQuickStepTest { @Test public void testToast() throws Exception { + // b/150303529 + if (Build.MODEL.contains("Cuttlefish")) return; + startAppFast(CALCULATOR_PACKAGE); final UsageStatsManager usageStatsManager = diff --git a/res/layout/search_result_icon_row.xml b/res/layout/search_result_icon_row.xml deleted file mode 100644 index 5ecc0c27b6..0000000000 --- a/res/layout/search_result_icon_row.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - \ No newline at end of file diff --git a/res/layout/search_result_shortcut.xml b/res/layout/search_result_shortcut.xml new file mode 100644 index 0000000000..c350c973da --- /dev/null +++ b/res/layout/search_result_shortcut.xml @@ -0,0 +1,42 @@ + + + + + + + + \ No newline at end of file diff --git a/res/layout/search_result_suggest.xml b/res/layout/search_result_suggest.xml deleted file mode 100644 index c5d96f03ea..0000000000 --- a/res/layout/search_result_suggest.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/res/layout/search_result_thumbnail.xml b/res/layout/search_result_thumbnail.xml deleted file mode 100644 index 0cc5a29f60..0000000000 --- a/res/layout/search_result_thumbnail.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - \ No newline at end of file diff --git a/res/values/config.xml b/res/values/config.xml index 46b8c23a62..325b62f9dc 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -59,6 +59,7 @@ true + diff --git a/robolectric_tests/src/com/android/launcher3/secondarydisplay/SDWorkModeTest.java b/robolectric_tests/src/com/android/launcher3/secondarydisplay/SDWorkModeTest.java index baae2a6a80..0ca5ce6f44 100644 --- a/robolectric_tests/src/com/android/launcher3/secondarydisplay/SDWorkModeTest.java +++ b/robolectric_tests/src/com/android/launcher3/secondarydisplay/SDWorkModeTest.java @@ -21,6 +21,7 @@ import static com.android.launcher3.util.Preconditions.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import android.content.Context; import android.os.UserManager; @@ -29,6 +30,8 @@ import android.provider.Settings; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.allapps.AllAppsPagedView; import com.android.launcher3.allapps.AllAppsRecyclerView; +import com.android.launcher3.logging.UserEventDispatcher; +import com.android.launcher3.shadows.ShadowOverrides; import com.android.launcher3.util.LauncherLayoutBuilder; import com.android.launcher3.util.LauncherModelHelper; @@ -66,6 +69,8 @@ public class SDWorkModeTest { mModelHelper = new LauncherModelHelper(); mTargetContext = RuntimeEnvironment.application; mIdp = InvariantDeviceProfile.INSTANCE.get(mTargetContext); + ShadowOverrides.setProvider(UserEventDispatcher.class, + c -> mock(UserEventDispatcher.class)); Settings.Global.putFloat(mTargetContext.getContentResolver(), Settings.Global.WINDOW_ANIMATION_SCALE, 0); diff --git a/robolectric_tests/src/com/android/launcher3/ui/LauncherUIScrollTest.java b/robolectric_tests/src/com/android/launcher3/ui/LauncherUIScrollTest.java index 957ae77eee..d330d10133 100644 --- a/robolectric_tests/src/com/android/launcher3/ui/LauncherUIScrollTest.java +++ b/robolectric_tests/src/com/android/launcher3/ui/LauncherUIScrollTest.java @@ -20,6 +20,7 @@ import static com.android.launcher3.util.LauncherUIHelper.doLayout; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.mockito.Mockito.mock; import android.content.Context; import android.os.SystemClock; @@ -35,6 +36,8 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.folder.FolderPagedView; +import com.android.launcher3.logging.UserEventDispatcher; +import com.android.launcher3.shadows.ShadowOverrides; import com.android.launcher3.util.LauncherLayoutBuilder; import com.android.launcher3.util.LauncherLayoutBuilder.FolderBuilder; import com.android.launcher3.util.LauncherModelHelper; @@ -67,6 +70,8 @@ public class LauncherUIScrollTest { mModelHelper = new LauncherModelHelper(); mTargetContext = RuntimeEnvironment.application; mIdp = InvariantDeviceProfile.INSTANCE.get(mTargetContext); + ShadowOverrides.setProvider(UserEventDispatcher.class, + c -> mock(UserEventDispatcher.class)); Settings.Global.putFloat(mTargetContext.getContentResolver(), Settings.Global.WINDOW_ANIMATION_SCALE, 0); diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java index 5e50e278f0..310c306f19 100644 --- a/src/com/android/launcher3/BaseActivity.java +++ b/src/com/android/launcher3/BaseActivity.java @@ -37,6 +37,8 @@ import androidx.annotation.IntDef; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.logging.StatsLogManager; +import com.android.launcher3.logging.UserEventDispatcher; +import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.ViewCache; import com.android.launcher3.views.ActivityContext; @@ -80,6 +82,7 @@ public abstract class BaseActivity extends Activity implements ActivityContext { new ArrayList<>(); protected DeviceProfile mDeviceProfile; + protected UserEventDispatcher mUserEventDispatcher; protected StatsLogManager mStatsLogManager; protected SystemUiController mSystemUiController; @@ -141,6 +144,8 @@ public abstract class BaseActivity extends Activity implements ActivityContext { return mDeviceProfile; } + public void modifyUserEvent(LauncherLogProto.LauncherEvent event) {} + public final StatsLogManager getStatsLogManager() { if (mStatsLogManager == null) { mStatsLogManager = StatsLogManager.newInstance(this); @@ -148,6 +153,13 @@ public abstract class BaseActivity extends Activity implements ActivityContext { return mStatsLogManager; } + public final UserEventDispatcher getUserEventDispatcher() { + if (mUserEventDispatcher == null) { + mUserEventDispatcher = UserEventDispatcher.newInstance(this); + } + return mUserEventDispatcher; + } + public SystemUiController getSystemUiController() { if (mSystemUiController == null) { mSystemUiController = new SystemUiController(getWindow()); diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 1e5a9e44d5..06bb263f23 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -23,7 +23,6 @@ import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; @@ -31,8 +30,6 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; -import android.graphics.PorterDuff.Mode; -import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -46,8 +43,6 @@ import android.view.View; import android.view.ViewDebug; import android.widget.TextView; -import androidx.core.graphics.ColorUtils; - import com.android.launcher3.Launcher.OnResumeCallback; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.dot.DotInfo; @@ -55,7 +50,6 @@ import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.graphics.IconShape; -import com.android.launcher3.graphics.PlaceHolderIconDrawable; import com.android.launcher3.graphics.PreloadIconDrawable; import com.android.launcher3.icons.DotRenderer; import com.android.launcher3.icons.IconCache.IconLoadRequest; @@ -65,7 +59,6 @@ import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.PackageItemInfo; import com.android.launcher3.model.data.PromiseAppInfo; -import com.android.launcher3.model.data.RemoteActionItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.SafeCloseable; import com.android.launcher3.views.ActivityContext; @@ -91,8 +84,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, private final PointF mTranslationForReorderBounce = new PointF(0, 0); private final PointF mTranslationForReorderPreview = new PointF(0, 0); - private static final int ICON_UPDATE_ANIMATION_DURATION = 375; - private float mScaleForReorderBounce = 1f; private static final Property DOT_SCALE_PROPERTY @@ -301,14 +292,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, verifyHighRes(); } - /** - * Apply label and tag using a {@link RemoteActionItemInfo} - */ - public void applyFromRemoteActionInfo(RemoteActionItemInfo remoteActionItemInfo) { - applyIconAndLabel(remoteActionItemInfo); - setTag(remoteActionItemInfo); - } - private void applyIconAndLabel(ItemInfoWithIcon info) { FastBitmapDrawable iconDrawable = newIcon(getContext(), info); mDotParams.color = IconPalette.getMutedColor(info.bitmap.color, 0.54f); @@ -653,14 +636,11 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, mDisableRelayout = mIcon != null; icon.setBounds(0, 0, mIconSize, mIconSize); - - updateIcon(icon); - - // If the current icon is a placeholder color, animate its update. - if (mIcon != null && mIcon instanceof PlaceHolderIconDrawable) { - animateIconUpdate((PlaceHolderIconDrawable) mIcon, icon); + if (mLayoutHorizontal) { + setCompoundDrawablesRelative(icon, null, null, null); + } else { + setCompoundDrawables(null, icon, null, null); } - mDisableRelayout = false; } @@ -690,8 +670,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, mActivity.invalidateParent(info); } else if (info instanceof PackageItemInfo) { applyFromItemInfoWithIcon((PackageItemInfo) info); - } else if (info instanceof RemoteActionItemInfo) { - applyFromRemoteActionInfo((RemoteActionItemInfo) info); } mDisableRelayout = false; @@ -798,33 +776,4 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, ((FastBitmapDrawable) mIcon).setScale(1f); } } - - private void updateIcon(Drawable newIcon) { - if (mLayoutHorizontal) { - setCompoundDrawablesRelative(newIcon, null, null, null); - } else { - setCompoundDrawables(null, newIcon, null, null); - } - } - - private static void animateIconUpdate(PlaceHolderIconDrawable oldIcon, Drawable newIcon) { - int placeholderColor = oldIcon.mPaint.getColor(); - int originalAlpha = Color.alpha(placeholderColor); - - ValueAnimator iconUpdateAnimation = ValueAnimator.ofInt(originalAlpha, 0); - iconUpdateAnimation.setDuration(ICON_UPDATE_ANIMATION_DURATION); - iconUpdateAnimation.addUpdateListener(valueAnimator -> { - int newAlpha = (int) valueAnimator.getAnimatedValue(); - int newColor = ColorUtils.setAlphaComponent(placeholderColor, newAlpha); - - newIcon.setColorFilter(new PorterDuffColorFilter(newColor, Mode.SRC_ATOP)); - }); - iconUpdateAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - newIcon.setColorFilter(null); - } - }); - iconUpdateAnimation.start(); - } } diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java index df005e6357..09827d664b 100644 --- a/src/com/android/launcher3/ButtonDropTarget.java +++ b/src/com/android/launcher3/ButtonDropTarget.java @@ -47,6 +47,7 @@ import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.Themes; import com.android.launcher3.util.Thunk; @@ -394,4 +395,6 @@ public abstract class ButtonDropTarget extends TextView TextUtils.TruncateAt.END); return !mText.equals(displayedText); } + + public abstract Target getDropTargetForLogging(); } diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 2809bd5a96..1cd201f99e 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -323,8 +323,11 @@ public class CellLayout extends ViewGroup { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - return mTouchHelper != null - || (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)); + if (mTouchHelper != null + || (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev))) { + return true; + } + return false; } public void enableHardwareLayer(boolean hasLayer) { diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java index cc119c9361..28574972ad 100644 --- a/src/com/android/launcher3/DeleteDropTarget.java +++ b/src/com/android/launcher3/DeleteDropTarget.java @@ -18,7 +18,8 @@ package com.android.launcher3; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_CANCEL; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_REMOVE; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNDO; +import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.UNDO; import android.content.Context; import android.text.TextUtils; @@ -27,19 +28,22 @@ import android.view.View; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.dragndrop.DragOptions; +import com.android.launcher3.logging.LoggerUtils; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.ModelWriter; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; +import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.views.Snackbar; public class DeleteDropTarget extends ButtonDropTarget { private final StatsLogManager mStatsLogManager; - private StatsLogManager.LauncherEvent mLauncherEvent; + private int mControlType = ControlType.DEFAULT_CONTROLTYPE; public DeleteDropTarget(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -111,8 +115,8 @@ public class DeleteDropTarget extends ButtonDropTarget { * Set mControlType depending on the drag item. */ private void setControlTypeBasedOnDragSource(ItemInfo item) { - mLauncherEvent = item.id != ItemInfo.NO_ID ? LAUNCHER_ITEM_DROPPED_ON_REMOVE - : LAUNCHER_ITEM_DROPPED_ON_CANCEL; + mControlType = item.id != ItemInfo.NO_ID ? ControlType.REMOVE_TARGET + : ControlType.CANCEL_TARGET; } @Override @@ -123,7 +127,8 @@ public class DeleteDropTarget extends ButtonDropTarget { } super.onDrop(d, options); mStatsLogManager.logger().withInstanceId(d.logInstanceId) - .log(mLauncherEvent); + .log(mControlType == ControlType.REMOVE_TARGET ? LAUNCHER_ITEM_DROPPED_ON_REMOVE + : LAUNCHER_ITEM_DROPPED_ON_CANCEL); } @Override @@ -136,7 +141,7 @@ public class DeleteDropTarget extends ButtonDropTarget { Runnable onUndoClicked = () -> { mLauncher.setPageToBindSynchronously(itemPage); modelWriter.abortDelete(); - mLauncher.getStatsLogManager().logger().log(LAUNCHER_UNDO); + mLauncher.getUserEventDispatcher().logActionOnControl(TAP, UNDO); }; Snackbar.show(mLauncher, R.string.item_removed, R.string.undo, modelWriter::commitDelete, onUndoClicked); @@ -156,4 +161,11 @@ public class DeleteDropTarget extends ButtonDropTarget { mLauncher.getDragLayer() .announceForAccessibility(getContext().getString(R.string.item_removed)); } + + @Override + public Target getDropTargetForLogging() { + Target t = LoggerUtils.newTarget(Target.Type.CONTROL); + t.controlType = mControlType; + return t; + } } diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java index 139d4a85e4..d3b86ded80 100644 --- a/src/com/android/launcher3/FastBitmapDrawable.java +++ b/src/com/android/launcher3/FastBitmapDrawable.java @@ -33,8 +33,6 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.Property; -import androidx.annotation.Nullable; - import com.android.launcher3.graphics.PlaceHolderIconDrawable; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; @@ -56,8 +54,6 @@ public class FastBitmapDrawable extends Drawable { protected Bitmap mBitmap; protected final int mIconColor; - @Nullable private ColorFilter mColorFilter; - private boolean mIsPressed; private boolean mIsDisabled; private float mDisabledAlpha = 1f; @@ -119,8 +115,7 @@ public class FastBitmapDrawable extends Drawable { @Override public void setColorFilter(ColorFilter cf) { - mColorFilter = cf; - updateFilter(); + // No op } @Override @@ -270,7 +265,7 @@ public class FastBitmapDrawable extends Drawable { * Updates the paint to reflect the current brightness and saturation. */ protected void updateFilter() { - mPaint.setColorFilter(mIsDisabled ? getDisabledColorFilter() : mColorFilter); + mPaint.setColorFilter(mIsDisabled ? getDisabledColorFilter() : null); invalidateSelf(); } diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 6547b53940..51f3819460 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -16,6 +16,8 @@ package com.android.launcher3; +import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; + import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; @@ -25,10 +27,14 @@ import android.view.ViewDebug; import android.view.ViewGroup; import android.widget.FrameLayout; -/** - * View class that represents the bottom row of the home screen. - */ -public class Hotseat extends CellLayout implements Insettable { +import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider; +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.launcher3.userevent.nano.LauncherLogProto.Target; + +import java.util.ArrayList; + +public class Hotseat extends CellLayout implements LogContainerProvider, Insettable { @ViewDebug.ExportedProperty(category = "launcher") private boolean mHasVerticalHotseat; @@ -72,6 +78,15 @@ public class Hotseat extends CellLayout implements Insettable { } } + @Override + public void fillInLogContainerData(ItemInfo childInfo, Target child, + ArrayList parents) { + child.rank = childInfo.rank; + child.gridX = childInfo.cellX; + child.gridY = childInfo.cellY; + parents.add(newContainerTarget(LauncherLogProto.ContainerType.HOTSEAT)); + } + @Override public void setInsets(Rect insets) { FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index ab8d7a5a69..4c5224b647 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -18,7 +18,6 @@ package com.android.launcher3; import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; -import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO; import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; @@ -37,10 +36,11 @@ import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.SPRING_LOADED; import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD; +import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONRESUME; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONSTOP; +import static com.android.launcher3.logging.StatsLogManager.containerTypeToAtomState; import static com.android.launcher3.model.ItemInstallQueue.FLAG_ACTIVITY_PAUSED; import static com.android.launcher3.model.ItemInstallQueue.FLAG_DRAG_AND_DROP; import static com.android.launcher3.model.ItemInstallQueue.FLAG_LOADER_RUNNING; @@ -70,7 +70,6 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.sqlite.SQLiteDatabase; -import android.graphics.Bitmap; import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; @@ -90,10 +89,9 @@ import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.WindowManager.LayoutParams; +import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.animation.OvershootInterpolator; -import android.widget.ImageView; import android.widget.Toast; import androidx.annotation.CallSuper; @@ -120,13 +118,13 @@ import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.folder.FolderGridOrganizer; import com.android.launcher3.folder.FolderIcon; -import com.android.launcher3.icons.BitmapRenderer; import com.android.launcher3.icons.IconCache; import com.android.launcher3.keyboard.CustomActionsPopup; import com.android.launcher3.keyboard.ViewGroupFocusHelper; import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logging.FileLog; import com.android.launcher3.logging.StatsLogManager; +import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.model.ModelUtils; @@ -154,6 +152,9 @@ import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.AllAppsSwipeController; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; +import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.ActivityResultInfo; import com.android.launcher3.util.ActivityTracker; import com.android.launcher3.util.ComponentKey; @@ -269,8 +270,6 @@ public class Launcher extends StatefulActivity implements Launche private static final int APPS_VIEW_ALPHA_CHANNEL_INDEX = 1; private static final int SCRIM_VIEW_ALPHA_CHANNEL_INDEX = 0; - private static final int THEME_CROSS_FADE_ANIMATION_DURATION = 375; - private LauncherAppTransitionManager mAppTransitionManager; private Configuration mOldConfig; @@ -402,7 +401,6 @@ public class Launcher extends StatefulActivity implements Launche inflateRootView(R.layout.launcher); setupViews(); - crossFadeWithPreviousAppearance(); mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots); mAppTransitionManager = LauncherAppTransitionManager.newInstance(this); @@ -479,7 +477,7 @@ public class Launcher extends StatefulActivity implements Launche () -> getStateManager().goToState(NORMAL)); if (Utilities.ATLEAST_R) { - getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING); + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); } mLifecycleRegistry = new LifecycleRegistry(this); @@ -557,6 +555,7 @@ public class Launcher extends StatefulActivity implements Launche } private void onIdpChanged(InvariantDeviceProfile idp) { + mUserEventDispatcher = null; initDeviceProfile(idp); dispatchDeviceProfileChanged(); @@ -912,7 +911,7 @@ public class Launcher extends StatefulActivity implements Launche mOverlayManager.onActivityStopped(this); } - logStopAndResume(false /* isResume */); + logStopAndResume(Action.Command.STOP); mAppWidgetHost.setListenIfResumed(false); NotificationListener.removeNotificationsChangedListener(); } @@ -934,7 +933,7 @@ public class Launcher extends StatefulActivity implements Launche @Override @CallSuper protected void onDeferredResumed() { - logStopAndResume(true /* isResume */); + logStopAndResume(Action.Command.RESUME); // Process any items that were added while Launcher was away. ItemInstallQueue.INSTANCE.get(this) @@ -951,28 +950,32 @@ public class Launcher extends StatefulActivity implements Launche protected void handlePendingActivityRequest() { } - private void logStopAndResume(boolean isResume) { + private void logStopAndResume(int command) { if (mPendingExecutor != null) return; int pageIndex = mWorkspace.isOverlayShown() ? -1 : mWorkspace.getCurrentPage(); - int statsLogOrdinal = mStateManager.getState().statsLogOrdinal; + int containerType = mStateManager.getState().containerType; StatsLogManager.EventEnum event; StatsLogManager.StatsLogger logger = getStatsLogManager().logger(); - if (isResume) { + if (command == Action.Command.RESUME) { logger.withSrcState(LAUNCHER_STATE_BACKGROUND) - .withDstState(mStateManager.getState().statsLogOrdinal); + .withDstState(containerTypeToAtomState(mStateManager.getState().containerType)); event = LAUNCHER_ONRESUME; } else { /* command == Action.Command.STOP */ - logger.withSrcState(mStateManager.getState().statsLogOrdinal) + logger.withSrcState(containerTypeToAtomState(mStateManager.getState().containerType)) .withDstState(LAUNCHER_STATE_BACKGROUND); event = LAUNCHER_ONSTOP; } - if (statsLogOrdinal == LAUNCHER_STATE_HOME && mWorkspace != null) { + if (containerType == ContainerType.WORKSPACE && mWorkspace != null) { + getUserEventDispatcher().logActionCommand(command, + containerType, -1, pageIndex); logger.withContainerInfo(LauncherAtom.ContainerInfo.newBuilder() .setWorkspace( LauncherAtom.WorkspaceContainer.newBuilder() .setPageIndex(pageIndex)).build()); + } else { + getUserEventDispatcher().logActionCommand(command, containerType, -1); } logger.log(event); } @@ -1362,18 +1365,6 @@ public class Launcher extends StatefulActivity implements Launche closeContextMenu(); } - @Override - public Object onRetainNonConfigurationInstance() { - int width = mDragLayer.getWidth(); - int height = mDragLayer.getHeight(); - - if (width <= 0 || height <= 0) { - return null; - } - - return BitmapRenderer.createHardwareBitmap(width, height, mDragLayer::draw); - } - public AllAppsTransitionController getAllAppsController() { return mAllAppsController; } @@ -1474,6 +1465,11 @@ public class Launcher extends StatefulActivity implements Launche } // Handle HOME_INTENT + UserEventDispatcher ued = getUserEventDispatcher(); + Target target = newContainerTarget(mStateManager.getState().containerType); + target.pageIndex = mWorkspace.getCurrentPage(); + ued.logActionCommand(Action.Command.HOME_INTENT, target, + newContainerTarget(ContainerType.WORKSPACE)); hideKeyboard(); if (mLauncherCallbacks != null) { @@ -2763,40 +2759,4 @@ public class Launcher extends StatefulActivity implements Launche void onLauncherResume(); } - - /** - * Cross-fades the launcher's updated appearance with its previous appearance. - * - * This method is used to cross-fade UI updates on activity creation, specifically dark mode - * updates. - */ - private void crossFadeWithPreviousAppearance() { - Bitmap previousAppearanceBitmap = (Bitmap) getLastNonConfigurationInstance(); - - if (previousAppearanceBitmap == null) { - return; - } - - ImageView crossFadeHelper = new ImageView(this); - - crossFadeHelper.setImageBitmap(previousAppearanceBitmap); - crossFadeHelper.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); - - InsettableFrameLayout.LayoutParams layoutParams = new InsettableFrameLayout.LayoutParams( - InsettableFrameLayout.LayoutParams.MATCH_PARENT, - InsettableFrameLayout.LayoutParams.MATCH_PARENT); - - layoutParams.ignoreInsets = true; - - crossFadeHelper.setLayoutParams(layoutParams); - - getRootView().addView(crossFadeHelper); - - crossFadeHelper - .animate() - .setDuration(THEME_CROSS_FADE_ANIMATION_DURATION) - .alpha(0f) - .withEndAction(() -> getRootView().removeView(crossFadeHelper)) - .start(); - } } diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index a4181c53c9..bfe327e40d 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -105,7 +105,7 @@ public class LauncherAppState { new Handler().post( () -> mInvariantDeviceProfile.verifyConfigChangedInBackground(context)); mInstallSessionTracker = InstallSessionHelper.INSTANCE.get(context) - .registerInstallTracker(mModel); + .registerInstallTracker(mModel, MODEL_EXECUTOR); // Register an observer to rebind the notification listener when dots are re-enabled. mNotificationDotsObserver = diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index eba0ac9633..b6bc500a58 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -16,7 +16,6 @@ package com.android.launcher3; import static com.android.launcher3.anim.Interpolators.ACCEL_2; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL; import static com.android.launcher3.testing.TestProtocol.BACKGROUND_APP_STATE_ORDINAL; import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL; @@ -36,6 +35,7 @@ import com.android.launcher3.states.SpringLoadedState; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.uioverrides.states.AllAppsState; import com.android.launcher3.uioverrides.states.OverviewState; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import java.util.Arrays; @@ -97,7 +97,7 @@ public abstract class LauncherState implements BaseState { * TODO: Create a separate class for NORMAL state. */ public static final LauncherState NORMAL = new LauncherState(NORMAL_STATE_ORDINAL, - LAUNCHER_STATE_HOME, + ContainerType.WORKSPACE, FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED | FLAG_HIDE_BACK_BUTTON | FLAG_HAS_SYS_UI_SCRIM) { @Override @@ -126,9 +126,9 @@ public abstract class LauncherState implements BaseState { public final int ordinal; /** - * Used for {@link com.android.launcher3.logging.StatsLogManager} + * Used for containerType in {@link com.android.launcher3.logging.UserEventDispatcher} */ - public final int statsLogOrdinal; + public final int containerType; /** * True if the state has overview panel visible. @@ -137,8 +137,8 @@ public abstract class LauncherState implements BaseState { private final int mFlags; - public LauncherState(int id, int statsLogOrdinal, int flags) { - this.statsLogOrdinal = statsLogOrdinal; + public LauncherState(int id, int containerType, int flags) { + this.containerType = containerType; this.mFlags = flags; this.overviewUi = (flags & FLAG_OVERVIEW_UI) != 0; this.ordinal = id; diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java index 92b88e6186..2df7f5ad20 100644 --- a/src/com/android/launcher3/SecondaryDropTarget.java +++ b/src/com/android/launcher3/SecondaryDropTarget.java @@ -37,11 +37,14 @@ import com.android.launcher3.Launcher.OnResumeCallback; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.logging.FileLog; +import com.android.launcher3.logging.LoggerUtils; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.StatsLogManager.StatsLogger; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.LauncherAppWidgetInfo; +import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; +import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.Themes; @@ -131,6 +134,19 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList return mCurrentAccessibilityAction; } + @Override + public Target getDropTargetForLogging() { + Target t = LoggerUtils.newTarget(Target.Type.CONTROL); + if (mCurrentAccessibilityAction == UNINSTALL) { + t.controlType = ControlType.UNINSTALL_TARGET; + } else if (mCurrentAccessibilityAction == DISMISS_PREDICTION) { + t.controlType = ControlType.DISMISS_PREDICTION; + } else { + t.controlType = ControlType.SETTINGS_BUTTON; + } + return t; + } + @Override protected boolean supportsDrop(ItemInfo info) { return supportsAccessibilityDrop(info, getViewUnderDrag(info)); diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java index 1bbbb2b59e..007e5f5370 100644 --- a/src/com/android/launcher3/SessionCommitReceiver.java +++ b/src/com/android/launcher3/SessionCommitReceiver.java @@ -25,11 +25,8 @@ import android.content.pm.PackageManager; import android.os.UserHandle; import android.text.TextUtils; -import androidx.annotation.WorkerThread; - import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.pm.InstallSessionHelper; -import com.android.launcher3.util.Executors; /** * BroadcastReceiver to handle session commit intent. @@ -41,11 +38,6 @@ public class SessionCommitReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - Executors.MODEL_EXECUTOR.execute(() -> processIntent(context, intent)); - } - - @WorkerThread - private static void processIntent(Context context, Intent intent) { if (!isEnabled(context)) { // User has decided to not add icons on homescreen. return; diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 43ccb7990c..dea2a8dfd2 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -133,10 +133,6 @@ public final class Utilities { public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET"; public static final String EXTRA_WALLPAPER_FLAVOR = "com.android.launcher3.WALLPAPER_FLAVOR"; - // An intent extra to indicate the launch source by launcher. - public static final String EXTRA_WALLPAPER_LAUNCH_SOURCE = - "com.android.wallpaper.LAUNCH_SOURCE"; - public static boolean IS_RUNNING_IN_TEST_HARNESS = ActivityManager.isRunningInTestHarness(); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 98328cf8af..45aaa1b673 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -85,6 +85,7 @@ import com.android.launcher3.icons.BitmapRenderer; import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.StatsLogManager.LauncherEvent; +import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; @@ -96,6 +97,8 @@ import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.WorkspaceTouchListener; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.Executors; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSparseArrayMap; @@ -1001,6 +1004,8 @@ public class Workspace extends PagedView public void onOverlayScrollChanged(float scroll) { if (Float.compare(scroll, 1f) == 0) { if (!mOverlayShown) { + mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE, + Action.Direction.LEFT, ContainerType.WORKSPACE, 0); mLauncher.getStatsLogManager().logger() .withSrcState(LAUNCHER_STATE_HOME) .withDstState(LAUNCHER_STATE_HOME) @@ -1015,16 +1020,20 @@ public class Workspace extends PagedView // Not announcing the overlay page for accessibility since it announces itself. } else if (Float.compare(scroll, 0f) == 0) { if (mOverlayShown) { - // TODO: this is logged unnecessarily on home gesture. - mLauncher.getStatsLogManager().logger() - .withSrcState(LAUNCHER_STATE_HOME) - .withDstState(LAUNCHER_STATE_HOME) - .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder() - .setWorkspace( - LauncherAtom.WorkspaceContainer.newBuilder() - .setPageIndex(-1)) - .build()) - .log(LAUNCHER_SWIPERIGHT); + UserEventDispatcher ued = mLauncher.getUserEventDispatcher(); + if (!ued.isPreviousHomeGesture()) { + mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE, + Action.Direction.RIGHT, ContainerType.WORKSPACE, -1); + mLauncher.getStatsLogManager().logger() + .withSrcState(LAUNCHER_STATE_HOME) + .withDstState(LAUNCHER_STATE_HOME) + .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder() + .setWorkspace( + LauncherAtom.WorkspaceContainer.newBuilder() + .setPageIndex(-1)) + .build()) + .log(LAUNCHER_SWIPERIGHT); + } } else if (Float.compare(mOverlayTranslation, 0f) != 0) { // When arriving to 0 overscroll from non-zero overscroll, announce page for // accessibility since default announcements were disabled while in overscroll @@ -1115,8 +1124,12 @@ public class Workspace extends PagedView protected void notifyPageSwitchListener(int prevPage) { super.notifyPageSwitchListener(prevPage); if (prevPage != mCurrentPage) { + int swipeDirection = (prevPage < mCurrentPage) + ? Action.Direction.RIGHT : Action.Direction.LEFT; StatsLogManager.EventEnum event = (prevPage < mCurrentPage) ? LAUNCHER_SWIPERIGHT : LAUNCHER_SWIPELEFT; + mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE, + swipeDirection, ContainerType.WORKSPACE, prevPage); mLauncher.getStatsLogManager().logger() .withSrcState(LAUNCHER_STATE_HOME) .withDstState(LAUNCHER_STATE_HOME) @@ -1162,6 +1175,13 @@ public class Workspace extends PagedView computeScrollHelper(false); } + @Override + protected void determineScrollingStart(MotionEvent ev, float touchSlopScale) { + if (!isSwitchingState()) { + super.determineScrollingStart(ev, touchSlopScale); + } + } + @Override public void announceForAccessibility(CharSequence text) { // Don't announce if apps is on top of us. diff --git a/src/com/android/launcher3/WorkspaceLayoutManager.java b/src/com/android/launcher3/WorkspaceLayoutManager.java index d6302ce580..ea887cc5eb 100644 --- a/src/com/android/launcher3/WorkspaceLayoutManager.java +++ b/src/com/android/launcher3/WorkspaceLayoutManager.java @@ -130,16 +130,12 @@ public interface WorkspaceLayoutManager { } child.setHapticFeedbackEnabled(false); - child.setOnLongClickListener(getWorkspaceChildOnLongClickListener()); + child.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE); if (child instanceof DropTarget) { onAddDropTarget((DropTarget) child); } } - default View.OnLongClickListener getWorkspaceChildOnLongClickListener() { - return ItemLongClickListener.INSTANCE_WORKSPACE; - } - Hotseat getHotseat(); CellLayout getScreenWithId(int screenId); diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java index 8bc8e53af3..d1340faf23 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -92,14 +92,10 @@ public class AllAppsGridAdapter extends public static final int VIEW_TYPE_SEARCH_SLICE = 1 << 9; - public static final int VIEW_TYPE_SEARCH_ICON_ROW = 1 << 10; + public static final int VIEW_TYPE_SEARCH_SHORTCUT = 1 << 10; public static final int VIEW_TYPE_SEARCH_PEOPLE = 1 << 11; - public static final int VIEW_TYPE_SEARCH_THUMBNAIL = 1 << 12; - - public static final int VIEW_TYPE_SEARCH_SUGGEST = 1 << 13; - // Common view type masks public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER; public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON; @@ -190,9 +186,7 @@ public class AllAppsGridAdapter extends || viewType == VIEW_TYPE_SEARCH_SLICE || viewType == VIEW_TYPE_SEARCH_ROW || viewType == VIEW_TYPE_SEARCH_PEOPLE - || viewType == VIEW_TYPE_SEARCH_THUMBNAIL - || viewType == VIEW_TYPE_SEARCH_ICON_ROW - || viewType == VIEW_TYPE_SEARCH_SUGGEST; + || viewType == VIEW_TYPE_SEARCH_SHORTCUT; } } @@ -203,7 +197,6 @@ public class AllAppsGridAdapter extends */ public static class AdapterItemWithPayload extends AdapterItem { private T mPayload; - private String mSearchSessionId; private AllAppsSearchPlugin mPlugin; private IntConsumer mSelectionHandler; @@ -225,14 +218,6 @@ public class AllAppsGridAdapter extends mSelectionHandler = runnable; } - public void setSearchSessionId(String searchSessionId) { - mSearchSessionId = searchSessionId; - } - - public String getSearchSessionId() { - return mSearchSessionId; - } - public IntConsumer getSelectionHandler() { return mSelectionHandler; } @@ -240,8 +225,6 @@ public class AllAppsGridAdapter extends public T getPayload() { return mPayload; } - - } /** @@ -324,21 +307,15 @@ public class AllAppsGridAdapter extends @Override public int getSpanSize(int position) { - int viewType = mApps.getAdapterItems().get(position).viewType; - if (isIconViewType(viewType)) { - return 1 * SPAN_MULTIPLIER; - } else if (viewType == VIEW_TYPE_SEARCH_THUMBNAIL) { - return mAppsPerRow; + if (isIconViewType(mApps.getAdapterItems().get(position).viewType)) { + return 1; } else { // Section breaks span the full width - return mAppsPerRow * SPAN_MULTIPLIER; + return mAppsPerRow; } } } - // multiplier to support adapter item column count that is not mAppsPerRow. - public static final int SPAN_MULTIPLIER = 3; - private final BaseDraggingActivity mLauncher; private final LayoutInflater mLayoutInflater; private final AlphabeticalAppsList mApps; @@ -375,7 +352,7 @@ public class AllAppsGridAdapter extends public void setAppsPerRow(int appsPerRow) { mAppsPerRow = appsPerRow; - mGridLayoutMgr.setSpanCount(mAppsPerRow * SPAN_MULTIPLIER); + mGridLayoutMgr.setSpanCount(mAppsPerRow); } /** @@ -461,18 +438,12 @@ public class AllAppsGridAdapter extends case VIEW_TYPE_SEARCH_SLICE: return new ViewHolder(mLayoutInflater.inflate( R.layout.search_result_slice, parent, false)); - case VIEW_TYPE_SEARCH_ICON_ROW: + case VIEW_TYPE_SEARCH_SHORTCUT: return new ViewHolder(mLayoutInflater.inflate( - R.layout.search_result_icon_row, parent, false)); + R.layout.search_result_shortcut, parent, false)); case VIEW_TYPE_SEARCH_PEOPLE: return new ViewHolder(mLayoutInflater.inflate( R.layout.search_result_people_item, parent, false)); - case VIEW_TYPE_SEARCH_THUMBNAIL: - return new ViewHolder(mLayoutInflater.inflate( - R.layout.search_result_thumbnail, parent, false)); - case VIEW_TYPE_SEARCH_SUGGEST: - return new ViewHolder(mLayoutInflater.inflate( - R.layout.search_result_suggest, parent, false)); default: throw new RuntimeException("Unexpected view type"); } @@ -493,27 +464,24 @@ public class AllAppsGridAdapter extends //TODO: replace with custom TopHitBubbleTextView with support for both shortcut // and apps if (adapterItem instanceof AdapterItemWithPayload) { - AdapterItemWithPayload item = (AdapterItemWithPayload) adapterItem; - item.setSelectionHandler(type -> { + AdapterItemWithPayload withPayload = (AdapterItemWithPayload) adapterItem; + IntConsumer selectionHandler = type -> { SearchTargetEvent e = new SearchTargetEvent(SearchTarget.ItemType.APP, - type, item.position, item.getSearchSessionId()); + type); e.bundle = HeroSearchResultView.getAppBundle(info); - if (item.getPlugin() != null) { - item.getPlugin().notifySearchTargetEvent(e); + if (withPayload.getPlugin() != null) { + withPayload.getPlugin().notifySearchTargetEvent(e); } - }); + }; icon.setOnClickListener(view -> { - item.getSelectionHandler().accept(SearchTargetEvent.SELECT); + selectionHandler.accept(SearchTargetEvent.SELECT); mOnIconClickListener.onClick(view); }); icon.setOnLongClickListener(view -> { - item.getSelectionHandler().accept(SearchTargetEvent.SELECT); + selectionHandler.accept(SearchTargetEvent.LONG_PRESS); return mOnIconLongClickListener.onLongClick(view); }); - } - else { - icon.setOnClickListener(mOnIconClickListener); - icon.setOnLongClickListener(mOnIconLongClickListener); + withPayload.setSelectionHandler(selectionHandler); } break; case VIEW_TYPE_EMPTY_SEARCH: @@ -532,22 +500,20 @@ public class AllAppsGridAdapter extends break; case VIEW_TYPE_SEARCH_SLICE: SliceView sliceView = (SliceView) holder.itemView; - AdapterItemWithPayload slicePayload = + AdapterItemWithPayload item = (AdapterItemWithPayload) mApps.getAdapterItems().get(position); sliceView.setOnSliceActionListener((info1, s) -> { - if (slicePayload.getPlugin() != null) { + if (item.getPlugin() != null) { SearchTargetEvent searchTargetEvent = new SearchTargetEvent( SearchTarget.ItemType.SETTINGS_SLICE, - SearchTargetEvent.CHILD_SELECT, slicePayload.position, - slicePayload.getSearchSessionId()); + SearchTargetEvent.CHILD_SELECT); searchTargetEvent.bundle = new Bundle(); - searchTargetEvent.bundle.putParcelable("uri", slicePayload.getPayload()); - slicePayload.getPlugin().notifySearchTargetEvent(searchTargetEvent); + searchTargetEvent.bundle.putParcelable("uri", item.getPayload()); + item.getPlugin().notifySearchTargetEvent(searchTargetEvent); } }); try { - LiveData liveData = SliceLiveData.fromUri(mLauncher, - slicePayload.getPayload()); + LiveData liveData = SliceLiveData.fromUri(mLauncher, item.getPayload()); liveData.observe((Launcher) mLauncher, sliceView); sliceView.setTag(liveData); } catch (Exception ignored) { @@ -557,14 +523,11 @@ public class AllAppsGridAdapter extends case VIEW_TYPE_SEARCH_ROW_WITH_BUTTON: case VIEW_TYPE_SEARCH_HERO_APP: case VIEW_TYPE_SEARCH_ROW: - case VIEW_TYPE_SEARCH_ICON_ROW: + case VIEW_TYPE_SEARCH_SHORTCUT: case VIEW_TYPE_SEARCH_PEOPLE: - case VIEW_TYPE_SEARCH_THUMBNAIL: - case VIEW_TYPE_SEARCH_SUGGEST: - AdapterItemWithPayload item = - (AdapterItemWithPayload) mApps.getAdapterItems().get(position); PayloadResultHandler payloadResultView = (PayloadResultHandler) holder.itemView; - payloadResultView.setup(item); + payloadResultView.applyAdapterInfo( + (AdapterItemWithPayload) mApps.getAdapterItems().get(position)); break; case VIEW_TYPE_ALL_APPS_DIVIDER: // nothing to do @@ -578,8 +541,8 @@ public class AllAppsGridAdapter extends if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) return; if (holder.itemView instanceof BubbleTextView) { BubbleTextView icon = (BubbleTextView) holder.itemView; - icon.setOnClickListener(null); - icon.setOnLongClickListener(null); + icon.setOnClickListener(mOnIconClickListener); + icon.setOnLongClickListener(mOnIconLongClickListener); } else if (holder.itemView instanceof SliceView) { SliceView sliceView = (SliceView) holder.itemView; sliceView.setOnSliceActionListener(null); @@ -590,6 +553,7 @@ public class AllAppsGridAdapter extends } } + @Override public boolean onFailedToRecycleView(ViewHolder holder) { // Always recycle and we will reset the view when it is bound diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java index 72b6d94192..13a93ff0cc 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -19,6 +19,8 @@ import static android.view.View.MeasureSpec.EXACTLY; import static android.view.View.MeasureSpec.UNSPECIFIED; import static android.view.View.MeasureSpec.makeMeasureSpec; +import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; + import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; @@ -36,6 +38,10 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsGridAdapter.AppsGridLayoutManager; +import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider; +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; +import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.views.RecyclerViewFastScroller; import java.util.ArrayList; @@ -44,7 +50,7 @@ import java.util.List; /** * A RecyclerView with custom fast scroll support for the all apps view. */ -public class AllAppsRecyclerView extends BaseRecyclerView { +public class AllAppsRecyclerView extends BaseRecyclerView implements LogContainerProvider { private AlphabeticalAppsList mApps; private final int mNumAppsPerRow; @@ -170,6 +176,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView { mAutoSizedOverlays.clear(); } + @Override + public void fillInLogContainerData(ItemInfo childInfo, Target child, + ArrayList parents) { + parents.add(newContainerTarget( + getApps().hasFilter() ? ContainerType.SEARCHRESULT : ContainerType.ALLAPPS)); + } + public void onSearchResultsChanged() { // Always scroll the view to the top so the user can see the changed results scrollToTop(); diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java index 0005db88c8..14595ca941 100644 --- a/src/com/android/launcher3/allapps/DiscoveryBounce.java +++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java @@ -18,6 +18,8 @@ package com.android.launcher3.allapps; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.HOTSEAT; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.PREDICTION; import android.animation.Animator; import android.animation.AnimatorInflater; @@ -118,10 +120,10 @@ public class DiscoveryBounce extends AbstractFloatingView { return (type & TYPE_DISCOVERY_BOUNCE) != 0; } - private void show() { + private void show(int containerType) { mIsOpen = true; mLauncher.getDragLayer().addView(this); - // TODO: add WW log for discovery bounce tip show event. + mLauncher.getUserEventDispatcher().logActionBounceTip(containerType); } public static void showForHomeIfNeeded(Launcher launcher) { @@ -144,7 +146,7 @@ public class DiscoveryBounce extends AbstractFloatingView { } onboardingPrefs.incrementEventCount(OnboardingPrefs.HOME_BOUNCE_COUNT); - new DiscoveryBounce(launcher, 0).show(); + new DiscoveryBounce(launcher, 0).show(HOTSEAT); } public static void showForOverviewIfNeeded(Launcher launcher, @@ -177,7 +179,7 @@ public class DiscoveryBounce extends AbstractFloatingView { onboardingPrefs.incrementEventCount(OnboardingPrefs.SHELF_BOUNCE_COUNT); new DiscoveryBounce(launcher, (1 - OVERVIEW.getVerticalProgress(launcher))) - .show(); + .show(PREDICTION); } /** diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java index d7fa5bc479..3320189a1d 100644 --- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java +++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java @@ -35,8 +35,6 @@ import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.PackageManagerHelper; import com.android.systemui.plugins.AllAppsSearchPlugin; -import com.android.systemui.plugins.shared.SearchTarget; -import com.android.systemui.plugins.shared.SearchTargetEvent; import java.util.ArrayList; import java.util.List; @@ -215,44 +213,6 @@ public class AllAppsSearchBarController /** * Updates View using Adapter's payload */ - - default void setup(AdapterItemWithPayload adapterItemWithPayload) { - Object[] targetInfo = getTargetInfo(); - if (targetInfo != null) { - targetInfo[0] = adapterItemWithPayload.getSearchSessionId(); - targetInfo[1] = adapterItemWithPayload.position; - } - applyAdapterInfo(adapterItemWithPayload); - } - void applyAdapterInfo(AdapterItemWithPayload adapterItemWithPayload); - - /** - * Gets object created by {@link PayloadResultHandler#createTargetInfo()} - */ - Object[] getTargetInfo(); - - /** - * Creates a wrapper object to hold searchSessionId and item position - */ - default Object[] createTargetInfo() { - return new Object[2]; - } - - /** - * Generates a SearchTargetEvent object for a PayloadHandlerView - */ - default SearchTargetEvent getSearchTargetEvent(SearchTarget.ItemType itemType, - int eventType) { - Object[] targetInfo = getTargetInfo(); - if (targetInfo == null) return null; - - String searchSessionId = (String) targetInfo[0]; - int position = (int) targetInfo[1]; - return new SearchTargetEvent(itemType, eventType, - position, searchSessionId); - } } - - } \ No newline at end of file diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java index 6dd316ed60..53625756b8 100644 --- a/src/com/android/launcher3/anim/PendingAnimation.java +++ b/src/com/android/launcher3/anim/PendingAnimation.java @@ -73,9 +73,9 @@ public class PendingAnimation implements PropertySetter { addAnimationHoldersRecur(a, mDuration, springProperty, mAnimHolders); } - public void finish(boolean isSuccess) { + public void finish(boolean isSuccess, int logAction) { for (Consumer listeners : mEndListeners) { - listeners.accept(new EndState(isSuccess)); + listeners.accept(new EndState(isSuccess, logAction)); } mEndListeners.clear(); } @@ -164,7 +164,7 @@ public class PendingAnimation implements PropertySetter { /** * Add a listener of receiving the end state. - * Note that the listeners are called as a result of calling {@link #finish(boolean)} + * Note that the listeners are called as a result of calling {@link #finish(boolean, int)} * and not automatically */ public void addEndListener(Consumer listener) { @@ -173,9 +173,11 @@ public class PendingAnimation implements PropertySetter { public static class EndState { public boolean isSuccess; + public int logAction; - public EndState(boolean isSuccess) { + public EndState(boolean isSuccess, int logAction) { this.isSuccess = isSuccess; + this.logAction = logAction; } } } diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java index 42e247aa9b..2d625c5373 100644 --- a/src/com/android/launcher3/dragndrop/AddItemActivity.java +++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java @@ -16,11 +16,10 @@ package com.android.launcher3.dragndrop; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_EXTERNAL_ITEM_BACK; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_EXTERNAL_ITEM_CANCELLED; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_EXTERNAL_ITEM_DRAGGED; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_EXTERNAL_ITEM_START; +import static com.android.launcher3.logging.LoggerUtils.newCommandAction; +import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; +import static com.android.launcher3.logging.LoggerUtils.newItemTarget; +import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.annotation.TargetApi; @@ -50,10 +49,11 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetHost; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.R; -import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.pm.PinRequestHelper; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.views.BaseDragLayer; import com.android.launcher3.widget.PendingAddShortcutInfo; @@ -125,7 +125,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener // savedInstanceState is null when the activity is created the first time (i.e., avoids // duplicate logging during rotation) if (savedInstanceState == null) { - logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_START); + logCommand(Action.Command.ENTRY); } } @@ -178,7 +178,6 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener startActivity(homeIntent, ActivityOptions.makeCustomAnimation(this, 0, android.R.anim.fade_out) .toBundle()); - logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_DRAGGED); mFinishOnPause = true; return false; } @@ -241,7 +240,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener * Called when the cancel button is clicked. */ public void onCancelClick(View v) { - logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_CANCELLED); + logCommand(Action.Command.CANCEL); finish(); } @@ -251,7 +250,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener public void onPlaceAutomaticallyClick(View v) { if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) { ItemInstallQueue.INSTANCE.get(this).queueItem(mRequest.getShortcutInfo()); - logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY); + logCommand(Action.Command.CONFIRM); mRequest.accept(); finish(); return; @@ -275,13 +274,13 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener .queueItem(mRequest.getAppWidgetProviderInfo(this), widgetId); mWidgetOptions.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); mRequest.accept(mWidgetOptions); - logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY); + logCommand(Action.Command.CONFIRM); finish(); } @Override public void onBackPressed() { - logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_BACK); + logCommand(Action.Command.BACK); super.onBackPressed(); } @@ -321,7 +320,10 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener throw new UnsupportedOperationException(); } - private void logCommand(StatsLogManager.EventEnum command) { - getStatsLogManager().logger().log(command); + private void logCommand(int command) { + getUserEventDispatcher().dispatchUserEvent(newLauncherEvent( + newCommandAction(command), + newItemTarget(mWidgetCell.getWidgetView(), mInstantAppResolver), + newContainerTarget(ContainerType.PINITEM)), null); } } diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java index 1cfe6acf05..ef666f0acd 100644 --- a/src/com/android/launcher3/dragndrop/DragController.java +++ b/src/com/android/launcher3/dragndrop/DragController.java @@ -206,6 +206,7 @@ public class DragController implements DragDriver.EventListener, TouchController } handleMoveEvent(mLastTouch.x, mLastTouch.y); + mLauncher.getUserEventDispatcher().resetActionDurationMillis(); if (!mLauncher.isTouchInProgress() && options.simulatedDndStartPoint == null) { // If it is an internal drag and the touch is already complete, cancel immediately @@ -543,6 +544,7 @@ public class DragController implements DragDriver.EventListener, TouchController } } final View dropTargetAsView = dropTarget instanceof View ? (View) dropTarget : null; + mLauncher.getUserEventDispatcher().logDragNDrop(mDragObject, dropTargetAsView); dispatchDropComplete(dropTargetAsView, accepted); } diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index 63fa391d43..281598a48b 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -23,6 +23,7 @@ import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; import static com.android.launcher3.config.FeatureFlags.ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS; +import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_LABEL_UPDATED; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED; @@ -94,6 +95,7 @@ import com.android.launcher3.model.data.FolderInfo.FolderListener; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pageindicators.PageIndicatorDots; +import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.util.Executors; import com.android.launcher3.util.Thunk; import com.android.launcher3.views.ClipPathView; @@ -597,6 +599,15 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo * is played. */ private void animateOpen(List items, int pageNo) { + animateOpen(items, pageNo, false); + } + + /** + * Opens the user folder described by the specified tag. The opening of the folder + * is animated relative to the specified View. If the View is null, no animation + * is played. + */ + private void animateOpen(List items, int pageNo, boolean skipUserEventLog) { Folder openFolder = getOpen(mLauncher); if (openFolder != null && openFolder != this) { // Close any open folder before opening a folder. @@ -646,6 +657,14 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo mState = STATE_OPEN; announceAccessibilityChanges(); + if (!skipUserEventLog) { + mLauncher.getUserEventDispatcher().logActionOnItem( + LauncherLogProto.Action.Touch.TAP, + LauncherLogProto.Action.Direction.NONE, + LauncherLogProto.ItemType.FOLDER_ICON, mInfo.cellX, mInfo.cellY); + } + + mContent.setFocusOnFirstChild(); } }); @@ -1494,6 +1513,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo } statsLogger.log(LAUNCHER_FOLDER_LABEL_UPDATED); + logFolderLabelState(mFromLabelState, toLabelState); mFolderName.dispatchBackKey(); } } @@ -1624,7 +1644,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo return true; } } else { - // TODO: add ww log if need to gather tap outside to close folder + mLauncher.getUserEventDispatcher().logActionTapOutside( + newContainerTarget(LauncherLogProto.ContainerType.FOLDER)); close(true); return true; } @@ -1659,6 +1680,17 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo return mContent; } + /** + * Logs current folder label info. + * + * @deprecated This method is only used for log validation and soon will be removed. + */ + @Deprecated + public void logFolderLabelState(FromState fromState, ToState toState) { + mLauncher.getUserEventDispatcher() + .logLauncherEvent(mInfo.getFolderLabelStateLauncherEvent(fromState, toState)); + } + /** Returns the height of the current folder's bottom edge from the bottom of the screen. */ private int getHeightFromBottom() { DragLayer.LayoutParams layoutParams = (DragLayer.LayoutParams) getLayoutParams(); diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index 3296eed5ca..32d061cb42 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -478,6 +478,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel // event is assumed to be folder creation on the server side. .withEditText(newTitle.toString()) .log(LAUNCHER_FOLDER_AUTO_LABELED); + mFolder.logFolderLabelState(fromState, ToState.TO_SUGGESTION0); } diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index effb3a4a0c..cd84c96171 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -513,7 +513,8 @@ public class LauncherPreviewRenderer extends ContextThemeWrapper } // Setup search view - SearchUiManager searchUiManager = mRootView.findViewById(R.id.search_container_all_apps); + SearchUiManager searchUiManager = + mRootView.findViewById(R.id.search_container_all_apps); mRootView.findViewById(R.id.apps_view).setTranslationY( mDp.heightPx - searchUiManager.getScrollRangeDelta(mInsets)); ViewGroup searchView = (ViewGroup) searchUiManager; diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java new file mode 100644 index 0000000000..cd4f034e83 --- /dev/null +++ b/src/com/android/launcher3/logging/LoggerUtils.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.logging; + +import android.util.ArrayMap; +import android.util.SparseArray; +import android.view.View; + +import com.android.launcher3.ButtonDropTarget; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.model.data.AppInfo; +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.userevent.nano.LauncherLogExtensions.TargetExtension; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action; +import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType; +import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent; +import com.android.launcher3.userevent.nano.LauncherLogProto.Target; +import com.android.launcher3.util.InstantAppResolver; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; + +/** + * Helper methods for logging. + */ +public class LoggerUtils { + private static final ArrayMap> sNameCache = new ArrayMap<>(); + private static final String UNKNOWN = "UNKNOWN"; + private static final int DEFAULT_PREDICTED_RANK = 10000; + private static final String DELIMITER_DOT = "\\."; + + public static String getFieldName(int value, Class c) { + SparseArray cache; + synchronized (sNameCache) { + cache = sNameCache.get(c); + if (cache == null) { + cache = new SparseArray<>(); + for (Field f : c.getDeclaredFields()) { + if (f.getType() == int.class && Modifier.isStatic(f.getModifiers())) { + try { + f.setAccessible(true); + cache.put(f.getInt(null), f.getName()); + } catch (IllegalAccessException e) { + // Ignore + } + } + } + sNameCache.put(c, cache); + } + } + String result = cache.get(value); + return result != null ? result : UNKNOWN; + } + + public static Target newItemTarget(int itemType) { + Target t = newTarget(Target.Type.ITEM); + t.itemType = itemType; + return t; + } + + public static Target newItemTarget(View v, InstantAppResolver instantAppResolver) { + return (v != null) && (v.getTag() instanceof ItemInfo) + ? newItemTarget((ItemInfo) v.getTag(), instantAppResolver) + : newTarget(Target.Type.ITEM); + } + + public static Target newItemTarget(ItemInfo info, InstantAppResolver instantAppResolver) { + Target t = newTarget(Target.Type.ITEM); + switch (info.itemType) { + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: + t.itemType = (instantAppResolver != null && info instanceof AppInfo + && instantAppResolver.isInstantApp(((AppInfo) info))) + ? ItemType.WEB_APP + : ItemType.APP_ICON; + t.predictedRank = DEFAULT_PREDICTED_RANK; + break; + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: + t.itemType = ItemType.SHORTCUT; + t.predictedRank = DEFAULT_PREDICTED_RANK; + break; + case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: + t.itemType = ItemType.FOLDER_ICON; + break; + case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: + t.itemType = ItemType.WIDGET; + break; + case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: + t.itemType = ItemType.DEEPSHORTCUT; + t.predictedRank = DEFAULT_PREDICTED_RANK; + break; + } + return t; + } + + public static Target newDropTarget(View v) { + if (!(v instanceof ButtonDropTarget)) { + return newTarget(Target.Type.CONTAINER); + } + if (v instanceof ButtonDropTarget) { + return ((ButtonDropTarget) v).getDropTargetForLogging(); + } + return newTarget(Target.Type.CONTROL); + } + + public static Target newTarget(int targetType, TargetExtension extension) { + Target t = new Target(); + t.type = targetType; + t.extension = extension; + return t; + } + + public static Target newTarget(int targetType) { + Target t = new Target(); + t.type = targetType; + return t; + } + + public static Target newControlTarget(int controlType) { + Target t = newTarget(Target.Type.CONTROL); + t.controlType = controlType; + return t; + } + + public static Target newContainerTarget(int containerType) { + Target t = newTarget(Target.Type.CONTAINER); + t.containerType = containerType; + return t; + } + + public static Action newAction(int type) { + Action a = new Action(); + a.type = type; + return a; + } + + public static Action newCommandAction(int command) { + Action a = newAction(Action.Type.COMMAND); + a.command = command; + return a; + } + + public static Action newTouchAction(int touch) { + Action a = newAction(Action.Type.TOUCH); + a.touch = touch; + return a; + } + + public static LauncherEvent newLauncherEvent(Action action, Target... srcTargets) { + LauncherEvent event = new LauncherEvent(); + event.srcTarget = srcTargets; + event.action = action; + return event; + } + + /** + * Creates LauncherEvent using Action and ArrayList of Targets + */ + public static LauncherEvent newLauncherEvent(Action action, ArrayList targets) { + Target[] targetsArray = new Target[targets.size()]; + targets.toArray(targetsArray); + return newLauncherEvent(action, targetsArray); + } + + /** + * String conversion for only the helpful parts of {@link Object#toString()} method + * @param stringToExtract "foo.bar.baz.MyObject@1234" + * @return "MyObject@1234" + */ + public static String extractObjectNameAndAddress(String stringToExtract) { + String[] superStringParts = stringToExtract.split(DELIMITER_DOT); + if (superStringParts.length == 0) { + return ""; + } + return superStringParts[superStringParts.length - 1]; + } +} diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 2c5bf320ad..ec1c3ef779 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -27,6 +27,7 @@ import com.android.launcher3.logger.LauncherAtom.ContainerInfo; import com.android.launcher3.logger.LauncherAtom.FromState; import com.android.launcher3.logger.LauncherAtom.ToState; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.userevent.LauncherLogProto; import com.android.launcher3.util.ResourceBasedOverride; import java.util.List; @@ -50,22 +51,40 @@ public class StatsLogManager implements ResourceBasedOverride { public static final int LAUNCHER_STATE_UNCHANGED = 5; /** - * Returns event enum based on the two state transition information when swipe + * Returns proper launcher state enum for {@link StatsLogManager}(to be removed during + * UserEventDispatcher cleanup) + */ + public static int containerTypeToAtomState(int containerType) { + switch (containerType) { + case LauncherLogProto.ContainerType.ALLAPPS_VALUE: + return LAUNCHER_STATE_ALLAPPS; + case LauncherLogProto.ContainerType.OVERVIEW_VALUE: + return LAUNCHER_STATE_OVERVIEW; + case LauncherLogProto.ContainerType.WORKSPACE_VALUE: + return LAUNCHER_STATE_HOME; + case LauncherLogProto.ContainerType.APP_VALUE: + return LAUNCHER_STATE_BACKGROUND; + } + return LAUNCHER_STATE_UNSPECIFIED; + } + + /** + * Returns event enum based on the two {@link ContainerType} transition information when swipe * gesture happens(to be removed during UserEventDispatcher cleanup). */ - public static EventEnum getLauncherAtomEvent(int startState, - int targetState, EventEnum fallbackEvent) { - if (startState == LAUNCHER_STATE_HOME - && targetState == LAUNCHER_STATE_HOME) { + public static EventEnum getLauncherAtomEvent(int startContainerType, + int targetContainerType, EventEnum fallbackEvent) { + if (startContainerType == LauncherLogProto.ContainerType.WORKSPACE.getNumber() + && targetContainerType == LauncherLogProto.ContainerType.WORKSPACE.getNumber()) { return LAUNCHER_HOME_GESTURE; - } else if (startState != LAUNCHER_STATE_OVERVIEW - && targetState == LAUNCHER_STATE_OVERVIEW) { + } else if (startContainerType != LauncherLogProto.ContainerType.TASKSWITCHER.getNumber() + && targetContainerType == LauncherLogProto.ContainerType.TASKSWITCHER.getNumber()) { return LAUNCHER_OVERVIEW_GESTURE; - } else if (startState != LAUNCHER_STATE_ALLAPPS - && targetState == LAUNCHER_STATE_ALLAPPS) { + } else if (startContainerType != LauncherLogProto.ContainerType.ALLAPPS.getNumber() + && targetContainerType == LauncherLogProto.ContainerType.ALLAPPS.getNumber()) { return LAUNCHER_ALLAPPS_OPEN_UP; - } else if (startState == LAUNCHER_STATE_ALLAPPS - && targetState != LAUNCHER_STATE_ALLAPPS) { + } else if (startContainerType == LauncherLogProto.ContainerType.ALLAPPS.getNumber() + && targetContainerType != LauncherLogProto.ContainerType.ALLAPPS.getNumber()) { return LAUNCHER_ALLAPPS_CLOSE_DOWN; } return fallbackEvent; // TODO fix @@ -303,38 +322,7 @@ public class StatsLogManager implements ResourceBasedOverride { LAUNCHER_FOLDER_CONVERTED_TO_ICON(628), @UiEvent(doc = "A hotseat prediction item was pinned") - LAUNCHER_HOTSEAT_PREDICTION_PINNED(629), - - @UiEvent(doc = "Activity to add external item was started") - LAUNCHER_ADD_EXTERNAL_ITEM_START(641), - - @UiEvent(doc = "Activity to add external item was cancelled") - LAUNCHER_ADD_EXTERNAL_ITEM_CANCELLED(642), - - @UiEvent(doc = "Activity to add external item was backed out") - LAUNCHER_ADD_EXTERNAL_ITEM_BACK(643), - - @UiEvent(doc = "Item was placed automatically in external item addition flow") - LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY(644), - - @UiEvent(doc = "Item was dragged in external item addition flow") - LAUNCHER_ADD_EXTERNAL_ITEM_DRAGGED(645), - - @UiEvent(doc = "Undo event was tapped.") - LAUNCHER_UNDO(648), - - @UiEvent(doc = "Task switcher clear all target was tapped.") - LAUNCHER_TASK_CLEAR_ALL(649), - - @UiEvent(doc = "Task preview was long pressed.") - LAUNCHER_TASK_PREVIEW_LONGPRESS(650), - - @UiEvent(doc = "User swiped down on workspace (triggering noti shade to open).") - LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN(651), - - @UiEvent(doc = "Notification dismissed by swiping right.") - LAUNCHER_NOTIFICATION_DISMISSED(652), - ; + LAUNCHER_HOTSEAT_PREDICTION_PINNED(629); // ADD MORE diff --git a/src/com/android/launcher3/logging/StatsLogUtils.java b/src/com/android/launcher3/logging/StatsLogUtils.java new file mode 100644 index 0000000000..a5cc7ea305 --- /dev/null +++ b/src/com/android/launcher3/logging/StatsLogUtils.java @@ -0,0 +1,49 @@ +package com.android.launcher3.logging; + +import android.view.View; +import android.view.ViewParent; + +import androidx.annotation.Nullable; + +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.userevent.nano.LauncherLogProto.Target; + +import java.util.ArrayList; + +public class StatsLogUtils { + private final static int MAXIMUM_VIEW_HIERARCHY_LEVEL = 5; + + /** + * Implemented by containers to provide a container source for a given child. + */ + public interface LogContainerProvider { + + /** + * Populates parent container targets for an item + */ + void fillInLogContainerData(ItemInfo childInfo, Target child, ArrayList parents); + } + + /** + * Recursively finds the parent of the given child which implements IconLogInfoProvider + */ + public static LogContainerProvider getLaunchProviderRecursive(@Nullable View v) { + ViewParent parent; + if (v != null) { + parent = v.getParent(); + } else { + return null; + } + + // Optimization to only check up to 5 parents. + int count = MAXIMUM_VIEW_HIERARCHY_LEVEL; + while (parent != null && count-- > 0) { + if (parent instanceof LogContainerProvider) { + return (LogContainerProvider) parent; + } else { + parent = parent.getParent(); + } + } + return null; + } +} diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java new file mode 100644 index 0000000000..a40cc263db --- /dev/null +++ b/src/com/android/launcher3/logging/UserEventDispatcher.java @@ -0,0 +1,373 @@ +/* + * 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.logging; + +import static com.android.launcher3.logging.LoggerUtils.newAction; +import static com.android.launcher3.logging.LoggerUtils.newCommandAction; +import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; +import static com.android.launcher3.logging.LoggerUtils.newDropTarget; +import static com.android.launcher3.logging.LoggerUtils.newItemTarget; +import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent; +import static com.android.launcher3.logging.LoggerUtils.newTarget; +import static com.android.launcher3.logging.LoggerUtils.newTouchAction; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType; +import static com.android.launcher3.userevent.nano.LauncherLogProto.TipType; + +import static java.util.Optional.ofNullable; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.SystemClock; +import android.util.Log; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.launcher3.DropTarget; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider; +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.userevent.LauncherLogProto; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action; +import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent; +import com.android.launcher3.userevent.nano.LauncherLogProto.Target; +import com.android.launcher3.util.InstantAppResolver; +import com.android.launcher3.util.LogConfig; +import com.android.launcher3.util.ResourceBasedOverride; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.nano.InvalidProtocolBufferNanoException; +import com.google.protobuf.nano.MessageNano; + +import java.util.ArrayList; +import java.util.UUID; + +/** + * Manages the creation of {@link LauncherEvent}. + * To debug this class, execute following command before side loading a new apk. + *

+ * $ adb shell setprop log.tag.UserEvent VERBOSE + */ +public class UserEventDispatcher implements ResourceBasedOverride { + + private static final String TAG = "UserEvent"; + private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.USEREVENT); + private static final String UUID_STORAGE = "uuid"; + + /** + * A factory method for UserEventDispatcher + */ + public static UserEventDispatcher newInstance(Context context) { + SharedPreferences sharedPrefs = Utilities.getDevicePrefs(context); + String uuidStr = sharedPrefs.getString(UUID_STORAGE, null); + if (uuidStr == null) { + uuidStr = UUID.randomUUID().toString(); + sharedPrefs.edit().putString(UUID_STORAGE, uuidStr).apply(); + } + UserEventDispatcher ued = Overrides.getObject(UserEventDispatcher.class, + context.getApplicationContext(), R.string.user_event_dispatcher_class); + ued.mUuidStr = uuidStr; + ued.mInstantAppResolver = InstantAppResolver.newInstance(context); + return ued; + } + + + /** + * Fills in the container data on the given event if the given view is not null. + * + * @return whether container data was added. + */ + private boolean fillLogContainer(@Nullable View v, Target child, + @Nullable ArrayList targets) { + LogContainerProvider firstParent = StatsLogUtils.getLaunchProviderRecursive(v); + if (v == null || !(v.getTag() instanceof ItemInfo) || firstParent == null) { + return false; + } + final ItemInfo itemInfo = (ItemInfo) v.getTag(); + firstParent.fillInLogContainerData(itemInfo, child, targets); + return true; + } + + protected void onFillInLogContainerData(@NonNull ItemInfo itemInfo, @NonNull Target target, + @NonNull ArrayList targets) { + } + + private boolean mSessionStarted; + private long mElapsedContainerMillis; + private long mElapsedSessionMillis; + private long mActionDurationMillis; + private String mUuidStr; + protected InstantAppResolver mInstantAppResolver; + private boolean mAppOrTaskLaunch; + private boolean mPreviousHomeGesture; + + private void fillComponentInfo(Target target, ComponentName cn) { + if (cn != null) { + target.packageNameHash = (mUuidStr + cn.getPackageName()).hashCode(); + target.componentHash = (mUuidStr + cn.flattenToString()).hashCode(); + } + } + + public void logActionCommand(int command, int srcContainerType, int dstContainerType) { + logActionCommand(command, newContainerTarget(srcContainerType), + dstContainerType >= 0 ? newContainerTarget(dstContainerType) : null); + } + + public void logActionCommand(int command, int srcContainerType, int dstContainerType, + int pageIndex) { + Target srcTarget = newContainerTarget(srcContainerType); + srcTarget.pageIndex = pageIndex; + logActionCommand(command, srcTarget, + dstContainerType >= 0 ? newContainerTarget(dstContainerType) : null); + } + + public void logActionCommand(int command, Target srcTarget, Target dstTarget) { + LauncherEvent event = newLauncherEvent(newCommandAction(command), srcTarget); + if (command == Action.Command.STOP) { + if (mAppOrTaskLaunch || !mSessionStarted) { + mSessionStarted = false; + return; + } + } + + if (dstTarget != null) { + event.destTarget = new Target[1]; + event.destTarget[0] = dstTarget; + event.action.isStateChange = true; + } + dispatchUserEvent(event, null); + } + + public void logActionOnControl(int action, int controlType) { + logActionOnControl(action, controlType, null); + } + + public void logActionOnControl(int action, int controlType, int parentContainerType) { + logActionOnControl(action, controlType, null, parentContainerType); + } + + /** + * Logs control action with proper parent hierarchy + */ + public void logActionOnControl(int actionType, int controlType, + @Nullable View controlInContainer, int... parentTypes) { + Target control = newTarget(Target.Type.CONTROL); + control.controlType = controlType; + Action action = newAction(actionType); + + ArrayList targets = makeTargetsList(control); + if (controlInContainer != null) { + fillLogContainer(controlInContainer, control, targets); + } + for (int parentContainerType : parentTypes) { + if (parentContainerType < 0) continue; + targets.add(newContainerTarget(parentContainerType)); + } + LauncherEvent event = newLauncherEvent(action, targets); + if (actionType == Action.Touch.DRAGDROP) { + event.actionDurationMillis = SystemClock.uptimeMillis() - mActionDurationMillis; + } + dispatchUserEvent(event, null); + } + + public void logActionTapOutside(Target target) { + LauncherEvent event = newLauncherEvent(newTouchAction(Action.Type.TOUCH), + target); + event.action.isOutside = true; + dispatchUserEvent(event, null); + } + + public void logActionBounceTip(int containerType) { + LauncherEvent event = newLauncherEvent(newAction(Action.Type.TIP), + newContainerTarget(containerType)); + event.srcTarget[0].tipType = TipType.BOUNCE; + dispatchUserEvent(event, null); + } + + public void logActionOnContainer(int action, int dir, int containerType) { + logActionOnContainer(action, dir, containerType, 0); + } + + public void logActionOnContainer(int action, int dir, int containerType, int pageIndex) { + LauncherEvent event = newLauncherEvent(newTouchAction(action), + newContainerTarget(containerType)); + event.action.dir = dir; + event.srcTarget[0].pageIndex = pageIndex; + dispatchUserEvent(event, null); + } + + /** + * Used primarily for swipe up and down when state changes when swipe up happens from the + * navbar bezel, the {@param srcChildContainerType} is NAVBAR and + * {@param srcParentContainerType} is either one of the two + * (1) WORKSPACE: if the launcher is the foreground activity + * (2) APP: if another app was the foreground activity + */ + public void logStateChangeAction(int action, int dir, int downX, int downY, + int srcChildTargetType, int srcParentContainerType, int dstContainerType, + int pageIndex) { + LauncherEvent event; + if (srcChildTargetType == ItemType.TASK) { + event = newLauncherEvent(newTouchAction(action), + newItemTarget(srcChildTargetType), + newContainerTarget(srcParentContainerType)); + } else { + event = newLauncherEvent(newTouchAction(action), + newContainerTarget(srcChildTargetType), + newContainerTarget(srcParentContainerType)); + } + event.destTarget = new Target[1]; + event.destTarget[0] = newContainerTarget(dstContainerType); + event.action.dir = dir; + event.action.isStateChange = true; + event.srcTarget[0].pageIndex = pageIndex; + event.srcTarget[0].spanX = downX; + event.srcTarget[0].spanY = downY; + dispatchUserEvent(event, null); + } + + public void logActionOnItem(int action, int dir, int itemType) { + logActionOnItem(action, dir, itemType, null, null); + } + + /** + * Creates new {@link LauncherEvent} of ITEM target type with input arguments and dispatches it. + * + * @param touchAction ENUM value of {@link LauncherLogProto.Action.Touch} Action + * @param dir ENUM value of {@link LauncherLogProto.Action.Direction} Action + * @param itemType ENUM value of {@link LauncherLogProto.ItemType} + * @param gridX Nullable X coordinate of item's position on the workspace grid + * @param gridY Nullable Y coordinate of item's position on the workspace grid + */ + public void logActionOnItem(int touchAction, int dir, int itemType, + @Nullable Integer gridX, @Nullable Integer gridY) { + Target itemTarget = newTarget(Target.Type.ITEM); + itemTarget.itemType = itemType; + ofNullable(gridX).ifPresent(value -> itemTarget.gridX = value); + ofNullable(gridY).ifPresent(value -> itemTarget.gridY = value); + LauncherEvent event = newLauncherEvent(newTouchAction(touchAction), itemTarget); + event.action.dir = dir; + dispatchUserEvent(event, null); + } + + /** + * Logs proto lite version of LauncherEvent object to clearcut. + */ + public void logLauncherEvent( + com.android.launcher3.userevent.LauncherLogProto.LauncherEvent launcherEvent) { + + if (mPreviousHomeGesture) { + mPreviousHomeGesture = false; + } + mAppOrTaskLaunch = false; + launcherEvent.toBuilder() + .setElapsedContainerMillis(SystemClock.uptimeMillis() - mElapsedContainerMillis) + .setElapsedSessionMillis( + SystemClock.uptimeMillis() - mElapsedSessionMillis).build(); + try { + dispatchUserEvent(LauncherEvent.parseFrom(launcherEvent.toByteArray()), null); + } catch (InvalidProtocolBufferNanoException e) { + throw new RuntimeException("Cannot convert LauncherEvent from Lite to Nano version."); + } + } + + public void logDeepShortcutsOpen(View icon) { + ItemInfo info = (ItemInfo) icon.getTag(); + Target child = newItemTarget(info, mInstantAppResolver); + ArrayList targets = makeTargetsList(child); + fillLogContainer(icon, child, targets); + dispatchUserEvent(newLauncherEvent(newTouchAction(Action.Touch.TAP), targets), null); + } + + public void logDragNDrop(DropTarget.DragObject dragObj, View dropTargetAsView) { + Target srcChild = newItemTarget(dragObj.originalDragInfo, mInstantAppResolver); + ArrayList srcTargets = makeTargetsList(srcChild); + + + Target destChild = newItemTarget(dragObj.originalDragInfo, mInstantAppResolver); + ArrayList destTargets = makeTargetsList(destChild); + + //dragObj.dragSource.fillInLogContainerData(dragObj.originalDragInfo, srcChild, srcTargets); + if (dropTargetAsView instanceof LogContainerProvider) { + ((LogContainerProvider) dropTargetAsView).fillInLogContainerData(dragObj.dragInfo, + destChild, destTargets); + } + else { + destTargets.add(newDropTarget(dropTargetAsView)); + } + LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.DRAGDROP), srcTargets); + Target[] destTargetsArray = new Target[destTargets.size()]; + destTargets.toArray(destTargetsArray); + event.destTarget = destTargetsArray; + + event.actionDurationMillis = SystemClock.uptimeMillis() - mActionDurationMillis; + dispatchUserEvent(event, null); + } + + public final void startSession() { + mSessionStarted = true; + mElapsedSessionMillis = SystemClock.uptimeMillis(); + mElapsedContainerMillis = SystemClock.uptimeMillis(); + } + + public final void setPreviousHomeGesture(boolean homeGesture) { + mPreviousHomeGesture = homeGesture; + } + + public final boolean isPreviousHomeGesture() { + return mPreviousHomeGesture; + } + + public final void resetActionDurationMillis() { + mActionDurationMillis = SystemClock.uptimeMillis(); + } + + public void dispatchUserEvent(LauncherEvent ev, Intent intent) { + if (mPreviousHomeGesture) { + mPreviousHomeGesture = false; + } + mAppOrTaskLaunch = false; + ev.elapsedContainerMillis = SystemClock.uptimeMillis() - mElapsedContainerMillis; + ev.elapsedSessionMillis = SystemClock.uptimeMillis() - mElapsedSessionMillis; + if (!IS_VERBOSE) { + return; + } + LauncherLogProto.LauncherEvent liteLauncherEvent; + try { + liteLauncherEvent = + LauncherLogProto.LauncherEvent.parseFrom(MessageNano.toByteArray(ev)); + } catch (InvalidProtocolBufferException e) { + throw new RuntimeException("Cannot parse LauncherEvent from Nano to Lite version"); + } + Log.d(TAG, liteLauncherEvent.toString()); + } + + /** + * Constructs an ArrayList with targets + */ + public static ArrayList makeTargetsList(Target... targets) { + ArrayList result = new ArrayList<>(); + for (Target target : targets) { + result.add(target); + } + return result; + } +} diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java index 06a2c92dab..41ccbd7054 100644 --- a/src/com/android/launcher3/model/data/FolderInfo.java +++ b/src/com/android/launcher3/model/data/FolderInfo.java @@ -20,9 +20,15 @@ import static android.text.TextUtils.isEmpty; import static androidx.core.util.Preconditions.checkNotNull; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT; import static com.android.launcher3.logger.LauncherAtom.Attribute.EMPTY_LABEL; import static com.android.launcher3.logger.LauncherAtom.Attribute.MANUAL_LABEL; import static com.android.launcher3.logger.LauncherAtom.Attribute.SUGGESTED_LABEL; +import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_CUSTOM; +import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_EMPTY; +import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_FOLDER_LABEL_STATE_UNSPECIFIED; +import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_SUGGESTED; import android.os.Process; @@ -37,6 +43,10 @@ import com.android.launcher3.logger.LauncherAtom.Attribute; import com.android.launcher3.logger.LauncherAtom.FromState; import com.android.launcher3.logger.LauncherAtom.ToState; import com.android.launcher3.model.ModelWriter; +import com.android.launcher3.userevent.LauncherLogProto; +import com.android.launcher3.userevent.LauncherLogProto.Target; +import com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState; +import com.android.launcher3.userevent.LauncherLogProto.Target.ToFolderLabelState; import com.android.launcher3.util.ContentWriter; import java.util.ArrayList; @@ -349,4 +359,113 @@ public class FolderInfo extends ItemInfo { } return LauncherAtom.ToState.TO_STATE_UNSPECIFIED; } + + /** + * Returns {@link LauncherLogProto.LauncherEvent} to log current folder label info. + * + * @deprecated This method is used only for validation purpose and soon will be removed. + */ + @Deprecated + public LauncherLogProto.LauncherEvent getFolderLabelStateLauncherEvent(FromState fromState, + ToState toState) { + return LauncherLogProto.LauncherEvent.newBuilder() + .setAction(LauncherLogProto.Action + .newBuilder() + .setType(LauncherLogProto.Action.Type.SOFT_KEYBOARD)) + .addSrcTarget(Target + .newBuilder() + .setType(Target.Type.ITEM) + .setItemType(LauncherLogProto.ItemType.EDITTEXT) + .setFromFolderLabelState(convertFolderLabelState(fromState)) + .setToFolderLabelState(convertFolderLabelState(toState))) + .addSrcTarget(Target.newBuilder() + .setType(Target.Type.CONTAINER) + .setContainerType(LauncherLogProto.ContainerType.FOLDER) + .setPageIndex(screenId) + .setGridX(cellX) + .setGridY(cellY) + .setCardinality(contents.size())) + .addSrcTarget(newParentContainerTarget()) + .build(); + } + + /** + * @deprecated This method is used only for validation purpose and soon will be removed. + */ + @Deprecated + private Target.Builder newParentContainerTarget() { + Target.Builder builder = Target.newBuilder().setType(Target.Type.CONTAINER); + switch (container) { + case CONTAINER_HOTSEAT: + return builder.setContainerType(LauncherLogProto.ContainerType.HOTSEAT); + case CONTAINER_DESKTOP: + return builder.setContainerType(LauncherLogProto.ContainerType.WORKSPACE); + default: + throw new AssertionError(String + .format("Expected container to be either %s or %s but found %s.", + CONTAINER_HOTSEAT, + CONTAINER_DESKTOP, + container)); + } + } + + /** + * @deprecated This method is used only for validation purpose and soon will be removed. + */ + @Deprecated + private static FromFolderLabelState convertFolderLabelState(FromState fromState) { + switch (fromState) { + case FROM_EMPTY: + return FROM_EMPTY; + case FROM_SUGGESTED: + return FROM_SUGGESTED; + case FROM_CUSTOM: + return FROM_CUSTOM; + default: + return FROM_FOLDER_LABEL_STATE_UNSPECIFIED; + } + } + + /** + * @deprecated This method is used only for validation purpose and soon will be removed. + */ + @Deprecated + private static ToFolderLabelState convertFolderLabelState(ToState toState) { + switch (toState) { + case UNCHANGED: + return ToFolderLabelState.UNCHANGED; + case TO_SUGGESTION0: + return ToFolderLabelState.TO_SUGGESTION0_WITH_VALID_PRIMARY; + case TO_SUGGESTION1_WITH_VALID_PRIMARY: + return ToFolderLabelState.TO_SUGGESTION1_WITH_VALID_PRIMARY; + case TO_SUGGESTION1_WITH_EMPTY_PRIMARY: + return ToFolderLabelState.TO_SUGGESTION1_WITH_EMPTY_PRIMARY; + case TO_SUGGESTION2_WITH_VALID_PRIMARY: + return ToFolderLabelState.TO_SUGGESTION2_WITH_VALID_PRIMARY; + case TO_SUGGESTION2_WITH_EMPTY_PRIMARY: + return ToFolderLabelState.TO_SUGGESTION2_WITH_EMPTY_PRIMARY; + case TO_SUGGESTION3_WITH_VALID_PRIMARY: + return ToFolderLabelState.TO_SUGGESTION3_WITH_VALID_PRIMARY; + case TO_SUGGESTION3_WITH_EMPTY_PRIMARY: + return ToFolderLabelState.TO_SUGGESTION3_WITH_EMPTY_PRIMARY; + case TO_EMPTY_WITH_VALID_PRIMARY: + return ToFolderLabelState.TO_EMPTY_WITH_VALID_PRIMARY; + case TO_EMPTY_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY: + return ToFolderLabelState.TO_EMPTY_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY; + case TO_EMPTY_WITH_EMPTY_SUGGESTIONS: + return ToFolderLabelState.TO_EMPTY_WITH_EMPTY_SUGGESTIONS; + case TO_EMPTY_WITH_SUGGESTIONS_DISABLED: + return ToFolderLabelState.TO_EMPTY_WITH_SUGGESTIONS_DISABLED; + case TO_CUSTOM_WITH_VALID_PRIMARY: + return ToFolderLabelState.TO_CUSTOM_WITH_VALID_PRIMARY; + case TO_CUSTOM_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY: + return ToFolderLabelState.TO_CUSTOM_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY; + case TO_CUSTOM_WITH_EMPTY_SUGGESTIONS: + return ToFolderLabelState.TO_CUSTOM_WITH_EMPTY_SUGGESTIONS; + case TO_CUSTOM_WITH_SUGGESTIONS_DISABLED: + return ToFolderLabelState.TO_CUSTOM_WITH_SUGGESTIONS_DISABLED; + default: + return ToFolderLabelState.TO_FOLDER_LABEL_STATE_UNSPECIFIED; + } + } } diff --git a/src/com/android/launcher3/model/data/RemoteActionItemInfo.java b/src/com/android/launcher3/model/data/RemoteActionItemInfo.java deleted file mode 100644 index 81f7f3a0a2..0000000000 --- a/src/com/android/launcher3/model/data/RemoteActionItemInfo.java +++ /dev/null @@ -1,64 +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.model.data; - -import android.app.RemoteAction; -import android.os.Process; - -/** - * Represents a launchable {@link RemoteAction} - */ -public class RemoteActionItemInfo extends ItemInfoWithIcon { - - private final RemoteAction mRemoteAction; - private final String mToken; - private final boolean mShouldStart; - - public RemoteActionItemInfo(RemoteAction remoteAction, String token, boolean shouldStart) { - mShouldStart = shouldStart; - mToken = token; - mRemoteAction = remoteAction; - title = remoteAction.getTitle(); - user = Process.myUserHandle(); - } - - public RemoteActionItemInfo(RemoteActionItemInfo info) { - super(info); - this.mShouldStart = info.mShouldStart; - this.mRemoteAction = info.mRemoteAction; - this.mToken = info.mToken; - } - - @Override - public ItemInfoWithIcon clone() { - return new RemoteActionItemInfo(this); - } - - public RemoteAction getRemoteAction() { - return mRemoteAction; - } - - public String getToken() { - return mToken; - } - - /** - * Getter method for mShouldStart - */ - public boolean shouldStartInLauncher() { - return mShouldStart; - } -} diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java index 9b065233b9..32f060ba85 100644 --- a/src/com/android/launcher3/notification/NotificationMainView.java +++ b/src/com/android/launcher3/notification/NotificationMainView.java @@ -17,7 +17,6 @@ package com.android.launcher3.notification; import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DISMISSED; import android.animation.Animator; import android.animation.ObjectAnimator; @@ -42,6 +41,7 @@ import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.touch.BaseSwipeDetector; import com.android.launcher3.touch.OverScroll; import com.android.launcher3.touch.SingleAxisSwipeDetector; +import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.util.Themes; /** @@ -168,7 +168,10 @@ public class NotificationMainView extends FrameLayout implements SingleAxisSwipe Launcher launcher = Launcher.getLauncher(getContext()); launcher.getPopupDataProvider().cancelNotification( mNotificationInfo.notificationKey); - launcher.getStatsLogManager().logger().log(LAUNCHER_NOTIFICATION_DISMISSED); + launcher.getUserEventDispatcher().logActionOnItem( + LauncherLogProto.Action.Touch.SWIPE, + LauncherLogProto.Action.Direction.RIGHT, // Assume all swipes are right for logging. + LauncherLogProto.ItemType.NOTIFICATION); } // SingleAxisSwipeDetector.Listener's diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java index fa25114d49..753a6dd85e 100644 --- a/src/com/android/launcher3/pm/InstallSessionHelper.java +++ b/src/com/android/launcher3/pm/InstallSessionHelper.java @@ -17,7 +17,6 @@ package com.android.launcher3.pm; import static com.android.launcher3.Utilities.getPrefs; -import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -32,7 +31,6 @@ import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; -import androidx.annotation.WorkerThread; import com.android.launcher3.LauncherSettings; import com.android.launcher3.SessionCommitReceiver; @@ -41,10 +39,10 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSet; +import com.android.launcher3.util.LooperExecutor; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; -import com.android.launcher3.util.Preconditions; import java.util.ArrayList; import java.util.HashMap; @@ -67,27 +65,27 @@ public class InstallSessionHelper { private final LauncherApps mLauncherApps; private final Context mAppContext; + private final IntSet mPromiseIconIds; private final PackageInstaller mInstaller; private final HashMap mSessionVerifiedMap = new HashMap<>(); - private IntSet mPromiseIconIds; - public InstallSessionHelper(Context context) { mInstaller = context.getPackageManager().getPackageInstaller(); mAppContext = context.getApplicationContext(); mLauncherApps = context.getSystemService(LauncherApps.class); + + mPromiseIconIds = IntSet.wrap(IntArray.fromConcatString( + getPrefs(context).getString(PROMISE_ICON_IDS, ""))); + + cleanUpPromiseIconIds(); } - @WorkerThread - private IntSet getPromiseIconIds() { - Preconditions.assertWorkerThread(); - if (mPromiseIconIds != null) { - return mPromiseIconIds; - } - mPromiseIconIds = IntSet.wrap(IntArray.fromConcatString( - getPrefs(mAppContext).getString(PROMISE_ICON_IDS, ""))); + public static UserHandle getUserHandle(SessionInfo info) { + return Utilities.ATLEAST_Q ? info.getUser() : Process.myUserHandle(); + } + protected void cleanUpPromiseIconIds() { IntArray existingIds = new IntArray(); for (SessionInfo info : getActiveSessions().values()) { existingIds.add(info.getSessionId()); @@ -102,7 +100,6 @@ public class InstallSessionHelper { for (int i = idsToRemove.size() - 1; i >= 0; --i) { mPromiseIconIds.getArray().removeValue(idsToRemove.get(i)); } - return mPromiseIconIds; } public HashMap getActiveSessions() { @@ -129,7 +126,7 @@ public class InstallSessionHelper { private void updatePromiseIconPrefs() { getPrefs(mAppContext).edit() - .putString(PROMISE_ICON_IDS, getPromiseIconIds().getArray().toConcatString()) + .putString(PROMISE_ICON_IDS, mPromiseIconIds.getArray().toConcatString()) .apply(); } @@ -187,15 +184,13 @@ public class InstallSessionHelper { return info.getInstallReason() == PackageManager.INSTALL_REASON_DEVICE_RESTORE; } - @WorkerThread public boolean promiseIconAddedForId(int sessionId) { - return getPromiseIconIds().contains(sessionId); + return mPromiseIconIds.contains(sessionId); } - @WorkerThread public void removePromiseIconId(int sessionId) { - if (promiseIconAddedForId(sessionId)) { - getPromiseIconIds().getArray().removeValue(sessionId); + if (mPromiseIconIds.contains(sessionId)) { + mPromiseIconIds.getArray().removeValue(sessionId); updatePromiseIconPrefs(); } } @@ -208,7 +203,6 @@ public class InstallSessionHelper { * - The app is not already installed * - A promise icon for the session has not already been created */ - @WorkerThread void tryQueuePromiseAppIcon(PackageInstaller.SessionInfo sessionInfo) { if (FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get() && SessionCommitReceiver.isEnabled(mAppContext) @@ -216,24 +210,25 @@ public class InstallSessionHelper { && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER && sessionInfo.getAppIcon() != null && !TextUtils.isEmpty(sessionInfo.getAppLabel()) - && !promiseIconAddedForId(sessionInfo.getSessionId()) + && !mPromiseIconIds.contains(sessionInfo.getSessionId()) && new PackageManagerHelper(mAppContext).getApplicationInfo( sessionInfo.getAppPackageName(), getUserHandle(sessionInfo), 0) == null) { ItemInstallQueue.INSTANCE.get(mAppContext) .queueItem(sessionInfo.getAppPackageName(), getUserHandle(sessionInfo)); - getPromiseIconIds().add(sessionInfo.getSessionId()); + mPromiseIconIds.add(sessionInfo.getSessionId()); updatePromiseIconPrefs(); } } - public InstallSessionTracker registerInstallTracker(InstallSessionTracker.Callback callback) { + public InstallSessionTracker registerInstallTracker( + InstallSessionTracker.Callback callback, LooperExecutor executor) { InstallSessionTracker tracker = new InstallSessionTracker(this, callback); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - mInstaller.registerSessionCallback(tracker, MODEL_EXECUTOR.getHandler()); + mInstaller.registerSessionCallback(tracker, executor.getHandler()); } else { - mLauncherApps.registerPackageInstallerSessionCallback(MODEL_EXECUTOR, tracker); + mLauncherApps.registerPackageInstallerSessionCallback(executor, tracker); } return tracker; } @@ -245,8 +240,4 @@ public class InstallSessionHelper { mLauncherApps.unregisterPackageInstallerSessionCallback(tracker); } } - - public static UserHandle getUserHandle(SessionInfo info) { - return Utilities.ATLEAST_Q ? info.getUser() : Process.myUserHandle(); - } } diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java index b0b907ab19..eb3ca7366b 100644 --- a/src/com/android/launcher3/pm/InstallSessionTracker.java +++ b/src/com/android/launcher3/pm/InstallSessionTracker.java @@ -24,11 +24,8 @@ import android.content.pm.PackageInstaller.SessionInfo; import android.os.UserHandle; import android.util.SparseArray; -import androidx.annotation.WorkerThread; - import com.android.launcher3.util.PackageUserKey; -@WorkerThread public class InstallSessionTracker extends PackageInstaller.SessionCallback { // Lazily initialized diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java index 5ade22be5e..2d7d6b092a 100644 --- a/src/com/android/launcher3/pm/UserCache.java +++ b/src/com/android/launcher3/pm/UserCache.java @@ -60,9 +60,6 @@ public class UserCache { private void onUsersChanged(Intent intent) { enableAndResetCache(); mUserChangeListeners.forEach(Runnable::run); - if (TestProtocol.sDebugTracing) { - Log.d(TestProtocol.WORK_PROFILE_REMOVED, "profile changed", new Exception()); - } } /** @@ -107,6 +104,9 @@ public class UserCache { mUsers = null; mUserToSerialMap = null; } + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.WORK_PROFILE_REMOVED, "Work profile removed", new Exception()); + } } } diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index 90285c470b..d5b32fccd1 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -151,52 +151,32 @@ public abstract class ArrowPopup extends Abstrac * @param viewsToFlip number of views from the top to to flip in case of reverse order */ protected void reorderAndShow(int viewsToFlip) { - setupForDisplay(); - boolean reverseOrder = mIsAboveIcon; - if (reverseOrder) { - reverseOrder(viewsToFlip); - } - onInflationComplete(reverseOrder); - addArrow(); - animateOpen(); - } - - /** - * Shows the popup at the desired location. - */ - protected void show() { - setupForDisplay(); - onInflationComplete(false); - addArrow(); - animateOpen(); - } - - private void setupForDisplay() { setVisibility(View.INVISIBLE); mIsOpen = true; getPopupContainer().addView(this); orientAboutObject(); - } - private void reverseOrder(int viewsToFlip) { - int count = getChildCount(); - ArrayList allViews = new ArrayList<>(count); - for (int i = 0; i < count; i++) { - if (i == viewsToFlip) { - Collections.reverse(allViews); + boolean reverseOrder = mIsAboveIcon; + if (reverseOrder) { + int count = getChildCount(); + ArrayList allViews = new ArrayList<>(count); + for (int i = 0; i < count; i++) { + if (i == viewsToFlip) { + Collections.reverse(allViews); + } + allViews.add(getChildAt(i)); + } + Collections.reverse(allViews); + removeAllViews(); + for (int i = 0; i < count; i++) { + addView(allViews.get(i)); } - allViews.add(getChildAt(i)); - } - Collections.reverse(allViews); - removeAllViews(); - for (int i = 0; i < count; i++) { - addView(allViews.get(i)); - } - orientAboutObject(); - } + orientAboutObject(); + } + onInflationComplete(reverseOrder); - private void addArrow() { + // Add the arrow. final Resources res = getResources(); final int arrowCenterOffset = res.getDimensionPixelSize(isAlignedWithStart() ? R.dimen.popup_arrow_horizontal_center_start @@ -234,6 +214,8 @@ public abstract class ArrowPopup extends Abstrac mArrow.setPivotX(arrowLp.width / 2); mArrow.setPivotY(mIsAboveIcon ? arrowLp.height : 0); + + animateOpen(); } protected boolean isAlignedWithStart() { diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 6d92b8b627..26b32b8195 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -19,8 +19,10 @@ package com.android.launcher3.popup; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.Utilities.squaredTouchSlop; +import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS; import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.animation.AnimatorSet; @@ -158,7 +160,8 @@ public class PopupContainerWithArrow extends Arr if (ev.getAction() == MotionEvent.ACTION_DOWN) { BaseDragLayer dl = getPopupContainer(); if (!dl.isEventOverView(this, ev)) { - // TODO: add WW log if want to log if tap closed deep shortcut container. + mLauncher.getUserEventDispatcher().logActionTapOutside( + newContainerTarget(ContainerType.DEEPSHORTCUTS)); close(true); // We let touches on the original icon go through so that users can launch @@ -432,9 +435,7 @@ public class PopupContainerWithArrow extends Arr // Make sure we keep the original icon hidden while it is being dragged. mOriginalIcon.setVisibility(INVISIBLE); } else { - // TODO: add WW logging if want to add logging for long press on popup - // container. - // mLauncher.getUserEventDispatcher().logDeepShortcutsOpen(mOriginalIcon); + mLauncher.getUserEventDispatcher().logDeepShortcutsOpen(mOriginalIcon); if (!mIsAboveIcon) { // Show the icon but keep the text hidden. mOriginalIcon.setVisibility(VISIBLE); diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java index 7c393ad1e2..61829c002b 100644 --- a/src/com/android/launcher3/popup/RemoteActionShortcut.java +++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java @@ -37,6 +37,7 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.userevent.nano.LauncherLogProto; @TargetApi(Build.VERSION_CODES.Q) public class RemoteActionShortcut extends SystemShortcut { @@ -106,6 +107,9 @@ public class RemoteActionShortcut extends SystemShortcut { Toast.LENGTH_SHORT) .show(); } + + mTarget.getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.Touch.TAP, + LauncherLogProto.ControlType.REMOTE_ACTION_SHORTCUT, view); } @Override diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index 577fe4afaa..81302ac1f7 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -21,6 +21,8 @@ import com.android.launcher3.R; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action; +import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; @@ -115,6 +117,8 @@ public abstract class SystemShortcut extends Ite (WidgetsBottomSheet) mTarget.getLayoutInflater().inflate( R.layout.widgets_bottom_sheet, mTarget.getDragLayer(), false); widgetsBottomSheet.populateAndShow(mItemInfo); + mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, + ControlType.WIDGETS_BUTTON, view); mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo) .log(LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP); } @@ -135,6 +139,8 @@ public abstract class SystemShortcut extends Ite Rect sourceBounds = mTarget.getViewBounds(view); new PackageManagerHelper(mTarget).startDetailsActivityForInfo( mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle()); + mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, + ControlType.APPINFO_TARGET, view); mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo) .log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP); } diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java index f4b059d8d8..4baecb7c56 100644 --- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java +++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java @@ -306,15 +306,6 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { return true; }); sandboxCategory.addPreference(launchAssistantTutorialPreference); - Preference launchSandboxModeTutorialPreference = new Preference(context); - launchSandboxModeTutorialPreference.setKey("launchSandboxMode"); - launchSandboxModeTutorialPreference.setTitle("Launch Sandbox Mode"); - launchSandboxModeTutorialPreference.setSummary("Practice navigation gestures"); - launchSandboxModeTutorialPreference.setOnPreferenceClickListener(preference -> { - startActivity(launchSandboxIntent.putExtra("tutorial_type", "SANDBOX_MODE")); - return true; - }); - sandboxCategory.addPreference(launchSandboxModeTutorialPreference); } private String toName(String action) { diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java index fd1d965982..b8a184fcfc 100644 --- a/src/com/android/launcher3/states/HintState.java +++ b/src/com/android/launcher3/states/HintState.java @@ -15,12 +15,11 @@ */ package com.android.launcher3.states; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; - import android.content.Context; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; /** * Scale down workspace/hotseat to hint at going to either overview (on pause) or first home screen. @@ -31,7 +30,7 @@ public class HintState extends LauncherState { | FLAG_HAS_SYS_UI_SCRIM; public HintState(int id) { - super(id, LAUNCHER_STATE_HOME, STATE_FLAGS); + super(id, ContainerType.DEFAULT_CONTAINERTYPE, STATE_FLAGS); } @Override diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java index 45172b56ef..2a4f887503 100644 --- a/src/com/android/launcher3/states/SpringLoadedState.java +++ b/src/com/android/launcher3/states/SpringLoadedState.java @@ -15,8 +15,6 @@ */ package com.android.launcher3.states; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; - import android.content.Context; import android.graphics.Rect; @@ -24,6 +22,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.Workspace; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; /** * Definition for spring loaded state used during drag and drop. @@ -36,7 +35,7 @@ public class SpringLoadedState extends LauncherState { | FLAG_HIDE_BACK_BUTTON; public SpringLoadedState(int id) { - super(id, LAUNCHER_STATE_HOME, STATE_FLAGS); + super(id, ContainerType.WORKSPACE, STATE_FLAGS); } @Override diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index 9fd53e2563..8ee5a6e533 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -21,9 +21,6 @@ import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity; import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEDOWN; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEUP; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS; @@ -55,6 +52,9 @@ import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.states.StateAnimationConfig.AnimationFlags; import com.android.launcher3.testing.TestProtocol; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.FlingBlockCheck; import com.android.launcher3.util.TouchController; @@ -190,6 +190,11 @@ public abstract class AbstractStateChangeTouchController protected abstract float initCurrentAnimation(@AnimationFlags int animComponents); + /** + * Returns the container that the touch started from when leaving NORMAL state. + */ + protected abstract int getLogContainerTypeForNormalState(MotionEvent ev); + private boolean reinitCurrentAnimation(boolean reachedToState, boolean isDragTowardPositive) { LauncherState newFromState = mFromState == null ? mLauncher.getStateManager().getState() : reachedToState ? mToState : mFromState; @@ -302,11 +307,11 @@ public abstract class AbstractStateChangeTouchController public boolean onDrag(float displacement, MotionEvent ev) { if (!mIsLogContainerSet) { if (mStartState == ALL_APPS) { - mStartContainerType = LAUNCHER_STATE_ALLAPPS; + mStartContainerType = ContainerType.ALLAPPS; } else if (mStartState == NORMAL) { - mStartContainerType = LAUNCHER_STATE_HOME; + mStartContainerType = getLogContainerTypeForNormalState(ev); } else if (mStartState == OVERVIEW) { - mStartContainerType = LAUNCHER_STATE_OVERVIEW; + mStartContainerType = ContainerType.TASKSWITCHER; } mIsLogContainerSet = true; } @@ -396,6 +401,7 @@ public abstract class AbstractStateChangeTouchController @Override public void onDragEnd(float velocity) { boolean fling = mDetector.isFling(velocity); + final int logAction = fling ? Touch.FLING : Touch.SWIPE; boolean blockedFling = fling && mFlingBlockCheck.isBlocked(); if (blockedFling) { @@ -452,7 +458,7 @@ public abstract class AbstractStateChangeTouchController } } - mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState)); + mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState, logAction)); ValueAnimator anim = mCurrentAnimation.getAnimationPlayer(); anim.setFloatValues(startProgress, endProgress); maybeUpdateAtomicAnim(mFromState, targetState, targetState == mToState ? 1f : 0f); @@ -516,7 +522,11 @@ public abstract class AbstractStateChangeTouchController .setInterpolator(scrollInterpolatorForVelocity(velocity)); } - protected void onSwipeInteractionCompleted(LauncherState targetState) { + protected int getDirectionForLog() { + return mToState.ordinal > mFromState.ordinal ? Direction.UP : Direction.DOWN; + } + + protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) { if (mAtomicComponentsController != null) { mAtomicComponentsController.getAnimationPlayer().end(); mAtomicComponentsController = null; @@ -525,18 +535,18 @@ public abstract class AbstractStateChangeTouchController boolean shouldGoToTargetState = true; if (mPendingAnimation != null) { boolean reachedTarget = mToState == targetState; - mPendingAnimation.finish(reachedTarget); + mPendingAnimation.finish(reachedTarget, logAction); mPendingAnimation = null; shouldGoToTargetState = !reachedTarget; } if (shouldGoToTargetState) { - goToTargetState(targetState); + goToTargetState(targetState, logAction); } } - protected void goToTargetState(LauncherState targetState) { + protected void goToTargetState(LauncherState targetState, int logAction) { if (targetState != mStartState) { - logReachedState(targetState); + logReachedState(logAction, targetState); } if (!mLauncher.isInState(targetState)) { // If we're already in the target state, don't jump to it at the end of the animation in @@ -546,18 +556,24 @@ public abstract class AbstractStateChangeTouchController mLauncher.getDragLayer().getScrim().createSysuiMultiplierAnim(1f).setDuration(0).start(); } - private void logReachedState(LauncherState targetState) { + private void logReachedState(int logAction, LauncherState targetState) { // Transition complete. log the action + mLauncher.getUserEventDispatcher().logStateChangeAction(logAction, + getDirectionForLog(), mDetector.getDownX(), mDetector.getDownY(), + mStartContainerType /* e.g., hotseat */, + mStartState.containerType /* e.g., workspace */, + targetState.containerType, + mLauncher.getWorkspace().getCurrentPage()); mLauncher.getStatsLogManager().logger() - .withSrcState(mStartState.statsLogOrdinal) - .withDstState(targetState.statsLogOrdinal) + .withSrcState(StatsLogManager.containerTypeToAtomState(mStartState.containerType)) + .withDstState(StatsLogManager.containerTypeToAtomState(targetState.containerType)) .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder() .setWorkspace( LauncherAtom.WorkspaceContainer.newBuilder() .setPageIndex(mLauncher.getWorkspace().getCurrentPage())) .build()) - .log(StatsLogManager.getLauncherAtomEvent(mStartState.statsLogOrdinal, - targetState.statsLogOrdinal, mToState.ordinal > mFromState.ordinal + .log(StatsLogManager.getLauncherAtomEvent(mStartState.containerType, + targetState.containerType, mToState.ordinal > mFromState.ordinal ? LAUNCHER_UNKNOWN_SWIPEUP : LAUNCHER_UNKNOWN_SWIPEDOWN)); } diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java index f9dcf2d2e9..4a202b65d8 100644 --- a/src/com/android/launcher3/touch/AllAppsSwipeController.java +++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java @@ -24,6 +24,7 @@ import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.states.StateAnimationConfig.AnimationFlags; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; /** * TouchController to switch between NORMAL and ALL_APPS state. @@ -68,6 +69,12 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController { return fromState; } + @Override + protected int getLogContainerTypeForNormalState(MotionEvent ev) { + return mLauncher.getDragLayer().isEventOverView(mLauncher.getHotseat(), mTouchDownEvent) + ? ContainerType.HOTSEAT : ContainerType.WORKSPACE; + } + @Override protected float initCurrentAnimation(@AnimationFlags int animComponents) { float range = getShiftRange(); diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java index d56391da3d..61d6f7d804 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -25,9 +25,7 @@ import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SA import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED; import android.app.AlertDialog; -import android.app.PendingIntent; import android.content.Intent; -import android.content.IntentSender; import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller.SessionInfo; import android.os.Process; @@ -51,7 +49,6 @@ import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.PromiseAppInfo; -import com.android.launcher3.model.data.RemoteActionItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.testing.TestLogging; @@ -239,27 +236,6 @@ public class ItemClickHandler { startAppShortcutOrInfoActivity(v, shortcut, launcher); } - /** - * Event handler for a {@link android.app.RemoteAction} click - * - */ - public static void onClickRemoteAction(Launcher launcher, - RemoteActionItemInfo remoteActionInfo) { - try { - PendingIntent pendingIntent = remoteActionInfo.getRemoteAction().getActionIntent(); - if (remoteActionInfo.shouldStartInLauncher()) { - launcher.startIntentSenderForResult(pendingIntent.getIntentSender(), 0, null, 0, 0, - 0); - } else { - pendingIntent.send(); - } - } catch (PendingIntent.CanceledException | IntentSender.SendIntentException e) { - Toast.makeText(launcher, - launcher.getResources().getText(R.string.shortcut_not_available), - Toast.LENGTH_SHORT).show(); - } - } - private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) { TestLogging.recordEvent( TestProtocol.SEQUENCE_MAIN, "start: startAppShortcutOrInfoActivity"); diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index 17f02be5b4..fb02f79c49 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -72,6 +72,7 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { out.halfPageSize = view.getNormalChildHeight() / 2; out.halfScreenSize = view.getMeasuredHeight() / 2; out.screenCenter = insets.top + view.getPaddingTop() + out.scroll + out.halfPageSize; + out.pageParentScale = view.getScaleY(); } @Override diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java index 114b75acec..354d78d0ac 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -112,6 +112,7 @@ public interface PagedOrientationHandler { public int halfPageSize; public int screenCenter; public int halfScreenSize; + public float pageParentScale; } class ChildBounds { diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index 5f5b2d1feb..06479e6b6a 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -70,6 +70,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { out.halfPageSize = view.getNormalChildWidth() / 2; out.halfScreenSize = view.getMeasuredWidth() / 2; out.screenCenter = insets.left + view.getPaddingLeft() + out.scroll + out.halfPageSize; + out.pageParentScale = view.getScaleX(); } @Override diff --git a/src/com/android/launcher3/util/Executors.java b/src/com/android/launcher3/util/Executors.java index a85ae458ed..0a32734fca 100644 --- a/src/com/android/launcher3/util/Executors.java +++ b/src/com/android/launcher3/util/Executors.java @@ -20,10 +20,8 @@ import android.os.Looper; import android.os.Process; import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; /** * Various different executors used in Launcher @@ -85,29 +83,4 @@ public class Executors { */ public static final LooperExecutor MODEL_EXECUTOR = new LooperExecutor(createAndStartNewLooper("launcher-loader")); - - /** - * A simple ThreadFactory to set the thread name and priority when used with executors. - */ - public static class SimpleThreadFactory implements ThreadFactory { - - private final int mPriority; - private final String mNamePrefix; - - private final AtomicInteger mCount = new AtomicInteger(0); - - public SimpleThreadFactory(String namePrefix, int priority) { - mNamePrefix = namePrefix; - mPriority = priority; - } - - @Override - public Thread newThread(Runnable runnable) { - Thread t = new Thread(() -> { - Process.setThreadPriority(mPriority); - runnable.run(); - }, mNamePrefix + mCount.incrementAndGet()); - return t; - } - } } diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index d9a14e9e3f..52a82f8e93 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -15,6 +15,7 @@ */ package com.android.launcher3.views; +import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA; import static com.android.launcher3.Utilities.getBadge; import static com.android.launcher3.Utilities.getFullDrawable; import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM; @@ -22,6 +23,9 @@ import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Canvas; @@ -70,6 +74,7 @@ public class FloatingIconView extends FrameLayout implements private static @Nullable IconLoadResult sIconLoadResult; public static final float SHAPE_PROGRESS_DURATION = 0.10f; + private static final int FADE_DURATION_MS = 200; private static final RectF sTmpRectF = new RectF(); private static final Object[] sTmpObjArray = new Object[1]; @@ -84,9 +89,6 @@ public class FloatingIconView extends FrameLayout implements private IconLoadResult mIconLoadResult; - // Draw the drawable of the BubbleTextView behind ClipIconView to reveal the built in shadow. - private View mBtvDrawable; - private ClipIconView mClipIconView; private @Nullable Drawable mBadge; @@ -96,6 +98,7 @@ public class FloatingIconView extends FrameLayout implements private final Rect mFinalDrawableBounds = new Rect(); + private AnimatorSet mFadeAnimatorSet; private ListenerView mListenerView; private Runnable mFastFinishRunnable; @@ -113,8 +116,6 @@ public class FloatingIconView extends FrameLayout implements mIsRtl = Utilities.isRtl(getResources()); mListenerView = new ListenerView(context, attrs); mClipIconView = new ClipIconView(context, attrs); - mBtvDrawable = new ImageView(context, attrs); - addView(mBtvDrawable); addView(mClipIconView); setWillNotDraw(false); } @@ -175,7 +176,6 @@ public class FloatingIconView extends FrameLayout implements setLayoutParams(lp); mClipIconView.setLayoutParams(new FrameLayout.LayoutParams(lp.width, lp.height)); - mBtvDrawable.setLayoutParams(new FrameLayout.LayoutParams(lp.width, lp.height)); } private void updatePosition(RectF pos, InsettableFrameLayout.LayoutParams lp) { @@ -292,8 +292,6 @@ public class FloatingIconView extends FrameLayout implements drawable = drawable == null ? null : drawable.getConstantState().newDrawable(); int iconOffset = getOffsetForIconBounds(l, drawable, pos); synchronized (iconLoadResult) { - iconLoadResult.btvDrawable = btvIcon == null || drawable == btvIcon - ? null : btvIcon.getConstantState().newDrawable(); iconLoadResult.drawable = drawable; iconLoadResult.badge = badge; iconLoadResult.iconOffset = iconOffset; @@ -313,8 +311,7 @@ public class FloatingIconView extends FrameLayout implements * @param iconOffset The amount of offset needed to match this view with the original view. */ @UiThread - private void setIcon(@Nullable Drawable drawable, @Nullable Drawable badge, - @Nullable Drawable btvIcon, int iconOffset) { + private void setIcon(@Nullable Drawable drawable, @Nullable Drawable badge, int iconOffset) { final InsettableFrameLayout.LayoutParams lp = (InsettableFrameLayout.LayoutParams) getLayoutParams(); mBadge = badge; @@ -345,10 +342,6 @@ public class FloatingIconView extends FrameLayout implements mBadge.setBounds(0, 0, clipViewOgWidth, clipViewOgHeight); } } - - if (!mIsOpening && btvIcon != null) { - mBtvDrawable.setBackground(btvIcon); - } invalidate(); } @@ -367,7 +360,7 @@ public class FloatingIconView extends FrameLayout implements synchronized (mIconLoadResult) { if (mIconLoadResult.isIconLoaded) { setIcon(mIconLoadResult.drawable, mIconLoadResult.badge, - mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset); + mIconLoadResult.iconOffset); setIconAndDotVisible(originalView, false); } else { mIconLoadResult.onIconLoaded = () -> { @@ -376,7 +369,7 @@ public class FloatingIconView extends FrameLayout implements } setIcon(mIconLoadResult.drawable, mIconLoadResult.badge, - mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset); + mIconLoadResult.iconOffset); setVisibility(VISIBLE); setIconAndDotVisible(originalView, false); @@ -441,6 +434,10 @@ public class FloatingIconView extends FrameLayout implements mEndRunnable.run(); mEndRunnable = null; } + if (mFadeAnimatorSet != null) { + mFadeAnimatorSet.end(); + mFadeAnimatorSet = null; + } } @Override @@ -549,16 +546,8 @@ public class FloatingIconView extends FrameLayout implements setIconAndDotVisible(originalView, true); view.finish(dragLayer); } else { - originalView.setVisibility(VISIBLE); - if (originalView instanceof IconLabelDotView) { - setIconAndDotVisible(originalView, true); - } - if (originalView instanceof BubbleTextView) { - BubbleTextView btv = (BubbleTextView) originalView; - btv.setIconVisible(true); - btv.setForceHideDot(true); - } - view.finish(dragLayer); + view.mFadeAnimatorSet = view.createFadeAnimation(originalView, dragLayer); + view.mFadeAnimatorSet.start(); } } else { view.finish(dragLayer); @@ -575,6 +564,47 @@ public class FloatingIconView extends FrameLayout implements return view; } + private AnimatorSet createFadeAnimation(View originalView, DragLayer dragLayer) { + AnimatorSet fade = new AnimatorSet(); + fade.setDuration(FADE_DURATION_MS); + fade.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + originalView.setVisibility(VISIBLE); + } + + @Override + public void onAnimationEnd(Animator animation) { + finish(dragLayer); + } + }); + + if (originalView instanceof IconLabelDotView) { + fade.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + setIconAndDotVisible(originalView, true); + } + }); + } + + if (originalView instanceof BubbleTextView) { + BubbleTextView btv = (BubbleTextView) originalView; + fade.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + btv.setIconVisible(true); + btv.setForceHideDot(true); + } + }); + fade.play(ObjectAnimator.ofInt(btv.getIcon(), DRAWABLE_ALPHA, 0, 255)); + } else if (!(originalView instanceof FolderIcon)) { + fade.play(ObjectAnimator.ofFloat(originalView, ALPHA, 0f, 1f)); + } + + return fade; + } + private void finish(DragLayer dragLayer) { ((ViewGroup) dragLayer.getParent()).removeView(this); dragLayer.removeView(mListenerView); @@ -598,7 +628,11 @@ public class FloatingIconView extends FrameLayout implements mLoadIconSignal = null; mEndRunnable = null; mFinalDrawableBounds.setEmpty(); + if (mFadeAnimatorSet != null) { + mFadeAnimatorSet.cancel(); + } mPositionOut = null; + mFadeAnimatorSet = null; mListenerView.setListener(null); mOriginalIcon = null; mOnTargetChangeRunnable = null; @@ -606,13 +640,11 @@ public class FloatingIconView extends FrameLayout implements sTmpObjArray[0] = null; mIconLoadResult = null; mClipIconView.recycle(); - mBtvDrawable.setBackground(null); mFastFinishRunnable = null; } private static class IconLoadResult { final ItemInfo itemInfo; - Drawable btvDrawable; Drawable drawable; Drawable badge; int iconOffset; diff --git a/src/com/android/launcher3/views/HeroSearchResultView.java b/src/com/android/launcher3/views/HeroSearchResultView.java index dd322d921a..a8e1c6b30c 100644 --- a/src/com/android/launcher3/views/HeroSearchResultView.java +++ b/src/com/android/launcher3/views/HeroSearchResultView.java @@ -16,16 +16,12 @@ package com.android.launcher3.views; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS; -import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; -import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.content.Context; import android.content.Intent; -import android.content.pm.ShortcutInfo; import android.graphics.Point; import android.os.Bundle; import android.util.AttributeSet; -import android.util.Pair; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; @@ -35,10 +31,9 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload; -import com.android.launcher3.allapps.search.AllAppsSearchBarController.PayloadResultHandler; +import com.android.launcher3.allapps.search.AllAppsSearchBarController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.graphics.DragPreviewProvider; @@ -58,10 +53,9 @@ import java.util.List; * A view representing a high confidence app search result that includes shortcuts */ public class HeroSearchResultView extends LinearLayout implements DragSource, - PayloadResultHandler>> { + AllAppsSearchBarController.PayloadResultHandler> { public static final int MAX_SHORTCUTS_COUNT = 2; - private final Object[] mTargetInfo = createTargetInfo(); BubbleTextView mBubbleTextView; View mIconView; BubbleTextView[] mDeepShortcutTextViews = new BubbleTextView[2]; @@ -108,7 +102,7 @@ public class HeroSearchResultView extends LinearLayout implements DragSource, grid.allAppsIconSizePx)); bubbleTextView.setOnClickListener(view -> { WorkspaceItemInfo itemInfo = (WorkspaceItemInfo) bubbleTextView.getTag(); - SearchTargetEvent event = getSearchTargetEvent( + SearchTargetEvent event = new SearchTargetEvent( SearchTarget.ItemType.APP_HERO, SearchTargetEvent.CHILD_SELECT); event.bundle = getAppBundle(itemInfo); @@ -125,36 +119,21 @@ public class HeroSearchResultView extends LinearLayout implements DragSource, * Apply {@link ItemInfo} for appIcon and shortcut Icons */ @Override - public void applyAdapterInfo( - AdapterItemWithPayload>> adapterItem) { + public void applyAdapterInfo(AdapterItemWithPayload> adapterItem) { mBubbleTextView.applyFromApplicationInfo(adapterItem.appInfo); mIconView.setBackground(mBubbleTextView.getIcon()); mIconView.setTag(adapterItem.appInfo); - List> shortcutDetails = adapterItem.getPayload(); - LauncherAppState appState = LauncherAppState.getInstance(getContext()); + List shorcutInfos = adapterItem.getPayload(); for (int i = 0; i < mDeepShortcutTextViews.length; i++) { - BubbleTextView shortcutView = mDeepShortcutTextViews[i]; - mDeepShortcutTextViews[i].setVisibility(shortcutDetails.size() > i ? VISIBLE : GONE); - if (i < shortcutDetails.size()) { - Pair p = shortcutDetails.get(i); - //apply ItemInfo and prepare view - shortcutView.applyFromWorkspaceItem((WorkspaceItemInfo) p.second); - MODEL_EXECUTOR.execute(() -> { - // load unbadged shortcut in background and update view when icon ready - appState.getIconCache().getUnbadgedShortcutIcon(p.second, p.first); - MAIN_EXECUTOR.post(() -> shortcutView.reapplyItemInfo(p.second)); - }); + mDeepShortcutTextViews[i].setVisibility(shorcutInfos.size() > i ? VISIBLE : GONE); + if (i < shorcutInfos.size()) { + mDeepShortcutTextViews[i].applyFromItemInfoWithIcon(shorcutInfos.get(i)); } } mPlugin = adapterItem.getPlugin(); adapterItem.setSelectionHandler(this::handleSelection); } - @Override - public Object[] getTargetInfo() { - return mTargetInfo; - } - @Override public void onDropCompleted(View target, DropTarget.DragObject d, boolean success) { mBubbleTextView.setVisibility(VISIBLE); @@ -190,7 +169,7 @@ public class HeroSearchResultView extends LinearLayout implements DragSource, mLauncher.getWorkspace().beginDragShared(mContainer.mBubbleTextView, draggableView, mContainer, itemInfo, previewProvider, new DragOptions()); - SearchTargetEvent event = mContainer.getSearchTargetEvent( + SearchTargetEvent event = new SearchTargetEvent( SearchTarget.ItemType.APP_HERO, SearchTargetEvent.LONG_PRESS); event.bundle = getAppBundle(itemInfo); if (mContainer.mPlugin != null) { @@ -207,7 +186,7 @@ public class HeroSearchResultView extends LinearLayout implements DragSource, Launcher launcher = Launcher.getLauncher(getContext()); launcher.startActivitySafely(this, itemInfo.getIntent(), itemInfo); - SearchTargetEvent event = getSearchTargetEvent( + SearchTargetEvent event = new SearchTargetEvent( SearchTarget.ItemType.APP_HERO, eventType); event.bundle = getAppBundle(itemInfo); if (mPlugin != null) { diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index 80f0981af5..3ec20d57a1 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -16,7 +16,6 @@ package com.android.launcher3.views; import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_FLAVOR; -import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_LAUNCH_SOURCE; import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_OFFSET; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS; @@ -133,7 +132,7 @@ public class OptionsPopupView extends ArrowPopup view.setOnLongClickListener(popup); popup.mItemMap.put(view, item); } - popup.show(); + popup.reorderAndShow(popup.getChildCount()); } @VisibleForTesting @@ -212,8 +211,7 @@ public class OptionsPopupView extends ArrowPopup Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) .putExtra(EXTRA_WALLPAPER_OFFSET, - launcher.getWorkspace().getWallpaperOffsetForCenterPage()) - .putExtra(EXTRA_WALLPAPER_LAUNCH_SOURCE, "app_launched_launcher"); + launcher.getWorkspace().getWallpaperOffsetForCenterPage()); if (!Utilities.existsStyleWallpapers(launcher)) { intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "wallpaper_only"); } else { diff --git a/src/com/android/launcher3/views/SearchResultIconRow.java b/src/com/android/launcher3/views/SearchResultIconRow.java deleted file mode 100644 index 313ae5e611..0000000000 --- a/src/com/android/launcher3/views/SearchResultIconRow.java +++ /dev/null @@ -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.launcher3.views; - -import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; -import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; -import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; - -import android.app.RemoteAction; -import android.content.Context; -import android.content.pm.ShortcutInfo; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.os.Bundle; -import android.util.AttributeSet; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload; -import com.android.launcher3.allapps.search.AllAppsSearchBarController; -import com.android.launcher3.icons.LauncherIcons; -import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.model.data.ItemInfoWithIcon; -import com.android.launcher3.model.data.RemoteActionItemInfo; -import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.touch.ItemClickHandler; -import com.android.systemui.plugins.AllAppsSearchPlugin; -import com.android.systemui.plugins.shared.SearchTarget; -import com.android.systemui.plugins.shared.SearchTarget.ItemType; -import com.android.systemui.plugins.shared.SearchTargetEvent; - -/** - * A view representing a stand alone shortcut search result - */ -public class SearchResultIconRow extends DoubleShadowBubbleTextView implements - AllAppsSearchBarController.PayloadResultHandler { - - private final Object[] mTargetInfo = createTargetInfo(); - private ShortcutInfo mShortcutInfo; - private AllAppsSearchPlugin mPlugin; - private AdapterItemWithPayload mAdapterItem; - - - public SearchResultIconRow(@NonNull Context context) { - super(context); - } - - public SearchResultIconRow(@NonNull Context context, - @Nullable AttributeSet attrs) { - super(context, attrs); - } - - public SearchResultIconRow(@NonNull Context context, @Nullable AttributeSet attrs, - int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @Override - public void applyAdapterInfo(AdapterItemWithPayload adapterItemWithPayload) { - if (mAdapterItem != null) { - mAdapterItem.setSelectionHandler(null); - } - mAdapterItem = adapterItemWithPayload; - SearchTarget payload = adapterItemWithPayload.getPayload(); - mPlugin = adapterItemWithPayload.getPlugin(); - - if (payload.mRemoteAction != null) { - prepareUsingRemoteAction(payload.mRemoteAction, - payload.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN), - payload.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START)); - } else { - prepareUsingShortcutInfo(payload.shortcuts.get(0)); - } - setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT)); - adapterItemWithPayload.setSelectionHandler(this::handleSelection); - } - - private void prepareUsingShortcutInfo(ShortcutInfo shortcutInfo) { - mShortcutInfo = shortcutInfo; - WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(mShortcutInfo, getContext()); - applyFromWorkspaceItem(workspaceItemInfo); - LauncherAppState launcherAppState = LauncherAppState.getInstance(getContext()); - MODEL_EXECUTOR.execute(() -> { - launcherAppState.getIconCache().getShortcutIcon(workspaceItemInfo, mShortcutInfo); - reapplyItemInfoAsync(workspaceItemInfo); - }); - } - - private void prepareUsingRemoteAction(RemoteAction remoteAction, String token, boolean start) { - RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(remoteAction, token, start); - - applyFromRemoteActionInfo(itemInfo); - UI_HELPER_EXECUTOR.post(() -> { - // If the Drawable from the remote action is not AdaptiveBitmap, styling will not work. - try (LauncherIcons li = LauncherIcons.obtain(getContext())) { - Drawable d = itemInfo.getRemoteAction().getIcon().loadDrawable(getContext()); - itemInfo.bitmap = li.createBadgedIconBitmap(d, itemInfo.user, - Build.VERSION.SDK_INT); - reapplyItemInfoAsync(itemInfo); - } - }); - - } - - void reapplyItemInfoAsync(ItemInfoWithIcon itemInfoWithIcon) { - MAIN_EXECUTOR.post(() -> reapplyItemInfo(itemInfoWithIcon)); - } - - @Override - public Object[] getTargetInfo() { - return mTargetInfo; - } - - private void handleSelection(int eventType) { - ItemInfo itemInfo = (ItemInfo) getTag(); - Launcher launcher = Launcher.getLauncher(getContext()); - final SearchTargetEvent searchTargetEvent; - if (itemInfo instanceof WorkspaceItemInfo) { - ItemClickHandler.onClickAppShortcut(this, (WorkspaceItemInfo) itemInfo, launcher); - searchTargetEvent = getSearchTargetEvent(SearchTarget.ItemType.SHORTCUT, - eventType); - searchTargetEvent.shortcut = mShortcutInfo; - } else { - RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo; - ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo); - searchTargetEvent = getSearchTargetEvent(ItemType.ACTION, - eventType); - searchTargetEvent.bundle = new Bundle(); - searchTargetEvent.remoteAction = remoteItemInfo.getRemoteAction(); - searchTargetEvent.bundle.putBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START, - remoteItemInfo.shouldStartInLauncher()); - searchTargetEvent.bundle.putString(SearchTarget.REMOTE_ACTION_TOKEN, - remoteItemInfo.getToken()); - } - if (mPlugin != null) { - mPlugin.notifySearchTargetEvent(searchTargetEvent); - } - } -} diff --git a/src/com/android/launcher3/views/SearchResultPeopleView.java b/src/com/android/launcher3/views/SearchResultPeopleView.java index 0c9a22f672..6e45e88b32 100644 --- a/src/com/android/launcher3/views/SearchResultPeopleView.java +++ b/src/com/android/launcher3/views/SearchResultPeopleView.java @@ -15,6 +15,9 @@ */ package com.android.launcher3.views; +import static android.content.Intent.URI_ALLOW_UNSAFE; +import static android.content.Intent.URI_ANDROID_APP_SCHEME; + import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; @@ -25,6 +28,7 @@ import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.Bundle; import android.util.AttributeSet; import android.view.View; @@ -46,6 +50,7 @@ import com.android.systemui.plugins.AllAppsSearchPlugin; import com.android.systemui.plugins.shared.SearchTarget; import com.android.systemui.plugins.shared.SearchTargetEvent; +import java.net.URISyntaxException; import java.util.ArrayList; /** @@ -61,8 +66,8 @@ public class SearchResultPeopleView extends LinearLayout implements private TextView mTitleView; private ImageButton[] mProviderButtons = new ImageButton[3]; private AllAppsSearchPlugin mPlugin; - private Intent mIntent; - private final Object[] mTargetInfo = createTargetInfo(); + private Uri mContactUri; + public SearchResultPeopleView(Context context) { this(context, null, 0); @@ -104,7 +109,7 @@ public class SearchResultPeopleView extends LinearLayout implements Bundle payload = adapterItemWithPayload.getPayload(); mPlugin = adapterItemWithPayload.getPlugin(); mTitleView.setText(payload.getString("title")); - mIntent = payload.getParcelable("intent"); + mContactUri = payload.getParcelable("contact_uri"); Bitmap icon = payload.getParcelable("icon"); if (icon != null) { RoundedBitmapDrawable d = RoundedBitmapDrawableFactory.create(getResources(), icon); @@ -120,20 +125,25 @@ public class SearchResultPeopleView extends LinearLayout implements for (int i = 0; i < mProviderButtons.length; i++) { ImageButton button = mProviderButtons[i]; if (providers != null && i < providers.size()) { - Bundle provider = providers.get(i); - Intent intent = provider.getParcelable("intent"); - setupProviderButton(button, provider, intent, adapterItemWithPayload); - String pkg = provider.getString("package_name"); - UI_HELPER_EXECUTOR.post(() -> { - try { - ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo( - pkg, 0); - Drawable appIcon = applicationInfo.loadIcon(mPackageManager); - MAIN_EXECUTOR.post(() -> button.setImageDrawable(appIcon)); - } catch (PackageManager.NameNotFoundException ignored) { - } + try { + Bundle provider = providers.get(i); + Intent intent = Intent.parseUri(provider.getString("intent_uri_str"), + URI_ANDROID_APP_SCHEME | URI_ALLOW_UNSAFE); + setupProviderButton(button, provider, intent); + String pkg = provider.getString("package_name"); + UI_HELPER_EXECUTOR.post(() -> { + try { + ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo( + pkg, 0); + Drawable appIcon = applicationInfo.loadIcon(mPackageManager); + MAIN_EXECUTOR.post(()-> button.setImageDrawable(appIcon)); + } catch (PackageManager.NameNotFoundException ignored) { + } - }); + }); + } catch (URISyntaxException ex) { + button.setVisibility(GONE); + } } else { button.setVisibility(GONE); } @@ -141,21 +151,15 @@ public class SearchResultPeopleView extends LinearLayout implements adapterItemWithPayload.setSelectionHandler(this::handleSelection); } - @Override - public Object[] getTargetInfo() { - return mTargetInfo; - } - - private void setupProviderButton(ImageButton button, Bundle provider, Intent intent, - AllAppsGridAdapter.AdapterItem adapterItem) { + private void setupProviderButton(ImageButton button, Bundle provider, Intent intent) { Launcher launcher = Launcher.getLauncher(getContext()); button.setOnClickListener(b -> { launcher.startActivitySafely(b, intent, null); - SearchTargetEvent searchTargetEvent = getSearchTargetEvent( + SearchTargetEvent searchTargetEvent = new SearchTargetEvent( SearchTarget.ItemType.PEOPLE, SearchTargetEvent.CHILD_SELECT); searchTargetEvent.bundle = new Bundle(); - searchTargetEvent.bundle.putParcelable("intent", mIntent); + searchTargetEvent.bundle.putParcelable("contact_uri", mContactUri); searchTargetEvent.bundle.putBundle("provider", provider); if (mPlugin != null) { mPlugin.notifySearchTargetEvent(searchTargetEvent); @@ -165,13 +169,14 @@ public class SearchResultPeopleView extends LinearLayout implements private void handleSelection(int eventType) { - if (mIntent != null) { + if (mContactUri != null) { Launcher launcher = Launcher.getLauncher(getContext()); - launcher.startActivitySafely(this, mIntent, null); - SearchTargetEvent searchTargetEvent = getSearchTargetEvent(SearchTarget.ItemType.PEOPLE, - eventType); + launcher.startActivitySafely(this, new Intent(Intent.ACTION_VIEW, mContactUri).setFlags( + Intent.FLAG_ACTIVITY_NEW_TASK), null); + SearchTargetEvent searchTargetEvent = new SearchTargetEvent( + SearchTarget.ItemType.PEOPLE, eventType); searchTargetEvent.bundle = new Bundle(); - searchTargetEvent.bundle.putParcelable("intent", mIntent); + searchTargetEvent.bundle.putParcelable("contact_uri", mContactUri); if (mPlugin != null) { mPlugin.notifySearchTargetEvent(searchTargetEvent); } diff --git a/src/com/android/launcher3/views/SearchResultPlayItem.java b/src/com/android/launcher3/views/SearchResultPlayItem.java index ff3ecc8bc3..8624609f80 100644 --- a/src/com/android/launcher3/views/SearchResultPlayItem.java +++ b/src/com/android/launcher3/views/SearchResultPlayItem.java @@ -58,8 +58,6 @@ public class SearchResultPlayItem extends LinearLayout implements private String mPackageName; private boolean mIsInstantGame; private AllAppsSearchPlugin mPlugin; - private final Object[] mTargetInfo = createTargetInfo(); - public SearchResultPlayItem(Context context) { this(context, null, 0); @@ -127,11 +125,6 @@ public class SearchResultPlayItem extends LinearLayout implements }); } - @Override - public Object[] getTargetInfo() { - return mTargetInfo; - } - private void showIfNecessary(TextView textView, @Nullable String string) { if (string == null || string.isEmpty()) { textView.setVisibility(GONE); @@ -167,7 +160,7 @@ public class SearchResultPlayItem extends LinearLayout implements } private void logSearchEvent(int eventType) { - SearchTargetEvent searchTargetEvent = getSearchTargetEvent( + SearchTargetEvent searchTargetEvent = new SearchTargetEvent( SearchTarget.ItemType.PLAY_RESULTS, eventType); searchTargetEvent.bundle = new Bundle(); searchTargetEvent.bundle.putString("package_name", mPackageName); diff --git a/src/com/android/launcher3/views/SearchResultShortcut.java b/src/com/android/launcher3/views/SearchResultShortcut.java new file mode 100644 index 0000000000..307cf34c7d --- /dev/null +++ b/src/com/android/launcher3/views/SearchResultShortcut.java @@ -0,0 +1,110 @@ +/* + * 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.views; + +import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; + +import android.content.Context; +import android.content.pm.ShortcutInfo; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.launcher3.BubbleTextView; +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.R; +import com.android.launcher3.allapps.AllAppsGridAdapter; +import com.android.launcher3.allapps.search.AllAppsSearchBarController; +import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.touch.ItemClickHandler; +import com.android.systemui.plugins.AllAppsSearchPlugin; +import com.android.systemui.plugins.shared.SearchTarget; +import com.android.systemui.plugins.shared.SearchTargetEvent; + +/** + * A view representing a stand alone shortcut search result + */ +public class SearchResultShortcut extends FrameLayout implements + AllAppsSearchBarController.PayloadResultHandler { + + private BubbleTextView mBubbleTextView; + private View mIconView; + private ShortcutInfo mShortcutInfo; + private AllAppsSearchPlugin mPlugin; + + public SearchResultShortcut(@NonNull Context context) { + super(context); + } + + public SearchResultShortcut(@NonNull Context context, + @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public SearchResultShortcut(@NonNull Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + Launcher launcher = Launcher.getLauncher(getContext()); + DeviceProfile grid = launcher.getDeviceProfile(); + mIconView = findViewById(R.id.icon); + ViewGroup.LayoutParams iconParams = mIconView.getLayoutParams(); + iconParams.height = grid.allAppsIconSizePx; + iconParams.width = grid.allAppsIconSizePx; + mBubbleTextView = findViewById(R.id.bubble_text); + setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT)); + } + + @Override + public void applyAdapterInfo( + AllAppsGridAdapter.AdapterItemWithPayload adapterItemWithPayload) { + SearchTarget payload = adapterItemWithPayload.getPayload(); + mPlugin = adapterItemWithPayload.getPlugin(); + mShortcutInfo = payload.shortcuts.get(0); + WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(mShortcutInfo, getContext()); + mBubbleTextView.applyFromWorkspaceItem(workspaceItemInfo); + mIconView.setBackground(mBubbleTextView.getIcon()); + LauncherAppState launcherAppState = LauncherAppState.getInstance(getContext()); + MODEL_EXECUTOR.execute(() -> { + launcherAppState.getIconCache().getShortcutIcon(workspaceItemInfo, mShortcutInfo); + mBubbleTextView.applyFromWorkspaceItem(workspaceItemInfo); + mIconView.setBackground(mBubbleTextView.getIcon()); + }); + adapterItemWithPayload.setSelectionHandler(this::handleSelection); + } + + private void handleSelection(int eventType) { + WorkspaceItemInfo itemInfo = (WorkspaceItemInfo) mBubbleTextView.getTag(); + ItemClickHandler.onClickAppShortcut(this, itemInfo, Launcher.getLauncher(getContext())); + + SearchTargetEvent searchTargetEvent = new SearchTargetEvent( + SearchTarget.ItemType.SHORTCUT, eventType); + searchTargetEvent.shortcut = mShortcutInfo; + if (mPlugin != null) { + mPlugin.notifySearchTargetEvent(searchTargetEvent); + } + } +} diff --git a/src/com/android/launcher3/views/SearchResultSuggestRow.java b/src/com/android/launcher3/views/SearchResultSuggestRow.java deleted file mode 100644 index b5abbcc724..0000000000 --- a/src/com/android/launcher3/views/SearchResultSuggestRow.java +++ /dev/null @@ -1,131 +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.views; - -import static com.android.systemui.plugins.shared.SearchTarget.ItemType.SUGGEST; - -import android.content.Context; -import android.os.Bundle; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.view.View; -import android.widget.LinearLayout; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.launcher3.Launcher; -import com.android.launcher3.R; -import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload; -import com.android.launcher3.allapps.search.AllAppsSearchBarController; -import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.model.data.RemoteActionItemInfo; -import com.android.launcher3.touch.ItemClickHandler; -import com.android.systemui.plugins.AllAppsSearchPlugin; -import com.android.systemui.plugins.shared.SearchTarget; -import com.android.systemui.plugins.shared.SearchTargetEvent; - -/** - * A view representing a fallback search suggestion row. - */ -public class SearchResultSuggestRow extends LinearLayout implements - View.OnClickListener, AllAppsSearchBarController.PayloadResultHandler { - - private final Object[] mTargetInfo = createTargetInfo(); - private AllAppsSearchPlugin mPlugin; - private AdapterItemWithPayload mAdapterItem; - private TextView mTitle; - - - public SearchResultSuggestRow(@NonNull Context context) { - super(context); - } - - public SearchResultSuggestRow(@NonNull Context context, - @Nullable AttributeSet attrs) { - super(context, attrs); - } - - public SearchResultSuggestRow(@NonNull Context context, @Nullable AttributeSet attrs, - int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mTitle = findViewById(R.id.title); - setOnClickListener(this); - } - @Override - public void applyAdapterInfo(AdapterItemWithPayload adapterItemWithPayload) { - mAdapterItem = adapterItemWithPayload; - SearchTarget payload = adapterItemWithPayload.getPayload(); - mPlugin = adapterItemWithPayload.getPlugin(); - - if (payload.mRemoteAction != null) { - RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(payload.mRemoteAction, - payload.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN), - payload.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START)); - setTag(itemInfo); - } - showIfAvailable(mTitle, payload.mRemoteAction.getTitle().toString()); - setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT)); - adapterItemWithPayload.setSelectionHandler(this::handleSelection); - } - - @Override - public Object[] getTargetInfo() { - return mTargetInfo; - } - - private void handleSelection(int eventType) { - ItemInfo itemInfo = (ItemInfo) getTag(); - Launcher launcher = Launcher.getLauncher(getContext()); - if (itemInfo instanceof RemoteActionItemInfo) return; - - RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo; - ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo); - SearchTargetEvent searchTargetEvent = getSearchTargetEvent(SUGGEST, eventType); - searchTargetEvent.bundle = new Bundle(); - searchTargetEvent.remoteAction = remoteItemInfo.getRemoteAction(); - searchTargetEvent.bundle.putBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START, - remoteItemInfo.shouldStartInLauncher()); - searchTargetEvent.bundle.putString(SearchTarget.REMOTE_ACTION_TOKEN, - remoteItemInfo.getToken()); - - if (mPlugin != null) { - mPlugin.notifySearchTargetEvent(searchTargetEvent); - } - } - - @Override - public void onClick(View view) { - handleSelection(SearchTargetEvent.SELECT); - } - - private void showIfAvailable(TextView view, @Nullable String string) { - System.out.println("Plugin suggest string:" + string); - if (TextUtils.isEmpty(string)) { - view.setVisibility(GONE); - } else { - System.out.println("Plugin suggest string:" + string); - view.setVisibility(VISIBLE); - view.setText(string); - } - } -} diff --git a/src/com/android/launcher3/views/SearchSectionHeaderView.java b/src/com/android/launcher3/views/SearchSectionHeaderView.java index 0fe0a43ff5..d439ee3d68 100644 --- a/src/com/android/launcher3/views/SearchSectionHeaderView.java +++ b/src/com/android/launcher3/views/SearchSectionHeaderView.java @@ -52,9 +52,4 @@ public class SearchSectionHeaderView extends TextView implements setVisibility(INVISIBLE); } } - - @Override - public Object[] getTargetInfo() { - return null; - } } diff --git a/src/com/android/launcher3/views/SearchSettingsRowView.java b/src/com/android/launcher3/views/SearchSettingsRowView.java index a1a0172547..93bcee2585 100644 --- a/src/com/android/launcher3/views/SearchSettingsRowView.java +++ b/src/com/android/launcher3/views/SearchSettingsRowView.java @@ -48,8 +48,6 @@ public class SearchSettingsRowView extends LinearLayout implements private TextView mBreadcrumbsView; private Intent mIntent; private AllAppsSearchPlugin mPlugin; - private final Object[] mTargetInfo = createTargetInfo(); - public SearchSettingsRowView(@NonNull Context context) { super(context); @@ -89,11 +87,6 @@ public class SearchSettingsRowView extends LinearLayout implements adapterItemWithPayload.setSelectionHandler(this::handleSelection); } - @Override - public Object[] getTargetInfo() { - return mTargetInfo; - } - private void showIfAvailable(TextView view, @Nullable String string) { if (TextUtils.isEmpty(string)) { view.setVisibility(GONE); @@ -115,7 +108,7 @@ public class SearchSettingsRowView extends LinearLayout implements Launcher launcher = Launcher.getLauncher(getContext()); launcher.startActivityForResult(mIntent, 0); - SearchTargetEvent searchTargetEvent = getSearchTargetEvent( + SearchTargetEvent searchTargetEvent = new SearchTargetEvent( SearchTarget.ItemType.SETTINGS_ROW, eventType); searchTargetEvent.bundle = new Bundle(); searchTargetEvent.bundle.putParcelable("intent", mIntent); diff --git a/src/com/android/launcher3/views/ThumbnailSearchResultView.java b/src/com/android/launcher3/views/ThumbnailSearchResultView.java deleted file mode 100644 index bbc47739f3..0000000000 --- a/src/com/android/launcher3/views/ThumbnailSearchResultView.java +++ /dev/null @@ -1,114 +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.views; - -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.net.Uri; -import android.util.AttributeSet; - -import androidx.core.graphics.drawable.RoundedBitmapDrawable; -import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; - -import com.android.launcher3.Launcher; -import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload; -import com.android.launcher3.allapps.search.AllAppsSearchBarController; -import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.model.data.RemoteActionItemInfo; -import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.touch.ItemClickHandler; -import com.android.launcher3.util.Themes; -import com.android.systemui.plugins.AllAppsSearchPlugin; -import com.android.systemui.plugins.shared.SearchTarget; -import com.android.systemui.plugins.shared.SearchTargetEvent; - -/** - * A view representing a high confidence app search result that includes shortcuts - */ -public class ThumbnailSearchResultView extends androidx.appcompat.widget.AppCompatImageView - implements AllAppsSearchBarController.PayloadResultHandler { - - private final Object[] mTargetInfo = createTargetInfo(); - AllAppsSearchPlugin mPlugin; - int mPosition; - - public ThumbnailSearchResultView(Context context) { - super(context); - } - - public ThumbnailSearchResultView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public ThumbnailSearchResultView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - private void handleSelection(int eventType) { - Launcher launcher = Launcher.getLauncher(getContext()); - ItemInfo itemInfo = (ItemInfo) getTag(); - if (itemInfo instanceof RemoteActionItemInfo) { - RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo; - ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo); - } else { - ItemClickHandler.onClickAppShortcut(this, (WorkspaceItemInfo) itemInfo, launcher); - } - if (mPlugin != null) { - SearchTargetEvent event = getSearchTargetEvent( - SearchTarget.ItemType.SCREENSHOT, eventType); - mPlugin.notifySearchTargetEvent(event); - } - } - - @Override - public void applyAdapterInfo(AdapterItemWithPayload adapterItem) { - Launcher launcher = Launcher.getLauncher(getContext()); - mPosition = adapterItem.position; - - SearchTarget target = adapterItem.getPayload(); - Bitmap bitmap; - if (target.mRemoteAction != null) { - RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(target.mRemoteAction, - target.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN), - target.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START)); - ItemClickHandler.onClickRemoteAction(launcher, itemInfo); - bitmap = ((BitmapDrawable) target.mRemoteAction.getIcon() - .loadDrawable(getContext())).getBitmap(); - setTag(itemInfo); - } else { - bitmap = (Bitmap) target.bundle.getParcelable("bitmap"); - WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(); - itemInfo.intent = new Intent(Intent.ACTION_VIEW) - .setData(Uri.parse(target.bundle.getString("uri"))) - .setType("image/*") - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - setTag(itemInfo); - } - RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(null, bitmap); - drawable.setCornerRadius(Themes.getDialogCornerRadius(getContext())); - setImageDrawable(drawable); - setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT)); - mPlugin = adapterItem.getPlugin(); - adapterItem.setSelectionHandler(this::handleSelection); - } - - @Override - public Object[] getTargetInfo() { - return mTargetInfo; - } -} diff --git a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java index aa3ab8f7e0..4fa670f44a 100644 --- a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java +++ b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java @@ -32,7 +32,7 @@ import java.util.function.Consumer; @ProvidesInterface(action = AllAppsSearchPlugin.ACTION, version = AllAppsSearchPlugin.VERSION) public interface AllAppsSearchPlugin extends Plugin { String ACTION = "com.android.systemui.action.PLUGIN_ALL_APPS_SEARCH_ACTIONS"; - int VERSION = 7; + int VERSION = 6; void setup(Activity activity, View view); @@ -42,12 +42,6 @@ public interface AllAppsSearchPlugin extends Plugin { void onStateTransitionStart(int fromState, int toState); void onStateTransitionComplete(int state); - /** - * Send launcher window focus and visibility changed signals. - */ - void onWindowFocusChanged(boolean hasFocus); - void onWindowVisibilityChanged(int visibility); - /** * Send signal when user starts typing, perform search, when search ends */ diff --git a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java index 3f0dc39cc1..c6b8300499 100644 --- a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java +++ b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java @@ -15,7 +15,6 @@ */ package com.android.systemui.plugins.shared; -import android.app.RemoteAction; import android.content.pm.ShortcutInfo; import android.os.Bundle; @@ -26,69 +25,17 @@ import java.util.List; */ public class SearchTarget implements Comparable { - - /** - * A bundle key for boolean value of whether remote action should be started in launcher or not - */ - public static final String REMOTE_ACTION_SHOULD_START = "should_start_for_result"; - public static final String REMOTE_ACTION_TOKEN = "action_token"; - - public enum ViewType { - - /** - * Consists of N number of icons. (N: launcher column count) - */ TOP_HIT(0), - - /** - * Consists of 1 icon and two subsidiary icons. - */ HERO(1), - - /** - * Main/sub/breadcrumb texts are rendered. - */ DETAIL(2), - - /** - * Consists of an icon, three detail strings. - */ ROW(3), - - /** - * Consists of an icon, three detail strings and a button. - */ ROW_WITH_BUTTON(4), - - /** - * Consists of a single slice view - */ SLICE(5), - - /** - * Similar to hero section. - */ SHORTCUT(6), - - /** - * Person icon and handling app icons are rendered. - */ - PEOPLE(7), - - /** - * N number of 1x1 ratio thumbnail is rendered. - * (current N = 3) - */ - THUMBNAIL(8), - - /** - * Fallback search icon and relevant text is rendered. - */ - SUGGEST(9); + PEOPLE(7); private final int mId; - ViewType(int id) { mId = id; } @@ -105,15 +52,9 @@ public class SearchTarget implements Comparable { APP(3, "", ViewType.TOP_HIT), APP_HERO(4, "", ViewType.HERO), SHORTCUT(5, "Shortcuts", ViewType.SHORTCUT), - PEOPLE(6, "People", ViewType.PEOPLE), - SCREENSHOT(7, "Screenshots", ViewType.THUMBNAIL), - ACTION(8, "Actions", ViewType.SHORTCUT), - SUGGEST(9, "Fallback Search", ViewType.SUGGEST), - CHROME_TAB(10, "Chrome Tab", ViewType.SHORTCUT); + PEOPLE(6, "People", ViewType.PEOPLE); private final int mId; - - /** Used to render section title. */ private final String mTitle; private final ViewType mViewType; @@ -140,21 +81,19 @@ public class SearchTarget implements Comparable { public List shortcuts; public Bundle bundle; public float score; - public String mSessionId; - public RemoteAction mRemoteAction; /** * Constructor to create the search target. Bundle is currently temporary to hold * search target primitives that cannot be expressed as java primitive objects * or AOSP native objects. + * */ public SearchTarget(ItemType itemType, List shortcuts, - Bundle bundle, float score, String sessionId) { + Bundle bundle, float score) { this.type = itemType; this.shortcuts = shortcuts; this.bundle = bundle; this.score = score; - this.mSessionId = sessionId; } @Override diff --git a/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java b/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java index 5016abc1e9..ac4bc333c6 100644 --- a/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java +++ b/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java @@ -15,7 +15,6 @@ */ package com.android.systemui.plugins.shared; -import android.app.RemoteAction; import android.content.pm.ShortcutInfo; import android.os.Bundle; @@ -30,17 +29,12 @@ public class SearchTargetEvent { public SearchTarget.ItemType type; public ShortcutInfo shortcut; - public RemoteAction remoteAction; public int eventType; public Bundle bundle; - public int index; - public String sessionIdentifier; + public float score; - public SearchTargetEvent(SearchTarget.ItemType itemType, int eventType, int index, - String sessionId) { + public SearchTargetEvent(SearchTarget.ItemType itemType, int eventType) { this.type = itemType; this.eventType = eventType; - this.index = index; - this.sessionIdentifier = sessionId; } } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java index a4e53a1cc0..ec3f93ff1b 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java @@ -16,13 +16,13 @@ package com.android.launcher3.uioverrides.states; import static com.android.launcher3.anim.Interpolators.DEACCEL_2; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS; import android.content.Context; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; /** * Definition for AllApps state @@ -41,7 +41,7 @@ public class AllAppsState extends LauncherState { }; public AllAppsState(int id) { - super(id, LAUNCHER_STATE_ALLAPPS, STATE_FLAGS); + super(id, ContainerType.ALLAPPS, STATE_FLAGS); } @Override diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java index da5a94f6fd..d102bccaad 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java @@ -15,11 +15,10 @@ */ package com.android.launcher3.uioverrides.states; -import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW; - import android.content.Context; import com.android.launcher3.LauncherState; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; /** * Definition for overview state @@ -27,7 +26,7 @@ import com.android.launcher3.LauncherState; public class OverviewState extends LauncherState { public OverviewState(int id) { - super(id, LAUNCHER_STATE_OVERVIEW, FLAG_DISABLE_RESTORE); + super(id, ContainerType.WORKSPACE, FLAG_DISABLE_RESTORE); } @Override diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index e118481570..5e42d9b988 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -279,8 +279,6 @@ public abstract class AbstractLauncherUiTest { if (userManager != null) { for (UserHandle userHandle : userManager.getUserProfiles()) { if (!userHandle.isSystem()) { - Log.d(TestProtocol.WORK_PROFILE_REMOVED, - "removing user " + userHandle.getIdentifier()); mDevice.executeShellCommand("pm remove-user " + userHandle.getIdentifier()); } } diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java index 8d594de926..f5f93c429f 100644 --- a/tests/src/com/android/launcher3/ui/WorkTabTest.java +++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java @@ -55,9 +55,7 @@ public class WorkTabTest extends AbstractLauncherUiTest { private static final int WORK_PAGE = AllAppsContainerView.AdapterHolder.WORK; @Before - @Override - public void setUp() throws Exception { - super.setUp(); + public void createWorkProfile() throws Exception { String output = mDevice.executeShellCommand( "pm create-user --profileOf 0 --managed TestProfile"); @@ -138,8 +136,7 @@ public class WorkTabTest extends AbstractLauncherUiTest { }); executeOnLauncher(launcher -> Log.d(TestProtocol.WORK_PROFILE_REMOVED, - "work profile status (" + mProfileUserId + ") :" - + launcher.getAppsView().isWorkTabVisible())); + "Work profile status: " + launcher.getAppsView().isPersonalTabVisible())); // verify work edu is seen next waitForLauncherCondition("Launcher did not show the next edu screen", l -> From 4fd82210af25e8365072e8b6d7c85197d0eb2c94 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Tue, 10 Nov 2020 16:53:25 -0800 Subject: [PATCH 02/17] Include more error logging for widget restore Bug: 171774227 Test: manually tested complete backup & restore flow Change-Id: Ieb4b39d80a24b4dff377ee74d24d9010acd0daca (cherry picked from commit ae1997b9d51f996dff41bd792a33176a112b1ef2) (cherry picked from commit af0391f9b25bcf7070b537b4e9cc95fcea8c441a) --- src/com/android/launcher3/Launcher.java | 4 +++- src/com/android/launcher3/LauncherProvider.java | 6 ++++++ src/com/android/launcher3/model/LoaderTask.java | 6 +++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 699734c0c5..59365a55d4 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -2330,7 +2330,9 @@ public class Launcher extends StatefulActivity implements Launche if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) { // Verify that we own the widget if (appWidgetInfo == null) { - FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId); + FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId + + ",title=" + item.title + + ",providerName=" + item.providerName.toShortString()); getModelWriter().deleteWidgetInfo(item, getAppWidgetHost()); return null; } diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index aeed16aa28..6af248cd78 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -85,6 +85,7 @@ import java.util.Arrays; import java.util.Locale; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; +import java.util.stream.Collectors; public class LauncherProvider extends ContentProvider { private static final String TAG = "LauncherProvider"; @@ -931,6 +932,11 @@ public class LauncherProvider extends ContentProvider { final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(db, Favorites.TABLE_NAME, Favorites.APPWIDGET_ID, "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null)); + final String allWidgetIds = Arrays.stream(allWidgets).mapToObj(String::valueOf) + .collect(Collectors.joining(",")); + final String validWidgetIds = validWidgets.getArray().toConcatString(); + FileLog.d(TAG, "All widget ids: " + allWidgetIds); + FileLog.d(TAG, "Valid widget ids: " + validWidgetIds); for (int widgetId : allWidgets) { if (!validWidgets.contains(widgetId)) { try { diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index b108788061..80a684d86e 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -745,7 +745,11 @@ public class LoaderTask implements Runnable { + "span=" + appWidgetInfo.spanX + "x" + appWidgetInfo.spanY + " minSpan=" + widgetProviderInfo.minSpanX + "x" - + widgetProviderInfo.minSpanY); + + widgetProviderInfo.minSpanY + + ", appWidgetInfo.provider=" + + appWidgetInfo.providerName.toShortString() + + ", widgetProviderInfo.provider=" + + widgetProviderInfo.provider.toShortString()); continue; } if (!c.isOnWorkspaceOrHotseat()) { From f21f8127621bb231621e18ab59783ac266212a83 Mon Sep 17 00:00:00 2001 From: Schneider Victor-tulias Date: Thu, 7 Jan 2021 19:44:44 +0000 Subject: [PATCH 03/17] Revert "Add UI updates for incremental app installs." This reverts commit 84269d349d093b6b0bd2b68e2306f7e0475cd4f5. Reason for revert: causes b/176884453 and b/176992421 Change-Id: I3398674a0acbad8329df5d341ae074ac073a6bf9 (cherry picked from commit 229497d1820f49450687bbc558041df97d0bf779) --- .../PackageInstallStateChangedTaskTest.java | 2 +- src/com/android/launcher3/BubbleTextView.java | 50 ++++------ src/com/android/launcher3/Launcher.java | 5 +- src/com/android/launcher3/LauncherModel.java | 10 -- src/com/android/launcher3/Utilities.java | 7 +- src/com/android/launcher3/Workspace.java | 2 +- .../launcher3/allapps/AllAppsStore.java | 12 +-- .../launcher3/folder/PreviewItemManager.java | 6 +- .../graphics/PreloadIconDrawable.java | 4 +- .../model/AddWorkspaceItemsTask.java | 5 +- .../android/launcher3/model/AllAppsList.java | 33 +++---- .../android/launcher3/model/BgDataModel.java | 7 +- .../android/launcher3/model/LoaderCursor.java | 23 ++--- .../android/launcher3/model/LoaderTask.java | 24 +---- ...PackageIncrementalDownloadUpdatedTask.java | 79 --------------- .../model/PackageInstallStateChangedTask.java | 21 ++-- .../android/launcher3/model/data/AppInfo.java | 40 +------- .../model/data/ItemInfoWithIcon.java | 97 ------------------- .../launcher3/model/data/PromiseAppInfo.java | 54 +++++++++++ .../model/data/WorkspaceItemInfo.java | 25 ++++- .../launcher3/pm/PackageInstallInfo.java | 4 +- .../SecondaryDisplayLauncher.java | 14 ++- .../launcher3/touch/ItemClickHandler.java | 19 ++-- .../launcher3/util/PackageManagerHelper.java | 20 +--- 24 files changed, 163 insertions(+), 400 deletions(-) delete mode 100644 src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java create mode 100644 src/com/android/launcher3/model/data/PromiseAppInfo.java diff --git a/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java index 412ace03ff..e43df21ae9 100644 --- a/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java @@ -67,7 +67,7 @@ public class PackageInstallStateChangedTaskTest { for (ItemInfo info : mModelHelper.getBgDataModel().itemsIdMap) { if (info instanceof WorkspaceItemInfo) { assertEquals(updates.contains(info.id) ? progress: 0, - ((WorkspaceItemInfo) info).getProgressLevel()); + ((WorkspaceItemInfo) info).getInstallProgress()); } else { assertEquals(updates.contains(info.id) ? progress: -1, ((LauncherAppWidgetInfo) info).installProgress); diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index f44f88b098..3eb52adf1a 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -50,7 +50,6 @@ import android.view.View; import android.view.ViewDebug; import android.widget.TextView; -import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import com.android.launcher3.Launcher.OnResumeCallback; @@ -72,6 +71,7 @@ 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.PackageItemInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.RemoteActionItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.SafeCloseable; @@ -287,7 +287,10 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, public void applyFromWorkspaceItem(WorkspaceItemInfo info, boolean promiseStateChanged) { applyIconAndLabel(info); setTag(info); - applyLoadingState(promiseStateChanged); + if (promiseStateChanged || (info.hasPromiseIconUi())) { + applyPromiseState(promiseStateChanged); + } + applyDotState(info, false /* animate */); } @@ -300,8 +303,9 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, // Verify high res immediately verifyHighRes(); - if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) { - applyProgressLevel(info.getProgressLevel()); + if (info instanceof PromiseAppInfo) { + PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info; + applyProgressLevel(promiseAppInfo.level); } applyDotState(info, false /* animate */); } @@ -331,10 +335,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, mDotParams.color = IconPalette.getMutedColor(info.bitmap.color, 0.54f); setIcon(iconDrawable); - applyLabel(info); - } - - private void applyLabel(ItemInfoWithIcon info) { setText(info.title); if (info.contentDescription != null) { setContentDescription(info.isDisabled() @@ -595,35 +595,21 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, mLongPressHelper.cancelLongPress(); } - /** Applies the loading progress value to the progress bar. - * - * If this app is installing, the progress bar will be updated with the installation progress. - * If this app is installed and downloading incrementally, the progress bar will be updated - * with the total download progress. - */ - public void applyLoadingState(boolean promiseStateChanged) { + public void applyPromiseState(boolean promiseStateChanged) { if (getTag() instanceof WorkspaceItemInfo) { WorkspaceItemInfo info = (WorkspaceItemInfo) getTag(); - int progressLevel = info.getProgressLevel(); - if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) - != 0) { - updateProgressBarUi(progressLevel, progressLevel == 100); - } else if (info.hasPromiseIconUi() || (info.runtimeStatusFlags - & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { - updateProgressBarUi(progressLevel, promiseStateChanged); + final boolean isPromise = info.hasPromiseIconUi(); + final int progressLevel = isPromise ? + ((info.hasStatusFlag(WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE) ? + info.getInstallProgress() : 0)) : 100; + + PreloadIconDrawable preloadDrawable = applyProgressLevel(progressLevel); + if (preloadDrawable != null && promiseStateChanged) { + preloadDrawable.maybePerformFinishedAnimation(); } } } - private void updateProgressBarUi(int progressLevel, boolean maybePerformFinishedAnimation) { - PreloadIconDrawable preloadDrawable = applyProgressLevel(progressLevel); - if (preloadDrawable != null && maybePerformFinishedAnimation) { - preloadDrawable.maybePerformFinishedAnimation(); - } - } - - /** Applies the given progress level to the this icon's progress bar. */ - @Nullable public PreloadIconDrawable applyProgressLevel(int progressLevel) { if (getTag() instanceof ItemInfoWithIcon) { ItemInfoWithIcon info = (ItemInfoWithIcon) getTag(); @@ -643,11 +629,9 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, if (mIcon instanceof PreloadIconDrawable) { preloadDrawable = (PreloadIconDrawable) mIcon; preloadDrawable.setLevel(progressLevel); - preloadDrawable.setIsDisabled(!info.isAppStartable()); } else { preloadDrawable = newPendingIcon(getContext(), info); preloadDrawable.setLevel(progressLevel); - preloadDrawable.setIsDisabled(!info.isAppStartable()); setIcon(preloadDrawable); } return preloadDrawable; diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 5b55c4b435..a96fabd66e 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -137,6 +137,7 @@ 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.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.pm.PinRequestHelper; @@ -2515,8 +2516,8 @@ public class Launcher extends StatefulActivity implements Launche } @Override - public void bindIncrementalDownloadProgressUpdated(AppInfo app) { - mAppsView.getAppsStore().updateProgressBar(app); + public void bindPromiseAppProgressUpdated(PromiseAppInfo app) { + mAppsView.getAppsStore().updatePromiseAppProgress(app); } @Override diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index e89b9b060a..8458152146 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -48,7 +48,6 @@ import com.android.launcher3.model.LoaderResults; import com.android.launcher3.model.LoaderTask; import com.android.launcher3.model.ModelDelegate; import com.android.launcher3.model.ModelWriter; -import com.android.launcher3.model.PackageIncrementalDownloadUpdatedTask; import com.android.launcher3.model.PackageInstallStateChangedTask; import com.android.launcher3.model.PackageUpdatedTask; import com.android.launcher3.model.ShortcutsChangedTask; @@ -196,15 +195,6 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi PackageUpdatedTask.OP_UNSUSPEND, user, packageNames)); } - @Override - public void onPackageLoadingProgressChanged( - String packageName, UserHandle user, float progress) { - if (Utilities.ATLEAST_S) { - enqueueModelUpdateTask(new PackageIncrementalDownloadUpdatedTask( - packageName, user, progress)); - } - } - @Override public void onShortcutsChanged(String packageName, List shortcuts, UserHandle user) { diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index df5d23428d..5c2f35b981 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -107,13 +107,12 @@ public final class Utilities { public static final String[] EMPTY_STRING_ARRAY = new String[0]; public static final Person[] EMPTY_PERSON_ARRAY = new Person[0]; - public static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; + public static final boolean ATLEAST_R = BuildCompat.isAtLeastR(); public static final boolean ATLEAST_Q = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; - public static final boolean ATLEAST_R = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R; - - public static final boolean ATLEAST_S = BuildCompat.isAtLeastS(); + public static final boolean ATLEAST_P = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; /** * Set on a motion event dispatched from the nav bar. See {@link MotionEvent#setEdgeFlags(int)}. diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 65eba20672..777ea3c7d5 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -3154,7 +3154,7 @@ public class Workspace extends PagedView ItemOperator op = (info, v) -> { if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView && updates.contains(info)) { - ((BubbleTextView) v).applyLoadingState(false /* promiseStateChanged */); + ((BubbleTextView) v).applyPromiseState(false /* promiseStateChanged */); } else if (v instanceof PendingAppWidgetHostView && info instanceof LauncherAppWidgetInfo && updates.contains(info)) { diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java index 00bdb70c4a..3ae0a18137 100644 --- a/src/com/android/launcher3/allapps/AllAppsStore.java +++ b/src/com/android/launcher3/allapps/AllAppsStore.java @@ -24,6 +24,7 @@ import android.view.ViewGroup; import com.android.launcher3.BubbleTextView; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageUserKey; @@ -144,17 +145,10 @@ public class AllAppsStore { }); } - /** - * Sets the AppInfo's associated icon's progress bar. - * - * If this app is installed and supports incremental downloads, the progress bar will be updated - * the app's total download progress. Otherwise, the progress bar will be updated to the app's - * installation progress. - */ - public void updateProgressBar(AppInfo app) { + public void updatePromiseAppProgress(PromiseAppInfo app) { updateAllIcons((child) -> { if (child.getTag() == app) { - child.applyProgressLevel(app.getProgressLevel()); + child.applyProgressLevel(app.level); } }); } diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java index 9ae7faf988..7f8a15c927 100644 --- a/src/com/android/launcher3/folder/PreviewItemManager.java +++ b/src/com/android/launcher3/folder/PreviewItemManager.java @@ -39,7 +39,6 @@ import androidx.annotation.NonNull; import com.android.launcher3.Utilities; import com.android.launcher3.graphics.PreloadIconDrawable; -import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.views.ActivityContext; @@ -395,10 +394,9 @@ public class PreviewItemManager { } private void setDrawable(PreviewItemDrawingParams p, WorkspaceItemInfo item) { - if (item.hasPromiseIconUi() || (item.runtimeStatusFlags - & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) { + if (item.hasPromiseIconUi()) { PreloadIconDrawable drawable = newPendingIcon(mContext, item); - drawable.setLevel(item.getProgressLevel()); + drawable.setLevel(item.getInstallProgress()); p.drawable = drawable; } else { p.drawable = newIcon(mContext, item); diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java index 9971990267..e85b056376 100644 --- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java +++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java @@ -117,8 +117,6 @@ public class PreloadIconDrawable extends FastBitmapDrawable { mIndicatorColor = IconPalette.getPreloadProgressColor(context, mIconColor); setInternalProgress(0); - - setIsDisabled(!info.isAppStartable()); } @Override @@ -268,12 +266,14 @@ public class PreloadIconDrawable extends FastBitmapDrawable { mIconScale = SMALL_SCALE; mScaledTrackPath.reset(); mTrackAlpha = MAX_PAINT_ALPHA; + setIsDisabled(true); } if (progress < 1 && progress > 0) { mPathMeasure.getSegment(0, progress * mTrackLength, mScaledProgressPath, true); mIconScale = SMALL_SCALE; mTrackAlpha = MAX_PAINT_ALPHA; + setIsDisabled(true); } else if (progress >= 1) { setIsDisabled(mItem.isDisabled()); mScaledTrackPath.set(mScaledProgressPath); diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java index 56dbbd33da..c236fa6dec 100644 --- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java +++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java @@ -34,7 +34,6 @@ import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.InstallSessionHelper; -import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.PackageManagerHelper; @@ -133,9 +132,7 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask { continue; } } else { - workspaceInfo.setProgressLevel( - (int) (sessionInfo.getProgress() * 100), - PackageInstallInfo.STATUS_INSTALLING); + workspaceInfo.setInstallProgress((int) sessionInfo.getProgress()); } if (hasActivity) { diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index 8d5cf7422f..2695e66591 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -21,11 +21,11 @@ import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.os.LocaleList; +import android.os.Process; import android.os.UserHandle; import android.util.Log; @@ -37,6 +37,7 @@ import com.android.launcher3.compat.AlphabeticIndexCompat; import com.android.launcher3.icons.IconCache; import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.data.AppInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.FlagOp; import com.android.launcher3.util.ItemInfoMatcher; @@ -149,7 +150,7 @@ public class AllAppsList { .getApplicationInfo(installInfo.packageName, installInfo.user, 0); // only if not yet installed if (applicationInfo == null) { - AppInfo info = new AppInfo(installInfo); + PromiseAppInfo info = new PromiseAppInfo(installInfo); mIconCache.getTitleAndIcon(info, info.usingLowResIcon()); info.sectionName = mIndex.computeSectionName(info.title); @@ -158,26 +159,24 @@ public class AllAppsList { } } - /** Updates the given PackageInstallInfo's associated AppInfo's installation info. */ - public List updatePromiseInstallInfo(PackageInstallInfo installInfo) { - List updatedAppInfos = new ArrayList<>(); - UserHandle user = installInfo.user; - for (int i = data.size() - 1; i >= 0; i--) { + public PromiseAppInfo updatePromiseInstallInfo(PackageInstallInfo installInfo) { + UserHandle user = Process.myUserHandle(); + for (int i=0; i < data.size(); i++) { final AppInfo appInfo = data.get(i); final ComponentName tgtComp = appInfo.getTargetComponent(); if (tgtComp != null && tgtComp.getPackageName().equals(installInfo.packageName) - && appInfo.user.equals(user)) { - if (installInfo.state == PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING - || installInfo.state == PackageInstallInfo.STATUS_INSTALLING) { - appInfo.setProgressLevel(installInfo); - - updatedAppInfos.add(appInfo); + && appInfo.user.equals(user) + && appInfo instanceof PromiseAppInfo) { + final PromiseAppInfo promiseAppInfo = (PromiseAppInfo) appInfo; + if (installInfo.state == PackageInstallInfo.STATUS_INSTALLING) { + promiseAppInfo.level = installInfo.progress; + return promiseAppInfo; } else if (installInfo.state == PackageInstallInfo.STATUS_FAILED) { removeApp(i); } } } - return updatedAppInfos; + return null; } private void removeApp(int index) { @@ -269,14 +268,8 @@ public class AllAppsList { if (applicationInfo == null) { add(new AppInfo(context, info, user), info); } else { - Intent launchIntent = AppInfo.makeLaunchIntent(info); - mIconCache.getTitleAndIcon(applicationInfo, info, true /* useLowResIcon */); applicationInfo.sectionName = mIndex.computeSectionName(applicationInfo.title); - applicationInfo.setProgressLevel( - PackageManagerHelper.getLoadingProgress(info), - PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING); - applicationInfo.intent = launchIntent; mDataChanged = true; } diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index 2d860a41d3..c217a475a1 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -39,6 +39,7 @@ 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.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.UserCache; import com.android.launcher3.shortcuts.ShortcutKey; @@ -458,11 +459,7 @@ public class BgDataModel { void preAddApps(); void bindAppsAdded(IntArray newScreens, ArrayList addNotAnimated, ArrayList addAnimated); - - /** - * Binds updated incremental download progress - */ - void bindIncrementalDownloadProgressUpdated(AppInfo app); + void bindPromiseAppProgressUpdated(PromiseAppInfo app); void bindWorkspaceItemsChanged(List updated); void bindWidgetsRestored(ArrayList widgets); void bindRestoreItemsChange(HashSet updates); diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 19d9af98dc..532834eeb8 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -35,13 +35,11 @@ import android.text.TextUtils; import android.util.Log; import android.util.LongSparseArray; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; -import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.config.FeatureFlags; @@ -94,9 +92,6 @@ public class LoaderCursor extends CursorWrapper { private final int restoredIndex; private final int intentIndex; - @Nullable - private LauncherActivityInfo mActivityInfo; - // Properties loaded per iteration public long serialNumber; public UserHandle user; @@ -137,8 +132,6 @@ public class LoaderCursor extends CursorWrapper { public boolean moveToNext() { boolean result = super.moveToNext(); if (result) { - mActivityInfo = null; - // Load common properties. itemType = getInt(itemTypeIndex); container = getInt(containerIndex); @@ -252,10 +245,6 @@ public class LoaderCursor extends CursorWrapper { return info; } - public LauncherActivityInfo getLauncherActivityInfo() { - return mActivityInfo; - } - /** * Make an WorkspaceItemInfo object for a shortcut that is an application. */ @@ -275,25 +264,25 @@ public class LoaderCursor extends CursorWrapper { Intent newIntent = new Intent(Intent.ACTION_MAIN, null); newIntent.addCategory(Intent.CATEGORY_LAUNCHER); newIntent.setComponent(componentName); - mActivityInfo = mContext.getSystemService(LauncherApps.class) + LauncherActivityInfo lai = mContext.getSystemService(LauncherApps.class) .resolveActivity(newIntent, user); - if ((mActivityInfo == null) && !allowMissingTarget) { + if ((lai == null) && !allowMissingTarget) { Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName); return null; } final WorkspaceItemInfo info = new WorkspaceItemInfo(); - info.itemType = Favorites.ITEM_TYPE_APPLICATION; + info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; info.user = user; info.intent = newIntent; - mIconCache.getTitleAndIcon(info, mActivityInfo, useLowResIcon); + mIconCache.getTitleAndIcon(info, lai, useLowResIcon); if (mIconCache.isDefaultIcon(info.bitmap, user)) { loadIcon(info); } - if (mActivityInfo != null) { - AppInfo.updateRuntimeFlagsForActivityTarget(info, mActivityInfo); + if (lai != null) { + AppInfo.updateRuntimeFlagsForActivityTarget(info, lai); } // from the db diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index f74c8b5c1c..8e085ce52d 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -69,7 +69,6 @@ import com.android.launcher3.logging.FileLog; 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.LauncherAppWidgetInfo; import com.android.launcher3.model.data.PackageItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -592,24 +591,11 @@ public class LoaderTask implements Runnable { if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) { tempPackageKey.update(targetPkg, c.user); SessionInfo si = installingPkgs.get(tempPackageKey); - LauncherActivityInfo activityInfo = - c.getLauncherActivityInfo(); - if (si == null) { - info.runtimeStatusFlags &= - ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; - } else if (activityInfo == null) { - int installProgress = (int) (si.getProgress() * 100); - - info.setProgressLevel( - installProgress, - PackageInstallInfo.STATUS_INSTALLING); - } else { - info.setProgressLevel( - PackageManagerHelper - .getLoadingProgress(activityInfo), - PackageInstallInfo - .STATUS_INSTALLED_DOWNLOADING); - } + if (si == null) { + info.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE; + } else { + info.setInstallProgress((int) (si.getProgress() * 100)); + } } c.checkAndAddItem(info, mBgDataModel); diff --git a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java deleted file mode 100644 index e3e87693b1..0000000000 --- a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java +++ /dev/null @@ -1,79 +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.model; - -import android.content.ComponentName; -import android.os.UserHandle; - -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.model.data.AppInfo; -import com.android.launcher3.model.data.ItemInfoWithIcon; -import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.pm.PackageInstallInfo; - -import java.util.ArrayList; -import java.util.List; - -/** - * Handles updates due to incremental download progress updates. - */ -public class PackageIncrementalDownloadUpdatedTask extends BaseModelUpdateTask { - - private final UserHandle mUser; - private final int mProgress; - private final String mPackageName; - - public PackageIncrementalDownloadUpdatedTask( - String packageName, UserHandle user, float progress) { - mUser = user; - mProgress = 1 - progress > 0.001 ? (int) (100 * progress) : 100; - mPackageName = packageName; - } - - @Override - public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) { - PackageInstallInfo downloadInfo = new PackageInstallInfo( - mPackageName, - PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING, - mProgress, - mUser); - - synchronized (appsList) { - List updatedAppInfos = appsList.updatePromiseInstallInfo(downloadInfo); - if (!updatedAppInfos.isEmpty()) { - for (AppInfo appInfo : updatedAppInfos) { - appInfo.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; - scheduleCallbackTask( - c -> c.bindIncrementalDownloadProgressUpdated(appInfo)); - } - } - bindApplicationsIfNeeded(); - } - - final ArrayList updatedWorkspaceItems = new ArrayList<>(); - synchronized (dataModel) { - dataModel.forAllWorkspaceItemInfos(mUser, si -> { - ComponentName cn = si.getTargetComponent(); - if ((cn != null) && cn.getPackageName().equals(mPackageName)) { - si.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; - si.setProgressLevel(downloadInfo); - updatedWorkspaceItems.add(si); - } - }); - } - bindUpdatedWorkspaceItems(updatedWorkspaceItems); - } -} diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java index 8215edd90b..8369c48e5c 100644 --- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java +++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java @@ -20,15 +20,14 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import com.android.launcher3.LauncherAppState; -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.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.PromiseAppInfo; +import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.InstantAppResolver; import java.util.HashSet; -import java.util.List; /** * Handles changes due to a sessions updates for a currently installing app. @@ -60,11 +59,9 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask { } synchronized (apps) { - List updatedAppInfos = apps.updatePromiseInstallInfo(mInstallInfo); - if (!updatedAppInfos.isEmpty()) { - for (AppInfo appInfo : updatedAppInfos) { - scheduleCallbackTask(c -> c.bindIncrementalDownloadProgressUpdated(appInfo)); - } + PromiseAppInfo updated = apps.updatePromiseInstallInfo(mInstallInfo); + if (updated != null) { + scheduleCallbackTask(c -> c.bindPromiseAppProgressUpdated(updated)); } bindApplicationsIfNeeded(); } @@ -74,13 +71,11 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask { dataModel.forAllWorkspaceItemInfos(mInstallInfo.user, si -> { ComponentName cn = si.getTargetComponent(); if (si.hasPromiseIconUi() && (cn != null) - && cn.getPackageName().equals(mInstallInfo.packageName)) { - int installProgress = mInstallInfo.progress; - - si.setProgressLevel(installProgress, PackageInstallInfo.STATUS_INSTALLING); + && mInstallInfo.packageName.equals(cn.getPackageName())) { + si.setInstallProgress(mInstallInfo.progress); if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) { // Mark this info as broken. - si.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; + si.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE; } updates.add(si); } diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java index 39247c221f..aee1f2a65b 100644 --- a/src/com/android/launcher3/model/data/AppInfo.java +++ b/src/com/android/launcher3/model/data/AppInfo.java @@ -28,13 +28,10 @@ import android.os.Process; import android.os.UserHandle; import android.os.UserManager; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Utilities; -import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageManagerHelper; @@ -107,37 +104,13 @@ public class AppInfo extends ItemInfoWithIcon { this.intent = intent; } - public AppInfo(@NonNull PackageInstallInfo installInfo) { - componentName = installInfo.componentName; - intent = new Intent(Intent.ACTION_MAIN) - .addCategory(Intent.CATEGORY_LAUNCHER) - .setComponent(componentName) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - user = installInfo.user; - } - @Override protected String dumpProperties() { return super.dumpProperties() + " componentName=" + componentName; } public WorkspaceItemInfo makeWorkspaceItem() { - WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(this); - - if ((runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) { - // We need to update the component name when the apk is installed - workspaceItemInfo.status |= WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON; - // Since the user is manually placing it on homescreen, it should not be auto-removed - // later - workspaceItemInfo.status |= WorkspaceItemInfo.FLAG_RESTORE_STARTED; - workspaceItemInfo.status |= FLAG_INSTALL_SESSION_ACTIVE; - } - if ((runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0) { - workspaceItemInfo.runtimeStatusFlags |= FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; - } - - return workspaceItemInfo; + return new WorkspaceItemInfo(this); } public ComponentKey toComponentKey() { @@ -156,12 +129,6 @@ public class AppInfo extends ItemInfoWithIcon { | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); } - @Nullable - @Override - public ComponentName getTargetComponent() { - return componentName; - } - public static void updateRuntimeFlagsForActivityTarget( ItemInfoWithIcon info, LauncherActivityInfo lai) { ApplicationInfo appInfo = lai.getApplicationInfo(); @@ -176,11 +143,6 @@ public class AppInfo extends ItemInfoWithIcon { // The icon for a non-primary user is badged, hence it's not exactly an adaptive icon. info.runtimeStatusFlags |= FLAG_ADAPTIVE_ICON; } - - // Sets the progress level, installation and incremental download flags. - info.setProgressLevel( - PackageManagerHelper.getLoadingProgress(lai), - PackageInstallInfo.STATUS_INSTALLED); } @Override diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java index b8a71d33e0..d95f94f79f 100644 --- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java +++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java @@ -16,15 +16,7 @@ package com.android.launcher3.model.data; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; - -import androidx.annotation.Nullable; - import com.android.launcher3.icons.BitmapInfo; -import com.android.launcher3.pm.PackageInstallInfo; -import com.android.launcher3.util.PackageManagerHelper; /** * Represents an ItemInfo which also holds an icon. @@ -95,35 +87,12 @@ public abstract class ItemInfoWithIcon extends ItemInfo { */ public static final int FLAG_ICON_BADGED = 1 << 9; - /** - * The icon is being installed. If {@link WorkspaceItemInfo#FLAG_RESTORED_ICON} or - * {@link WorkspaceItemInfo#FLAG_AUTOINSTALL_ICON} is set, then the icon is either being - * installed or is in a broken state. - */ - public static final int FLAG_INSTALL_SESSION_ACTIVE = 1 << 10; - - /** - * This icon is still being downloaded. - */ - public static final int FLAG_INCREMENTAL_DOWNLOAD_ACTIVE = 1 << 11; - - public static final int FLAG_SHOW_DOWNLOAD_PROGRESS_MASK = FLAG_INSTALL_SESSION_ACTIVE - | FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; - /** * Status associated with the system state of the underlying item. This is calculated every * time a new info is created and not persisted on the disk. */ public int runtimeStatusFlags = 0; - /** - * The download progress of the package that this shortcut represents. For legacy apps, this - * will always be the installation progress. For apps that support incremental downloads, this - * will only match be the installation progress until the app is installed, then this will the - * total download progress. - */ - private int mProgressLevel = 100; - protected ItemInfoWithIcon() { } protected ItemInfoWithIcon(ItemInfoWithIcon info) { @@ -144,72 +113,6 @@ public abstract class ItemInfoWithIcon extends ItemInfo { return bitmap.isLowRes(); } - /** - * Returns whether the app this shortcut represents is able to be started. For legacy apps, - * this returns whether it is fully installed. For apps that support incremental downloads, - * this returns whether the app is either fully downloaded or has installed and is downloading - * incrementally. - */ - public boolean isAppStartable() { - return ((runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) == 0) - && (((runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0) - || mProgressLevel == 100); - } - - /** - * Returns the download progress for the app this shortcut represents. If this app is not yet - * installed or does not support incremental downloads, this will return the installation - * progress. - */ - public int getProgressLevel() { - if ((runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) { - return mProgressLevel; - } - return 100; - } - - /** - * Sets the download progress for the app this shortcut represents. If this app is not yet - * installed or does not support incremental downloads, this will set - * {@code FLAG_INSTALL_SESSION_ACTIVE}. If this app is downloading incrementally, this will - * set {@code FLAG_INCREMENTAL_DOWNLOAD_ACTIVE}. Otherwise, this will remove both flags. - */ - public void setProgressLevel(PackageInstallInfo installInfo) { - setProgressLevel(installInfo.progress, installInfo.state); - } - - /** - * Sets the download progress for the app this shortcut represents. - */ - public void setProgressLevel(int progress, int status) { - if (status == PackageInstallInfo.STATUS_INSTALLING) { - mProgressLevel = progress; - runtimeStatusFlags = progress < 100 - ? runtimeStatusFlags | FLAG_INSTALL_SESSION_ACTIVE - : runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE; - } else if (status == PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING) { - mProgressLevel = progress; - runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE; - runtimeStatusFlags = progress < 100 - ? runtimeStatusFlags | FLAG_INCREMENTAL_DOWNLOAD_ACTIVE - : runtimeStatusFlags & ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; - } else { - mProgressLevel = status == PackageInstallInfo.STATUS_INSTALLED ? 100 : 0; - runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE; - runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; - } - } - - /** Creates an intent to that launches the app store at this app's page. */ - @Nullable - public Intent getMarketIntent(Context context) { - ComponentName componentName = getTargetComponent(); - - return componentName != null - ? new PackageManagerHelper(context).getMarketIntent(componentName.getPackageName()) - : null; - } - /** * @return a copy of this */ diff --git a/src/com/android/launcher3/model/data/PromiseAppInfo.java b/src/com/android/launcher3/model/data/PromiseAppInfo.java new file mode 100644 index 0000000000..b6231ede19 --- /dev/null +++ b/src/com/android/launcher3/model/data/PromiseAppInfo.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.model.data; + +import android.content.Context; +import android.content.Intent; + +import androidx.annotation.NonNull; + +import com.android.launcher3.pm.PackageInstallInfo; +import com.android.launcher3.util.PackageManagerHelper; + +public class PromiseAppInfo extends AppInfo { + + public int level = 0; + + public PromiseAppInfo(@NonNull PackageInstallInfo installInfo) { + componentName = installInfo.componentName; + intent = new Intent(Intent.ACTION_MAIN) + .addCategory(Intent.CATEGORY_LAUNCHER) + .setComponent(componentName) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + } + + @Override + public WorkspaceItemInfo makeWorkspaceItem() { + WorkspaceItemInfo shortcut = new WorkspaceItemInfo(this); + shortcut.setInstallProgress(level); + // We need to update the component name when the apk is installed + shortcut.status |= WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON; + // Since the user is manually placing it on homescreen, it should not be auto-removed later + shortcut.status |= WorkspaceItemInfo.FLAG_RESTORE_STARTED; + return shortcut; + } + + public Intent getMarketIntent(Context context) { + return new PackageManagerHelper(context).getMarketIntent(componentName.getPackageName()); + } +} diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java index 690e904a02..1e1d093b13 100644 --- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java +++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java @@ -57,15 +57,21 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { */ public static final int FLAG_AUTOINSTALL_ICON = 1 << 1; + /** + * The icon is being installed. If {@link #FLAG_RESTORED_ICON} or {@link #FLAG_AUTOINSTALL_ICON} + * is set, then the icon is either being installed or is in a broken state. + */ + public static final int FLAG_INSTALL_SESSION_ACTIVE = 1 << 2; + /** * Indicates that the widget restore has started. */ - public static final int FLAG_RESTORE_STARTED = 1 << 2; + public static final int FLAG_RESTORE_STARTED = 1 << 3; /** * Web UI supported. */ - public static final int FLAG_SUPPORTS_WEB_UI = 1 << 3; + public static final int FLAG_SUPPORTS_WEB_UI = 1 << 4; /** * The intent used to start the application. @@ -92,6 +98,11 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { */ @NonNull private String[] personKeys = Utilities.EMPTY_STRING_ARRAY; + /** + * The installation progress [0-100] of the package that this shortcut represents. + */ + private int mInstallProgress; + public WorkspaceItemInfo() { itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; @@ -103,6 +114,7 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { intent = new Intent(info.intent); iconResource = info.iconResource; status = info.status; + mInstallProgress = info.mInstallProgress; personKeys = info.personKeys.clone(); } @@ -156,6 +168,15 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { return isPromise() && !hasStatusFlag(FLAG_SUPPORTS_WEB_UI); } + public int getInstallProgress() { + return mInstallProgress; + } + + public void setInstallProgress(int progress) { + mInstallProgress = progress; + status |= FLAG_INSTALL_SESSION_ACTIVE; + } + public void updateFromDeepShortcutInfo(ShortcutInfo shortcutInfo, Context context) { // {@link ShortcutInfo#getActivity} can change during an update. Recreate the intent intent = ShortcutKey.makeIntent(shortcutInfo); diff --git a/src/com/android/launcher3/pm/PackageInstallInfo.java b/src/com/android/launcher3/pm/PackageInstallInfo.java index fad904f968..7997d16756 100644 --- a/src/com/android/launcher3/pm/PackageInstallInfo.java +++ b/src/com/android/launcher3/pm/PackageInstallInfo.java @@ -25,8 +25,7 @@ public final class PackageInstallInfo { public static final int STATUS_INSTALLED = 0; public static final int STATUS_INSTALLING = 1; - public static final int STATUS_INSTALLED_DOWNLOADING = 2; - public static final int STATUS_FAILED = 3; + public static final int STATUS_FAILED = 2; public final ComponentName componentName; public final String packageName; @@ -57,4 +56,5 @@ public final class PackageInstallInfo { public static PackageInstallInfo fromState(int state, String packageName, UserHandle user) { return new PackageInstallInfo(packageName, state, 0 /* progress */, user); } + } diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java index 026634529f..b496608ac5 100644 --- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java +++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java @@ -35,8 +35,8 @@ import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.model.BgDataModel; 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.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.popup.PopupDataProvider; @@ -215,8 +215,8 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity ArrayList addAnimated) { } @Override - public void bindIncrementalDownloadProgressUpdated(AppInfo app) { - mAppsView.getAppsStore().updateProgressBar(app); + public void bindPromiseAppProgressUpdated(PromiseAppInfo app) { + mAppsView.getAppsStore().updatePromiseAppProgress(app); } @Override @@ -315,11 +315,9 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity if (tag instanceof ItemInfo) { ItemInfo item = (ItemInfo) tag; Intent intent; - if (item instanceof ItemInfoWithIcon - && (((ItemInfoWithIcon) item).runtimeStatusFlags - & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { - ItemInfoWithIcon appInfo = (ItemInfoWithIcon) item; - intent = appInfo.getMarketIntent(this); + if (item instanceof PromiseAppInfo) { + PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item; + intent = promiseAppInfo.getMarketIntent(this); } else { intent = item.getIntent(); } diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java index 41587357f5..9b9cb0a61b 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -49,8 +49,8 @@ import com.android.launcher3.logging.StatsLogManager; 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.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.RemoteActionItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.InstallSessionHelper; @@ -231,12 +231,8 @@ public class ItemClickHandler { ? shortcut.getIntent().getComponent().getPackageName() : shortcut.getIntent().getPackage(); if (!TextUtils.isEmpty(packageName)) { - onClickPendingAppItem( - v, - launcher, - packageName, - (shortcut.runtimeStatusFlags - & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0); + onClickPendingAppItem(v, launcher, packageName, + shortcut.hasStatusFlag(WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE)); return; } } @@ -270,12 +266,9 @@ public class ItemClickHandler { TestLogging.recordEvent( TestProtocol.SEQUENCE_MAIN, "start: startAppShortcutOrInfoActivity"); Intent intent; - if (item instanceof ItemInfoWithIcon - && (((ItemInfoWithIcon) item).runtimeStatusFlags - & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { - ItemInfoWithIcon appInfo = (ItemInfoWithIcon) item; - intent = new PackageManagerHelper(launcher) - .getMarketIntent(appInfo.getTargetComponent().getPackageName()); + if (item instanceof PromiseAppInfo) { + PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item; + intent = promiseAppInfo.getMarketIntent(launcher); } else { intent = item.getIntent(); } diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java index 7b264275d4..523545af43 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -45,11 +45,10 @@ import android.widget.Toast; import com.android.launcher3.PendingAddItemInfo; import com.android.launcher3.R; -import com.android.launcher3.Utilities; 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.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import java.net.URISyntaxException; @@ -201,12 +200,9 @@ public class PackageManagerHelper { * Starts the details activity for {@code info} */ public void startDetailsActivityForInfo(ItemInfo info, Rect sourceBounds, Bundle opts) { - if (info instanceof ItemInfoWithIcon - && (((ItemInfoWithIcon) info).runtimeStatusFlags - & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { - ItemInfoWithIcon appInfo = (ItemInfoWithIcon) info; - mContext.startActivity(new PackageManagerHelper(mContext) - .getMarketIntent(appInfo.getTargetComponent().getPackageName())); + if (info instanceof PromiseAppInfo) { + PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info; + mContext.startActivity(promiseAppInfo.getMarketIntent(mContext)); return; } ComponentName componentName = null; @@ -323,12 +319,4 @@ public class PackageManagerHelper { } return false; } - - /** Returns the incremental download progress for the given shortcut's app. */ - public static int getLoadingProgress(LauncherActivityInfo info) { - if (Utilities.ATLEAST_S) { - return (int) (100 * info.getLoadingProgress()); - } - return 100; - } } From a994593bde4cd06bf2634b8a6ea654b0f159eb84 Mon Sep 17 00:00:00 2001 From: Schneider Victor-tulias Date: Thu, 7 Jan 2021 19:44:44 +0000 Subject: [PATCH 04/17] Revert "Add UI updates for incremental app installs." This reverts commit 84269d349d093b6b0bd2b68e2306f7e0475cd4f5. Reason for revert: causes b/176884453 and b/176992421 Change-Id: I3398674a0acbad8329df5d341ae074ac073a6bf9 (cherry picked from commit 229497d1820f49450687bbc558041df97d0bf779) --- .../PackageInstallStateChangedTaskTest.java | 2 +- src/com/android/launcher3/BubbleTextView.java | 50 ++++------ src/com/android/launcher3/Launcher.java | 5 +- src/com/android/launcher3/LauncherModel.java | 10 -- src/com/android/launcher3/Utilities.java | 7 +- src/com/android/launcher3/Workspace.java | 2 +- .../launcher3/allapps/AllAppsStore.java | 12 +-- .../launcher3/folder/PreviewItemManager.java | 6 +- .../graphics/PreloadIconDrawable.java | 4 +- .../model/AddWorkspaceItemsTask.java | 5 +- .../android/launcher3/model/AllAppsList.java | 33 +++---- .../android/launcher3/model/BgDataModel.java | 7 +- .../android/launcher3/model/LoaderCursor.java | 23 ++--- .../android/launcher3/model/LoaderTask.java | 24 +---- ...PackageIncrementalDownloadUpdatedTask.java | 79 --------------- .../model/PackageInstallStateChangedTask.java | 21 ++-- .../android/launcher3/model/data/AppInfo.java | 40 +------- .../model/data/ItemInfoWithIcon.java | 97 ------------------- .../launcher3/model/data/PromiseAppInfo.java | 54 +++++++++++ .../model/data/WorkspaceItemInfo.java | 25 ++++- .../launcher3/pm/PackageInstallInfo.java | 4 +- .../SecondaryDisplayLauncher.java | 14 ++- .../launcher3/touch/ItemClickHandler.java | 19 ++-- .../launcher3/util/PackageManagerHelper.java | 20 +--- 24 files changed, 163 insertions(+), 400 deletions(-) delete mode 100644 src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java create mode 100644 src/com/android/launcher3/model/data/PromiseAppInfo.java diff --git a/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java index 412ace03ff..e43df21ae9 100644 --- a/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java @@ -67,7 +67,7 @@ public class PackageInstallStateChangedTaskTest { for (ItemInfo info : mModelHelper.getBgDataModel().itemsIdMap) { if (info instanceof WorkspaceItemInfo) { assertEquals(updates.contains(info.id) ? progress: 0, - ((WorkspaceItemInfo) info).getProgressLevel()); + ((WorkspaceItemInfo) info).getInstallProgress()); } else { assertEquals(updates.contains(info.id) ? progress: -1, ((LauncherAppWidgetInfo) info).installProgress); diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index f44f88b098..3eb52adf1a 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -50,7 +50,6 @@ import android.view.View; import android.view.ViewDebug; import android.widget.TextView; -import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import com.android.launcher3.Launcher.OnResumeCallback; @@ -72,6 +71,7 @@ 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.PackageItemInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.RemoteActionItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.SafeCloseable; @@ -287,7 +287,10 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, public void applyFromWorkspaceItem(WorkspaceItemInfo info, boolean promiseStateChanged) { applyIconAndLabel(info); setTag(info); - applyLoadingState(promiseStateChanged); + if (promiseStateChanged || (info.hasPromiseIconUi())) { + applyPromiseState(promiseStateChanged); + } + applyDotState(info, false /* animate */); } @@ -300,8 +303,9 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, // Verify high res immediately verifyHighRes(); - if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) { - applyProgressLevel(info.getProgressLevel()); + if (info instanceof PromiseAppInfo) { + PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info; + applyProgressLevel(promiseAppInfo.level); } applyDotState(info, false /* animate */); } @@ -331,10 +335,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, mDotParams.color = IconPalette.getMutedColor(info.bitmap.color, 0.54f); setIcon(iconDrawable); - applyLabel(info); - } - - private void applyLabel(ItemInfoWithIcon info) { setText(info.title); if (info.contentDescription != null) { setContentDescription(info.isDisabled() @@ -595,35 +595,21 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, mLongPressHelper.cancelLongPress(); } - /** Applies the loading progress value to the progress bar. - * - * If this app is installing, the progress bar will be updated with the installation progress. - * If this app is installed and downloading incrementally, the progress bar will be updated - * with the total download progress. - */ - public void applyLoadingState(boolean promiseStateChanged) { + public void applyPromiseState(boolean promiseStateChanged) { if (getTag() instanceof WorkspaceItemInfo) { WorkspaceItemInfo info = (WorkspaceItemInfo) getTag(); - int progressLevel = info.getProgressLevel(); - if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) - != 0) { - updateProgressBarUi(progressLevel, progressLevel == 100); - } else if (info.hasPromiseIconUi() || (info.runtimeStatusFlags - & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { - updateProgressBarUi(progressLevel, promiseStateChanged); + final boolean isPromise = info.hasPromiseIconUi(); + final int progressLevel = isPromise ? + ((info.hasStatusFlag(WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE) ? + info.getInstallProgress() : 0)) : 100; + + PreloadIconDrawable preloadDrawable = applyProgressLevel(progressLevel); + if (preloadDrawable != null && promiseStateChanged) { + preloadDrawable.maybePerformFinishedAnimation(); } } } - private void updateProgressBarUi(int progressLevel, boolean maybePerformFinishedAnimation) { - PreloadIconDrawable preloadDrawable = applyProgressLevel(progressLevel); - if (preloadDrawable != null && maybePerformFinishedAnimation) { - preloadDrawable.maybePerformFinishedAnimation(); - } - } - - /** Applies the given progress level to the this icon's progress bar. */ - @Nullable public PreloadIconDrawable applyProgressLevel(int progressLevel) { if (getTag() instanceof ItemInfoWithIcon) { ItemInfoWithIcon info = (ItemInfoWithIcon) getTag(); @@ -643,11 +629,9 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, if (mIcon instanceof PreloadIconDrawable) { preloadDrawable = (PreloadIconDrawable) mIcon; preloadDrawable.setLevel(progressLevel); - preloadDrawable.setIsDisabled(!info.isAppStartable()); } else { preloadDrawable = newPendingIcon(getContext(), info); preloadDrawable.setLevel(progressLevel); - preloadDrawable.setIsDisabled(!info.isAppStartable()); setIcon(preloadDrawable); } return preloadDrawable; diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 5b55c4b435..a96fabd66e 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -137,6 +137,7 @@ 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.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.pm.PinRequestHelper; @@ -2515,8 +2516,8 @@ public class Launcher extends StatefulActivity implements Launche } @Override - public void bindIncrementalDownloadProgressUpdated(AppInfo app) { - mAppsView.getAppsStore().updateProgressBar(app); + public void bindPromiseAppProgressUpdated(PromiseAppInfo app) { + mAppsView.getAppsStore().updatePromiseAppProgress(app); } @Override diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index e89b9b060a..8458152146 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -48,7 +48,6 @@ import com.android.launcher3.model.LoaderResults; import com.android.launcher3.model.LoaderTask; import com.android.launcher3.model.ModelDelegate; import com.android.launcher3.model.ModelWriter; -import com.android.launcher3.model.PackageIncrementalDownloadUpdatedTask; import com.android.launcher3.model.PackageInstallStateChangedTask; import com.android.launcher3.model.PackageUpdatedTask; import com.android.launcher3.model.ShortcutsChangedTask; @@ -196,15 +195,6 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi PackageUpdatedTask.OP_UNSUSPEND, user, packageNames)); } - @Override - public void onPackageLoadingProgressChanged( - String packageName, UserHandle user, float progress) { - if (Utilities.ATLEAST_S) { - enqueueModelUpdateTask(new PackageIncrementalDownloadUpdatedTask( - packageName, user, progress)); - } - } - @Override public void onShortcutsChanged(String packageName, List shortcuts, UserHandle user) { diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index df5d23428d..5c2f35b981 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -107,13 +107,12 @@ public final class Utilities { public static final String[] EMPTY_STRING_ARRAY = new String[0]; public static final Person[] EMPTY_PERSON_ARRAY = new Person[0]; - public static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; + public static final boolean ATLEAST_R = BuildCompat.isAtLeastR(); public static final boolean ATLEAST_Q = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; - public static final boolean ATLEAST_R = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R; - - public static final boolean ATLEAST_S = BuildCompat.isAtLeastS(); + public static final boolean ATLEAST_P = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; /** * Set on a motion event dispatched from the nav bar. See {@link MotionEvent#setEdgeFlags(int)}. diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 65eba20672..777ea3c7d5 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -3154,7 +3154,7 @@ public class Workspace extends PagedView ItemOperator op = (info, v) -> { if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView && updates.contains(info)) { - ((BubbleTextView) v).applyLoadingState(false /* promiseStateChanged */); + ((BubbleTextView) v).applyPromiseState(false /* promiseStateChanged */); } else if (v instanceof PendingAppWidgetHostView && info instanceof LauncherAppWidgetInfo && updates.contains(info)) { diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java index 00bdb70c4a..3ae0a18137 100644 --- a/src/com/android/launcher3/allapps/AllAppsStore.java +++ b/src/com/android/launcher3/allapps/AllAppsStore.java @@ -24,6 +24,7 @@ import android.view.ViewGroup; import com.android.launcher3.BubbleTextView; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageUserKey; @@ -144,17 +145,10 @@ public class AllAppsStore { }); } - /** - * Sets the AppInfo's associated icon's progress bar. - * - * If this app is installed and supports incremental downloads, the progress bar will be updated - * the app's total download progress. Otherwise, the progress bar will be updated to the app's - * installation progress. - */ - public void updateProgressBar(AppInfo app) { + public void updatePromiseAppProgress(PromiseAppInfo app) { updateAllIcons((child) -> { if (child.getTag() == app) { - child.applyProgressLevel(app.getProgressLevel()); + child.applyProgressLevel(app.level); } }); } diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java index 9ae7faf988..7f8a15c927 100644 --- a/src/com/android/launcher3/folder/PreviewItemManager.java +++ b/src/com/android/launcher3/folder/PreviewItemManager.java @@ -39,7 +39,6 @@ import androidx.annotation.NonNull; import com.android.launcher3.Utilities; import com.android.launcher3.graphics.PreloadIconDrawable; -import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.views.ActivityContext; @@ -395,10 +394,9 @@ public class PreviewItemManager { } private void setDrawable(PreviewItemDrawingParams p, WorkspaceItemInfo item) { - if (item.hasPromiseIconUi() || (item.runtimeStatusFlags - & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) { + if (item.hasPromiseIconUi()) { PreloadIconDrawable drawable = newPendingIcon(mContext, item); - drawable.setLevel(item.getProgressLevel()); + drawable.setLevel(item.getInstallProgress()); p.drawable = drawable; } else { p.drawable = newIcon(mContext, item); diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java index 9971990267..e85b056376 100644 --- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java +++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java @@ -117,8 +117,6 @@ public class PreloadIconDrawable extends FastBitmapDrawable { mIndicatorColor = IconPalette.getPreloadProgressColor(context, mIconColor); setInternalProgress(0); - - setIsDisabled(!info.isAppStartable()); } @Override @@ -268,12 +266,14 @@ public class PreloadIconDrawable extends FastBitmapDrawable { mIconScale = SMALL_SCALE; mScaledTrackPath.reset(); mTrackAlpha = MAX_PAINT_ALPHA; + setIsDisabled(true); } if (progress < 1 && progress > 0) { mPathMeasure.getSegment(0, progress * mTrackLength, mScaledProgressPath, true); mIconScale = SMALL_SCALE; mTrackAlpha = MAX_PAINT_ALPHA; + setIsDisabled(true); } else if (progress >= 1) { setIsDisabled(mItem.isDisabled()); mScaledTrackPath.set(mScaledProgressPath); diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java index 56dbbd33da..c236fa6dec 100644 --- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java +++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java @@ -34,7 +34,6 @@ import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.InstallSessionHelper; -import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.PackageManagerHelper; @@ -133,9 +132,7 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask { continue; } } else { - workspaceInfo.setProgressLevel( - (int) (sessionInfo.getProgress() * 100), - PackageInstallInfo.STATUS_INSTALLING); + workspaceInfo.setInstallProgress((int) sessionInfo.getProgress()); } if (hasActivity) { diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index 8d5cf7422f..2695e66591 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -21,11 +21,11 @@ import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.os.LocaleList; +import android.os.Process; import android.os.UserHandle; import android.util.Log; @@ -37,6 +37,7 @@ import com.android.launcher3.compat.AlphabeticIndexCompat; import com.android.launcher3.icons.IconCache; import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.data.AppInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.FlagOp; import com.android.launcher3.util.ItemInfoMatcher; @@ -149,7 +150,7 @@ public class AllAppsList { .getApplicationInfo(installInfo.packageName, installInfo.user, 0); // only if not yet installed if (applicationInfo == null) { - AppInfo info = new AppInfo(installInfo); + PromiseAppInfo info = new PromiseAppInfo(installInfo); mIconCache.getTitleAndIcon(info, info.usingLowResIcon()); info.sectionName = mIndex.computeSectionName(info.title); @@ -158,26 +159,24 @@ public class AllAppsList { } } - /** Updates the given PackageInstallInfo's associated AppInfo's installation info. */ - public List updatePromiseInstallInfo(PackageInstallInfo installInfo) { - List updatedAppInfos = new ArrayList<>(); - UserHandle user = installInfo.user; - for (int i = data.size() - 1; i >= 0; i--) { + public PromiseAppInfo updatePromiseInstallInfo(PackageInstallInfo installInfo) { + UserHandle user = Process.myUserHandle(); + for (int i=0; i < data.size(); i++) { final AppInfo appInfo = data.get(i); final ComponentName tgtComp = appInfo.getTargetComponent(); if (tgtComp != null && tgtComp.getPackageName().equals(installInfo.packageName) - && appInfo.user.equals(user)) { - if (installInfo.state == PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING - || installInfo.state == PackageInstallInfo.STATUS_INSTALLING) { - appInfo.setProgressLevel(installInfo); - - updatedAppInfos.add(appInfo); + && appInfo.user.equals(user) + && appInfo instanceof PromiseAppInfo) { + final PromiseAppInfo promiseAppInfo = (PromiseAppInfo) appInfo; + if (installInfo.state == PackageInstallInfo.STATUS_INSTALLING) { + promiseAppInfo.level = installInfo.progress; + return promiseAppInfo; } else if (installInfo.state == PackageInstallInfo.STATUS_FAILED) { removeApp(i); } } } - return updatedAppInfos; + return null; } private void removeApp(int index) { @@ -269,14 +268,8 @@ public class AllAppsList { if (applicationInfo == null) { add(new AppInfo(context, info, user), info); } else { - Intent launchIntent = AppInfo.makeLaunchIntent(info); - mIconCache.getTitleAndIcon(applicationInfo, info, true /* useLowResIcon */); applicationInfo.sectionName = mIndex.computeSectionName(applicationInfo.title); - applicationInfo.setProgressLevel( - PackageManagerHelper.getLoadingProgress(info), - PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING); - applicationInfo.intent = launchIntent; mDataChanged = true; } diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index 2d860a41d3..c217a475a1 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -39,6 +39,7 @@ 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.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.UserCache; import com.android.launcher3.shortcuts.ShortcutKey; @@ -458,11 +459,7 @@ public class BgDataModel { void preAddApps(); void bindAppsAdded(IntArray newScreens, ArrayList addNotAnimated, ArrayList addAnimated); - - /** - * Binds updated incremental download progress - */ - void bindIncrementalDownloadProgressUpdated(AppInfo app); + void bindPromiseAppProgressUpdated(PromiseAppInfo app); void bindWorkspaceItemsChanged(List updated); void bindWidgetsRestored(ArrayList widgets); void bindRestoreItemsChange(HashSet updates); diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 19d9af98dc..532834eeb8 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -35,13 +35,11 @@ import android.text.TextUtils; import android.util.Log; import android.util.LongSparseArray; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; -import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.config.FeatureFlags; @@ -94,9 +92,6 @@ public class LoaderCursor extends CursorWrapper { private final int restoredIndex; private final int intentIndex; - @Nullable - private LauncherActivityInfo mActivityInfo; - // Properties loaded per iteration public long serialNumber; public UserHandle user; @@ -137,8 +132,6 @@ public class LoaderCursor extends CursorWrapper { public boolean moveToNext() { boolean result = super.moveToNext(); if (result) { - mActivityInfo = null; - // Load common properties. itemType = getInt(itemTypeIndex); container = getInt(containerIndex); @@ -252,10 +245,6 @@ public class LoaderCursor extends CursorWrapper { return info; } - public LauncherActivityInfo getLauncherActivityInfo() { - return mActivityInfo; - } - /** * Make an WorkspaceItemInfo object for a shortcut that is an application. */ @@ -275,25 +264,25 @@ public class LoaderCursor extends CursorWrapper { Intent newIntent = new Intent(Intent.ACTION_MAIN, null); newIntent.addCategory(Intent.CATEGORY_LAUNCHER); newIntent.setComponent(componentName); - mActivityInfo = mContext.getSystemService(LauncherApps.class) + LauncherActivityInfo lai = mContext.getSystemService(LauncherApps.class) .resolveActivity(newIntent, user); - if ((mActivityInfo == null) && !allowMissingTarget) { + if ((lai == null) && !allowMissingTarget) { Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName); return null; } final WorkspaceItemInfo info = new WorkspaceItemInfo(); - info.itemType = Favorites.ITEM_TYPE_APPLICATION; + info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; info.user = user; info.intent = newIntent; - mIconCache.getTitleAndIcon(info, mActivityInfo, useLowResIcon); + mIconCache.getTitleAndIcon(info, lai, useLowResIcon); if (mIconCache.isDefaultIcon(info.bitmap, user)) { loadIcon(info); } - if (mActivityInfo != null) { - AppInfo.updateRuntimeFlagsForActivityTarget(info, mActivityInfo); + if (lai != null) { + AppInfo.updateRuntimeFlagsForActivityTarget(info, lai); } // from the db diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index f74c8b5c1c..8e085ce52d 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -69,7 +69,6 @@ import com.android.launcher3.logging.FileLog; 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.LauncherAppWidgetInfo; import com.android.launcher3.model.data.PackageItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -592,24 +591,11 @@ public class LoaderTask implements Runnable { if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) { tempPackageKey.update(targetPkg, c.user); SessionInfo si = installingPkgs.get(tempPackageKey); - LauncherActivityInfo activityInfo = - c.getLauncherActivityInfo(); - if (si == null) { - info.runtimeStatusFlags &= - ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; - } else if (activityInfo == null) { - int installProgress = (int) (si.getProgress() * 100); - - info.setProgressLevel( - installProgress, - PackageInstallInfo.STATUS_INSTALLING); - } else { - info.setProgressLevel( - PackageManagerHelper - .getLoadingProgress(activityInfo), - PackageInstallInfo - .STATUS_INSTALLED_DOWNLOADING); - } + if (si == null) { + info.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE; + } else { + info.setInstallProgress((int) (si.getProgress() * 100)); + } } c.checkAndAddItem(info, mBgDataModel); diff --git a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java deleted file mode 100644 index e3e87693b1..0000000000 --- a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java +++ /dev/null @@ -1,79 +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.model; - -import android.content.ComponentName; -import android.os.UserHandle; - -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.model.data.AppInfo; -import com.android.launcher3.model.data.ItemInfoWithIcon; -import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.pm.PackageInstallInfo; - -import java.util.ArrayList; -import java.util.List; - -/** - * Handles updates due to incremental download progress updates. - */ -public class PackageIncrementalDownloadUpdatedTask extends BaseModelUpdateTask { - - private final UserHandle mUser; - private final int mProgress; - private final String mPackageName; - - public PackageIncrementalDownloadUpdatedTask( - String packageName, UserHandle user, float progress) { - mUser = user; - mProgress = 1 - progress > 0.001 ? (int) (100 * progress) : 100; - mPackageName = packageName; - } - - @Override - public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) { - PackageInstallInfo downloadInfo = new PackageInstallInfo( - mPackageName, - PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING, - mProgress, - mUser); - - synchronized (appsList) { - List updatedAppInfos = appsList.updatePromiseInstallInfo(downloadInfo); - if (!updatedAppInfos.isEmpty()) { - for (AppInfo appInfo : updatedAppInfos) { - appInfo.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; - scheduleCallbackTask( - c -> c.bindIncrementalDownloadProgressUpdated(appInfo)); - } - } - bindApplicationsIfNeeded(); - } - - final ArrayList updatedWorkspaceItems = new ArrayList<>(); - synchronized (dataModel) { - dataModel.forAllWorkspaceItemInfos(mUser, si -> { - ComponentName cn = si.getTargetComponent(); - if ((cn != null) && cn.getPackageName().equals(mPackageName)) { - si.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; - si.setProgressLevel(downloadInfo); - updatedWorkspaceItems.add(si); - } - }); - } - bindUpdatedWorkspaceItems(updatedWorkspaceItems); - } -} diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java index 8215edd90b..8369c48e5c 100644 --- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java +++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java @@ -20,15 +20,14 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import com.android.launcher3.LauncherAppState; -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.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.PromiseAppInfo; +import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.InstantAppResolver; import java.util.HashSet; -import java.util.List; /** * Handles changes due to a sessions updates for a currently installing app. @@ -60,11 +59,9 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask { } synchronized (apps) { - List updatedAppInfos = apps.updatePromiseInstallInfo(mInstallInfo); - if (!updatedAppInfos.isEmpty()) { - for (AppInfo appInfo : updatedAppInfos) { - scheduleCallbackTask(c -> c.bindIncrementalDownloadProgressUpdated(appInfo)); - } + PromiseAppInfo updated = apps.updatePromiseInstallInfo(mInstallInfo); + if (updated != null) { + scheduleCallbackTask(c -> c.bindPromiseAppProgressUpdated(updated)); } bindApplicationsIfNeeded(); } @@ -74,13 +71,11 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask { dataModel.forAllWorkspaceItemInfos(mInstallInfo.user, si -> { ComponentName cn = si.getTargetComponent(); if (si.hasPromiseIconUi() && (cn != null) - && cn.getPackageName().equals(mInstallInfo.packageName)) { - int installProgress = mInstallInfo.progress; - - si.setProgressLevel(installProgress, PackageInstallInfo.STATUS_INSTALLING); + && mInstallInfo.packageName.equals(cn.getPackageName())) { + si.setInstallProgress(mInstallInfo.progress); if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) { // Mark this info as broken. - si.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; + si.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE; } updates.add(si); } diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java index 39247c221f..aee1f2a65b 100644 --- a/src/com/android/launcher3/model/data/AppInfo.java +++ b/src/com/android/launcher3/model/data/AppInfo.java @@ -28,13 +28,10 @@ import android.os.Process; import android.os.UserHandle; import android.os.UserManager; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Utilities; -import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageManagerHelper; @@ -107,37 +104,13 @@ public class AppInfo extends ItemInfoWithIcon { this.intent = intent; } - public AppInfo(@NonNull PackageInstallInfo installInfo) { - componentName = installInfo.componentName; - intent = new Intent(Intent.ACTION_MAIN) - .addCategory(Intent.CATEGORY_LAUNCHER) - .setComponent(componentName) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - user = installInfo.user; - } - @Override protected String dumpProperties() { return super.dumpProperties() + " componentName=" + componentName; } public WorkspaceItemInfo makeWorkspaceItem() { - WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(this); - - if ((runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) { - // We need to update the component name when the apk is installed - workspaceItemInfo.status |= WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON; - // Since the user is manually placing it on homescreen, it should not be auto-removed - // later - workspaceItemInfo.status |= WorkspaceItemInfo.FLAG_RESTORE_STARTED; - workspaceItemInfo.status |= FLAG_INSTALL_SESSION_ACTIVE; - } - if ((runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0) { - workspaceItemInfo.runtimeStatusFlags |= FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; - } - - return workspaceItemInfo; + return new WorkspaceItemInfo(this); } public ComponentKey toComponentKey() { @@ -156,12 +129,6 @@ public class AppInfo extends ItemInfoWithIcon { | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); } - @Nullable - @Override - public ComponentName getTargetComponent() { - return componentName; - } - public static void updateRuntimeFlagsForActivityTarget( ItemInfoWithIcon info, LauncherActivityInfo lai) { ApplicationInfo appInfo = lai.getApplicationInfo(); @@ -176,11 +143,6 @@ public class AppInfo extends ItemInfoWithIcon { // The icon for a non-primary user is badged, hence it's not exactly an adaptive icon. info.runtimeStatusFlags |= FLAG_ADAPTIVE_ICON; } - - // Sets the progress level, installation and incremental download flags. - info.setProgressLevel( - PackageManagerHelper.getLoadingProgress(lai), - PackageInstallInfo.STATUS_INSTALLED); } @Override diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java index b8a71d33e0..d95f94f79f 100644 --- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java +++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java @@ -16,15 +16,7 @@ package com.android.launcher3.model.data; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; - -import androidx.annotation.Nullable; - import com.android.launcher3.icons.BitmapInfo; -import com.android.launcher3.pm.PackageInstallInfo; -import com.android.launcher3.util.PackageManagerHelper; /** * Represents an ItemInfo which also holds an icon. @@ -95,35 +87,12 @@ public abstract class ItemInfoWithIcon extends ItemInfo { */ public static final int FLAG_ICON_BADGED = 1 << 9; - /** - * The icon is being installed. If {@link WorkspaceItemInfo#FLAG_RESTORED_ICON} or - * {@link WorkspaceItemInfo#FLAG_AUTOINSTALL_ICON} is set, then the icon is either being - * installed or is in a broken state. - */ - public static final int FLAG_INSTALL_SESSION_ACTIVE = 1 << 10; - - /** - * This icon is still being downloaded. - */ - public static final int FLAG_INCREMENTAL_DOWNLOAD_ACTIVE = 1 << 11; - - public static final int FLAG_SHOW_DOWNLOAD_PROGRESS_MASK = FLAG_INSTALL_SESSION_ACTIVE - | FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; - /** * Status associated with the system state of the underlying item. This is calculated every * time a new info is created and not persisted on the disk. */ public int runtimeStatusFlags = 0; - /** - * The download progress of the package that this shortcut represents. For legacy apps, this - * will always be the installation progress. For apps that support incremental downloads, this - * will only match be the installation progress until the app is installed, then this will the - * total download progress. - */ - private int mProgressLevel = 100; - protected ItemInfoWithIcon() { } protected ItemInfoWithIcon(ItemInfoWithIcon info) { @@ -144,72 +113,6 @@ public abstract class ItemInfoWithIcon extends ItemInfo { return bitmap.isLowRes(); } - /** - * Returns whether the app this shortcut represents is able to be started. For legacy apps, - * this returns whether it is fully installed. For apps that support incremental downloads, - * this returns whether the app is either fully downloaded or has installed and is downloading - * incrementally. - */ - public boolean isAppStartable() { - return ((runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) == 0) - && (((runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0) - || mProgressLevel == 100); - } - - /** - * Returns the download progress for the app this shortcut represents. If this app is not yet - * installed or does not support incremental downloads, this will return the installation - * progress. - */ - public int getProgressLevel() { - if ((runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) { - return mProgressLevel; - } - return 100; - } - - /** - * Sets the download progress for the app this shortcut represents. If this app is not yet - * installed or does not support incremental downloads, this will set - * {@code FLAG_INSTALL_SESSION_ACTIVE}. If this app is downloading incrementally, this will - * set {@code FLAG_INCREMENTAL_DOWNLOAD_ACTIVE}. Otherwise, this will remove both flags. - */ - public void setProgressLevel(PackageInstallInfo installInfo) { - setProgressLevel(installInfo.progress, installInfo.state); - } - - /** - * Sets the download progress for the app this shortcut represents. - */ - public void setProgressLevel(int progress, int status) { - if (status == PackageInstallInfo.STATUS_INSTALLING) { - mProgressLevel = progress; - runtimeStatusFlags = progress < 100 - ? runtimeStatusFlags | FLAG_INSTALL_SESSION_ACTIVE - : runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE; - } else if (status == PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING) { - mProgressLevel = progress; - runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE; - runtimeStatusFlags = progress < 100 - ? runtimeStatusFlags | FLAG_INCREMENTAL_DOWNLOAD_ACTIVE - : runtimeStatusFlags & ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; - } else { - mProgressLevel = status == PackageInstallInfo.STATUS_INSTALLED ? 100 : 0; - runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE; - runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; - } - } - - /** Creates an intent to that launches the app store at this app's page. */ - @Nullable - public Intent getMarketIntent(Context context) { - ComponentName componentName = getTargetComponent(); - - return componentName != null - ? new PackageManagerHelper(context).getMarketIntent(componentName.getPackageName()) - : null; - } - /** * @return a copy of this */ diff --git a/src/com/android/launcher3/model/data/PromiseAppInfo.java b/src/com/android/launcher3/model/data/PromiseAppInfo.java new file mode 100644 index 0000000000..b6231ede19 --- /dev/null +++ b/src/com/android/launcher3/model/data/PromiseAppInfo.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.model.data; + +import android.content.Context; +import android.content.Intent; + +import androidx.annotation.NonNull; + +import com.android.launcher3.pm.PackageInstallInfo; +import com.android.launcher3.util.PackageManagerHelper; + +public class PromiseAppInfo extends AppInfo { + + public int level = 0; + + public PromiseAppInfo(@NonNull PackageInstallInfo installInfo) { + componentName = installInfo.componentName; + intent = new Intent(Intent.ACTION_MAIN) + .addCategory(Intent.CATEGORY_LAUNCHER) + .setComponent(componentName) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + } + + @Override + public WorkspaceItemInfo makeWorkspaceItem() { + WorkspaceItemInfo shortcut = new WorkspaceItemInfo(this); + shortcut.setInstallProgress(level); + // We need to update the component name when the apk is installed + shortcut.status |= WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON; + // Since the user is manually placing it on homescreen, it should not be auto-removed later + shortcut.status |= WorkspaceItemInfo.FLAG_RESTORE_STARTED; + return shortcut; + } + + public Intent getMarketIntent(Context context) { + return new PackageManagerHelper(context).getMarketIntent(componentName.getPackageName()); + } +} diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java index 690e904a02..1e1d093b13 100644 --- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java +++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java @@ -57,15 +57,21 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { */ public static final int FLAG_AUTOINSTALL_ICON = 1 << 1; + /** + * The icon is being installed. If {@link #FLAG_RESTORED_ICON} or {@link #FLAG_AUTOINSTALL_ICON} + * is set, then the icon is either being installed or is in a broken state. + */ + public static final int FLAG_INSTALL_SESSION_ACTIVE = 1 << 2; + /** * Indicates that the widget restore has started. */ - public static final int FLAG_RESTORE_STARTED = 1 << 2; + public static final int FLAG_RESTORE_STARTED = 1 << 3; /** * Web UI supported. */ - public static final int FLAG_SUPPORTS_WEB_UI = 1 << 3; + public static final int FLAG_SUPPORTS_WEB_UI = 1 << 4; /** * The intent used to start the application. @@ -92,6 +98,11 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { */ @NonNull private String[] personKeys = Utilities.EMPTY_STRING_ARRAY; + /** + * The installation progress [0-100] of the package that this shortcut represents. + */ + private int mInstallProgress; + public WorkspaceItemInfo() { itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; @@ -103,6 +114,7 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { intent = new Intent(info.intent); iconResource = info.iconResource; status = info.status; + mInstallProgress = info.mInstallProgress; personKeys = info.personKeys.clone(); } @@ -156,6 +168,15 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { return isPromise() && !hasStatusFlag(FLAG_SUPPORTS_WEB_UI); } + public int getInstallProgress() { + return mInstallProgress; + } + + public void setInstallProgress(int progress) { + mInstallProgress = progress; + status |= FLAG_INSTALL_SESSION_ACTIVE; + } + public void updateFromDeepShortcutInfo(ShortcutInfo shortcutInfo, Context context) { // {@link ShortcutInfo#getActivity} can change during an update. Recreate the intent intent = ShortcutKey.makeIntent(shortcutInfo); diff --git a/src/com/android/launcher3/pm/PackageInstallInfo.java b/src/com/android/launcher3/pm/PackageInstallInfo.java index fad904f968..7997d16756 100644 --- a/src/com/android/launcher3/pm/PackageInstallInfo.java +++ b/src/com/android/launcher3/pm/PackageInstallInfo.java @@ -25,8 +25,7 @@ public final class PackageInstallInfo { public static final int STATUS_INSTALLED = 0; public static final int STATUS_INSTALLING = 1; - public static final int STATUS_INSTALLED_DOWNLOADING = 2; - public static final int STATUS_FAILED = 3; + public static final int STATUS_FAILED = 2; public final ComponentName componentName; public final String packageName; @@ -57,4 +56,5 @@ public final class PackageInstallInfo { public static PackageInstallInfo fromState(int state, String packageName, UserHandle user) { return new PackageInstallInfo(packageName, state, 0 /* progress */, user); } + } diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java index 026634529f..b496608ac5 100644 --- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java +++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java @@ -35,8 +35,8 @@ import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.model.BgDataModel; 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.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.popup.PopupDataProvider; @@ -215,8 +215,8 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity ArrayList addAnimated) { } @Override - public void bindIncrementalDownloadProgressUpdated(AppInfo app) { - mAppsView.getAppsStore().updateProgressBar(app); + public void bindPromiseAppProgressUpdated(PromiseAppInfo app) { + mAppsView.getAppsStore().updatePromiseAppProgress(app); } @Override @@ -315,11 +315,9 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity if (tag instanceof ItemInfo) { ItemInfo item = (ItemInfo) tag; Intent intent; - if (item instanceof ItemInfoWithIcon - && (((ItemInfoWithIcon) item).runtimeStatusFlags - & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { - ItemInfoWithIcon appInfo = (ItemInfoWithIcon) item; - intent = appInfo.getMarketIntent(this); + if (item instanceof PromiseAppInfo) { + PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item; + intent = promiseAppInfo.getMarketIntent(this); } else { intent = item.getIntent(); } diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java index 41587357f5..9b9cb0a61b 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -49,8 +49,8 @@ import com.android.launcher3.logging.StatsLogManager; 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.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.RemoteActionItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.InstallSessionHelper; @@ -231,12 +231,8 @@ public class ItemClickHandler { ? shortcut.getIntent().getComponent().getPackageName() : shortcut.getIntent().getPackage(); if (!TextUtils.isEmpty(packageName)) { - onClickPendingAppItem( - v, - launcher, - packageName, - (shortcut.runtimeStatusFlags - & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0); + onClickPendingAppItem(v, launcher, packageName, + shortcut.hasStatusFlag(WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE)); return; } } @@ -270,12 +266,9 @@ public class ItemClickHandler { TestLogging.recordEvent( TestProtocol.SEQUENCE_MAIN, "start: startAppShortcutOrInfoActivity"); Intent intent; - if (item instanceof ItemInfoWithIcon - && (((ItemInfoWithIcon) item).runtimeStatusFlags - & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { - ItemInfoWithIcon appInfo = (ItemInfoWithIcon) item; - intent = new PackageManagerHelper(launcher) - .getMarketIntent(appInfo.getTargetComponent().getPackageName()); + if (item instanceof PromiseAppInfo) { + PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item; + intent = promiseAppInfo.getMarketIntent(launcher); } else { intent = item.getIntent(); } diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java index 7b264275d4..523545af43 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -45,11 +45,10 @@ import android.widget.Toast; import com.android.launcher3.PendingAddItemInfo; import com.android.launcher3.R; -import com.android.launcher3.Utilities; 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.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import java.net.URISyntaxException; @@ -201,12 +200,9 @@ public class PackageManagerHelper { * Starts the details activity for {@code info} */ public void startDetailsActivityForInfo(ItemInfo info, Rect sourceBounds, Bundle opts) { - if (info instanceof ItemInfoWithIcon - && (((ItemInfoWithIcon) info).runtimeStatusFlags - & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { - ItemInfoWithIcon appInfo = (ItemInfoWithIcon) info; - mContext.startActivity(new PackageManagerHelper(mContext) - .getMarketIntent(appInfo.getTargetComponent().getPackageName())); + if (info instanceof PromiseAppInfo) { + PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info; + mContext.startActivity(promiseAppInfo.getMarketIntent(mContext)); return; } ComponentName componentName = null; @@ -323,12 +319,4 @@ public class PackageManagerHelper { } return false; } - - /** Returns the incremental download progress for the given shortcut's app. */ - public static int getLoadingProgress(LauncherActivityInfo info) { - if (Utilities.ATLEAST_S) { - return (int) (100 * info.getLoadingProgress()); - } - return 100; - } } From 70e2d12ef20f3fa27b730e9faee1aab0e0d6746a Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 14 Jan 2021 14:16:09 -0800 Subject: [PATCH 05/17] Fixing preview rendering in device search mode When the flag is disabled, search box may not show in preview Bug: 177500166 Test: Presubmit Change-Id: I064ba6ca22e71030056a4ceafea27e6ef0517d01 (cherry picked from commit e733e79946058b749476f22284043757d3508111) --- res/layout/launcher_preview_layout.xml | 19 ++----------------- .../graphics/LauncherPreviewRenderer.java | 11 ----------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/res/layout/launcher_preview_layout.xml b/res/layout/launcher_preview_layout.xml index 4a20c705b6..16916800f3 100644 --- a/res/layout/launcher_preview_layout.xml +++ b/res/layout/launcher_preview_layout.xml @@ -29,23 +29,8 @@ launcher:containerType="workspace" launcher:pageIndicator="@+id/page_indicator"/> - - - - - - - + layout="@layout/hotseat" /> \ No newline at end of file diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index efc1201bba..3a9986ee42 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -64,7 +64,6 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; import com.android.launcher3.WorkspaceLayoutManager; -import com.android.launcher3.allapps.SearchUiManager; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.icons.BaseIconFactory; @@ -512,16 +511,6 @@ public class LauncherPreviewRenderer extends ContextThemeWrapper mWorkspace.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true); } - // Setup search view - SearchUiManager searchUiManager = mRootView.findViewById(R.id.search_container_all_apps); - mRootView.findViewById(R.id.apps_view).setTranslationY( - mDp.heightPx - searchUiManager.getScrollRangeDelta(mInsets)); - ViewGroup searchView = (ViewGroup) searchUiManager; - searchView.setEnabled(false); - for (int i = 0; i < searchView.getChildCount(); i++) { - searchView.getChildAt(i).setEnabled(false); - } - measureView(mRootView, mDp.widthPx, mDp.heightPx); dispatchVisibilityAggregated(mRootView, true); measureView(mRootView, mDp.widthPx, mDp.heightPx); From e678cc18d7b5411272c20a6c8a79d67df1542b82 Mon Sep 17 00:00:00 2001 From: Schneider Victor-tulias Date: Tue, 19 Jan 2021 19:50:18 +0000 Subject: [PATCH 06/17] Revert "Add UI updates for incremental app installs." This reverts commit b803f7e2cb8dbaab2c1453693c61155c03fd90c8. Reason for revert: causes b/177642572 Change-Id: I48b85e8495734a2d3a7b477dfb20929879465b6a (cherry picked from commit 6e60380abb66c904ac4a291a64ab6224acd8be40) --- src/com/android/launcher3/model/AllAppsList.java | 9 ++------- src/com/android/launcher3/model/PackageUpdatedTask.java | 2 -- src/com/android/launcher3/model/data/AppInfo.java | 3 ++- .../android/launcher3/model/data/ItemInfoWithIcon.java | 6 ++---- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index c57c3e495a..8d5cf7422f 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -26,7 +26,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.os.LocaleList; -import android.os.Process; import android.os.UserHandle; import android.util.Log; @@ -162,18 +161,14 @@ public class AllAppsList { /** Updates the given PackageInstallInfo's associated AppInfo's installation info. */ public List updatePromiseInstallInfo(PackageInstallInfo installInfo) { List updatedAppInfos = new ArrayList<>(); - UserHandle user = Process.myUserHandle(); + UserHandle user = installInfo.user; for (int i = data.size() - 1; i >= 0; i--) { final AppInfo appInfo = data.get(i); final ComponentName tgtComp = appInfo.getTargetComponent(); if (tgtComp != null && tgtComp.getPackageName().equals(installInfo.packageName) && appInfo.user.equals(user)) { if (installInfo.state == PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING - || installInfo.state == PackageInstallInfo.STATUS_INSTALLING) { - if (appInfo.isAppStartable() - && installInfo.state == PackageInstallInfo.STATUS_INSTALLING) { - continue; - } + || installInfo.state == PackageInstallInfo.STATUS_INSTALLING) { appInfo.setProgressLevel(installInfo); updatedAppInfos.add(appInfo); diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 3275d59488..896bfb666e 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -38,7 +38,6 @@ import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.pm.UserCache; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.util.FlagOp; @@ -247,7 +246,6 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { if (isNewApkAvailable && si.itemType == Favorites.ITEM_TYPE_APPLICATION) { - si.setProgressLevel(100, PackageInstallInfo.STATUS_INSTALLED); iconCache.getTitleAndIcon(si, si.usingLowResIcon()); infoUpdated = true; } diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java index dde0cf4674..39247c221f 100644 --- a/src/com/android/launcher3/model/data/AppInfo.java +++ b/src/com/android/launcher3/model/data/AppInfo.java @@ -94,6 +94,8 @@ public class AppInfo extends ItemInfoWithIcon { componentName = info.componentName; title = Utilities.trim(info.title); intent = new Intent(info.intent); + user = info.user; + runtimeStatusFlags = info.runtimeStatusFlags; } @VisibleForTesting @@ -112,7 +114,6 @@ public class AppInfo extends ItemInfoWithIcon { .setComponent(componentName) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - setProgressLevel(installInfo); user = installInfo.user; } diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java index d95e7080de..b8a71d33e0 100644 --- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java +++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java @@ -129,9 +129,7 @@ public abstract class ItemInfoWithIcon extends ItemInfo { protected ItemInfoWithIcon(ItemInfoWithIcon info) { super(info); bitmap = info.bitmap; - mProgressLevel = info.mProgressLevel; runtimeStatusFlags = info.runtimeStatusFlags; - user = info.user; } @Override @@ -197,8 +195,8 @@ public abstract class ItemInfoWithIcon extends ItemInfo { : runtimeStatusFlags & ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; } else { mProgressLevel = status == PackageInstallInfo.STATUS_INSTALLED ? 100 : 0; - runtimeStatusFlags &= ~FLAG_INSTALL_SESSION_ACTIVE; - runtimeStatusFlags &= ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; + runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE; + runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; } } From 3c66b72ee8926d74a74f4cdd4bb8131b4d0fbf04 Mon Sep 17 00:00:00 2001 From: Schneider Victor-tulias Date: Tue, 19 Jan 2021 19:50:18 +0000 Subject: [PATCH 07/17] Revert "Add UI updates for incremental app installs." This reverts commit b803f7e2cb8dbaab2c1453693c61155c03fd90c8. Reason for revert: causes b/177642572 Change-Id: I48b85e8495734a2d3a7b477dfb20929879465b6a (cherry picked from commit 6e60380abb66c904ac4a291a64ab6224acd8be40) --- src/com/android/launcher3/model/AllAppsList.java | 9 ++------- src/com/android/launcher3/model/PackageUpdatedTask.java | 2 -- src/com/android/launcher3/model/data/AppInfo.java | 3 ++- .../android/launcher3/model/data/ItemInfoWithIcon.java | 6 ++---- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index c57c3e495a..8d5cf7422f 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -26,7 +26,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.os.LocaleList; -import android.os.Process; import android.os.UserHandle; import android.util.Log; @@ -162,18 +161,14 @@ public class AllAppsList { /** Updates the given PackageInstallInfo's associated AppInfo's installation info. */ public List updatePromiseInstallInfo(PackageInstallInfo installInfo) { List updatedAppInfos = new ArrayList<>(); - UserHandle user = Process.myUserHandle(); + UserHandle user = installInfo.user; for (int i = data.size() - 1; i >= 0; i--) { final AppInfo appInfo = data.get(i); final ComponentName tgtComp = appInfo.getTargetComponent(); if (tgtComp != null && tgtComp.getPackageName().equals(installInfo.packageName) && appInfo.user.equals(user)) { if (installInfo.state == PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING - || installInfo.state == PackageInstallInfo.STATUS_INSTALLING) { - if (appInfo.isAppStartable() - && installInfo.state == PackageInstallInfo.STATUS_INSTALLING) { - continue; - } + || installInfo.state == PackageInstallInfo.STATUS_INSTALLING) { appInfo.setProgressLevel(installInfo); updatedAppInfos.add(appInfo); diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 3275d59488..896bfb666e 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -38,7 +38,6 @@ import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.pm.UserCache; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.util.FlagOp; @@ -247,7 +246,6 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { if (isNewApkAvailable && si.itemType == Favorites.ITEM_TYPE_APPLICATION) { - si.setProgressLevel(100, PackageInstallInfo.STATUS_INSTALLED); iconCache.getTitleAndIcon(si, si.usingLowResIcon()); infoUpdated = true; } diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java index dde0cf4674..39247c221f 100644 --- a/src/com/android/launcher3/model/data/AppInfo.java +++ b/src/com/android/launcher3/model/data/AppInfo.java @@ -94,6 +94,8 @@ public class AppInfo extends ItemInfoWithIcon { componentName = info.componentName; title = Utilities.trim(info.title); intent = new Intent(info.intent); + user = info.user; + runtimeStatusFlags = info.runtimeStatusFlags; } @VisibleForTesting @@ -112,7 +114,6 @@ public class AppInfo extends ItemInfoWithIcon { .setComponent(componentName) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - setProgressLevel(installInfo); user = installInfo.user; } diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java index d95e7080de..b8a71d33e0 100644 --- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java +++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java @@ -129,9 +129,7 @@ public abstract class ItemInfoWithIcon extends ItemInfo { protected ItemInfoWithIcon(ItemInfoWithIcon info) { super(info); bitmap = info.bitmap; - mProgressLevel = info.mProgressLevel; runtimeStatusFlags = info.runtimeStatusFlags; - user = info.user; } @Override @@ -197,8 +195,8 @@ public abstract class ItemInfoWithIcon extends ItemInfo { : runtimeStatusFlags & ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; } else { mProgressLevel = status == PackageInstallInfo.STATUS_INSTALLED ? 100 : 0; - runtimeStatusFlags &= ~FLAG_INSTALL_SESSION_ACTIVE; - runtimeStatusFlags &= ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; + runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE; + runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; } } From ca535d9403c2e8d3dda4de7830817fabe3b17d26 Mon Sep 17 00:00:00 2001 From: Chris Fries Date: Tue, 9 Mar 2021 15:19:37 +0000 Subject: [PATCH 08/17] Revert "[Search] Support flexible results-per-row in AllApps" Revert "[Search] Support flexible results-per-row in AllApps" Revert submission 13786530-grid_adapter Bug: 182236647 Reason for revert: b/182236647 [TP1A][SP1A] Launcher crashing on opening Quick search bar from home screen Reverted Changes: I36882e12b:[Search] Support flexible results-per-row in AllAp... Idc3d24daf:[Search] Support flexible results-per-row in AllAp... Change-Id: Ief3888e63f4946fec43217ce66a1f0a3fb5ff64f (cherry picked from commit 0cf925dc542309e21c2407a9ad47975302944a1d) --- .../launcher3/allapps/AllAppsGridAdapter.java | 19 +++++++++---------- .../allapps/search/SearchAdapterProvider.java | 11 ++--------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java index a05e036701..5030c5e1a3 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -240,18 +240,20 @@ public class AllAppsGridAdapter extends @Override public int getSpanSize(int position) { int viewType = mApps.getAdapterItems().get(position).viewType; - int totalSpans = mGridLayoutMgr.getSpanCount(); if (isIconViewType(viewType)) { - return totalSpans / mAppsPerRow; + return 1 * SPAN_MULTIPLIER; } else if (mSearchAdapterProvider.isSearchView(viewType)) { - return totalSpans / mSearchAdapterProvider.getItemsPerRow(viewType, mAppsPerRow); + return mSearchAdapterProvider.getGridSpanSize(viewType, mAppsPerRow); } else { // Section breaks span the full width - return totalSpans; + return mAppsPerRow * SPAN_MULTIPLIER; } } } + // multiplier to support adapter item column count that is not mAppsPerRow. + public static final int SPAN_MULTIPLIER = 3; + private final BaseDraggingActivity mLauncher; private final LayoutInflater mLayoutInflater; private final AlphabeticalAppsList mApps; @@ -283,17 +285,14 @@ public class AllAppsGridAdapter extends mOnIconClickListener = launcher.getItemOnClickListener(); - mSearchAdapterProvider = searchAdapterProvider; setAppsPerRow(mLauncher.getDeviceProfile().inv.numAllAppsColumns); + + mSearchAdapterProvider = searchAdapterProvider; } public void setAppsPerRow(int appsPerRow) { mAppsPerRow = appsPerRow; - int totalSpans = mAppsPerRow; - for (int itemPerRow : mSearchAdapterProvider.getSupportedItemsPerRow()) { - totalSpans *= itemPerRow; - } - mGridLayoutMgr.setSpanCount(totalSpans); + mGridLayoutMgr.setSpanCount(mAppsPerRow * SPAN_MULTIPLIER); } /** diff --git a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java index 6d491fdd2e..a79ec437fb 100644 --- a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java +++ b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java @@ -50,18 +50,11 @@ public abstract class SearchAdapterProvider { public abstract AllAppsGridAdapter.ViewHolder onCreateViewHolder(LayoutInflater layoutInflater, ViewGroup parent, int viewType); - /** - * Returns supported item per row combinations supported - */ - public int[] getSupportedItemsPerRow() { - return new int[]{}; - } - /** * Returns how many cells a view should span */ - public int getItemsPerRow(int viewType, int appsPerRow) { - return appsPerRow; + public int getGridSpanSize(int viewType, int appsPerRow) { + return appsPerRow * AllAppsGridAdapter.SPAN_MULTIPLIER; } /** From db05108c3c211b62cf90a572e58f87dda4db7808 Mon Sep 17 00:00:00 2001 From: Steven Ng Date: Fri, 9 Apr 2021 15:25:43 +0100 Subject: [PATCH 09/17] Fix drag-n-drop for recommended widgets Bug: 184917820 Test: Drag-n-drop a recommended widget from the all widgets tray Change-Id: If9efffc2e156836ff1b4048c3d40782ba4d5976b (cherry picked from commit f7b7faed7747743941177ab4bdb48a50c15a5300) --- .../widget/picker/WidgetsRecommendationTableLayout.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java index 6569fb0d48..eacd01c590 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java +++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java @@ -19,6 +19,7 @@ import android.content.Context; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import android.widget.TableLayout; import android.widget.TableRow; @@ -31,7 +32,6 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.widget.WidgetCell; -import com.android.launcher3.widget.WidgetImageView; import java.util.ArrayList; import java.util.List; @@ -119,9 +119,9 @@ public final class WidgetsRecommendationTableLayout extends TableLayout { getContext()).inflate(R.layout.widget_cell, parent, false); widget.setOnTouchListener(mWidgetCellOnTouchListener); - WidgetImageView preview = widget.findViewById(R.id.widget_preview); - preview.setOnClickListener(mWidgetCellOnClickListener); - preview.setOnLongClickListener(mWidgetCellOnLongClickListener); + View previewContainer = widget.findViewById(R.id.widget_preview_container); + previewContainer.setOnClickListener(mWidgetCellOnClickListener); + previewContainer.setOnLongClickListener(mWidgetCellOnLongClickListener); widget.setAnimatePreview(false); parent.addView(widget); From 97eb2d3cc07cc225a40fde26f20b536deacf6c99 Mon Sep 17 00:00:00 2001 From: Bill Lin Date: Mon, 26 Apr 2021 13:00:00 +0000 Subject: [PATCH 10/17] Revert "2/ Resolve gesture one handed conflicts swipe up recents" This reverts commit 789aa86617c99f290ec2cc25cb3539b0f4feaedf. Reason for revert: for clarify b/186197537 Change-Id: Ia921d073c2ad4e427c5436370313c2095f2adea8 (cherry picked from commit d7b6a429cd3d1eea3e1b6f6f9a9edf2cba10597b) --- .../src/com/android/quickstep/TouchInteractionService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 18c0b7a1ef..f3fe0b49a4 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -515,8 +515,7 @@ public class TouchInteractionService extends Service implements PluginListener Date: Fri, 30 Apr 2021 18:08:09 +0000 Subject: [PATCH 11/17] Revert "Calling pageTransisionEnd only after edgeEffect finishes" This reverts commit 05b59c080fe78236bfab817a8fbd2f383bc1d8fd. Reason for revert: DF blocking Bug:186822776 Change-Id: Ia4e6168459907f6ed9eb6e22f5497eff3e1ea297 (cherry picked from commit 189d92c3d531311cbcf9e8eaead0f24b98194325) --- src/com/android/launcher3/PagedView.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index f7de3cac71..c9cc3721a8 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -388,8 +388,7 @@ public abstract class PagedView extends ViewGrou } protected void pageEndTransition() { - if (mIsPageInTransition && !mIsBeingDragged && mScroller.isFinished() - && mEdgeGlowLeft.isFinished() && mEdgeGlowRight.isFinished()) { + if (mIsPageInTransition) { mIsPageInTransition = false; onPageEndTransition(); } @@ -1741,7 +1740,6 @@ public abstract class PagedView extends ViewGrou public void draw(Canvas canvas) { super.draw(canvas); drawEdgeEffect(canvas); - pageEndTransition(); } protected void drawEdgeEffect(Canvas canvas) { From 59f67752ad0215c37d090f93d08f6f6301bf312f Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 5 May 2021 12:10:04 -0700 Subject: [PATCH 12/17] Some cleanup for handler invalidation - Cancel reapplyWindowTransformAnim when STATE_HANDLER_INVALIDATED - Set mActivity and mRecentsView = null in invalidateHandlerWithLauncher() instead of posting from invalidateHandler() - Just in case, ignore onActivityInit() if we're already invalidated Test: Tap repeatedly in nav region in an app, no crash Fixes: 186983662 Change-Id: I3c005099b46ebb7c9203bcfcceedf48679dd1965 (cherry picked from commit 95e62812b2f17ccee77fb0e956b0bffde65409fc) --- .../android/quickstep/AbsSwipeUpHandler.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 10384a8a6e..fe1090878a 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -338,6 +338,10 @@ public abstract class AbsSwipeUpHandler, } protected boolean onActivityInit(Boolean alreadyOnHome) { + if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) { + return false; + } + T createdActivity = mActivityInterface.getCreatedActivity(); if (createdActivity != null) { initTransitionEndpoints(createdActivity.getDeviceProfile()); @@ -567,6 +571,8 @@ public abstract class AbsSwipeUpHandler, } }); reapplyWindowTransformAnim.setDuration(RECENTS_ATTACH_DURATION).start(); + mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED, + reapplyWindowTransformAnim::cancel); } else { applyWindowTransform(); } @@ -1376,12 +1382,6 @@ public abstract class AbsSwipeUpHandler, mActivityInitListener.unregister(); ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mActivityRestartListener); mTaskSnapshot = null; - mHandler.post(() -> { - // Defer clearing the activity since invalidation can happen over multiple callbacks - // ie. invalidateHandlerWithLauncher() - mActivity = null; - mRecentsView = null; - }); } private void invalidateHandlerWithLauncher() { @@ -1392,6 +1392,12 @@ public abstract class AbsSwipeUpHandler, mRecentsView.removeOnScrollChangedListener(mOnRecentsScrollListener); resetLauncherListeners(); + + mHandler.post(() -> { + // Defer clearing the activity since invalidation can happen over multiple callbacks. + mActivity = null; + mRecentsView = null; + }); } private void endLauncherTransitionController() { From f0ae43d5e5a71c4a5bff86ea9cffd14c59b68676 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Wed, 19 May 2021 09:38:35 -0700 Subject: [PATCH 13/17] Remove min/max values for RectFSpringAnim2. - Fixes crash on landscape - We added this to stop the windows from going way out of bounds. But we no longer need it since we've tightened up the stiffness so that it would take a super aggressive swipe/high velocity for the window to go out of bounds Bug: 188617892 Test: manual Change-Id: Icc2a0af0a1b26985502ddbc7a5a370e7eecdb346 (cherry picked from commit a2ef1a02384181ca17ae48f4bab14ec375006845) --- .../src/com/android/quickstep/util/RectFSpringAnim2.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java index 97be2b1787..edd3dc3e29 100644 --- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java +++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java @@ -34,8 +34,6 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat; import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; -import com.android.launcher3.DeviceProfile; -import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.util.DynamicResource; @@ -193,12 +191,8 @@ public class RectFSpringAnim2 extends RectFSpringAnim { * @param velocityPxPerMs Velocity of swipe in px/ms. */ public void start(Context context, PointF velocityPxPerMs) { - DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(context).getDeviceProfile(context); - mRectXAnim = new SpringAnimation(this, RECT_CENTER_X) .setStartValue(mCurrentCenterX) - .setMinValue(Math.min(0, mCurrentCenterX)) - .setMaxValue(Math.max(dp.widthPx, mCurrentCenterX)) .setStartVelocity(velocityPxPerMs.x * 1000) .setSpring(new SpringForce(mTargetX) .setStiffness(mXStiffness) @@ -210,8 +204,6 @@ public class RectFSpringAnim2 extends RectFSpringAnim { mRectYAnim = new SpringAnimation(this, RECT_Y) .setStartValue(mCurrentCenterY) - .setMinValue(Math.min(0, mCurrentCenterY)) - .setMaxValue(Math.max(dp.heightPx, mCurrentCenterY)) .setStartVelocity(velocityPxPerMs.y * 1000) .setSpring(new SpringForce(mTargetY) .setStiffness(mYStiffness) From 97db58f969a2c35e33d31c758f7189dda78a8e6d Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Wed, 19 May 2021 09:38:35 -0700 Subject: [PATCH 14/17] Remove min/max values for RectFSpringAnim2. - Fixes crash on landscape - We added this to stop the windows from going way out of bounds. But we no longer need it since we've tightened up the stiffness so that it would take a super aggressive swipe/high velocity for the window to go out of bounds Bug: 188617892 Test: manual Change-Id: Icc2a0af0a1b26985502ddbc7a5a370e7eecdb346 (cherry picked from commit a2ef1a02384181ca17ae48f4bab14ec375006845) --- .../src/com/android/quickstep/util/RectFSpringAnim2.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java index 97be2b1787..edd3dc3e29 100644 --- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java +++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java @@ -34,8 +34,6 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat; import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; -import com.android.launcher3.DeviceProfile; -import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.util.DynamicResource; @@ -193,12 +191,8 @@ public class RectFSpringAnim2 extends RectFSpringAnim { * @param velocityPxPerMs Velocity of swipe in px/ms. */ public void start(Context context, PointF velocityPxPerMs) { - DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(context).getDeviceProfile(context); - mRectXAnim = new SpringAnimation(this, RECT_CENTER_X) .setStartValue(mCurrentCenterX) - .setMinValue(Math.min(0, mCurrentCenterX)) - .setMaxValue(Math.max(dp.widthPx, mCurrentCenterX)) .setStartVelocity(velocityPxPerMs.x * 1000) .setSpring(new SpringForce(mTargetX) .setStiffness(mXStiffness) @@ -210,8 +204,6 @@ public class RectFSpringAnim2 extends RectFSpringAnim { mRectYAnim = new SpringAnimation(this, RECT_Y) .setStartValue(mCurrentCenterY) - .setMinValue(Math.min(0, mCurrentCenterY)) - .setMaxValue(Math.max(dp.heightPx, mCurrentCenterY)) .setStartVelocity(velocityPxPerMs.y * 1000) .setSpring(new SpringForce(mTargetY) .setStiffness(mYStiffness) From b9472327b19c5b4ddb2489bb0e53f3acf3b66047 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Mon, 9 Aug 2021 17:45:22 -0700 Subject: [PATCH 15/17] Adjust all apps zoom level The All Apps scrim fades in early, covering part of the zoom animation. We need to adjust the max zoom in order to make All Apps consistent with Overview, -1, and Shade. Test: pull up the all apps drawer Fixes: 195992422 Change-Id: Ia7bbe17fe7f227dd0a16ba7d21b402cff57176f0 (cherry picked from commit f168bb7aaf94dc3e7c483278ee6eb671485c38c1) (cherry picked from commit 3f6a4e6bf5c1618583770a88a16a0647df8a27d2) --- .../android/launcher3/uioverrides/states/AllAppsState.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java index d822c8cf82..f8c9fd128f 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java @@ -70,7 +70,9 @@ public class AllAppsState extends LauncherState { @Override protected float getDepthUnchecked(Context context) { - return 1f; + // The scrim fades in at approximately 50% of the swipe gesture. + // This means that the depth should be greater than 1, in order to fully zoom out. + return 2f; } @Override From 0ab476cb92a7c2e826be60d9572964519eec5da8 Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Wed, 1 Sep 2021 18:43:40 +0100 Subject: [PATCH 16/17] Only call setCurrentPage in applyLoadPlan if mCurrentPage is outdated - Apply the same for all 3 setCurrentPage cases as they can all causes page jumping Bug: 197493120 Test: manual Change-Id: I5f7013ce3ce4d6fe84c67123618c3bebeeffc43a Merged-In: I5f7013ce3ce4d6fe84c67123618c3bebeeffc43a (cherry picked from commit dacb37c1435e68be5c96d374ba18cd58c37a19dd) --- .../src/com/android/quickstep/views/RecentsView.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index ce79125be1..388706071c 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1146,20 +1146,24 @@ public abstract class RecentsView 0) { - setCurrentPage(indexOfChild(getTaskViewAt(0))); + targetPage = indexOfChild(getTaskViewAt(0)); } } else if (currentTaskId != -1) { currentTaskView = getTaskView(currentTaskId); if (currentTaskView != null) { - setCurrentPage(indexOfChild(currentTaskView)); + targetPage = indexOfChild(currentTaskView); } } + if (targetPage != -1 && mCurrentPage != targetPage) { + setCurrentPage(targetPage); + } if (mIgnoreResetTaskId != -1 && getTaskView(mIgnoreResetTaskId) != ignoreResetTaskView) { // If the taskView mapping is changing, do not preserve the visuals. Since we are From 0d53b02d23f7dcce4a109a42dae5f3359db54bcd Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 6 Aug 2021 11:52:10 -0700 Subject: [PATCH 17/17] Fixing ModelPreload cancelling existing load When a model preload call was made while the loader task is running (eg: on enabling/disabling icon theme, Launcher reloads and then launcher preview start a model-preload), it would cancel the original loader and then start a new loader with empty callbacks. So the model indeed get loaded, but the original callbacks never got notified of it. > Instead we only start preload if an existing task is not running. > Also when preloading, we use existing callbacks, instead of using empty callbacks Bug: 193851085 Bug: 195155924 Test: Verified repro steps Change-Id: I0a96310be8489756f364aa2a12e4345e1418733d (cherry picked from commit 57d4f748b89b2a07e2b33acdfdbcc3767df0aa41) --- src/com/android/launcher3/LauncherModel.java | 33 ++++---- .../graphics/PreviewSurfaceRenderer.java | 18 ++--- .../android/launcher3/model/ModelPreload.java | 76 ------------------- 3 files changed, 22 insertions(+), 105 deletions(-) delete mode 100644 src/com/android/launcher3/model/ModelPreload.java diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index eef3980f96..545f4c3999 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -72,6 +72,7 @@ import java.util.HashSet; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.Executor; +import java.util.function.Consumer; import java.util.function.Supplier; /** @@ -376,7 +377,13 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi loaderResults.bindWidgets(); return true; } else { - startLoaderForResults(loaderResults); + stopLoader(); + mLoaderTask = new LoaderTask( + mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, loaderResults); + + // Always post the loader task, instead of running directly + // (even on same thread) so that we exit any nested synchronized blocks + MODEL_EXECUTOR.post(mLoaderTask); } } } @@ -399,25 +406,17 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi } } - public void startLoaderForResults(LoaderResults results) { + /** + * Loads the model if not loaded + * @param callback called with the data model upon successful load or null on model thread. + */ + public void loadAsync(Consumer callback) { synchronized (mLock) { - stopLoader(); - mLoaderTask = new LoaderTask( - mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, results); - - // Always post the loader task, instead of running directly (even on same thread) so - // that we exit any nested synchronized blocks - MODEL_EXECUTOR.post(mLoaderTask); - } - } - - public void startLoaderForResultsIfNotLoaded(LoaderResults results) { - synchronized (mLock) { - if (!isModelLoaded()) { - Log.d(TAG, "Workspace not loaded, loading now"); - startLoaderForResults(results); + if (!mModelLoaded && !mIsLoaderTaskRunning) { + startLoader(); } } + MODEL_EXECUTOR.post(() -> callback.accept(isModelLoaded() ? mBgDataModel : null)); } @Override diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java index df493599ed..3b140a06bd 100644 --- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java +++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java @@ -49,7 +49,6 @@ import com.android.launcher3.model.GridSizeMigrationTask; import com.android.launcher3.model.GridSizeMigrationTaskV2; import com.android.launcher3.model.LoaderTask; import com.android.launcher3.model.ModelDelegate; -import com.android.launcher3.model.ModelPreload; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.Themes; @@ -174,18 +173,13 @@ public class PreviewSurfaceRenderer { } }.run(); } else { - new ModelPreload() { - - @Override - public void onComplete(boolean isSuccess) { - if (isSuccess) { - MAIN_EXECUTOR.execute(() -> - renderView(inflationContext, getBgDataModel(), null)); - } else { - Log.e(TAG, "Model loading failed"); - } + LauncherAppState.getInstance(inflationContext).getModel().loadAsync(dataModel -> { + if (dataModel != null) { + MAIN_EXECUTOR.execute(() -> renderView(inflationContext, dataModel, null)); + } else { + Log.e(TAG, "Model loading failed"); } - }.start(inflationContext); + }); } } diff --git a/src/com/android/launcher3/model/ModelPreload.java b/src/com/android/launcher3/model/ModelPreload.java deleted file mode 100644 index 756b7da759..0000000000 --- a/src/com/android/launcher3/model/ModelPreload.java +++ /dev/null @@ -1,76 +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.model; - -import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; - -import android.content.Context; -import android.util.Log; - -import androidx.annotation.WorkerThread; - -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherModel; -import com.android.launcher3.LauncherModel.ModelUpdateTask; -import com.android.launcher3.model.BgDataModel.Callbacks; - -import java.util.concurrent.Executor; - -/** - * Utility class to preload LauncherModel - */ -public class ModelPreload implements ModelUpdateTask { - - private static final String TAG = "ModelPreload"; - - private LauncherAppState mApp; - private LauncherModel mModel; - private BgDataModel mBgDataModel; - private AllAppsList mAllAppsList; - - @Override - public final void init(LauncherAppState app, LauncherModel model, BgDataModel dataModel, - AllAppsList allAppsList, Executor uiExecutor) { - mApp = app; - mModel = model; - mBgDataModel = dataModel; - mAllAppsList = allAppsList; - } - - @Override - public final void run() { - mModel.startLoaderForResultsIfNotLoaded( - new LoaderResults(mApp, mBgDataModel, mAllAppsList, new Callbacks[0])); - MODEL_EXECUTOR.post(() -> { - Log.d(TAG, "Preload completed : " + mModel.isModelLoaded()); - onComplete(mModel.isModelLoaded()); - }); - } - - public BgDataModel getBgDataModel() { - return mBgDataModel; - } - - /** - * Called when the task is complete - */ - @WorkerThread - public void onComplete(boolean isSuccess) { } - - public void start(Context context) { - LauncherAppState.getInstance(context).getModel().enqueueModelUpdateTask(this); - } -} \ No newline at end of file