From 087a9e39b663dade90d8dfd74300e42575649b87 Mon Sep 17 00:00:00 2001 From: Alistair Delva Date: Mon, 5 Oct 2020 14:46:26 +0000 Subject: [PATCH] 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 --- 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 54c2383be9..68111d2632 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.content.Intent; @@ -309,10 +307,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 4b75a33fc1..90566f3ce8 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; @@ -89,10 +88,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; @@ -119,13 +117,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; @@ -153,6 +151,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; @@ -268,8 +269,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; @@ -401,7 +400,6 @@ public class Launcher extends StatefulActivity implements Launche inflateRootView(R.layout.launcher); setupViews(); - crossFadeWithPreviousAppearance(); mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots); mAppTransitionManager = LauncherAppTransitionManager.newInstance(this); @@ -478,7 +476,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); @@ -556,6 +554,7 @@ public class Launcher extends StatefulActivity implements Launche } private void onIdpChanged(InvariantDeviceProfile idp) { + mUserEventDispatcher = null; initDeviceProfile(idp); dispatchDeviceProfileChanged(); @@ -911,7 +910,7 @@ public class Launcher extends StatefulActivity implements Launche mOverlayManager.onActivityStopped(this); } - logStopAndResume(false /* isResume */); + logStopAndResume(Action.Command.STOP); mAppWidgetHost.setListenIfResumed(false); NotificationListener.removeNotificationsChangedListener(); } @@ -933,7 +932,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) @@ -950,28 +949,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); } @@ -1361,18 +1364,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; } @@ -1473,6 +1464,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) { @@ -2762,40 +2758,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 ->