diff --git a/Android.mk b/Android.mk index 25f5412d21..349a134d75 100644 --- a/Android.mk +++ b/Android.mk @@ -36,18 +36,12 @@ 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 @@ -135,7 +129,6 @@ 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 @@ -203,7 +196,6 @@ 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 534ca65115..28a05d569c 100644 --- a/build.gradle +++ b/build.gradle @@ -82,7 +82,6 @@ android { manifest.srcFile 'AndroidManifest-common.xml' proto { srcDir 'protos/' - srcDir 'proto_overrides/' } } @@ -150,7 +149,6 @@ dependencies { implementation "androidx.preference:preference:${ANDROID_X_VERSION}" implementation project(':IconLoader') withQuickstepImplementation project(':SharedLibWrapper') - implementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/libs", include: 'launcher_protos.jar') // Recents lib dependency withQuickstepImplementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/quickstep/libs", include: 'sysui_shared.jar') @@ -171,20 +169,16 @@ dependencies { protobuf { // Configure the protoc executable protoc { - artifact = 'com.google.protobuf:protoc:3.0.0' - - generateProtoTasks { - all().each { task -> - task.builtins { - remove java - javanano { - option "java_package=launcher_log_extension.proto|com.android.launcher3.userevent.nano" - option "java_package=launcher_log.proto|com.android.launcher3.userevent.nano" - option "java_package=launcher_dump.proto|com.android.launcher3.model.nano" - option "enum_style=java" - } + artifact = "com.google.protobuf:protoc:${protocVersion}" + } + generateProtoTasks { + all().each { task -> + task.builtins { + remove java + java { + option "lite" } } } } -} +} \ No newline at end of file diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto deleted file mode 100644 index 9423cb2642..0000000000 --- a/protos/launcher_log.proto +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -syntax = "proto2"; - -import "launcher_log_extension.proto"; - -option java_package = "com.android.launcher3.userevent"; -option java_outer_classname = "LauncherLogProto"; - -package userevent; - -message Target { - enum Type { - NONE = 0; - ITEM = 1; - CONTROL = 2; - CONTAINER = 3; - } - - optional Type type = 1; - - // For container type and item type - // Used mainly for ContainerType.FOLDER, ItemType.* - optional int32 page_index = 2; - optional int32 rank = 3; - optional int32 grid_x = 4; - optional int32 grid_y = 5; - - // For container types only - optional ContainerType container_type = 6; - optional int32 cardinality = 7; - - // For control types only - optional ControlType control_type = 8; - - // For item types only - optional ItemType item_type = 9; - optional int32 package_name_hash = 10; - optional int32 component_hash = 11; // Used for ItemType.WIDGET - optional int32 intent_hash = 12; // Used for ItemType.SHORTCUT - optional int32 span_x = 13 [default = 1];// Used for ItemType.WIDGET - optional int32 span_y = 14 [default = 1];// Used for ItemType.WIDGET - optional int32 predictedRank = 15; - optional TargetExtension extension = 16; - optional TipType tip_type = 17; - optional int32 search_query_length = 18; - optional bool is_work_app = 19; - optional FromFolderLabelState from_folder_label_state = 20; - optional ToFolderLabelState to_folder_label_state = 21; - - // Note: proto does not support duplicate enum values, even if they belong to different enum type. - // Hence "FROM" and "TO" prefix added. - enum FromFolderLabelState { - FROM_FOLDER_LABEL_STATE_UNSPECIFIED = 0; - FROM_EMPTY = 1; - FROM_CUSTOM = 2; - FROM_SUGGESTED = 3; - } - - enum ToFolderLabelState { - TO_FOLDER_LABEL_STATE_UNSPECIFIED = 0; - TO_SUGGESTION0_WITH_VALID_PRIMARY = 1; - TO_SUGGESTION1_WITH_VALID_PRIMARY = 2; - TO_SUGGESTION1_WITH_EMPTY_PRIMARY = 3; - TO_SUGGESTION2_WITH_VALID_PRIMARY = 4; - TO_SUGGESTION2_WITH_EMPTY_PRIMARY = 5; - TO_SUGGESTION3_WITH_VALID_PRIMARY = 6; - TO_SUGGESTION3_WITH_EMPTY_PRIMARY = 7; - TO_EMPTY_WITH_VALID_SUGGESTIONS = 8 [deprecated = true]; - TO_EMPTY_WITH_VALID_PRIMARY = 15; - TO_EMPTY_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY = 16; - TO_EMPTY_WITH_EMPTY_SUGGESTIONS = 9; - TO_EMPTY_WITH_SUGGESTIONS_DISABLED = 10; - TO_CUSTOM_WITH_VALID_SUGGESTIONS = 11 [deprecated = true]; - TO_CUSTOM_WITH_VALID_PRIMARY = 17; - TO_CUSTOM_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY = 18; - TO_CUSTOM_WITH_EMPTY_SUGGESTIONS = 12; - TO_CUSTOM_WITH_SUGGESTIONS_DISABLED = 13; - UNCHANGED = 14; - } -} - -// Used to define what type of item a Target would represent. -enum ItemType { - DEFAULT_ITEMTYPE = 0; - APP_ICON = 1; - SHORTCUT = 2; - WIDGET = 3; - FOLDER_ICON = 4; - DEEPSHORTCUT = 5; - SEARCHBOX = 6; - EDITTEXT = 7; - NOTIFICATION = 8; - TASK = 9; // Each page of Recents UI (QuickStep) - WEB_APP = 10; - TASK_ICON = 11; -} - -// Used to define what type of container a Target would represent. -enum ContainerType { - DEFAULT_CONTAINERTYPE = 0; - WORKSPACE = 1; - HOTSEAT = 2; - FOLDER = 3; - ALLAPPS = 4; - WIDGETS = 5; - OVERVIEW = 6; // Zoomed out workspace (without QuickStep) - PREDICTION = 7; - SEARCHRESULT = 8; - DEEPSHORTCUTS = 9; - PINITEM = 10; // confirmation screen - NAVBAR = 11; - TASKSWITCHER = 12; // Recents UI Container (QuickStep) - APP = 13; // Foreground activity is another app (QuickStep) - TIP = 14; // Onboarding texts (QuickStep) - OTHER_LAUNCHER_APP = 15; -} - -// Used to define what type of control a Target would represent. -enum ControlType { - DEFAULT_CONTROLTYPE = 0; - ALL_APPS_BUTTON = 1; - WIDGETS_BUTTON = 2; - WALLPAPER_BUTTON = 3; - SETTINGS_BUTTON = 4; - REMOVE_TARGET = 5; - UNINSTALL_TARGET = 6; - APPINFO_TARGET = 7; - RESIZE_HANDLE = 8; - VERTICAL_SCROLL = 9; - HOME_INTENT = 10; // Deprecated, use enum Command instead - BACK_BUTTON = 11; - QUICK_SCRUB_BUTTON = 12; - CLEAR_ALL_BUTTON = 13; - CANCEL_TARGET = 14; - TASK_PREVIEW = 15; - SPLIT_SCREEN_TARGET = 16; - REMOTE_ACTION_SHORTCUT = 17; - APP_USAGE_SETTINGS = 18; - BACK_GESTURE = 19; - UNDO = 20; - DISMISS_PREDICTION = 21; - HYBRID_HOTSEAT_ACCEPTED = 22; - HYBRID_HOTSEAT_CANCELED = 23; - OVERVIEW_ACTIONS_SHARE_BUTTON = 24; - OVERVIEW_ACTIONS_SCREENSHOT_BUTTON = 25; - OVERVIEW_ACTIONS_SELECT_BUTTON = 26; - SELECT_MODE_CLOSE_BUTTON = 27; - SELECT_MODE_ITEM = 28; -} - -enum TipType { - DEFAULT_NONE = 0; - BOUNCE = 1; - SWIPE_UP_TEXT = 2; - QUICK_SCRUB_TEXT = 3; - PREDICTION_TEXT = 4; - DWB_TOAST = 5; - HYBRID_HOTSEAT = 6; -} - -// Used to define the action component of the LauncherEvent. -message Action { - enum Type { - TOUCH = 0; - AUTOMATED = 1; - COMMAND = 2; - TIP = 3; - SOFT_KEYBOARD = 4; - // HARD_KEYBOARD, ASSIST - } - - enum Touch { - TAP = 0; - LONGPRESS = 1; - DRAGDROP = 2; - SWIPE = 3; - FLING = 4; - PINCH = 5; - SWIPE_NOOP = 6; - } - - enum Direction { - NONE = 0; - UP = 1; - DOWN = 2; - LEFT = 3; - RIGHT = 4; - UPRIGHT = 5; - UPLEFT = 6; - } - enum Command { - HOME_INTENT = 0; - BACK = 1; - ENTRY = 2; // Indicates entry to one of Launcher container type target - // not using the HOME_INTENT - CANCEL = 3; // Indicates that a confirmation screen was cancelled - CONFIRM = 4; // Indicates thata confirmation screen was accepted - STOP = 5; // Indicates onStop() was called (screen time out, power off) - RECENTS_BUTTON = 6; // Indicates that Recents button was pressed - RESUME = 7; // Indicates onResume() was called - } - - optional Type type = 1; - optional Touch touch = 2; - optional Direction dir = 3; - optional Command command = 4; - // Log if the action was performed on outside of the container - optional bool is_outside = 5; - optional bool is_state_change = 6; -} - -// -// Context free grammar of typical user interaction: -// Action (Touch) + Target -// Action (Touch) + Target + Target -// -message LauncherEvent { - required Action action = 1; - // List of targets that touch actions can be operated on. - repeated Target src_target = 2; - repeated Target dest_target = 3; - - optional int64 action_duration_millis = 4; - optional int64 elapsed_container_millis = 5; - optional int64 elapsed_session_millis = 6; - - optional bool is_in_multi_window_mode = 7 [deprecated = true]; - optional bool is_in_landscape_mode = 8 [deprecated = true]; - - optional LauncherEventExtension extension = 9; -} diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml index 43bf0ea966..52475dfc8a 100644 --- a/quickstep/res/layout/gesture_tutorial_fragment.xml +++ b/quickstep/res/layout/gesture_tutorial_fragment.xml @@ -13,7 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. --> - @@ -93,11 +94,11 @@ style="@style/TextAppearance.GestureTutorial.Feedback" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_above="@id/gesture_tutorial_fragment_action_button" + android:layout_below="@id/gesture_tutorial_fragment_titles_container" 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_marginBottom="10dp"/> + android:layout_marginTop="40dp"/> @@ -126,4 +127,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 86120e3b97..4b45b10d4d 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -149,6 +149,21 @@ 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 bc3b4ab0ef..44d43c6784 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -22,6 +22,8 @@ import static com.android.launcher3.LauncherState.NORMAL; import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY; +import com.android.systemui.shared.system.InteractionJankMonitorWrapper; + import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.app.ActivityOptions; @@ -319,4 +321,10 @@ 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 b35b33c418..5c8463c2a7 100644 --- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java +++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java @@ -34,8 +34,7 @@ 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, - WrappedAnimationRunnerImpl { +public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat { 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 b53e834db4..057c0f4aaa 100644 --- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java @@ -66,6 +66,7 @@ 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; @@ -81,6 +82,7 @@ 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; @@ -795,6 +797,36 @@ 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. */ @@ -859,21 +891,9 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans // is initialized. if (launcherIsATargetWithMode(appTargets, MODE_OPENING) || mLauncher.isForceInvisible()) { - 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); - } - }); - } + addCujInstrumentation( + anim, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME, + TRANSITION_OPEN_LAUNCHER); // Only register the content animation for cancellation when state changes mLauncher.getStateManager().setCurrentAnimation(anim); @@ -942,25 +962,12 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans launcherClosing); } - 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); - } - }); - } + 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 (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 d3c4c3d62d..5b066c6be6 100644 --- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java +++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java @@ -16,11 +16,8 @@ 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; @@ -43,7 +40,6 @@ 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; @@ -53,13 +49,11 @@ 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; @@ -68,7 +62,7 @@ import java.util.List; @TargetApi(Build.VERSION_CODES.P) public class PredictionRowView extends LinearLayout implements - LogContainerProvider, OnDeviceProfileChangeListener, FloatingHeaderRow { + OnDeviceProfileChangeListener, FloatingHeaderRow { private static final IntProperty TEXT_ALPHA = new IntProperty("textAlpha") { @@ -271,29 +265,6 @@ 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 151a113d1e..380735044d 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -55,7 +55,6 @@ 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 bce73cd4e4..a2e3bdf8a0 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java @@ -16,6 +16,7 @@ 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; @@ -23,7 +24,6 @@ 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, ContainerType.ALLAPPS, STATE_FLAGS); + super(id, LAUNCHER_STATE_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 8ff05f2aaa..4b4f955204 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java @@ -15,12 +15,13 @@ */ 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; @@ -33,7 +34,7 @@ public class BackgroundAppState extends OverviewState { | FLAG_WORKSPACE_INACCESSIBLE | FLAG_NON_INTERACTIVE | FLAG_CLOSE_POPUPS; public BackgroundAppState(int id) { - this(id, LauncherLogProto.ContainerType.TASKSWITCHER); + this(id, LAUNCHER_STATE_BACKGROUND); } 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 fc0dcd5119..41c689d16d 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java @@ -15,13 +15,14 @@ */ 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; /** @@ -34,7 +35,7 @@ public class OverviewModalTaskState extends OverviewState { FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_WORKSPACE_INACCESSIBLE; public OverviewModalTaskState(int id) { - super(id, ContainerType.OVERVIEW, STATE_FLAGS); + super(id, LAUNCHER_STATE_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 bbe7821864..525ff5816d 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -16,6 +16,7 @@ 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; @@ -29,7 +30,6 @@ 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, ContainerType.TASKSWITCHER, stateFlags); + this(id, LAUNCHER_STATE_OVERVIEW, 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 2c7373e206..51e72dacdc 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java @@ -15,8 +15,9 @@ */ 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 @@ -26,7 +27,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto; public class QuickSwitchState extends BackgroundAppState { public QuickSwitchState(int id) { - super(id, LauncherLogProto.ContainerType.APP); + super(id, LAUNCHER_STATE_BACKGROUND); } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java index bef191ef8f..7a0f634b45 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java @@ -12,8 +12,6 @@ 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; /** @@ -45,11 +43,6 @@ 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(); @@ -65,13 +58,8 @@ public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchContro } @Override - protected int getDirectionForLog() { - return mLauncher.getDeviceProfile().isSeascape() ? Direction.RIGHT : Direction.LEFT; - } - - @Override - protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) { - super.onSwipeInteractionCompleted(targetState, logAction); + protected void onSwipeInteractionCompleted(LauncherState targetState) { + super.onSwipeInteractionCompleted(targetState); 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 76168440a8..d210bc6851 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java @@ -45,12 +45,9 @@ 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; @@ -211,7 +208,6 @@ 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 @@ -230,7 +226,7 @@ public class NavBarToHomeTouchController implements TouchController, () -> onSwipeInteractionCompleted(mEndState)); } if (mStartState != mEndState) { - // TODO: add to WW log + logHomeGesture(); } AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(mLauncher); if (topOpenView != null) { @@ -255,17 +251,10 @@ public class NavBarToHomeTouchController implements TouchController, AccessibilityManagerCompat.sendStateEventToTest(mLauncher, targetState.ordinal); } - 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()); + private void logHomeGesture() { mLauncher.getStatsLogManager().logger() - .withSrcState(StatsLogManager.containerTypeToAtomState(mStartState.containerType)) - .withDstState(StatsLogManager.containerTypeToAtomState(mEndState.containerType)) + .withSrcState(mStartState.statsLogOrdinal) + .withDstState(mEndState.statsLogOrdinal) .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 c78d4741d8..2a3bdbfcb8 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java @@ -49,7 +49,6 @@ 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; @@ -207,7 +206,7 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch private void maybeSwipeInteractionToOverviewComplete() { if (mReachedOverview && mDetector.isSettlingState()) { - onSwipeInteractionCompleted(OVERVIEW, Touch.SWIPE); + onSwipeInteractionCompleted(OVERVIEW); } } @@ -251,7 +250,7 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch private void goToOverviewOrHomeOnDragEnd(float velocity) { boolean goToHomeInsteadOfOverview = !mMotionPauseDetector.isPaused(); if (goToHomeInsteadOfOverview) { - new OverviewToHomeAnim(mLauncher, ()-> onSwipeInteractionCompleted(NORMAL, Touch.FLING)) + new OverviewToHomeAnim(mLauncher, ()-> onSwipeInteractionCompleted(NORMAL)) .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 a6a3497f04..f378848a71 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java @@ -57,13 +57,9 @@ 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; @@ -287,7 +283,6 @@ 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(); @@ -298,7 +293,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController, overviewAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - onAnimationToStateCompleted(OVERVIEW, logAction); + onAnimationToStateCompleted(OVERVIEW); } }); overviewAnim.start(); @@ -393,7 +388,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController, } nonOverviewAnim.setDuration(Math.max(xDuration, yDuration)); - mNonOverviewAnim.setEndAction(() -> onAnimationToStateCompleted(targetState, logAction)); + mNonOverviewAnim.setEndAction(() -> onAnimationToStateCompleted(targetState)); cancelAnimations(); xOverviewAnim.start(); @@ -401,27 +396,17 @@ public class NoButtonQuickSwitchTouchController implements TouchController, nonOverviewAnim.start(); } - 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()); + private void onAnimationToStateCompleted(LauncherState targetState) { mLauncher.getStatsLogManager().logger() .withSrcState(LAUNCHER_STATE_HOME) - .withDstState(StatsLogManager.containerTypeToAtomState(targetState.containerType)) - .log(getLauncherAtomEvent(mStartState.containerType, targetState.containerType, + .withDstState(targetState.statsLogOrdinal) + .log(getLauncherAtomEvent(mStartState.statsLogOrdinal, targetState.statsLogOrdinal, 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 90911684ec..45e5e2fb7c 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java @@ -25,7 +25,6 @@ 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; @@ -73,9 +72,4 @@ 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 059a703075..037d9889fd 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java @@ -48,8 +48,6 @@ 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; @@ -172,11 +170,6 @@ 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; @@ -285,7 +278,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr private void cancelPendingAnim() { if (mPendingAnimation != null) { - mPendingAnimation.finish(false, Touch.SWIPE); + mPendingAnimation.finish(false); mPendingAnimation = null; } } @@ -320,8 +313,8 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr } @Override - protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) { - super.onSwipeInteractionCompleted(targetState, logAction); + protected void onSwipeInteractionCompleted(LauncherState targetState) { + super.onSwipeInteractionCompleted(targetState); 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 c643858e5c..b8c2030852 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java @@ -21,6 +21,7 @@ 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; @@ -41,8 +42,6 @@ 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; @@ -92,14 +91,14 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll @Override public void onDragStart(boolean start, float startDisplacement) { super.onDragStart(start, startDisplacement); - mStartContainerType = LauncherLogProto.ContainerType.NAVBAR; + mStartContainerType = LAUNCHER_STATE_BACKGROUND; ActivityManagerWrapper.getInstance() .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); } @Override - protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) { - super.onSwipeInteractionCompleted(targetState, logAction); + protected void onSwipeInteractionCompleted(LauncherState targetState) { + super.onSwipeInteractionCompleted(targetState); } @Override @@ -153,14 +152,4 @@ 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 16bd9ed384..fe69c9b87d 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java @@ -15,10 +15,12 @@ */ 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 android.view.MotionEvent.ACTION_CANCEL; + +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN; import android.graphics.PointF; import android.util.SparseArray; @@ -31,12 +33,9 @@ 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 java.io.PrintWriter; /** @@ -133,9 +132,8 @@ public class StatusBarTouchController implements TouchController { int action = ev.getAction(); if (action == ACTION_UP || action == ACTION_CANCEL) { dispatchTouchEvent(ev); - mLauncher.getUserEventDispatcher().logActionOnContainer(action == ACTION_UP ? - Touch.FLING : Touch.SWIPE, Direction.DOWN, ContainerType.WORKSPACE, - mLauncher.getWorkspace().getCurrentPage()); + mLauncher.getStatsLogManager().logger() + .log(LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN); 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 df6194d4b2..186caf6dc1 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java @@ -36,7 +36,6 @@ 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; @@ -203,7 +202,7 @@ public abstract class TaskViewTouchController mCurrentAnimation.setPlayFraction(0); } if (mPendingAnimation != null) { - mPendingAnimation.finish(false, Touch.SWIPE); + mPendingAnimation.finish(false); mPendingAnimation = null; } @@ -285,7 +284,6 @@ 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; @@ -294,11 +292,9 @@ 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( @@ -307,14 +303,14 @@ public abstract class TaskViewTouchController animationDuration *= LauncherAnimUtils.blockedFlingDurationFactor(velocity); } - mCurrentAnimation.setEndAction(() -> onCurrentAnimationEnd(goingToEnd, logAction)); + mCurrentAnimation.setEndAction(() -> onCurrentAnimationEnd(goingToEnd)); mCurrentAnimation.startWithVelocity(mActivity, goingToEnd, velocity, mEndDisplacement, animationDuration); } - private void onCurrentAnimationEnd(boolean wasSuccess, int logAction) { + private void onCurrentAnimationEnd(boolean wasSuccess) { if (mPendingAnimation != null) { - mPendingAnimation.finish(wasSuccess, logAction); + mPendingAnimation.finish(wasSuccess); mPendingAnimation = null; } clearState(); @@ -326,7 +322,7 @@ public abstract class TaskViewTouchController mTaskBeingDragged = null; mCurrentAnimation = null; if (mPendingAnimation != null) { - mPendingAnimation.finish(false, Touch.SWIPE); + mPendingAnimation.finish(false); mPendingAnimation = null; } } diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 5fc9cca3c5..91d4c64c78 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -76,12 +76,8 @@ 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; @@ -104,6 +100,7 @@ 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; @@ -222,8 +219,7 @@ public abstract class AbsSwipeUpHandler, Q extends private boolean mPassedOverviewThreshold; private boolean mGestureStarted; - private int mLogAction = Touch.SWIPE; - private int mLogDirection = Direction.UP; + private boolean mLogDirectionUpOrLeft = true; private PointF mDownPos; private boolean mIsLikelyToStartNewTask; @@ -441,9 +437,13 @@ public abstract class AbsSwipeUpHandler, Q extends mOnDeferredActivityLaunch); mGestureState.runOnceAtState(STATE_END_TARGET_SET, - () -> mDeviceState.getRotationTouchHelper(). - onEndTargetCalculated(mGestureState.getEndTarget(), - mActivityInterface)); + () -> { + mDeviceState.getRotationTouchHelper() + .onEndTargetCalculated(mGestureState.getEndTarget(), + mActivityInterface); + + mRecentsView.onGestureEndTargetCalculated(mGestureState.getEndTarget()); + }); notifyGestureStartedAsync(); } @@ -745,7 +745,6 @@ 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 */); } @@ -761,13 +760,11 @@ 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) { - mLogDirection = velocity.y < 0 ? Direction.UP : Direction.DOWN; + mLogDirectionUpOrLeft = velocity.y < 0; } else { - mLogDirection = velocity.x < 0 ? Direction.LEFT : Direction.RIGHT; + mLogDirectionUpOrLeft = velocity.x < 0; } mDownPos = downPos; handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */); @@ -979,8 +976,7 @@ public abstract class AbsSwipeUpHandler, Q extends break; case LAST_TASK: case NEW_TASK: - event = (mLogDirection == Direction.LEFT) - ? LAUNCHER_QUICKSWITCH_LEFT + event = mLogDirectionUpOrLeft ? LAUNCHER_QUICKSWITCH_LEFT : LAUNCHER_QUICKSWITCH_RIGHT; break; default: @@ -988,12 +984,10 @@ public abstract class AbsSwipeUpHandler, Q extends } StatsLogger logger = StatsLogManager.newInstance(mContext).logger() .withSrcState(LAUNCHER_STATE_BACKGROUND) - .withDstState(StatsLogManager.containerTypeToAtomState(endTarget.containerType)); + .withDstState(endTarget.containerType); if (targetTask != null) { logger.withItemInfo(targetTask.getItemInfo()); } - logger.log(event); - DeviceProfile dp = mDp; if (dp == null || mDownPos == null) { @@ -1003,12 +997,8 @@ public abstract class AbsSwipeUpHandler, Q extends int pageIndex = endTarget == LAST_TASK ? LOG_NO_OP_PAGE_INDEX : mRecentsView.getNextPage(); - UserEventDispatcher.newInstance(mContext).logStateChangeAction( - mLogAction, mLogDirection, - (int) mDownPos.x, (int) mDownPos.y, - ContainerType.NAVBAR, ContainerType.APP, - endTarget.containerType, - pageIndex); + // TODO: set correct container using the pageIndex + logger.log(event); } /** Animates to the given progress, where 0 is the current app and 1 is overview. */ @@ -1204,10 +1194,12 @@ 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(); } @@ -1221,6 +1213,13 @@ 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 8b108ac299..d35e270dd5 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -152,11 +152,6 @@ public abstract class BaseActivityInterface mAnimationProvider; private final long mToggleClickedTime = SystemClock.uptimeMillis(); - private boolean mUserEventLogged; private ActivityInitListener mListener; public RecentsActivityCommand() { @@ -160,7 +156,7 @@ public class OverviewCommandHelper { ActivityManagerWrapper.getInstance().getRunningTask(), mDeviceState); // Preload the plan - mRecentsModel.getTasks(null); + RecentsModel.INSTANCE.get(mContext).getTasks(null); } @Override @@ -212,13 +208,6 @@ 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 6f2f9fb523..2f55f14a9b 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -41,7 +41,10 @@ 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; @@ -87,6 +90,9 @@ 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. */ @@ -118,7 +124,6 @@ public final class RecentsActivity extends StatefulActivity { * etc.) */ protected void onHandleConfigChanged() { - mUserEventDispatcher = null; initDeviceProfile(); AbstractFloatingView.closeOpenViews(this, true, @@ -170,8 +175,11 @@ public final class RecentsActivity extends StatefulActivity { } final TaskView taskView = (TaskView) v; - RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mUiHandler, - true /* startAtFrontOfQueue */) { + mActivityLaunchAnimationRunner = new WrappedAnimationRunnerImpl() { + @Override + public Handler getHandler() { + return mUiHandler; + } @Override public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, @@ -182,8 +190,10 @@ public final class RecentsActivity extends StatefulActivity { result.setAnimation(anim, RecentsActivity.this); } }; + final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner<>( + mActivityLaunchAnimationRunner, true /* startAtFrontOfQueue */); return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat( - runner, RECENTS_LAUNCH_DURATION, + wrapper, RECENTS_LAUNCH_DURATION, RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION - STATUS_BAR_TRANSITION_PRE_DELAY)); } @@ -288,6 +298,7 @@ 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 6c302ae5d7..d47217b770 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -18,7 +18,6 @@ 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; @@ -26,11 +25,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; @@ -40,6 +39,8 @@ 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; /** @@ -52,6 +53,9 @@ 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; @@ -61,12 +65,10 @@ 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, looper); - mThumbnailCache = new TaskThumbnailCache(context, looper); + mIconCache = new TaskIconCache(context, RECENTS_MODEL_EXECUTOR); + mThumbnailCache = new TaskThumbnailCache(context, RECENTS_MODEL_EXECUTOR); 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 7ff799ec55..65e89cfa2f 100644 --- a/quickstep/src/com/android/quickstep/TaskIconCache.java +++ b/quickstep/src/com/android/quickstep/TaskIconCache.java @@ -17,7 +17,6 @@ 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; @@ -27,8 +26,6 @@ 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; @@ -37,12 +34,11 @@ 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; @@ -50,6 +46,7 @@ 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; /** @@ -57,7 +54,7 @@ import java.util.function.Consumer; */ public class TaskIconCache { - private final Handler mBackgroundHandler; + private final Executor mBgExecutor; private final AccessibilityManager mAccessibilityManager; private final Context mContext; @@ -65,9 +62,9 @@ public class TaskIconCache { private final SparseArray mDefaultIcons = new SparseArray<>(); private final IconProvider mIconProvider; - public TaskIconCache(Context context, Looper backgroundLooper) { + public TaskIconCache(Context context, Executor bgExecutor) { mContext = context; - mBackgroundHandler = new Handler(backgroundLooper); + mBgExecutor = bgExecutor; mAccessibilityManager = context.getSystemService(AccessibilityManager.class); Resources res = context.getResources(); @@ -83,31 +80,27 @@ 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 IconLoadRequest updateIconInBackground(Task task, Consumer callback) { + public CancellableTask updateIconInBackground(Task task, Consumer callback) { Preconditions.assertUIThread(); if (task.icon != null) { // Nothing to load, the icon is already loaded callback.accept(task); return null; } - - IconLoadRequest request = new IconLoadRequest(mBackgroundHandler) { + CancellableTask request = new CancellableTask() { @Override - 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(); - }); + public TaskCacheEntry getResultOnBg() { + return getCacheEntry(task); + } + + @Override + public void handleResult(TaskCacheEntry result) { + task.icon = result.icon; + task.titleDescription = result.contentDescription; + callback.accept(task); } }; - Utilities.postAsyncCallback(mBackgroundHandler, request); + mBgExecutor.execute(request); return request; } @@ -120,9 +113,8 @@ public class TaskIconCache { } void invalidateCacheEntries(String pkg, UserHandle handle) { - Utilities.postAsyncCallback(mBackgroundHandler, - () -> mIconCache.removeAll(key -> - pkg.equals(key.getPackageName()) && handle.getIdentifier() == key.userId)); + mBgExecutor.execute(() -> mIconCache.removeAll(key -> + pkg.equals(key.getPackageName()) && handle.getIdentifier() == key.userId)); } @WorkerThread @@ -208,12 +200,6 @@ 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 2b55b805c6..65bb0f35d1 100644 --- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java +++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java @@ -21,7 +21,6 @@ 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; @@ -39,7 +38,6 @@ 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; @@ -228,8 +226,6 @@ 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 2b7a8ec250..a8a0219594 100644 --- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java +++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java @@ -15,17 +15,12 @@ */ 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; @@ -33,11 +28,12 @@ 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 Handler mBackgroundHandler; + private final Executor mBgExecutor; private final int mCacheSize; private final TaskKeyLruCache mCache; @@ -94,8 +90,8 @@ public class TaskThumbnailCache { } } - public TaskThumbnailCache(Context context, Looper backgroundLooper) { - mBackgroundHandler = new Handler(backgroundLooper); + public TaskThumbnailCache(Context context, Executor bgExecutor) { + mBgExecutor = bgExecutor; mHighResLoadingState = new HighResLoadingState(context); Resources res = context.getResources(); @@ -130,7 +126,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 ThumbnailLoadRequest updateThumbnailInBackground( + public CancellableTask updateThumbnailInBackground( Task task, Consumer callback) { Preconditions.assertUIThread(); @@ -142,14 +138,13 @@ public class TaskThumbnailCache { return null; } - return updateThumbnailInBackground(task.key, !mHighResLoadingState.isEnabled(), t -> { task.thumbnail = t; callback.accept(t); }); } - private ThumbnailLoadRequest updateThumbnailInBackground(TaskKey key, boolean lowResolution, + private CancellableTask updateThumbnailInBackground(TaskKey key, boolean lowResolution, Consumer callback) { Preconditions.assertUIThread(); @@ -160,26 +155,20 @@ public class TaskThumbnailCache { return null; } - ThumbnailLoadRequest request = new ThumbnailLoadRequest(mBackgroundHandler, - lowResolution) { + CancellableTask request = new CancellableTask() { @Override - public void run() { - ThumbnailData thumbnail = ActivityManagerWrapper.getInstance().getTaskThumbnail( + public ThumbnailData getResultOnBg() { + return ActivityManagerWrapper.getInstance().getTaskThumbnail( key.id, lowResolution); + } - 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(); - }); + @Override + public void handleResult(ThumbnailData result) { + mCache.put(key, result); + callback.accept(result); } }; - Utilities.postAsyncCallback(mBackgroundHandler, request); + mBgExecutor.execute(request); return request; } @@ -218,15 +207,6 @@ 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 df93e0b6a2..3e05b07074 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -20,6 +20,7 @@ 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; @@ -687,7 +688,7 @@ public class TouchInteractionService extends Service implements PluginListener } /** - * When the gesture ends and recents view become interactive, we also remove the temporary + * When the gesture ends and we're going to recents view, 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 onGestureAnimationEnd() { - super.onGestureAnimationEnd(); - if (mHomeTaskInfo != null) { + public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) { + super.onGestureEndTargetCalculated(endTarget); + if (mHomeTaskInfo != null && endTarget == RECENTS) { 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 89e6931ed9..580e4ec807 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java @@ -25,12 +25,6 @@ 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; @@ -47,7 +41,6 @@ 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; @@ -80,7 +73,6 @@ public class AssistantInputConsumer extends DelegateInputConsumer { private float mTimeFraction; private long mDragTime; private float mLastProgress; - private int mDirection; private BaseActivityInterface mActivityInterface; private final float mDragDistThreshold; @@ -197,8 +189,6 @@ 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); @@ -223,7 +213,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(SWIPE); + startAssistantInternal(); Bundle args = new Bundle(); args.putInt(OPA_BUNDLE_TRIGGER, OPA_BUNDLE_TRIGGER_DIAG_SWIPE_GESTURE); @@ -236,10 +226,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer { } } - private void startAssistantInternal(int gestureType) { - UserEventDispatcher.newInstance(mContext) - .logActionOnContainer(gestureType, mDirection, NAVBAR); - + private void startAssistantInternal() { BaseDraggingActivity launcherActivity = mActivityInterface.getCreatedActivity(); if (launcherActivity != null) { launcherActivity.getRootView().performHapticFeedback( @@ -253,7 +240,6 @@ 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 @@ -272,7 +258,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer { mLastProgress = 1; SystemUiProxy.INSTANCE.get(mContext).onAssistantGestureCompletion( (float) Math.sqrt(velocityX * velocityX + velocityY * velocityY)); - startAssistantInternal(FLING); + startAssistantInternal(); 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 b1a1133885..35dbee9490 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -67,6 +67,7 @@ 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; @@ -92,6 +93,7 @@ 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; @@ -135,8 +137,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState, TaskAnimationManager taskAnimationManager, GestureState gestureState, boolean isDeferredDownTarget, Consumer onCompleteCallback, - InputMonitorCompat inputMonitorCompat, boolean disableHorizontalSwipe, - Factory handlerFactory) { + InputMonitorCompat inputMonitorCompat, InputEventReceiver inputEventReceiver, + boolean disableHorizontalSwipe, Factory handlerFactory) { super(base); mDeviceState = deviceState; mNavBarPosition = mDeviceState.getNavBarPosition(); @@ -154,6 +156,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mOnCompleteCallback = onCompleteCallback; mVelocityTracker = VelocityTracker.obtain(); mInputMonitorCompat = inputMonitorCompat; + mInputEventReceiver = inputEventReceiver; boolean continuingPreviousGesture = mTaskAnimationManager.isRecentsAnimationRunning(); mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget; @@ -215,6 +218,9 @@ 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); @@ -351,6 +357,8 @@ 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 1c77a0593d..924b32c015 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java @@ -15,6 +15,7 @@ */ 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; @@ -27,9 +28,6 @@ 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; @@ -82,17 +80,12 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer, mContext.startActivity(mGestureState.getHomeIntent()); ActiveGestureLog.INSTANCE.addLog("startQuickstep"); BaseActivity activity = BaseDraggingActivity.fromContext(mContext); - 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) + int state = (mGestureState != null && mGestureState.getEndTarget() != null) ? mGestureState.getEndTarget().containerType - : LauncherLogProto.ContainerType.WORKSPACE; - activity.getUserEventDispatcher().logActionOnContainer( - wasFling ? Touch.FLING : Touch.SWIPE, Direction.UP, containerType, pageIndex); - activity.getUserEventDispatcher().setPreviousHomeGesture(true); + : LAUNCHER_STATE_HOME; activity.getStatsLogManager().logger() - .withSrcState(LAUNCHER_STATE_HOME) - .withDstState(LAUNCHER_STATE_HOME) + .withSrcState(LAUNCHER_STATE_BACKGROUND) + .withDstState(state) .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 70181fb9ca..16886ec177 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 - int getHandAnimationResId() { + Integer 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 bef50ea8df..41db684d44 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 - int getHandAnimationResId() { + Integer 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 e4b348e51b..9489bac266 100644 --- a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java +++ b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java @@ -143,6 +143,10 @@ 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 e2a9d1276c..63595a5283 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 - int getHandAnimationResId() { + Integer 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 f897ecc01a..d1b0a7088f 100644 --- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java +++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java @@ -250,6 +250,12 @@ 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 3357b70497..93200bb21d 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 - int getHandAnimationResId() { + Integer 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 new file mode 100644 index 0000000000..db1afc2012 --- /dev/null +++ b/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java @@ -0,0 +1,44 @@ +/* + * 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 new file mode 100644 index 0000000000..80ffe6609e --- /dev/null +++ b/quickstep/src/com/android/quickstep/interaction/SandboxLauncherRenderer.java @@ -0,0 +1,44 @@ +/* + * 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 new file mode 100644 index 0000000000..d54efc56e5 --- /dev/null +++ b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java @@ -0,0 +1,102 @@ +/* + * 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 new file mode 100644 index 0000000000..955a2f7d2e --- /dev/null +++ b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java @@ -0,0 +1,43 @@ +/* + * 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 73f1f8cb8c..2198ade105 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java @@ -47,11 +47,12 @@ 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; - final TutorialHandAnimation mHandCoachingAnimation; + @Nullable final TutorialHandAnimation mHandCoachingAnimation; final ImageView mHandCoachingView; final Button mActionTextButton; final Button mActionButton; @@ -68,6 +69,7 @@ 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); @@ -143,13 +145,16 @@ abstract class TutorialController implements BackGestureAttemptCallback, void onActionTextButtonClicked(View button) {} void showHandCoachingAnimation() { - if (isComplete()) { + if (isComplete() || mHandCoachingAnimation == null) { return; } mHandCoachingAnimation.startLoopedAnimation(mTutorialType); } void hideHandCoachingAnimation() { + if (mHandCoachingAnimation == null) { + return; + } mHandCoachingAnimation.stop(); mHandCoachingView.setVisibility(View.INVISIBLE); } @@ -162,8 +167,10 @@ abstract class TutorialController implements BackGestureAttemptCallback, if (isComplete()) { hideHandCoachingAnimation(); + mLauncherView.setVisibility(View.INVISIBLE); } else { showHandCoachingAnimation(); + mLauncherView.setVisibility(View.VISIBLE); } } @@ -206,7 +213,8 @@ 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.ASSISTANT_COMPLETE + || mTutorialType == TutorialType.SANDBOX_MODE; } /** Denotes the type of the tutorial. */ @@ -219,6 +227,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, OVERVIEW_NAVIGATION, OVERVIEW_NAVIGATION_COMPLETE, ASSISTANT, - ASSISTANT_COMPLETE + ASSISTANT_COMPLETE, + SANDBOX_MODE } } diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java index 9a8264d098..f297d5a835 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java @@ -31,6 +31,7 @@ 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; @@ -42,9 +43,10 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { TutorialType mTutorialType; @Nullable TutorialController mTutorialController = null; View mRootView; - TutorialHandAnimation mHandCoachingAnimation; + @Nullable TutorialHandAnimation mHandCoachingAnimation = null; EdgeBackGestureHandler mEdgeBackGestureHandler; NavBarGestureHandler mNavBarGestureHandler; + private View mLauncherView; public static TutorialFragment newInstance(TutorialType tutorialType) { TutorialFragment fragment = getFragmentForTutorialType(tutorialType); @@ -74,13 +76,17 @@ 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; } - abstract int getHandAnimationResId(); + @Nullable Integer getHandAnimationResId() { + return null; + } abstract TutorialController createController(TutorialType type); @@ -114,8 +120,14 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { return insets; }); mRootView.setOnTouchListener(this); - mHandCoachingAnimation = new TutorialHandAnimation(getContext(), mRootView, - getHandAnimationResId()); + 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); return mRootView; } @@ -128,16 +140,25 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { @Override public void onPause() { super.onPause(); - mHandCoachingAnimation.stop(); + + if (mHandCoachingAnimation != null) { + 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()); } @@ -168,7 +189,11 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener { return mRootView; } - TutorialHandAnimation getHandAnimation() { + View getLauncherView() { + return mLauncherView; + } + + @Nullable TutorialHandAnimation getHandAnimation() { return mHandCoachingAnimation; } diff --git a/quickstep/src/com/android/quickstep/util/CancellableTask.java b/quickstep/src/com/android/quickstep/util/CancellableTask.java new file mode 100644 index 0000000000..a6e2e81589 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/CancellableTask.java @@ -0,0 +1,68 @@ +/* + * 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 4a298d3bad..1031c5b080 100644 --- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java +++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java @@ -18,8 +18,10 @@ 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; @@ -110,7 +112,7 @@ public class OverviewToHomeAnim { boolean isLayoutNaturalToLauncher = recentsView.getPagedOrientationHandler() .isLayoutNaturalToLauncher(); config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, isLayoutNaturalToLauncher - ? DEACCEL : FINAL_FRAME); + ? clampToProgress(FAST_OUT_SLOW_IN, 0, 0.75f) : FINAL_FRAME); config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, FINAL_FRAME); config.setInterpolator(ANIM_OVERVIEW_SCALE, FINAL_FRAME); config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, INSTANT); diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java index df9b0cf435..de44e07bae 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java +++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java @@ -23,7 +23,6 @@ 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; @@ -72,6 +71,7 @@ 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,4 +534,13 @@ 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 04308c80cb..19c6588877 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java +++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java @@ -21,6 +21,8 @@ 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; @@ -28,14 +30,17 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; public abstract class RemoteAnimationProvider { - LauncherAnimationRunner mAnimationRunner; + WrappedAnimationRunnerImpl mAnimationRunner; public abstract AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, RemoteAnimationTargetCompat[] wallpaperTargets); ActivityOptions toActivityOptions(Handler handler, long duration, Context context) { - mAnimationRunner = new LauncherAnimationRunner(handler, - false /* startAtFrontOfQueue */) { + mAnimationRunner = new WrappedAnimationRunnerImpl() { + @Override + public Handler getHandler() { + return handler; + } @Override public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, @@ -45,7 +50,6 @@ 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 903e87a7f8..3a54bd61aa 100644 --- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java +++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java @@ -278,7 +278,6 @@ 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); } @@ -297,9 +296,9 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { mMatrix.postTranslate(insets.left, insets.top); mMatrix.postScale(scale, scale); - // Apply TaskView matrix: translate, scale, scroll - mMatrix.postTranslate(mTaskRect.left, mTaskRect.top + mOffsetY); + // Apply TaskView matrix: scale, translate, scroll mMatrix.postScale(mCurveScale, mCurveScale, taskWidth / 2, taskHeight / 2); + mMatrix.postTranslate(mTaskRect.left, mTaskRect.top + mOffsetY); 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 b06d4bc355..95bde801bf 100644 --- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java +++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java @@ -42,7 +42,6 @@ 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; @@ -217,8 +216,8 @@ public final class DigitalWellBeingToast { view, 0, 0, view.getWidth(), view.getHeight()); activity.startActivity(intent, options.toBundle()); - activity.getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.Touch.TAP, - LauncherLogProto.ControlType.APP_USAGE_SETTINGS, view); + + // TODO: add WW logging on the app usage settings click. } 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 b338bd07ee..52a7466429 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -36,7 +36,6 @@ 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; @@ -177,14 +176,8 @@ public class LauncherRecentsView extends RecentsView @Override protected boolean shouldStealTouchFromSiblingsBelow(MotionEvent 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); + return mActivity.getStateManager().getState().overviewUi + && 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 2a6c9e92db..b8e07cb189 100644 --- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java @@ -54,7 +54,6 @@ 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 { } @@ -62,8 +61,7 @@ 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_GESTURE_RUNNING = 1 << 3; - public static final int HIDDEN_NO_RECENTS = 1 << 4; + public static final int HIDDEN_NO_RECENTS = 1 << 3; @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 0362377399..7a8e11df78 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -35,16 +35,14 @@ 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; @@ -109,7 +107,6 @@ 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; @@ -118,6 +115,7 @@ 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; @@ -1129,7 +1127,6 @@ public abstract class RecentsView extends PagedView setEnableDrawingLiveTile(false); setRunningTaskHidden(true); setRunningTaskIconScaledDown(true); - mActionsView.updateHiddenFlags(HIDDEN_GESTURE_RUNNING, true); } /** @@ -1183,7 +1180,14 @@ public abstract class RecentsView extends PagedView } /** - * Called when a gesture from an app has finished. + * 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. */ public void onGestureAnimationEnd() { if (mOrientationState.setGestureActive(false)) { @@ -1322,7 +1326,6 @@ 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); @@ -1407,13 +1410,12 @@ public abstract class RecentsView extends PagedView * Updates linearInterpolation for the provided child position */ public void updateInterpolation(float childStart) { - float scaledHalfPageSize = halfPageSize / pageParentScale; - float pageCenter = childStart + scaledHalfPageSize; + float pageCenter = childStart + halfPageSize; 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 - + scaledHalfPageSize * (1 - TaskView.EDGE_SCALE_DOWN_FACTOR); + + halfPageSize * (1 - TaskView.EDGE_SCALE_DOWN_FACTOR); linearInterpolation = Math.min(1, Math.abs(distanceFromScreenCenter) / distanceToReachEdge); } @@ -1459,7 +1461,7 @@ public abstract class RecentsView extends PagedView public PendingAnimation createTaskDismissAnimation(TaskView taskView, boolean animateTaskView, boolean shouldRemoveTask, long duration) { if (mPendingAnimation != null) { - mPendingAnimation.finish(false, Touch.SWIPE); + mPendingAnimation.finish(false); } PendingAnimation anim = new PendingAnimation(duration); @@ -1621,7 +1623,7 @@ public abstract class RecentsView extends PagedView protected void runDismissAnimation(PendingAnimation pendingAnim) { AnimatorPlaybackController controller = pendingAnim.createPlaybackController(); controller.dispatchOnStart(); - controller.setEndAction(() -> pendingAnim.finish(true, Touch.SWIPE)); + controller.setEndAction(() -> pendingAnim.finish(true)); controller.getAnimationPlayer().setInterpolator(FAST_OUT_SLOW_IN); controller.start(); } @@ -1634,7 +1636,7 @@ public abstract class RecentsView extends PagedView @SuppressWarnings("unused") private void dismissAllTasks(View view) { runDismissAnimation(createAllTasksDismissAnimation(DISMISS_TASK_DURATION)); - mActivity.getUserEventDispatcher().logActionOnControl(TAP, CLEAR_ALL_BUTTON); + mActivity.getStatsLogManager().logger().log(LAUNCHER_TASK_CLEAR_ALL); } private void dismissCurrentTask() { @@ -2159,7 +2161,12 @@ public abstract class RecentsView extends PagedView tv.notifyTaskLaunchFailed(TAG); } }; - tv.launchTask(false, onLaunchResult, getHandler()); + if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { + finishRecentsAnimation(false /* toRecents */, null); + onLaunchResult.accept(true /* success */); + } else { + 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 d47eba6408..4aff7e3211 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java @@ -16,6 +16,7 @@ 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; @@ -229,7 +230,16 @@ 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(menuOption); + 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); + } + }); mOptionLayout.addView(menuOptionView); } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 321821b573..3d6d423077 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -73,15 +73,11 @@ 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; @@ -90,6 +86,7 @@ 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; @@ -189,8 +186,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private boolean mShowScreenshot; // The current background requests to load the task thumbnail and icon - private TaskThumbnailCache.ThumbnailLoadRequest mThumbnailLoadRequest; - private TaskIconCache.IconLoadRequest mIconLoadRequest; + private CancellableTask mThumbnailLoadRequest; + private CancellableTask mIconLoadRequest; // Order in which the footers appear. Lower order appear below higher order. public static final int INDEX_DIGITAL_WELLBEING_TOAST = 0; @@ -220,6 +217,7 @@ 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 */); @@ -365,10 +363,7 @@ 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, Touch.SWIPE); - launchTask(false); - }); + currentAnimation.setEndAction(() -> pendingAnimation.finish(true)); return currentAnimation; } @@ -391,20 +386,6 @@ 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( @@ -481,15 +462,13 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } } - private boolean showTaskMenu(int action) { + private boolean showTaskMenu() { 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); } @@ -500,10 +479,10 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private void setIcon(Drawable icon) { if (icon != null) { mIconView.setDrawable(icon); - mIconView.setOnClickListener(v -> showTaskMenu(Touch.TAP)); + mIconView.setOnClickListener(v -> showTaskMenu()); mIconView.setOnLongClickListener(v -> { requestDisallowInterceptTouchEvent(true); - return showTaskMenu(Touch.LONGPRESS); + return showTaskMenu(); }); } 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 ccfa3fc0fb..2a7da7eca8 100644 --- a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java +++ b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java @@ -3,6 +3,8 @@ 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; @@ -11,12 +13,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; @@ -34,9 +36,6 @@ 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 new file mode 100644 index 0000000000..5ecc0c27b6 --- /dev/null +++ b/res/layout/search_result_icon_row.xml @@ -0,0 +1,31 @@ + + + + \ No newline at end of file diff --git a/res/layout/search_result_shortcut.xml b/res/layout/search_result_shortcut.xml deleted file mode 100644 index c350c973da..0000000000 --- a/res/layout/search_result_shortcut.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/res/layout/search_result_suggest.xml b/res/layout/search_result_suggest.xml new file mode 100644 index 0000000000..c5d96f03ea --- /dev/null +++ b/res/layout/search_result_suggest.xml @@ -0,0 +1,38 @@ + + + + + + \ No newline at end of file diff --git a/res/layout/search_result_thumbnail.xml b/res/layout/search_result_thumbnail.xml new file mode 100644 index 0000000000..0cc5a29f60 --- /dev/null +++ b/res/layout/search_result_thumbnail.xml @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/res/values/config.xml b/res/values/config.xml index 325b62f9dc..46b8c23a62 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -59,7 +59,6 @@ true - diff --git a/robolectric_tests/src/com/android/launcher3/secondarydisplay/SDWorkModeTest.java b/robolectric_tests/src/com/android/launcher3/secondarydisplay/SDWorkModeTest.java index 0ca5ce6f44..baae2a6a80 100644 --- a/robolectric_tests/src/com/android/launcher3/secondarydisplay/SDWorkModeTest.java +++ b/robolectric_tests/src/com/android/launcher3/secondarydisplay/SDWorkModeTest.java @@ -21,7 +21,6 @@ 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; @@ -30,8 +29,6 @@ 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; @@ -69,8 +66,6 @@ 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 d330d10133..957ae77eee 100644 --- a/robolectric_tests/src/com/android/launcher3/ui/LauncherUIScrollTest.java +++ b/robolectric_tests/src/com/android/launcher3/ui/LauncherUIScrollTest.java @@ -20,7 +20,6 @@ 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; @@ -36,8 +35,6 @@ 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; @@ -70,8 +67,6 @@ 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 310c306f19..5e50e278f0 100644 --- a/src/com/android/launcher3/BaseActivity.java +++ b/src/com/android/launcher3/BaseActivity.java @@ -37,8 +37,6 @@ 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; @@ -82,7 +80,6 @@ public abstract class BaseActivity extends Activity implements ActivityContext { new ArrayList<>(); protected DeviceProfile mDeviceProfile; - protected UserEventDispatcher mUserEventDispatcher; protected StatsLogManager mStatsLogManager; protected SystemUiController mSystemUiController; @@ -144,8 +141,6 @@ 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); @@ -153,13 +148,6 @@ 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 06bb263f23..1e5a9e44d5 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -23,6 +23,7 @@ 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; @@ -30,6 +31,8 @@ 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; @@ -43,6 +46,8 @@ 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; @@ -50,6 +55,7 @@ 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; @@ -59,6 +65,7 @@ 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; @@ -84,6 +91,8 @@ 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 @@ -292,6 +301,14 @@ 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); @@ -636,11 +653,14 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, mDisableRelayout = mIcon != null; icon.setBounds(0, 0, mIconSize, mIconSize); - if (mLayoutHorizontal) { - setCompoundDrawablesRelative(icon, null, null, null); - } else { - setCompoundDrawables(null, icon, null, null); + + updateIcon(icon); + + // If the current icon is a placeholder color, animate its update. + if (mIcon != null && mIcon instanceof PlaceHolderIconDrawable) { + animateIconUpdate((PlaceHolderIconDrawable) mIcon, icon); } + mDisableRelayout = false; } @@ -670,6 +690,8 @@ 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; @@ -776,4 +798,33 @@ 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 09827d664b..df005e6357 100644 --- a/src/com/android/launcher3/ButtonDropTarget.java +++ b/src/com/android/launcher3/ButtonDropTarget.java @@ -47,7 +47,6 @@ 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; @@ -395,6 +394,4 @@ 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 1cd201f99e..2809bd5a96 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -323,11 +323,8 @@ public class CellLayout extends ViewGroup { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - if (mTouchHelper != null - || (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev))) { - return true; - } - return false; + return mTouchHelper != null + || (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)); } public void enableHardwareLayer(boolean hasLayer) { diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java index 28574972ad..cc119c9361 100644 --- a/src/com/android/launcher3/DeleteDropTarget.java +++ b/src/com/android/launcher3/DeleteDropTarget.java @@ -18,8 +18,7 @@ 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.userevent.nano.LauncherLogProto.Action.Touch.TAP; -import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.UNDO; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNDO; import android.content.Context; import android.text.TextUtils; @@ -28,22 +27,19 @@ 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 int mControlType = ControlType.DEFAULT_CONTROLTYPE; + private StatsLogManager.LauncherEvent mLauncherEvent; public DeleteDropTarget(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -115,8 +111,8 @@ public class DeleteDropTarget extends ButtonDropTarget { * Set mControlType depending on the drag item. */ private void setControlTypeBasedOnDragSource(ItemInfo item) { - mControlType = item.id != ItemInfo.NO_ID ? ControlType.REMOVE_TARGET - : ControlType.CANCEL_TARGET; + mLauncherEvent = item.id != ItemInfo.NO_ID ? LAUNCHER_ITEM_DROPPED_ON_REMOVE + : LAUNCHER_ITEM_DROPPED_ON_CANCEL; } @Override @@ -127,8 +123,7 @@ public class DeleteDropTarget extends ButtonDropTarget { } super.onDrop(d, options); mStatsLogManager.logger().withInstanceId(d.logInstanceId) - .log(mControlType == ControlType.REMOVE_TARGET ? LAUNCHER_ITEM_DROPPED_ON_REMOVE - : LAUNCHER_ITEM_DROPPED_ON_CANCEL); + .log(mLauncherEvent); } @Override @@ -141,7 +136,7 @@ public class DeleteDropTarget extends ButtonDropTarget { Runnable onUndoClicked = () -> { mLauncher.setPageToBindSynchronously(itemPage); modelWriter.abortDelete(); - mLauncher.getUserEventDispatcher().logActionOnControl(TAP, UNDO); + mLauncher.getStatsLogManager().logger().log(LAUNCHER_UNDO); }; Snackbar.show(mLauncher, R.string.item_removed, R.string.undo, modelWriter::commitDelete, onUndoClicked); @@ -161,11 +156,4 @@ 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 d3b86ded80..139d4a85e4 100644 --- a/src/com/android/launcher3/FastBitmapDrawable.java +++ b/src/com/android/launcher3/FastBitmapDrawable.java @@ -33,6 +33,8 @@ 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; @@ -54,6 +56,8 @@ 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; @@ -115,7 +119,8 @@ public class FastBitmapDrawable extends Drawable { @Override public void setColorFilter(ColorFilter cf) { - // No op + mColorFilter = cf; + updateFilter(); } @Override @@ -265,7 +270,7 @@ public class FastBitmapDrawable extends Drawable { * Updates the paint to reflect the current brightness and saturation. */ protected void updateFilter() { - mPaint.setColorFilter(mIsDisabled ? getDisabledColorFilter() : null); + mPaint.setColorFilter(mIsDisabled ? getDisabledColorFilter() : mColorFilter); invalidateSelf(); } diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 51f3819460..6547b53940 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -16,8 +16,6 @@ package com.android.launcher3; -import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; - import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; @@ -27,14 +25,10 @@ import android.view.ViewDebug; import android.view.ViewGroup; import android.widget.FrameLayout; -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 { +/** + * View class that represents the bottom row of the home screen. + */ +public class Hotseat extends CellLayout implements Insettable { @ViewDebug.ExportedProperty(category = "launcher") private boolean mHasVerticalHotseat; @@ -78,15 +72,6 @@ public class Hotseat extends CellLayout implements LogContainerProvider, Insetta } } - @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 4c5224b647..ab8d7a5a69 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -18,6 +18,7 @@ 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; @@ -36,11 +37,10 @@ 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,6 +70,7 @@ 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,9 +90,10 @@ import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; import android.view.accessibility.AccessibilityEvent; import android.view.animation.OvershootInterpolator; +import android.widget.ImageView; import android.widget.Toast; import androidx.annotation.CallSuper; @@ -118,13 +120,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; @@ -152,9 +154,6 @@ 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; @@ -270,6 +269,8 @@ 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,6 +402,7 @@ public class Launcher extends StatefulActivity implements Launche inflateRootView(R.layout.launcher); setupViews(); + crossFadeWithPreviousAppearance(); mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots); mAppTransitionManager = LauncherAppTransitionManager.newInstance(this); @@ -477,7 +479,7 @@ public class Launcher extends StatefulActivity implements Launche () -> getStateManager().goToState(NORMAL)); if (Utilities.ATLEAST_R) { - getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); + getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING); } mLifecycleRegistry = new LifecycleRegistry(this); @@ -555,7 +557,6 @@ public class Launcher extends StatefulActivity implements Launche } private void onIdpChanged(InvariantDeviceProfile idp) { - mUserEventDispatcher = null; initDeviceProfile(idp); dispatchDeviceProfileChanged(); @@ -911,7 +912,7 @@ public class Launcher extends StatefulActivity implements Launche mOverlayManager.onActivityStopped(this); } - logStopAndResume(Action.Command.STOP); + logStopAndResume(false /* isResume */); mAppWidgetHost.setListenIfResumed(false); NotificationListener.removeNotificationsChangedListener(); } @@ -933,7 +934,7 @@ public class Launcher extends StatefulActivity implements Launche @Override @CallSuper protected void onDeferredResumed() { - logStopAndResume(Action.Command.RESUME); + logStopAndResume(true /* isResume */); // Process any items that were added while Launcher was away. ItemInstallQueue.INSTANCE.get(this) @@ -950,32 +951,28 @@ public class Launcher extends StatefulActivity implements Launche protected void handlePendingActivityRequest() { } - private void logStopAndResume(int command) { + private void logStopAndResume(boolean isResume) { if (mPendingExecutor != null) return; int pageIndex = mWorkspace.isOverlayShown() ? -1 : mWorkspace.getCurrentPage(); - int containerType = mStateManager.getState().containerType; + int statsLogOrdinal = mStateManager.getState().statsLogOrdinal; StatsLogManager.EventEnum event; StatsLogManager.StatsLogger logger = getStatsLogManager().logger(); - if (command == Action.Command.RESUME) { + if (isResume) { logger.withSrcState(LAUNCHER_STATE_BACKGROUND) - .withDstState(containerTypeToAtomState(mStateManager.getState().containerType)); + .withDstState(mStateManager.getState().statsLogOrdinal); event = LAUNCHER_ONRESUME; } else { /* command == Action.Command.STOP */ - logger.withSrcState(containerTypeToAtomState(mStateManager.getState().containerType)) + logger.withSrcState(mStateManager.getState().statsLogOrdinal) .withDstState(LAUNCHER_STATE_BACKGROUND); event = LAUNCHER_ONSTOP; } - if (containerType == ContainerType.WORKSPACE && mWorkspace != null) { - getUserEventDispatcher().logActionCommand(command, - containerType, -1, pageIndex); + if (statsLogOrdinal == LAUNCHER_STATE_HOME && mWorkspace != null) { logger.withContainerInfo(LauncherAtom.ContainerInfo.newBuilder() .setWorkspace( LauncherAtom.WorkspaceContainer.newBuilder() .setPageIndex(pageIndex)).build()); - } else { - getUserEventDispatcher().logActionCommand(command, containerType, -1); } logger.log(event); } @@ -1365,6 +1362,18 @@ 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; } @@ -1465,11 +1474,6 @@ 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) { @@ -2759,4 +2763,40 @@ 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 bfe327e40d..a4181c53c9 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, MODEL_EXECUTOR); + .registerInstallTracker(mModel); // 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 b6bc500a58..eba0ac9633 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -16,6 +16,7 @@ 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; @@ -35,7 +36,6 @@ 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, - ContainerType.WORKSPACE, + LAUNCHER_STATE_HOME, 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 containerType in {@link com.android.launcher3.logging.UserEventDispatcher} + * Used for {@link com.android.launcher3.logging.StatsLogManager} */ - public final int containerType; + public final int statsLogOrdinal; /** * 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 containerType, int flags) { - this.containerType = containerType; + public LauncherState(int id, int statsLogOrdinal, int flags) { + this.statsLogOrdinal = statsLogOrdinal; 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 2df7f5ad20..92b88e6186 100644 --- a/src/com/android/launcher3/SecondaryDropTarget.java +++ b/src/com/android/launcher3/SecondaryDropTarget.java @@ -37,14 +37,11 @@ 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; @@ -134,19 +131,6 @@ 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 007e5f5370..1bbbb2b59e 100644 --- a/src/com/android/launcher3/SessionCommitReceiver.java +++ b/src/com/android/launcher3/SessionCommitReceiver.java @@ -25,8 +25,11 @@ 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. @@ -38,6 +41,11 @@ 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 dea2a8dfd2..43ccb7990c 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -133,6 +133,10 @@ 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 45aaa1b673..98328cf8af 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -85,7 +85,6 @@ 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; @@ -97,8 +96,6 @@ 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; @@ -1004,8 +1001,6 @@ 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) @@ -1020,20 +1015,16 @@ 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) { - 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); - } + // 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); } 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 @@ -1124,12 +1115,8 @@ 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) @@ -1175,13 +1162,6 @@ 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 ea887cc5eb..d6302ce580 100644 --- a/src/com/android/launcher3/WorkspaceLayoutManager.java +++ b/src/com/android/launcher3/WorkspaceLayoutManager.java @@ -130,12 +130,16 @@ public interface WorkspaceLayoutManager { } child.setHapticFeedbackEnabled(false); - child.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE); + child.setOnLongClickListener(getWorkspaceChildOnLongClickListener()); 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 d1340faf23..8bc8e53af3 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -92,10 +92,14 @@ public class AllAppsGridAdapter extends public static final int VIEW_TYPE_SEARCH_SLICE = 1 << 9; - public static final int VIEW_TYPE_SEARCH_SHORTCUT = 1 << 10; + public static final int VIEW_TYPE_SEARCH_ICON_ROW = 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; @@ -186,7 +190,9 @@ public class AllAppsGridAdapter extends || viewType == VIEW_TYPE_SEARCH_SLICE || viewType == VIEW_TYPE_SEARCH_ROW || viewType == VIEW_TYPE_SEARCH_PEOPLE - || viewType == VIEW_TYPE_SEARCH_SHORTCUT; + || viewType == VIEW_TYPE_SEARCH_THUMBNAIL + || viewType == VIEW_TYPE_SEARCH_ICON_ROW + || viewType == VIEW_TYPE_SEARCH_SUGGEST; } } @@ -197,6 +203,7 @@ public class AllAppsGridAdapter extends */ public static class AdapterItemWithPayload extends AdapterItem { private T mPayload; + private String mSearchSessionId; private AllAppsSearchPlugin mPlugin; private IntConsumer mSelectionHandler; @@ -218,6 +225,14 @@ public class AllAppsGridAdapter extends mSelectionHandler = runnable; } + public void setSearchSessionId(String searchSessionId) { + mSearchSessionId = searchSessionId; + } + + public String getSearchSessionId() { + return mSearchSessionId; + } + public IntConsumer getSelectionHandler() { return mSelectionHandler; } @@ -225,6 +240,8 @@ public class AllAppsGridAdapter extends public T getPayload() { return mPayload; } + + } /** @@ -307,15 +324,21 @@ public class AllAppsGridAdapter extends @Override public int getSpanSize(int position) { - if (isIconViewType(mApps.getAdapterItems().get(position).viewType)) { - return 1; + int viewType = mApps.getAdapterItems().get(position).viewType; + if (isIconViewType(viewType)) { + return 1 * SPAN_MULTIPLIER; + } else if (viewType == VIEW_TYPE_SEARCH_THUMBNAIL) { + return mAppsPerRow; } else { // Section breaks span the full width - return mAppsPerRow; + return mAppsPerRow * SPAN_MULTIPLIER; } } } + // multiplier to support adapter item column count that is not mAppsPerRow. + public static final int SPAN_MULTIPLIER = 3; + private final BaseDraggingActivity mLauncher; private final LayoutInflater mLayoutInflater; private final AlphabeticalAppsList mApps; @@ -352,7 +375,7 @@ public class AllAppsGridAdapter extends public void setAppsPerRow(int appsPerRow) { mAppsPerRow = appsPerRow; - mGridLayoutMgr.setSpanCount(mAppsPerRow); + mGridLayoutMgr.setSpanCount(mAppsPerRow * SPAN_MULTIPLIER); } /** @@ -438,12 +461,18 @@ 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_SHORTCUT: + case VIEW_TYPE_SEARCH_ICON_ROW: return new ViewHolder(mLayoutInflater.inflate( - R.layout.search_result_shortcut, parent, false)); + R.layout.search_result_icon_row, 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"); } @@ -464,24 +493,27 @@ public class AllAppsGridAdapter extends //TODO: replace with custom TopHitBubbleTextView with support for both shortcut // and apps if (adapterItem instanceof AdapterItemWithPayload) { - AdapterItemWithPayload withPayload = (AdapterItemWithPayload) adapterItem; - IntConsumer selectionHandler = type -> { + AdapterItemWithPayload item = (AdapterItemWithPayload) adapterItem; + item.setSelectionHandler(type -> { SearchTargetEvent e = new SearchTargetEvent(SearchTarget.ItemType.APP, - type); + type, item.position, item.getSearchSessionId()); e.bundle = HeroSearchResultView.getAppBundle(info); - if (withPayload.getPlugin() != null) { - withPayload.getPlugin().notifySearchTargetEvent(e); + if (item.getPlugin() != null) { + item.getPlugin().notifySearchTargetEvent(e); } - }; + }); icon.setOnClickListener(view -> { - selectionHandler.accept(SearchTargetEvent.SELECT); + item.getSelectionHandler().accept(SearchTargetEvent.SELECT); mOnIconClickListener.onClick(view); }); icon.setOnLongClickListener(view -> { - selectionHandler.accept(SearchTargetEvent.LONG_PRESS); + item.getSelectionHandler().accept(SearchTargetEvent.SELECT); return mOnIconLongClickListener.onLongClick(view); }); - withPayload.setSelectionHandler(selectionHandler); + } + else { + icon.setOnClickListener(mOnIconClickListener); + icon.setOnLongClickListener(mOnIconLongClickListener); } break; case VIEW_TYPE_EMPTY_SEARCH: @@ -500,20 +532,22 @@ public class AllAppsGridAdapter extends break; case VIEW_TYPE_SEARCH_SLICE: SliceView sliceView = (SliceView) holder.itemView; - AdapterItemWithPayload item = + AdapterItemWithPayload slicePayload = (AdapterItemWithPayload) mApps.getAdapterItems().get(position); sliceView.setOnSliceActionListener((info1, s) -> { - if (item.getPlugin() != null) { + if (slicePayload.getPlugin() != null) { SearchTargetEvent searchTargetEvent = new SearchTargetEvent( SearchTarget.ItemType.SETTINGS_SLICE, - SearchTargetEvent.CHILD_SELECT); + SearchTargetEvent.CHILD_SELECT, slicePayload.position, + slicePayload.getSearchSessionId()); searchTargetEvent.bundle = new Bundle(); - searchTargetEvent.bundle.putParcelable("uri", item.getPayload()); - item.getPlugin().notifySearchTargetEvent(searchTargetEvent); + searchTargetEvent.bundle.putParcelable("uri", slicePayload.getPayload()); + slicePayload.getPlugin().notifySearchTargetEvent(searchTargetEvent); } }); try { - LiveData liveData = SliceLiveData.fromUri(mLauncher, item.getPayload()); + LiveData liveData = SliceLiveData.fromUri(mLauncher, + slicePayload.getPayload()); liveData.observe((Launcher) mLauncher, sliceView); sliceView.setTag(liveData); } catch (Exception ignored) { @@ -523,11 +557,14 @@ 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_SHORTCUT: + case VIEW_TYPE_SEARCH_ICON_ROW: 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.applyAdapterInfo( - (AdapterItemWithPayload) mApps.getAdapterItems().get(position)); + payloadResultView.setup(item); break; case VIEW_TYPE_ALL_APPS_DIVIDER: // nothing to do @@ -541,8 +578,8 @@ public class AllAppsGridAdapter extends if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) return; if (holder.itemView instanceof BubbleTextView) { BubbleTextView icon = (BubbleTextView) holder.itemView; - icon.setOnClickListener(mOnIconClickListener); - icon.setOnLongClickListener(mOnIconLongClickListener); + icon.setOnClickListener(null); + icon.setOnLongClickListener(null); } else if (holder.itemView instanceof SliceView) { SliceView sliceView = (SliceView) holder.itemView; sliceView.setOnSliceActionListener(null); @@ -553,7 +590,6 @@ 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 13a93ff0cc..72b6d94192 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -19,8 +19,6 @@ 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; @@ -38,10 +36,6 @@ 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; @@ -50,7 +44,7 @@ import java.util.List; /** * A RecyclerView with custom fast scroll support for the all apps view. */ -public class AllAppsRecyclerView extends BaseRecyclerView implements LogContainerProvider { +public class AllAppsRecyclerView extends BaseRecyclerView { private AlphabeticalAppsList mApps; private final int mNumAppsPerRow; @@ -176,13 +170,6 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine 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 14595ca941..0005db88c8 100644 --- a/src/com/android/launcher3/allapps/DiscoveryBounce.java +++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java @@ -18,8 +18,6 @@ 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; @@ -120,10 +118,10 @@ public class DiscoveryBounce extends AbstractFloatingView { return (type & TYPE_DISCOVERY_BOUNCE) != 0; } - private void show(int containerType) { + private void show() { mIsOpen = true; mLauncher.getDragLayer().addView(this); - mLauncher.getUserEventDispatcher().logActionBounceTip(containerType); + // TODO: add WW log for discovery bounce tip show event. } public static void showForHomeIfNeeded(Launcher launcher) { @@ -146,7 +144,7 @@ public class DiscoveryBounce extends AbstractFloatingView { } onboardingPrefs.incrementEventCount(OnboardingPrefs.HOME_BOUNCE_COUNT); - new DiscoveryBounce(launcher, 0).show(HOTSEAT); + new DiscoveryBounce(launcher, 0).show(); } public static void showForOverviewIfNeeded(Launcher launcher, @@ -179,7 +177,7 @@ public class DiscoveryBounce extends AbstractFloatingView { onboardingPrefs.incrementEventCount(OnboardingPrefs.SHELF_BOUNCE_COUNT); new DiscoveryBounce(launcher, (1 - OVERVIEW.getVerticalProgress(launcher))) - .show(PREDICTION); + .show(); } /** diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java index 3320189a1d..d7fa5bc479 100644 --- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java +++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java @@ -35,6 +35,8 @@ 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; @@ -213,6 +215,44 @@ 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 53625756b8..6dd316ed60 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, int logAction) { + public void finish(boolean isSuccess) { for (Consumer listeners : mEndListeners) { - listeners.accept(new EndState(isSuccess, logAction)); + listeners.accept(new EndState(isSuccess)); } 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, int)} + * Note that the listeners are called as a result of calling {@link #finish(boolean)} * and not automatically */ public void addEndListener(Consumer listener) { @@ -173,11 +173,9 @@ public class PendingAnimation implements PropertySetter { public static class EndState { public boolean isSuccess; - public int logAction; - public EndState(boolean isSuccess, int logAction) { + public EndState(boolean isSuccess) { 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 2d625c5373..42e247aa9b 100644 --- a/src/com/android/launcher3/dragndrop/AddItemActivity.java +++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java @@ -16,10 +16,11 @@ package com.android.launcher3.dragndrop; -import static com.android.launcher3.logging.LoggerUtils.newCommandAction; -import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; -import static com.android.launcher3.logging.LoggerUtils.newItemTarget; -import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent; +import 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.util.Executors.MODEL_EXECUTOR; import android.annotation.TargetApi; @@ -49,11 +50,10 @@ 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(Action.Command.ENTRY); + logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_START); } } @@ -178,6 +178,7 @@ 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; } @@ -240,7 +241,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener * Called when the cancel button is clicked. */ public void onCancelClick(View v) { - logCommand(Action.Command.CANCEL); + logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_CANCELLED); finish(); } @@ -250,7 +251,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(Action.Command.CONFIRM); + logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY); mRequest.accept(); finish(); return; @@ -274,13 +275,13 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener .queueItem(mRequest.getAppWidgetProviderInfo(this), widgetId); mWidgetOptions.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); mRequest.accept(mWidgetOptions); - logCommand(Action.Command.CONFIRM); + logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY); finish(); } @Override public void onBackPressed() { - logCommand(Action.Command.BACK); + logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_BACK); super.onBackPressed(); } @@ -320,10 +321,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener throw new UnsupportedOperationException(); } - private void logCommand(int command) { - getUserEventDispatcher().dispatchUserEvent(newLauncherEvent( - newCommandAction(command), - newItemTarget(mWidgetCell.getWidgetView(), mInstantAppResolver), - newContainerTarget(ContainerType.PINITEM)), null); + private void logCommand(StatsLogManager.EventEnum command) { + getStatsLogManager().logger().log(command); } } diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java index ef666f0acd..1cfe6acf05 100644 --- a/src/com/android/launcher3/dragndrop/DragController.java +++ b/src/com/android/launcher3/dragndrop/DragController.java @@ -206,7 +206,6 @@ 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 @@ -544,7 +543,6 @@ 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 281598a48b..63fa391d43 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -23,7 +23,6 @@ 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; @@ -95,7 +94,6 @@ 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; @@ -599,15 +597,6 @@ 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. @@ -657,14 +646,6 @@ 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(); } }); @@ -1513,7 +1494,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo } statsLogger.log(LAUNCHER_FOLDER_LABEL_UPDATED); - logFolderLabelState(mFromLabelState, toLabelState); mFolderName.dispatchBackKey(); } } @@ -1644,8 +1624,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo return true; } } else { - mLauncher.getUserEventDispatcher().logActionTapOutside( - newContainerTarget(LauncherLogProto.ContainerType.FOLDER)); + // TODO: add ww log if need to gather tap outside to close folder close(true); return true; } @@ -1680,17 +1659,6 @@ 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 32d061cb42..3296eed5ca 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -478,7 +478,6 @@ 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 cd84c96171..effb3a4a0c 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -513,8 +513,7 @@ 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 deleted file mode 100644 index cd4f034e83..0000000000 --- a/src/com/android/launcher3/logging/LoggerUtils.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -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 ec1c3ef779..2c5bf320ad 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -27,7 +27,6 @@ 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; @@ -51,40 +50,22 @@ public class StatsLogManager implements ResourceBasedOverride { public static final int LAUNCHER_STATE_UNCHANGED = 5; /** - * 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 + * Returns event enum based on the two state transition information when swipe * gesture happens(to be removed during UserEventDispatcher cleanup). */ - public static EventEnum getLauncherAtomEvent(int startContainerType, - int targetContainerType, EventEnum fallbackEvent) { - if (startContainerType == LauncherLogProto.ContainerType.WORKSPACE.getNumber() - && targetContainerType == LauncherLogProto.ContainerType.WORKSPACE.getNumber()) { + public static EventEnum getLauncherAtomEvent(int startState, + int targetState, EventEnum fallbackEvent) { + if (startState == LAUNCHER_STATE_HOME + && targetState == LAUNCHER_STATE_HOME) { return LAUNCHER_HOME_GESTURE; - } else if (startContainerType != LauncherLogProto.ContainerType.TASKSWITCHER.getNumber() - && targetContainerType == LauncherLogProto.ContainerType.TASKSWITCHER.getNumber()) { + } else if (startState != LAUNCHER_STATE_OVERVIEW + && targetState == LAUNCHER_STATE_OVERVIEW) { return LAUNCHER_OVERVIEW_GESTURE; - } else if (startContainerType != LauncherLogProto.ContainerType.ALLAPPS.getNumber() - && targetContainerType == LauncherLogProto.ContainerType.ALLAPPS.getNumber()) { + } else if (startState != LAUNCHER_STATE_ALLAPPS + && targetState == LAUNCHER_STATE_ALLAPPS) { return LAUNCHER_ALLAPPS_OPEN_UP; - } else if (startContainerType == LauncherLogProto.ContainerType.ALLAPPS.getNumber() - && targetContainerType != LauncherLogProto.ContainerType.ALLAPPS.getNumber()) { + } else if (startState == LAUNCHER_STATE_ALLAPPS + && targetState != LAUNCHER_STATE_ALLAPPS) { return LAUNCHER_ALLAPPS_CLOSE_DOWN; } return fallbackEvent; // TODO fix @@ -322,7 +303,38 @@ public class StatsLogManager implements ResourceBasedOverride { LAUNCHER_FOLDER_CONVERTED_TO_ICON(628), @UiEvent(doc = "A hotseat prediction item was pinned") - LAUNCHER_HOTSEAT_PREDICTION_PINNED(629); + 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), + ; // ADD MORE diff --git a/src/com/android/launcher3/logging/StatsLogUtils.java b/src/com/android/launcher3/logging/StatsLogUtils.java deleted file mode 100644 index a5cc7ea305..0000000000 --- a/src/com/android/launcher3/logging/StatsLogUtils.java +++ /dev/null @@ -1,49 +0,0 @@ -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 deleted file mode 100644 index a40cc263db..0000000000 --- a/src/com/android/launcher3/logging/UserEventDispatcher.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.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 41ccbd7054..06a2c92dab 100644 --- a/src/com/android/launcher3/model/data/FolderInfo.java +++ b/src/com/android/launcher3/model/data/FolderInfo.java @@ -20,15 +20,9 @@ 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; @@ -43,10 +37,6 @@ 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; @@ -359,113 +349,4 @@ 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 new file mode 100644 index 0000000000..81f7f3a0a2 --- /dev/null +++ b/src/com/android/launcher3/model/data/RemoteActionItemInfo.java @@ -0,0 +1,64 @@ +/* + * 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 32f060ba85..9b065233b9 100644 --- a/src/com/android/launcher3/notification/NotificationMainView.java +++ b/src/com/android/launcher3/notification/NotificationMainView.java @@ -17,6 +17,7 @@ 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; @@ -41,7 +42,6 @@ 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,10 +168,7 @@ public class NotificationMainView extends FrameLayout implements SingleAxisSwipe Launcher launcher = Launcher.getLauncher(getContext()); launcher.getPopupDataProvider().cancelNotification( mNotificationInfo.notificationKey); - launcher.getUserEventDispatcher().logActionOnItem( - LauncherLogProto.Action.Touch.SWIPE, - LauncherLogProto.Action.Direction.RIGHT, // Assume all swipes are right for logging. - LauncherLogProto.ItemType.NOTIFICATION); + launcher.getStatsLogManager().logger().log(LAUNCHER_NOTIFICATION_DISMISSED); } // SingleAxisSwipeDetector.Listener's diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java index 753a6dd85e..fa25114d49 100644 --- a/src/com/android/launcher3/pm/InstallSessionHelper.java +++ b/src/com/android/launcher3/pm/InstallSessionHelper.java @@ -17,6 +17,7 @@ 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; @@ -31,6 +32,7 @@ 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; @@ -39,10 +41,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; @@ -65,27 +67,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); + } + @WorkerThread + private IntSet getPromiseIconIds() { + Preconditions.assertWorkerThread(); + if (mPromiseIconIds != null) { + return mPromiseIconIds; + } mPromiseIconIds = IntSet.wrap(IntArray.fromConcatString( - getPrefs(context).getString(PROMISE_ICON_IDS, ""))); + getPrefs(mAppContext).getString(PROMISE_ICON_IDS, ""))); - cleanUpPromiseIconIds(); - } - - 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()); @@ -100,6 +102,7 @@ public class InstallSessionHelper { for (int i = idsToRemove.size() - 1; i >= 0; --i) { mPromiseIconIds.getArray().removeValue(idsToRemove.get(i)); } + return mPromiseIconIds; } public HashMap getActiveSessions() { @@ -126,7 +129,7 @@ public class InstallSessionHelper { private void updatePromiseIconPrefs() { getPrefs(mAppContext).edit() - .putString(PROMISE_ICON_IDS, mPromiseIconIds.getArray().toConcatString()) + .putString(PROMISE_ICON_IDS, getPromiseIconIds().getArray().toConcatString()) .apply(); } @@ -184,13 +187,15 @@ public class InstallSessionHelper { return info.getInstallReason() == PackageManager.INSTALL_REASON_DEVICE_RESTORE; } + @WorkerThread public boolean promiseIconAddedForId(int sessionId) { - return mPromiseIconIds.contains(sessionId); + return getPromiseIconIds().contains(sessionId); } + @WorkerThread public void removePromiseIconId(int sessionId) { - if (mPromiseIconIds.contains(sessionId)) { - mPromiseIconIds.getArray().removeValue(sessionId); + if (promiseIconAddedForId(sessionId)) { + getPromiseIconIds().getArray().removeValue(sessionId); updatePromiseIconPrefs(); } } @@ -203,6 +208,7 @@ 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) @@ -210,25 +216,24 @@ public class InstallSessionHelper { && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER && sessionInfo.getAppIcon() != null && !TextUtils.isEmpty(sessionInfo.getAppLabel()) - && !mPromiseIconIds.contains(sessionInfo.getSessionId()) + && !promiseIconAddedForId(sessionInfo.getSessionId()) && new PackageManagerHelper(mAppContext).getApplicationInfo( sessionInfo.getAppPackageName(), getUserHandle(sessionInfo), 0) == null) { ItemInstallQueue.INSTANCE.get(mAppContext) .queueItem(sessionInfo.getAppPackageName(), getUserHandle(sessionInfo)); - mPromiseIconIds.add(sessionInfo.getSessionId()); + getPromiseIconIds().add(sessionInfo.getSessionId()); updatePromiseIconPrefs(); } } - public InstallSessionTracker registerInstallTracker( - InstallSessionTracker.Callback callback, LooperExecutor executor) { + public InstallSessionTracker registerInstallTracker(InstallSessionTracker.Callback callback) { InstallSessionTracker tracker = new InstallSessionTracker(this, callback); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - mInstaller.registerSessionCallback(tracker, executor.getHandler()); + mInstaller.registerSessionCallback(tracker, MODEL_EXECUTOR.getHandler()); } else { - mLauncherApps.registerPackageInstallerSessionCallback(executor, tracker); + mLauncherApps.registerPackageInstallerSessionCallback(MODEL_EXECUTOR, tracker); } return tracker; } @@ -240,4 +245,8 @@ 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 eb3ca7366b..b0b907ab19 100644 --- a/src/com/android/launcher3/pm/InstallSessionTracker.java +++ b/src/com/android/launcher3/pm/InstallSessionTracker.java @@ -24,8 +24,11 @@ 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 2d7d6b092a..5ade22be5e 100644 --- a/src/com/android/launcher3/pm/UserCache.java +++ b/src/com/android/launcher3/pm/UserCache.java @@ -60,6 +60,9 @@ 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()); + } } /** @@ -104,9 +107,6 @@ 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 d5b32fccd1..90285c470b 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -151,32 +151,52 @@ 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(); + } - 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)); + 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); } - Collections.reverse(allViews); - removeAllViews(); - for (int i = 0; i < count; i++) { - addView(allViews.get(i)); - } - - orientAboutObject(); + allViews.add(getChildAt(i)); + } + Collections.reverse(allViews); + removeAllViews(); + for (int i = 0; i < count; i++) { + addView(allViews.get(i)); } - onInflationComplete(reverseOrder); - // Add the arrow. + orientAboutObject(); + } + + private void addArrow() { final Resources res = getResources(); final int arrowCenterOffset = res.getDimensionPixelSize(isAlignedWithStart() ? R.dimen.popup_arrow_horizontal_center_start @@ -214,8 +234,6 @@ 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 26b32b8195..6d92b8b627 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -19,10 +19,8 @@ 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; @@ -160,8 +158,7 @@ public class PopupContainerWithArrow extends Arr if (ev.getAction() == MotionEvent.ACTION_DOWN) { BaseDragLayer dl = getPopupContainer(); if (!dl.isEventOverView(this, ev)) { - mLauncher.getUserEventDispatcher().logActionTapOutside( - newContainerTarget(ContainerType.DEEPSHORTCUTS)); + // TODO: add WW log if want to log if tap closed deep shortcut container. close(true); // We let touches on the original icon go through so that users can launch @@ -435,7 +432,9 @@ public class PopupContainerWithArrow extends Arr // Make sure we keep the original icon hidden while it is being dragged. mOriginalIcon.setVisibility(INVISIBLE); } else { - mLauncher.getUserEventDispatcher().logDeepShortcutsOpen(mOriginalIcon); + // TODO: add WW logging if want to add logging for long press on popup + // container. + // 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 61829c002b..7c393ad1e2 100644 --- a/src/com/android/launcher3/popup/RemoteActionShortcut.java +++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java @@ -37,7 +37,6 @@ 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 { @@ -107,9 +106,6 @@ 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 81302ac1f7..577fe4afaa 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -21,8 +21,6 @@ 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; @@ -117,8 +115,6 @@ 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); } @@ -139,8 +135,6 @@ 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 4baecb7c56..f4b059d8d8 100644 --- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java +++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java @@ -306,6 +306,15 @@ 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 b8a184fcfc..fd1d965982 100644 --- a/src/com/android/launcher3/states/HintState.java +++ b/src/com/android/launcher3/states/HintState.java @@ -15,11 +15,12 @@ */ 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. @@ -30,7 +31,7 @@ public class HintState extends LauncherState { | FLAG_HAS_SYS_UI_SCRIM; public HintState(int id) { - super(id, ContainerType.DEFAULT_CONTAINERTYPE, STATE_FLAGS); + super(id, LAUNCHER_STATE_HOME, STATE_FLAGS); } @Override diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java index 2a4f887503..45172b56ef 100644 --- a/src/com/android/launcher3/states/SpringLoadedState.java +++ b/src/com/android/launcher3/states/SpringLoadedState.java @@ -15,6 +15,8 @@ */ package com.android.launcher3.states; +import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; + import android.content.Context; import android.graphics.Rect; @@ -22,7 +24,6 @@ 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. @@ -35,7 +36,7 @@ public class SpringLoadedState extends LauncherState { | FLAG_HIDE_BACK_BUTTON; public SpringLoadedState(int id) { - super(id, ContainerType.WORKSPACE, STATE_FLAGS); + super(id, LAUNCHER_STATE_HOME, STATE_FLAGS); } @Override diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index 8ee5a6e533..9fd53e2563 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -21,6 +21,9 @@ 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; @@ -52,9 +55,6 @@ 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,11 +190,6 @@ 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; @@ -307,11 +302,11 @@ public abstract class AbstractStateChangeTouchController public boolean onDrag(float displacement, MotionEvent ev) { if (!mIsLogContainerSet) { if (mStartState == ALL_APPS) { - mStartContainerType = ContainerType.ALLAPPS; + mStartContainerType = LAUNCHER_STATE_ALLAPPS; } else if (mStartState == NORMAL) { - mStartContainerType = getLogContainerTypeForNormalState(ev); + mStartContainerType = LAUNCHER_STATE_HOME; } else if (mStartState == OVERVIEW) { - mStartContainerType = ContainerType.TASKSWITCHER; + mStartContainerType = LAUNCHER_STATE_OVERVIEW; } mIsLogContainerSet = true; } @@ -401,7 +396,6 @@ 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) { @@ -458,7 +452,7 @@ public abstract class AbstractStateChangeTouchController } } - mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState, logAction)); + mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState)); ValueAnimator anim = mCurrentAnimation.getAnimationPlayer(); anim.setFloatValues(startProgress, endProgress); maybeUpdateAtomicAnim(mFromState, targetState, targetState == mToState ? 1f : 0f); @@ -522,11 +516,7 @@ public abstract class AbstractStateChangeTouchController .setInterpolator(scrollInterpolatorForVelocity(velocity)); } - protected int getDirectionForLog() { - return mToState.ordinal > mFromState.ordinal ? Direction.UP : Direction.DOWN; - } - - protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) { + protected void onSwipeInteractionCompleted(LauncherState targetState) { if (mAtomicComponentsController != null) { mAtomicComponentsController.getAnimationPlayer().end(); mAtomicComponentsController = null; @@ -535,18 +525,18 @@ public abstract class AbstractStateChangeTouchController boolean shouldGoToTargetState = true; if (mPendingAnimation != null) { boolean reachedTarget = mToState == targetState; - mPendingAnimation.finish(reachedTarget, logAction); + mPendingAnimation.finish(reachedTarget); mPendingAnimation = null; shouldGoToTargetState = !reachedTarget; } if (shouldGoToTargetState) { - goToTargetState(targetState, logAction); + goToTargetState(targetState); } } - protected void goToTargetState(LauncherState targetState, int logAction) { + protected void goToTargetState(LauncherState targetState) { if (targetState != mStartState) { - logReachedState(logAction, targetState); + logReachedState(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 @@ -556,24 +546,18 @@ public abstract class AbstractStateChangeTouchController mLauncher.getDragLayer().getScrim().createSysuiMultiplierAnim(1f).setDuration(0).start(); } - private void logReachedState(int logAction, LauncherState targetState) { + private void logReachedState(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(StatsLogManager.containerTypeToAtomState(mStartState.containerType)) - .withDstState(StatsLogManager.containerTypeToAtomState(targetState.containerType)) + .withSrcState(mStartState.statsLogOrdinal) + .withDstState(targetState.statsLogOrdinal) .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder() .setWorkspace( LauncherAtom.WorkspaceContainer.newBuilder() .setPageIndex(mLauncher.getWorkspace().getCurrentPage())) .build()) - .log(StatsLogManager.getLauncherAtomEvent(mStartState.containerType, - targetState.containerType, mToState.ordinal > mFromState.ordinal + .log(StatsLogManager.getLauncherAtomEvent(mStartState.statsLogOrdinal, + targetState.statsLogOrdinal, 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 4a202b65d8..f9dcf2d2e9 100644 --- a/src/com/android/launcher3/touch/AllAppsSwipeController.java +++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java @@ -24,7 +24,6 @@ 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. @@ -69,12 +68,6 @@ 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 61d6f7d804..d56391da3d 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -25,7 +25,9 @@ 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; @@ -49,6 +51,7 @@ 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; @@ -236,6 +239,27 @@ 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 fb02f79c49..17f02be5b4 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -72,7 +72,6 @@ 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 354d78d0ac..114b75acec 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -112,7 +112,6 @@ 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 06479e6b6a..5f5b2d1feb 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -70,7 +70,6 @@ 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 0a32734fca..a85ae458ed 100644 --- a/src/com/android/launcher3/util/Executors.java +++ b/src/com/android/launcher3/util/Executors.java @@ -20,8 +20,10 @@ 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 @@ -83,4 +85,29 @@ 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 52a82f8e93..d9a14e9e3f 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -15,7 +15,6 @@ */ 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; @@ -23,9 +22,6 @@ 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; @@ -74,7 +70,6 @@ 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]; @@ -89,6 +84,9 @@ 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; @@ -98,7 +96,6 @@ public class FloatingIconView extends FrameLayout implements private final Rect mFinalDrawableBounds = new Rect(); - private AnimatorSet mFadeAnimatorSet; private ListenerView mListenerView; private Runnable mFastFinishRunnable; @@ -116,6 +113,8 @@ 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); } @@ -176,6 +175,7 @@ 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,6 +292,8 @@ 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; @@ -311,7 +313,8 @@ 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, int iconOffset) { + private void setIcon(@Nullable Drawable drawable, @Nullable Drawable badge, + @Nullable Drawable btvIcon, int iconOffset) { final InsettableFrameLayout.LayoutParams lp = (InsettableFrameLayout.LayoutParams) getLayoutParams(); mBadge = badge; @@ -342,6 +345,10 @@ public class FloatingIconView extends FrameLayout implements mBadge.setBounds(0, 0, clipViewOgWidth, clipViewOgHeight); } } + + if (!mIsOpening && btvIcon != null) { + mBtvDrawable.setBackground(btvIcon); + } invalidate(); } @@ -360,7 +367,7 @@ public class FloatingIconView extends FrameLayout implements synchronized (mIconLoadResult) { if (mIconLoadResult.isIconLoaded) { setIcon(mIconLoadResult.drawable, mIconLoadResult.badge, - mIconLoadResult.iconOffset); + mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset); setIconAndDotVisible(originalView, false); } else { mIconLoadResult.onIconLoaded = () -> { @@ -369,7 +376,7 @@ public class FloatingIconView extends FrameLayout implements } setIcon(mIconLoadResult.drawable, mIconLoadResult.badge, - mIconLoadResult.iconOffset); + mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset); setVisibility(VISIBLE); setIconAndDotVisible(originalView, false); @@ -434,10 +441,6 @@ public class FloatingIconView extends FrameLayout implements mEndRunnable.run(); mEndRunnable = null; } - if (mFadeAnimatorSet != null) { - mFadeAnimatorSet.end(); - mFadeAnimatorSet = null; - } } @Override @@ -546,8 +549,16 @@ public class FloatingIconView extends FrameLayout implements setIconAndDotVisible(originalView, true); view.finish(dragLayer); } else { - view.mFadeAnimatorSet = view.createFadeAnimation(originalView, dragLayer); - view.mFadeAnimatorSet.start(); + 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); } } else { view.finish(dragLayer); @@ -564,47 +575,6 @@ 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); @@ -628,11 +598,7 @@ 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; @@ -640,11 +606,13 @@ 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 a8e1c6b30c..dd322d921a 100644 --- a/src/com/android/launcher3/views/HeroSearchResultView.java +++ b/src/com/android/launcher3/views/HeroSearchResultView.java @@ -16,12 +16,16 @@ 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; @@ -31,9 +35,10 @@ 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; +import com.android.launcher3.allapps.search.AllAppsSearchBarController.PayloadResultHandler; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.graphics.DragPreviewProvider; @@ -53,9 +58,10 @@ import java.util.List; * A view representing a high confidence app search result that includes shortcuts */ public class HeroSearchResultView extends LinearLayout implements DragSource, - AllAppsSearchBarController.PayloadResultHandler> { + PayloadResultHandler>> { public static final int MAX_SHORTCUTS_COUNT = 2; + private final Object[] mTargetInfo = createTargetInfo(); BubbleTextView mBubbleTextView; View mIconView; BubbleTextView[] mDeepShortcutTextViews = new BubbleTextView[2]; @@ -102,7 +108,7 @@ public class HeroSearchResultView extends LinearLayout implements DragSource, grid.allAppsIconSizePx)); bubbleTextView.setOnClickListener(view -> { WorkspaceItemInfo itemInfo = (WorkspaceItemInfo) bubbleTextView.getTag(); - SearchTargetEvent event = new SearchTargetEvent( + SearchTargetEvent event = getSearchTargetEvent( SearchTarget.ItemType.APP_HERO, SearchTargetEvent.CHILD_SELECT); event.bundle = getAppBundle(itemInfo); @@ -119,21 +125,36 @@ 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 shorcutInfos = adapterItem.getPayload(); + List> shortcutDetails = adapterItem.getPayload(); + LauncherAppState appState = LauncherAppState.getInstance(getContext()); for (int i = 0; i < mDeepShortcutTextViews.length; i++) { - mDeepShortcutTextViews[i].setVisibility(shorcutInfos.size() > i ? VISIBLE : GONE); - if (i < shorcutInfos.size()) { - mDeepShortcutTextViews[i].applyFromItemInfoWithIcon(shorcutInfos.get(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)); + }); } } 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); @@ -169,7 +190,7 @@ public class HeroSearchResultView extends LinearLayout implements DragSource, mLauncher.getWorkspace().beginDragShared(mContainer.mBubbleTextView, draggableView, mContainer, itemInfo, previewProvider, new DragOptions()); - SearchTargetEvent event = new SearchTargetEvent( + SearchTargetEvent event = mContainer.getSearchTargetEvent( SearchTarget.ItemType.APP_HERO, SearchTargetEvent.LONG_PRESS); event.bundle = getAppBundle(itemInfo); if (mContainer.mPlugin != null) { @@ -186,7 +207,7 @@ public class HeroSearchResultView extends LinearLayout implements DragSource, Launcher launcher = Launcher.getLauncher(getContext()); launcher.startActivitySafely(this, itemInfo.getIntent(), itemInfo); - SearchTargetEvent event = new SearchTargetEvent( + SearchTargetEvent event = getSearchTargetEvent( 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 3ec20d57a1..80f0981af5 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -16,6 +16,7 @@ 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; @@ -132,7 +133,7 @@ public class OptionsPopupView extends ArrowPopup view.setOnLongClickListener(popup); popup.mItemMap.put(view, item); } - popup.reorderAndShow(popup.getChildCount()); + popup.show(); } @VisibleForTesting @@ -211,7 +212,8 @@ 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()); + launcher.getWorkspace().getWallpaperOffsetForCenterPage()) + .putExtra(EXTRA_WALLPAPER_LAUNCH_SOURCE, "app_launched_launcher"); 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 new file mode 100644 index 0000000000..313ae5e611 --- /dev/null +++ b/src/com/android/launcher3/views/SearchResultIconRow.java @@ -0,0 +1,155 @@ +/* + * 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 6e45e88b32..0c9a22f672 100644 --- a/src/com/android/launcher3/views/SearchResultPeopleView.java +++ b/src/com/android/launcher3/views/SearchResultPeopleView.java @@ -15,9 +15,6 @@ */ 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; @@ -28,7 +25,6 @@ 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; @@ -50,7 +46,6 @@ 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; /** @@ -66,8 +61,8 @@ public class SearchResultPeopleView extends LinearLayout implements private TextView mTitleView; private ImageButton[] mProviderButtons = new ImageButton[3]; private AllAppsSearchPlugin mPlugin; - private Uri mContactUri; - + private Intent mIntent; + private final Object[] mTargetInfo = createTargetInfo(); public SearchResultPeopleView(Context context) { this(context, null, 0); @@ -109,7 +104,7 @@ public class SearchResultPeopleView extends LinearLayout implements Bundle payload = adapterItemWithPayload.getPayload(); mPlugin = adapterItemWithPayload.getPlugin(); mTitleView.setText(payload.getString("title")); - mContactUri = payload.getParcelable("contact_uri"); + mIntent = payload.getParcelable("intent"); Bitmap icon = payload.getParcelable("icon"); if (icon != null) { RoundedBitmapDrawable d = RoundedBitmapDrawableFactory.create(getResources(), icon); @@ -125,25 +120,20 @@ public class SearchResultPeopleView extends LinearLayout implements for (int i = 0; i < mProviderButtons.length; i++) { ImageButton button = mProviderButtons[i]; if (providers != null && i < providers.size()) { - 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) { - } + 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) { + } - }); - } catch (URISyntaxException ex) { - button.setVisibility(GONE); - } + }); } else { button.setVisibility(GONE); } @@ -151,15 +141,21 @@ public class SearchResultPeopleView extends LinearLayout implements adapterItemWithPayload.setSelectionHandler(this::handleSelection); } - private void setupProviderButton(ImageButton button, Bundle provider, Intent intent) { + @Override + public Object[] getTargetInfo() { + return mTargetInfo; + } + + private void setupProviderButton(ImageButton button, Bundle provider, Intent intent, + AllAppsGridAdapter.AdapterItem adapterItem) { Launcher launcher = Launcher.getLauncher(getContext()); button.setOnClickListener(b -> { launcher.startActivitySafely(b, intent, null); - SearchTargetEvent searchTargetEvent = new SearchTargetEvent( + SearchTargetEvent searchTargetEvent = getSearchTargetEvent( SearchTarget.ItemType.PEOPLE, SearchTargetEvent.CHILD_SELECT); searchTargetEvent.bundle = new Bundle(); - searchTargetEvent.bundle.putParcelable("contact_uri", mContactUri); + searchTargetEvent.bundle.putParcelable("intent", mIntent); searchTargetEvent.bundle.putBundle("provider", provider); if (mPlugin != null) { mPlugin.notifySearchTargetEvent(searchTargetEvent); @@ -169,14 +165,13 @@ public class SearchResultPeopleView extends LinearLayout implements private void handleSelection(int eventType) { - if (mContactUri != null) { + if (mIntent != null) { Launcher launcher = Launcher.getLauncher(getContext()); - launcher.startActivitySafely(this, new Intent(Intent.ACTION_VIEW, mContactUri).setFlags( - Intent.FLAG_ACTIVITY_NEW_TASK), null); - SearchTargetEvent searchTargetEvent = new SearchTargetEvent( - SearchTarget.ItemType.PEOPLE, eventType); + launcher.startActivitySafely(this, mIntent, null); + SearchTargetEvent searchTargetEvent = getSearchTargetEvent(SearchTarget.ItemType.PEOPLE, + eventType); searchTargetEvent.bundle = new Bundle(); - searchTargetEvent.bundle.putParcelable("contact_uri", mContactUri); + searchTargetEvent.bundle.putParcelable("intent", mIntent); 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 8624609f80..ff3ecc8bc3 100644 --- a/src/com/android/launcher3/views/SearchResultPlayItem.java +++ b/src/com/android/launcher3/views/SearchResultPlayItem.java @@ -58,6 +58,8 @@ 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); @@ -125,6 +127,11 @@ 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); @@ -160,7 +167,7 @@ public class SearchResultPlayItem extends LinearLayout implements } private void logSearchEvent(int eventType) { - SearchTargetEvent searchTargetEvent = new SearchTargetEvent( + SearchTargetEvent searchTargetEvent = getSearchTargetEvent( 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 deleted file mode 100644 index 307cf34c7d..0000000000 --- a/src/com/android/launcher3/views/SearchResultShortcut.java +++ /dev/null @@ -1,110 +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.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 new file mode 100644 index 0000000000..b5abbcc724 --- /dev/null +++ b/src/com/android/launcher3/views/SearchResultSuggestRow.java @@ -0,0 +1,131 @@ +/* + * 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 d439ee3d68..0fe0a43ff5 100644 --- a/src/com/android/launcher3/views/SearchSectionHeaderView.java +++ b/src/com/android/launcher3/views/SearchSectionHeaderView.java @@ -52,4 +52,9 @@ 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 93bcee2585..a1a0172547 100644 --- a/src/com/android/launcher3/views/SearchSettingsRowView.java +++ b/src/com/android/launcher3/views/SearchSettingsRowView.java @@ -48,6 +48,8 @@ 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); @@ -87,6 +89,11 @@ 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); @@ -108,7 +115,7 @@ public class SearchSettingsRowView extends LinearLayout implements Launcher launcher = Launcher.getLauncher(getContext()); launcher.startActivityForResult(mIntent, 0); - SearchTargetEvent searchTargetEvent = new SearchTargetEvent( + SearchTargetEvent searchTargetEvent = getSearchTargetEvent( 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 new file mode 100644 index 0000000000..bbc47739f3 --- /dev/null +++ b/src/com/android/launcher3/views/ThumbnailSearchResultView.java @@ -0,0 +1,114 @@ +/* + * 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 4fa670f44a..aa3ab8f7e0 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 = 6; + int VERSION = 7; void setup(Activity activity, View view); @@ -42,6 +42,12 @@ 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 c6b8300499..3f0dc39cc1 100644 --- a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java +++ b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java @@ -15,6 +15,7 @@ */ package com.android.systemui.plugins.shared; +import android.app.RemoteAction; import android.content.pm.ShortcutInfo; import android.os.Bundle; @@ -25,17 +26,69 @@ 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), - PEOPLE(7); + + /** + * 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); private final int mId; + ViewType(int id) { mId = id; } @@ -52,9 +105,15 @@ 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); + 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); private final int mId; + + /** Used to render section title. */ private final String mTitle; private final ViewType mViewType; @@ -81,19 +140,21 @@ 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) { + Bundle bundle, float score, String sessionId) { 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 ac4bc333c6..5016abc1e9 100644 --- a/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java +++ b/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java @@ -15,6 +15,7 @@ */ package com.android.systemui.plugins.shared; +import android.app.RemoteAction; import android.content.pm.ShortcutInfo; import android.os.Bundle; @@ -29,12 +30,17 @@ public class SearchTargetEvent { public SearchTarget.ItemType type; public ShortcutInfo shortcut; + public RemoteAction remoteAction; public int eventType; public Bundle bundle; - public float score; + public int index; + public String sessionIdentifier; - public SearchTargetEvent(SearchTarget.ItemType itemType, int eventType) { + public SearchTargetEvent(SearchTarget.ItemType itemType, int eventType, int index, + String sessionId) { 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 ec3f93ff1b..a4e53a1cc0 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, ContainerType.ALLAPPS, STATE_FLAGS); + super(id, LAUNCHER_STATE_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 d102bccaad..da5a94f6fd 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java @@ -15,10 +15,11 @@ */ 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 @@ -26,7 +27,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; public class OverviewState extends LauncherState { public OverviewState(int id) { - super(id, ContainerType.WORKSPACE, FLAG_DISABLE_RESTORE); + super(id, LAUNCHER_STATE_OVERVIEW, 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 5e42d9b988..e118481570 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -279,6 +279,8 @@ 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 f5f93c429f..8d594de926 100644 --- a/tests/src/com/android/launcher3/ui/WorkTabTest.java +++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java @@ -55,7 +55,9 @@ public class WorkTabTest extends AbstractLauncherUiTest { private static final int WORK_PAGE = AllAppsContainerView.AdapterHolder.WORK; @Before - public void createWorkProfile() throws Exception { + @Override + public void setUp() throws Exception { + super.setUp(); String output = mDevice.executeShellCommand( "pm create-user --profileOf 0 --managed TestProfile"); @@ -136,7 +138,8 @@ public class WorkTabTest extends AbstractLauncherUiTest { }); executeOnLauncher(launcher -> Log.d(TestProtocol.WORK_PROFILE_REMOVED, - "Work profile status: " + launcher.getAppsView().isPersonalTabVisible())); + "work profile status (" + mProfileUserId + ") :" + + launcher.getAppsView().isWorkTabVisible())); // verify work edu is seen next waitForLauncherCondition("Launcher did not show the next edu screen", l ->