Revert "Merge commit '8d14dbe041199d611839140f1c9285fd4174e9f4' ..."

Revert "Merging from ub-launcher3-master @ build 6877130"

Revert "Merging from ub-launcher3-master @ build 6877130"

Revert "Merging from ub-launcher3-master @ build 6877130"

Revert submission 12738409-merge_ub-launcher3-master_6877130

Reason for revert: Introduced crashes to global presubmit

Reverted Changes:
I624658ce6:Merge commit '8d14dbe041199d611839140f1c9285fd4174...
Iccd2f1e3a:Merging from ub-launcher3-master @ build 6877130
I791d64951:Merging from ub-launcher3-master @ build 6877130
Icdd32ab01:Merging from ub-launcher3-master @ build 6877130

Bug: 169963211
Change-Id: I77a4ae59e823147beae8dd7cb9b54ccdace2c7f4
This commit is contained in:
Alistair Delva 2020-10-05 14:46:26 +00:00
parent 49a94be109
commit 087a9e39b6
138 changed files with 2135 additions and 1944 deletions

View File

@ -36,12 +36,18 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
launcher_log_protos_lite
LOCAL_SRC_FILES := \
$(call all-proto-files-under, protos) \
$(call all-proto-files-under, proto_overrides) \
$(call all-java-files-under, src_build_config) \
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ --proto_path=$(LOCAL_PATH)/proto_overrides/
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := enum_style=java
LOCAL_SDK_VERSION := current
LOCAL_MIN_SDK_VERSION := 26
LOCAL_MODULE := Launcher3CommonDepsLib
@ -129,6 +135,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := \
SystemUI-statsd \
SystemUISharedLib \
launcherprotosnano \
launcher_log_protos_lite
ifneq (,$(wildcard frameworks/base))
LOCAL_PRIVATE_PLATFORM_APIS := true
@ -196,6 +203,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := \
SystemUI-statsd \
SystemUISharedLib \
launcherprotosnano \
launcher_log_protos_lite
ifneq (,$(wildcard frameworks/base))
LOCAL_PRIVATE_PLATFORM_APIS := true

View File

@ -82,6 +82,7 @@ android {
manifest.srcFile 'AndroidManifest-common.xml'
proto {
srcDir 'protos/'
srcDir 'proto_overrides/'
}
}
@ -149,6 +150,7 @@ dependencies {
implementation "androidx.preference:preference:${ANDROID_X_VERSION}"
implementation project(':IconLoader')
withQuickstepImplementation project(':SharedLibWrapper')
implementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/libs", include: 'launcher_protos.jar')
// Recents lib dependency
withQuickstepImplementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/quickstep/libs", include: 'sysui_shared.jar')
@ -169,16 +171,20 @@ dependencies {
protobuf {
// Configure the protoc executable
protoc {
artifact = "com.google.protobuf:protoc:${protocVersion}"
}
generateProtoTasks {
all().each { task ->
task.builtins {
remove java
java {
option "lite"
artifact = 'com.google.protobuf:protoc:3.0.0'
generateProtoTasks {
all().each { task ->
task.builtins {
remove java
javanano {
option "java_package=launcher_log_extension.proto|com.android.launcher3.userevent.nano"
option "java_package=launcher_log.proto|com.android.launcher3.userevent.nano"
option "java_package=launcher_dump.proto|com.android.launcher3.model.nano"
option "enum_style=java"
}
}
}
}
}
}
}

245
protos/launcher_log.proto Normal file
View File

@ -0,0 +1,245 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
syntax = "proto2";
import "launcher_log_extension.proto";
option java_package = "com.android.launcher3.userevent";
option java_outer_classname = "LauncherLogProto";
package userevent;
message Target {
enum Type {
NONE = 0;
ITEM = 1;
CONTROL = 2;
CONTAINER = 3;
}
optional Type type = 1;
// For container type and item type
// Used mainly for ContainerType.FOLDER, ItemType.*
optional int32 page_index = 2;
optional int32 rank = 3;
optional int32 grid_x = 4;
optional int32 grid_y = 5;
// For container types only
optional ContainerType container_type = 6;
optional int32 cardinality = 7;
// For control types only
optional ControlType control_type = 8;
// For item types only
optional ItemType item_type = 9;
optional int32 package_name_hash = 10;
optional int32 component_hash = 11; // Used for ItemType.WIDGET
optional int32 intent_hash = 12; // Used for ItemType.SHORTCUT
optional int32 span_x = 13 [default = 1];// Used for ItemType.WIDGET
optional int32 span_y = 14 [default = 1];// Used for ItemType.WIDGET
optional int32 predictedRank = 15;
optional TargetExtension extension = 16;
optional TipType tip_type = 17;
optional int32 search_query_length = 18;
optional bool is_work_app = 19;
optional FromFolderLabelState from_folder_label_state = 20;
optional ToFolderLabelState to_folder_label_state = 21;
// Note: proto does not support duplicate enum values, even if they belong to different enum type.
// Hence "FROM" and "TO" prefix added.
enum FromFolderLabelState {
FROM_FOLDER_LABEL_STATE_UNSPECIFIED = 0;
FROM_EMPTY = 1;
FROM_CUSTOM = 2;
FROM_SUGGESTED = 3;
}
enum ToFolderLabelState {
TO_FOLDER_LABEL_STATE_UNSPECIFIED = 0;
TO_SUGGESTION0_WITH_VALID_PRIMARY = 1;
TO_SUGGESTION1_WITH_VALID_PRIMARY = 2;
TO_SUGGESTION1_WITH_EMPTY_PRIMARY = 3;
TO_SUGGESTION2_WITH_VALID_PRIMARY = 4;
TO_SUGGESTION2_WITH_EMPTY_PRIMARY = 5;
TO_SUGGESTION3_WITH_VALID_PRIMARY = 6;
TO_SUGGESTION3_WITH_EMPTY_PRIMARY = 7;
TO_EMPTY_WITH_VALID_SUGGESTIONS = 8 [deprecated = true];
TO_EMPTY_WITH_VALID_PRIMARY = 15;
TO_EMPTY_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY = 16;
TO_EMPTY_WITH_EMPTY_SUGGESTIONS = 9;
TO_EMPTY_WITH_SUGGESTIONS_DISABLED = 10;
TO_CUSTOM_WITH_VALID_SUGGESTIONS = 11 [deprecated = true];
TO_CUSTOM_WITH_VALID_PRIMARY = 17;
TO_CUSTOM_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY = 18;
TO_CUSTOM_WITH_EMPTY_SUGGESTIONS = 12;
TO_CUSTOM_WITH_SUGGESTIONS_DISABLED = 13;
UNCHANGED = 14;
}
}
// Used to define what type of item a Target would represent.
enum ItemType {
DEFAULT_ITEMTYPE = 0;
APP_ICON = 1;
SHORTCUT = 2;
WIDGET = 3;
FOLDER_ICON = 4;
DEEPSHORTCUT = 5;
SEARCHBOX = 6;
EDITTEXT = 7;
NOTIFICATION = 8;
TASK = 9; // Each page of Recents UI (QuickStep)
WEB_APP = 10;
TASK_ICON = 11;
}
// Used to define what type of container a Target would represent.
enum ContainerType {
DEFAULT_CONTAINERTYPE = 0;
WORKSPACE = 1;
HOTSEAT = 2;
FOLDER = 3;
ALLAPPS = 4;
WIDGETS = 5;
OVERVIEW = 6; // Zoomed out workspace (without QuickStep)
PREDICTION = 7;
SEARCHRESULT = 8;
DEEPSHORTCUTS = 9;
PINITEM = 10; // confirmation screen
NAVBAR = 11;
TASKSWITCHER = 12; // Recents UI Container (QuickStep)
APP = 13; // Foreground activity is another app (QuickStep)
TIP = 14; // Onboarding texts (QuickStep)
OTHER_LAUNCHER_APP = 15;
}
// Used to define what type of control a Target would represent.
enum ControlType {
DEFAULT_CONTROLTYPE = 0;
ALL_APPS_BUTTON = 1;
WIDGETS_BUTTON = 2;
WALLPAPER_BUTTON = 3;
SETTINGS_BUTTON = 4;
REMOVE_TARGET = 5;
UNINSTALL_TARGET = 6;
APPINFO_TARGET = 7;
RESIZE_HANDLE = 8;
VERTICAL_SCROLL = 9;
HOME_INTENT = 10; // Deprecated, use enum Command instead
BACK_BUTTON = 11;
QUICK_SCRUB_BUTTON = 12;
CLEAR_ALL_BUTTON = 13;
CANCEL_TARGET = 14;
TASK_PREVIEW = 15;
SPLIT_SCREEN_TARGET = 16;
REMOTE_ACTION_SHORTCUT = 17;
APP_USAGE_SETTINGS = 18;
BACK_GESTURE = 19;
UNDO = 20;
DISMISS_PREDICTION = 21;
HYBRID_HOTSEAT_ACCEPTED = 22;
HYBRID_HOTSEAT_CANCELED = 23;
OVERVIEW_ACTIONS_SHARE_BUTTON = 24;
OVERVIEW_ACTIONS_SCREENSHOT_BUTTON = 25;
OVERVIEW_ACTIONS_SELECT_BUTTON = 26;
SELECT_MODE_CLOSE_BUTTON = 27;
SELECT_MODE_ITEM = 28;
}
enum TipType {
DEFAULT_NONE = 0;
BOUNCE = 1;
SWIPE_UP_TEXT = 2;
QUICK_SCRUB_TEXT = 3;
PREDICTION_TEXT = 4;
DWB_TOAST = 5;
HYBRID_HOTSEAT = 6;
}
// Used to define the action component of the LauncherEvent.
message Action {
enum Type {
TOUCH = 0;
AUTOMATED = 1;
COMMAND = 2;
TIP = 3;
SOFT_KEYBOARD = 4;
// HARD_KEYBOARD, ASSIST
}
enum Touch {
TAP = 0;
LONGPRESS = 1;
DRAGDROP = 2;
SWIPE = 3;
FLING = 4;
PINCH = 5;
SWIPE_NOOP = 6;
}
enum Direction {
NONE = 0;
UP = 1;
DOWN = 2;
LEFT = 3;
RIGHT = 4;
UPRIGHT = 5;
UPLEFT = 6;
}
enum Command {
HOME_INTENT = 0;
BACK = 1;
ENTRY = 2; // Indicates entry to one of Launcher container type target
// not using the HOME_INTENT
CANCEL = 3; // Indicates that a confirmation screen was cancelled
CONFIRM = 4; // Indicates thata confirmation screen was accepted
STOP = 5; // Indicates onStop() was called (screen time out, power off)
RECENTS_BUTTON = 6; // Indicates that Recents button was pressed
RESUME = 7; // Indicates onResume() was called
}
optional Type type = 1;
optional Touch touch = 2;
optional Direction dir = 3;
optional Command command = 4;
// Log if the action was performed on outside of the container
optional bool is_outside = 5;
optional bool is_state_change = 6;
}
//
// Context free grammar of typical user interaction:
// Action (Touch) + Target
// Action (Touch) + Target + Target
//
message LauncherEvent {
required Action action = 1;
// List of targets that touch actions can be operated on.
repeated Target src_target = 2;
repeated Target dest_target = 3;
optional int64 action_duration_millis = 4;
optional int64 elapsed_container_millis = 5;
optional int64 elapsed_session_millis = 6;
optional bool is_in_multi_window_mode = 7 [deprecated = true];
optional bool is_in_landscape_mode = 8 [deprecated = true];
optional LauncherEventExtension extension = 9;
}

View File

@ -13,8 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<com.android.quickstep.interaction.RootSandboxLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/colorBackground">
@ -94,11 +93,11 @@
style="@style/TextAppearance.GestureTutorial.Feedback"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/gesture_tutorial_fragment_titles_container"
android:layout_above="@id/gesture_tutorial_fragment_action_button"
android:layout_centerHorizontal="true"
android:layout_marginStart="@dimen/gesture_tutorial_feedback_margin_start_end"
android:layout_marginEnd="@dimen/gesture_tutorial_feedback_margin_start_end"
android:layout_marginTop="40dp"/>
android:layout_marginBottom="10dp"/>
<!-- android:stateListAnimator="@null" removes shadow and normal on click behavior (increase
of elevation and shadow) which is replaced by ripple effect in android:foreground -->
@ -127,4 +126,4 @@
android:background="@null"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:stateListAnimator="@null"/>
</com.android.quickstep.interaction.RootSandboxLayout>
</RelativeLayout>

View File

@ -149,21 +149,6 @@
<!-- Feedback shown during interactive parts of Assistant gesture tutorial when the gesture doesn't go far enough. [CHAR LIMIT=100] -->
<string name="assistant_gesture_feedback_swipe_not_long_enough" translatable="false">Try swiping further</string>
<!-- Title shown in sandbox mode part of gesture tutorial. [CHAR LIMIT=30] -->
<string name="sandbox_mode_title" translatable="false">Sandbox Mode</string>
<!-- Subtitle shown in sandbox mode part of gesture tutorial. [CHAR LIMIT=60] -->
<string name="sandbox_mode_subtitle" translatable="false">Try any navigation gesture</string>
<!-- Feedback shown in sandbox mode when the back gesture is successfully issued. [CHAR LIMIT=60] -->
<string name="sandbox_mode_back_gesture_feedback_successful" translatable="false">Back gesture successful</string>
<!-- Feedback shown in sandbox mode when the assistant gesture is a successfully issued. [CHAR LIMIT=60] -->
<string name="sandbox_mode_assistant_gesture_feedback_successful" translatable="false">Assistant gesture successful</string>
<!-- Feedback shown in sandbox mode when the home gesture is a successfully issued. [CHAR LIMIT=60] -->
<string name="sandbox_mode_home_gesture_feedback_successful" translatable="false">Home gesture successful</string>
<!-- Feedback shown in sandbox mode when the overview gesture is a successfully issued. [CHAR LIMIT=60] -->
<string name="sandbox_mode_overview_gesture_feedback_successful" translatable="false">Overview gesture successful</string>
<!-- Feedback shown in sandbox mode when the back gesture swipe is too far from the edge. [CHAR LIMIT=60] -->
<string name="sandbox_mode_back_gesture_feedback_swipe_too_far_from_edge" translatable="false">Make sure you swipe from the left/right edge of the screen</string>
<!-- Title shown on the confirmation screen after successful gesture. [CHAR LIMIT=30] -->
<string name="gesture_tutorial_confirm_title" translatable="false">All set</string>
<!-- Button text shown on a button on the confirm screen to leave the tutorial. [CHAR LIMIT=14] -->

View File

@ -22,8 +22,6 @@ import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Intent;
@ -309,10 +307,4 @@ public abstract class BaseQuickstepLauncher extends Launcher
public void setHintUserWillBeActive() {
addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
InteractionJankMonitorWrapper.init(getWindow().getDecorView());
}
}

View File

@ -34,7 +34,8 @@ import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@TargetApi(Build.VERSION_CODES.P)
public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {
public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat,
WrappedAnimationRunnerImpl {
private static final String TAG = "LauncherAnimationRunner";

View File

@ -66,7 +66,6 @@ import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.shortcuts.DeepShortcutView;
@ -82,7 +81,6 @@ import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.systemui.shared.system.ActivityCompat;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat;
@ -797,36 +795,6 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
== PackageManager.PERMISSION_GRANTED;
}
private void addCujInstrumentation(Animator anim, int cuj, String transition) {
if (Trace.isEnabled()) {
anim.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
Trace.beginAsyncSection(transition, 0);
InteractionJankMonitorWrapper.begin(cuj);
super.onAnimationStart(animation);
}
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
InteractionJankMonitorWrapper.cancel(cuj);
}
@Override
public void onAnimationSuccess(Animator animator) {
InteractionJankMonitorWrapper.end(cuj);
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
Trace.endAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
}
});
}
}
/**
* Remote animation runner for animation from the app to Launcher, including recents.
*/
@ -891,9 +859,21 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
// is initialized.
if (launcherIsATargetWithMode(appTargets, MODE_OPENING)
|| mLauncher.isForceInvisible()) {
addCujInstrumentation(
anim, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME,
TRANSITION_OPEN_LAUNCHER);
if (Trace.isEnabled()) {
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
Trace.beginAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
super.onAnimationStart(animation);
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
Trace.endAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
}
});
}
// Only register the content animation for cancellation when state changes
mLauncher.getStateManager().setCurrentAnimation(anim);
@ -962,12 +942,25 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
launcherClosing);
}
addCujInstrumentation(anim,
launchingFromRecents
? InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_RECENTS
: InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_ICON,
launchingFromRecents
? TRANSITION_LAUNCH_FROM_RECENTS : TRANSITION_LAUNCH_FROM_ICON);
if (Trace.isEnabled()) {
final String section =
launchingFromRecents
? TRANSITION_LAUNCH_FROM_RECENTS : TRANSITION_LAUNCH_FROM_ICON;
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
Trace.beginAsyncSection(section, 0);
super.onAnimationStart(animation);
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
Trace.endAsyncSection(section, 0);
}
});
}
if (launcherClosing) {
anim.addListener(mForceInvisibleListener);

View File

@ -16,8 +16,11 @@
package com.android.launcher3.appprediction;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.logging.LoggerUtils.newTarget;
import android.annotation.TargetApi;
import android.content.Context;
@ -40,6 +43,7 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsSectionDecorator;
import com.android.launcher3.allapps.FloatingHeaderRow;
@ -49,11 +53,13 @@ import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.keyboard.FocusIndicatorHelper;
import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.Themes;
import com.android.quickstep.AnimatedFloat;
@ -62,7 +68,7 @@ import java.util.List;
@TargetApi(Build.VERSION_CODES.P)
public class PredictionRowView extends LinearLayout implements
OnDeviceProfileChangeListener, FloatingHeaderRow {
LogContainerProvider, OnDeviceProfileChangeListener, FloatingHeaderRow {
private static final IntProperty<PredictionRowView> TEXT_ALPHA =
new IntProperty<PredictionRowView>("textAlpha") {
@ -265,6 +271,29 @@ public class PredictionRowView extends LinearLayout implements
mParent.onHeightUpdated();
}
@Override
public void fillInLogContainerData(ItemInfo childInfo, LauncherLogProto.Target child,
ArrayList<LauncherLogProto.Target> parents) {
for (int i = 0; i < mPredictedApps.size(); i++) {
ItemInfoWithIcon appInfo = mPredictedApps.get(i);
if (appInfo == childInfo) {
child.predictedRank = i;
break;
}
}
parents.add(newContainerTarget(LauncherLogProto.ContainerType.PREDICTION));
// include where the prediction is coming this used to be Launcher#modifyUserEvent
LauncherLogProto.Target parent = newTarget(LauncherLogProto.Target.Type.CONTAINER);
LauncherState state = mLauncher.getStateManager().getState();
if (state == LauncherState.ALL_APPS) {
parent.containerType = LauncherLogProto.ContainerType.ALLAPPS;
} else if (state == OVERVIEW) {
parent.containerType = LauncherLogProto.ContainerType.TASKSWITCHER;
}
parents.add(parent);
}
public void setTextAlpha(int textAlpha) {
mIconLastSetTextAlpha = textAlpha;
if (getAlpha() < 1 && textAlpha > 0) {

View File

@ -55,6 +55,7 @@ import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.Snackbar;

View File

@ -16,7 +16,6 @@
package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import android.content.Context;
@ -24,6 +23,7 @@ import android.content.Context;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
* Definition for AllApps state
@ -40,7 +40,7 @@ public class AllAppsState extends LauncherState {
};
public AllAppsState(int id) {
super(id, LAUNCHER_STATE_ALLAPPS, STATE_FLAGS);
super(id, ContainerType.ALLAPPS, STATE_FLAGS);
}
@Override

View File

@ -15,13 +15,12 @@
*/
package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import android.content.Context;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
@ -34,7 +33,7 @@ public class BackgroundAppState extends OverviewState {
| FLAG_WORKSPACE_INACCESSIBLE | FLAG_NON_INTERACTIVE | FLAG_CLOSE_POPUPS;
public BackgroundAppState(int id) {
this(id, LAUNCHER_STATE_BACKGROUND);
this(id, LauncherLogProto.ContainerType.TASKSWITCHER);
}
protected BackgroundAppState(int id, int logContainer) {

View File

@ -15,14 +15,13 @@
*/
package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import android.content.Context;
import android.graphics.Rect;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.views.RecentsView;
/**
@ -35,7 +34,7 @@ public class OverviewModalTaskState extends OverviewState {
FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_WORKSPACE_INACCESSIBLE;
public OverviewModalTaskState(int id) {
super(id, LAUNCHER_STATE_OVERVIEW, STATE_FLAGS);
super(id, ContainerType.OVERVIEW, STATE_FLAGS);
}
@Override

View File

@ -16,7 +16,6 @@
package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.hideShelfInTwoButtonLandscape;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
@ -30,6 +29,7 @@ import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Workspace;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
@ -51,7 +51,7 @@ public class OverviewState extends LauncherState {
}
protected OverviewState(int id, int stateFlags) {
this(id, LAUNCHER_STATE_OVERVIEW, stateFlags);
this(id, ContainerType.TASKSWITCHER, stateFlags);
}
protected OverviewState(int id, int logContainer, int stateFlags) {

View File

@ -15,9 +15,8 @@
*/
package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import com.android.launcher3.Launcher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
/**
* State to indicate we are about to launch a recent task. Note that this state is only used when
@ -27,7 +26,7 @@ import com.android.launcher3.Launcher;
public class QuickSwitchState extends BackgroundAppState {
public QuickSwitchState(int id) {
super(id, LAUNCHER_STATE_BACKGROUND);
super(id, LauncherLogProto.ContainerType.APP);
}
@Override

View File

@ -12,6 +12,8 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.quickstep.SystemUiProxy;
/**
@ -43,6 +45,11 @@ public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchContro
return draggingFromNav ? OVERVIEW : NORMAL;
}
@Override
protected int getLogContainerTypeForNormalState(MotionEvent ev) {
return LauncherLogProto.ContainerType.NAVBAR;
}
@Override
protected float getShiftRange() {
return mLauncher.getDragLayer().getWidth();
@ -58,8 +65,13 @@ public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchContro
}
@Override
protected void onSwipeInteractionCompleted(LauncherState targetState) {
super.onSwipeInteractionCompleted(targetState);
protected int getDirectionForLog() {
return mLauncher.getDeviceProfile().isSeascape() ? Direction.RIGHT : Direction.LEFT;
}
@Override
protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
super.onSwipeInteractionCompleted(targetState, logAction);
if (mStartState == NORMAL && targetState == OVERVIEW) {
SystemUiProxy.INSTANCE.get(mLauncher).onOverviewShown(true, TAG);
}

View File

@ -45,9 +45,12 @@ import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.OverviewScrim;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.AssistantUtilities;
@ -208,6 +211,7 @@ public class NavBarToHomeTouchController implements TouchController,
@Override
public void onDragEnd(float velocity) {
boolean fling = mSwipeDetector.isFling(velocity);
final int logAction = fling ? Touch.FLING : Touch.SWIPE;
float progress = mCurrentAnimation.getProgressFraction();
float interpolatedProgress = PULLBACK_INTERPOLATOR.getInterpolation(progress);
boolean success = interpolatedProgress >= SUCCESS_TRANSITION_PROGRESS
@ -226,7 +230,7 @@ public class NavBarToHomeTouchController implements TouchController,
() -> onSwipeInteractionCompleted(mEndState));
}
if (mStartState != mEndState) {
logHomeGesture();
// TODO: add to WW log
}
AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(mLauncher);
if (topOpenView != null) {
@ -251,10 +255,17 @@ public class NavBarToHomeTouchController implements TouchController,
AccessibilityManagerCompat.sendStateEventToTest(mLauncher, targetState.ordinal);
}
private void logHomeGesture() {
private void logStateChange(int startContainerType, int logAction) {
mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
LauncherLogProto.Action.Direction.UP,
mSwipeDetector.getDownX(), mSwipeDetector.getDownY(),
LauncherLogProto.ContainerType.NAVBAR,
startContainerType,
mEndState.containerType,
mLauncher.getWorkspace().getCurrentPage());
mLauncher.getStatsLogManager().logger()
.withSrcState(mStartState.statsLogOrdinal)
.withDstState(mEndState.statsLogOrdinal)
.withSrcState(StatsLogManager.containerTypeToAtomState(mStartState.containerType))
.withDstState(StatsLogManager.containerTypeToAtomState(mEndState.containerType))
.log(LAUNCHER_HOME_GESTURE);
}
}

View File

@ -49,6 +49,7 @@ import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.graphics.OverviewScrim;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.VibratorWrapper;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.AnimatorControllerWithResistance;
@ -206,7 +207,7 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch
private void maybeSwipeInteractionToOverviewComplete() {
if (mReachedOverview && mDetector.isSettlingState()) {
onSwipeInteractionCompleted(OVERVIEW);
onSwipeInteractionCompleted(OVERVIEW, Touch.SWIPE);
}
}
@ -250,7 +251,7 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch
private void goToOverviewOrHomeOnDragEnd(float velocity) {
boolean goToHomeInsteadOfOverview = !mMotionPauseDetector.isPaused();
if (goToHomeInsteadOfOverview) {
new OverviewToHomeAnim(mLauncher, ()-> onSwipeInteractionCompleted(NORMAL))
new OverviewToHomeAnim(mLauncher, ()-> onSwipeInteractionCompleted(NORMAL, Touch.FLING))
.animateWithVelocity(velocity);
}
if (mReachedOverview) {

View File

@ -57,9 +57,13 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.graphics.OverviewScrim;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.BaseSwipeDetector;
import com.android.launcher3.touch.BothAxesSwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.VibratorWrapper;
import com.android.quickstep.AnimatedFloat;
@ -283,6 +287,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
boolean horizontalFling = mSwipeDetector.isFling(velocity.x);
boolean verticalFling = mSwipeDetector.isFling(velocity.y);
boolean noFling = !horizontalFling && !verticalFling;
int logAction = noFling ? Touch.SWIPE : Touch.FLING;
if (mMotionPauseDetector.isPaused() && noFling) {
cancelAnimations();
@ -293,7 +298,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
overviewAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
onAnimationToStateCompleted(OVERVIEW);
onAnimationToStateCompleted(OVERVIEW, logAction);
}
});
overviewAnim.start();
@ -388,7 +393,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
}
nonOverviewAnim.setDuration(Math.max(xDuration, yDuration));
mNonOverviewAnim.setEndAction(() -> onAnimationToStateCompleted(targetState));
mNonOverviewAnim.setEndAction(() -> onAnimationToStateCompleted(targetState, logAction));
cancelAnimations();
xOverviewAnim.start();
@ -396,17 +401,27 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
nonOverviewAnim.start();
}
private void onAnimationToStateCompleted(LauncherState targetState) {
private void onAnimationToStateCompleted(LauncherState targetState, int logAction) {
mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
getDirectionForLog(), mSwipeDetector.getDownX(), mSwipeDetector.getDownY(),
LauncherLogProto.ContainerType.NAVBAR,
mStartState.containerType,
targetState.containerType,
mLauncher.getWorkspace().getCurrentPage());
mLauncher.getStatsLogManager().logger()
.withSrcState(LAUNCHER_STATE_HOME)
.withDstState(targetState.statsLogOrdinal)
.log(getLauncherAtomEvent(mStartState.statsLogOrdinal, targetState.statsLogOrdinal,
.withDstState(StatsLogManager.containerTypeToAtomState(targetState.containerType))
.log(getLauncherAtomEvent(mStartState.containerType, targetState.containerType,
targetState.ordinal > mStartState.ordinal
? LAUNCHER_UNKNOWN_SWIPEUP
: LAUNCHER_UNKNOWN_SWIPEDOWN));
mLauncher.getStateManager().goToState(targetState, false, this::clearState);
}
private int getDirectionForLog() {
return Utilities.isRtl(mLauncher.getResources()) ? Direction.LEFT : Direction.RIGHT;
}
private void cancelAnimations() {
if (mNonOverviewAnim != null) {
mNonOverviewAnim.getAnimationPlayer().cancel();

View File

@ -25,6 +25,7 @@ import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.views.RecentsView;
@ -72,4 +73,9 @@ public class OverviewToAllAppsTouchController extends PortraitStatesTouchControl
}
return fromState;
}
@Override
protected int getLogContainerTypeForNormalState(MotionEvent ev) {
return LauncherLogProto.ContainerType.WORKSPACE;
}
}

View File

@ -48,6 +48,8 @@ import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.util.LayoutUtils;
@ -170,6 +172,11 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
return fromState;
}
@Override
protected int getLogContainerTypeForNormalState(MotionEvent ev) {
return isTouchOverHotseat(mLauncher, ev) ? ContainerType.HOTSEAT : ContainerType.WORKSPACE;
}
private StateAnimationConfig getNormalToOverviewAnimation() {
mAllAppsInterpolatorWrapper.baseInterpolator = LINEAR;
@ -278,7 +285,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
private void cancelPendingAnim() {
if (mPendingAnimation != null) {
mPendingAnimation.finish(false);
mPendingAnimation.finish(false, Touch.SWIPE);
mPendingAnimation = null;
}
}
@ -313,8 +320,8 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
}
@Override
protected void onSwipeInteractionCompleted(LauncherState targetState) {
super.onSwipeInteractionCompleted(targetState);
protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
super.onSwipeInteractionCompleted(targetState, logAction);
if (mStartState == NORMAL && targetState == OVERVIEW) {
SystemUiProxy.INSTANCE.get(mLauncher).onOverviewShown(true, TAG);
}

View File

@ -21,7 +21,6 @@ import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
@ -42,6 +41,8 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SystemUiProxy;
@ -91,14 +92,14 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll
@Override
public void onDragStart(boolean start, float startDisplacement) {
super.onDragStart(start, startDisplacement);
mStartContainerType = LAUNCHER_STATE_BACKGROUND;
mStartContainerType = LauncherLogProto.ContainerType.NAVBAR;
ActivityManagerWrapper.getInstance()
.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
}
@Override
protected void onSwipeInteractionCompleted(LauncherState targetState) {
super.onSwipeInteractionCompleted(targetState);
protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
super.onSwipeInteractionCompleted(targetState, logAction);
}
@Override
@ -152,4 +153,14 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll
protected float getShiftRange() {
return mLauncher.getDeviceProfile().widthPx / 2f;
}
@Override
protected int getLogContainerTypeForNormalState(MotionEvent ev) {
return LauncherLogProto.ContainerType.NAVBAR;
}
@Override
protected int getDirectionForLog() {
return Utilities.isRtl(mLauncher.getResources()) ? Direction.LEFT : Direction.RIGHT;
}
}

View File

@ -15,12 +15,10 @@
*/
package com.android.launcher3.uioverrides.touchcontrollers;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN;
import static android.view.MotionEvent.ACTION_CANCEL;
import android.graphics.PointF;
import android.util.SparseArray;
@ -33,9 +31,12 @@ import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.SystemUiProxy;
import java.io.PrintWriter;
/**
@ -132,8 +133,9 @@ public class StatusBarTouchController implements TouchController {
int action = ev.getAction();
if (action == ACTION_UP || action == ACTION_CANCEL) {
dispatchTouchEvent(ev);
mLauncher.getStatsLogManager().logger()
.log(LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN);
mLauncher.getUserEventDispatcher().logActionOnContainer(action == ACTION_UP ?
Touch.FLING : Touch.SWIPE, Direction.DOWN, ContainerType.WORKSPACE,
mLauncher.getWorkspace().getCurrentPage());
setWindowSlippery(false);
return true;
}

View File

@ -36,6 +36,7 @@ import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.touch.BaseSwipeDetector;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.FlingBlockCheck;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
@ -202,7 +203,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
mCurrentAnimation.setPlayFraction(0);
}
if (mPendingAnimation != null) {
mPendingAnimation.finish(false);
mPendingAnimation.finish(false, Touch.SWIPE);
mPendingAnimation = null;
}
@ -284,6 +285,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
public void onDragEnd(float velocity) {
boolean fling = mDetector.isFling(velocity);
final boolean goingToEnd;
final int logAction;
boolean blockedFling = fling && mFlingBlockCheck.isBlocked();
if (blockedFling) {
fling = false;
@ -292,9 +294,11 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
float progress = mCurrentAnimation.getProgressFraction();
float interpolatedProgress = mCurrentAnimation.getInterpolatedProgress();
if (fling) {
logAction = Touch.FLING;
boolean goingUp = orientationHandler.isGoingUp(velocity, mIsRtl);
goingToEnd = goingUp == mCurrentAnimationIsGoingUp;
} else {
logAction = Touch.SWIPE;
goingToEnd = interpolatedProgress > SUCCESS_TRANSITION_PROGRESS;
}
long animationDuration = BaseSwipeDetector.calculateDuration(
@ -303,14 +307,14 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
animationDuration *= LauncherAnimUtils.blockedFlingDurationFactor(velocity);
}
mCurrentAnimation.setEndAction(() -> onCurrentAnimationEnd(goingToEnd));
mCurrentAnimation.setEndAction(() -> onCurrentAnimationEnd(goingToEnd, logAction));
mCurrentAnimation.startWithVelocity(mActivity, goingToEnd,
velocity, mEndDisplacement, animationDuration);
}
private void onCurrentAnimationEnd(boolean wasSuccess) {
private void onCurrentAnimationEnd(boolean wasSuccess, int logAction) {
if (mPendingAnimation != null) {
mPendingAnimation.finish(wasSuccess);
mPendingAnimation.finish(wasSuccess, logAction);
mPendingAnimation = null;
}
clearState();
@ -322,7 +326,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
mTaskBeingDragged = null;
mCurrentAnimation = null;
if (mPendingAnimation != null) {
mPendingAnimation.finish(false);
mPendingAnimation.finish(false, Touch.SWIPE);
mPendingAnimation = null;
}
}

View File

@ -75,8 +75,12 @@ import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.WindowBounds;
@ -97,7 +101,6 @@ import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.TaskInfoCompat;
@ -216,7 +219,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
private boolean mPassedOverviewThreshold;
private boolean mGestureStarted;
private boolean mLogDirectionUpOrLeft = true;
private int mLogAction = Touch.SWIPE;
private int mLogDirection = Direction.UP;
private PointF mDownPos;
private boolean mIsLikelyToStartNewTask;
@ -430,13 +434,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
mOnDeferredActivityLaunch);
mGestureState.runOnceAtState(STATE_END_TARGET_SET,
() -> {
mDeviceState.getRotationTouchHelper()
.onEndTargetCalculated(mGestureState.getEndTarget(),
mActivityInterface);
mRecentsView.onGestureEndTargetCalculated(mGestureState.getEndTarget());
});
() -> mDeviceState.getRotationTouchHelper().
onEndTargetCalculated(mGestureState.getEndTarget(),
mActivityInterface));
notifyGestureStartedAsync();
}
@ -741,6 +741,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
public void onGestureCancelled() {
updateDisplacement(0);
mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED);
mLogAction = Touch.SWIPE_NOOP;
handleNormalGestureEnd(0, false, new PointF(), true /* isCancel */);
}
@ -756,11 +757,13 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
boolean isFling = mGestureStarted && !mIsMotionPaused
&& Math.abs(endVelocity) > flingThreshold;
mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED);
mLogAction = isFling ? Touch.FLING : Touch.SWIPE;
boolean isVelocityVertical = Math.abs(velocity.y) > Math.abs(velocity.x);
if (isVelocityVertical) {
mLogDirectionUpOrLeft = velocity.y < 0;
mLogDirection = velocity.y < 0 ? Direction.UP : Direction.DOWN;
} else {
mLogDirectionUpOrLeft = velocity.x < 0;
mLogDirection = velocity.x < 0 ? Direction.LEFT : Direction.RIGHT;
}
mDownPos = downPos;
handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */);
@ -972,7 +975,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
break;
case LAST_TASK:
case NEW_TASK:
event = mLogDirectionUpOrLeft ? LAUNCHER_QUICKSWITCH_LEFT
event = (mLogDirection == Direction.LEFT)
? LAUNCHER_QUICKSWITCH_LEFT
: LAUNCHER_QUICKSWITCH_RIGHT;
break;
default:
@ -980,10 +984,12 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
}
StatsLogger logger = StatsLogManager.newInstance(mContext).logger()
.withSrcState(LAUNCHER_STATE_BACKGROUND)
.withDstState(endTarget.containerType);
.withDstState(StatsLogManager.containerTypeToAtomState(endTarget.containerType));
if (targetTask != null) {
logger.withItemInfo(targetTask.getItemInfo());
}
logger.log(event);
DeviceProfile dp = mDp;
if (dp == null || mDownPos == null) {
@ -993,8 +999,12 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
int pageIndex = endTarget == LAST_TASK
? LOG_NO_OP_PAGE_INDEX
: mRecentsView.getNextPage();
// TODO: set correct container using the pageIndex
logger.log(event);
UserEventDispatcher.newInstance(mContext).logStateChangeAction(
mLogAction, mLogDirection,
(int) mDownPos.x, (int) mDownPos.y,
ContainerType.NAVBAR, ContainerType.APP,
endTarget.containerType,
pageIndex);
}
/** Animates to the given progress, where 0 is the current app and 1 is overview. */
@ -1131,12 +1141,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, Q extends
anim.addOnUpdateListener((r, p) -> {
updateSysUiFlags(Math.max(p, mCurrentShift.value));
});
final int cuj = InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME;
anim.addAnimatorListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
Trace.beginAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
InteractionJankMonitorWrapper.begin(cuj);
if (mActivity != null) {
removeLiveTileOverlay();
}
@ -1150,13 +1158,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<?>, 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

View File

@ -152,6 +152,11 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
public abstract void onExitOverview(RotationTouchHelper deviceState,
Runnable exitRunnable);
/**
* Used for containerType in {@link com.android.launcher3.logging.UserEventDispatcher}
*/
public abstract int getContainerType();
public abstract boolean isInLiveTileMode();
public abstract void onLaunchTaskFailed();

View File

@ -28,6 +28,7 @@ import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
@ -143,6 +144,15 @@ public final class FallbackActivityInterface extends
// no-op, fake landscape not supported for 3P
}
@Override
public int getContainerType() {
RecentsActivity activity = getCreatedActivity();
boolean visible = activity != null && activity.isStarted() && activity.hasWindowFocus();
return visible
? LauncherLogProto.ContainerType.OTHER_LAUNCHER_APP
: LauncherLogProto.ContainerType.APP;
}
@Override
public boolean isInLiveTileMode() {
return false;

View File

@ -15,9 +15,6 @@
*/
package com.android.quickstep;
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.LAUNCHER_STATE_OVERVIEW;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import android.annotation.TargetApi;
@ -26,6 +23,7 @@ import android.content.Intent;
import android.os.Build;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@ -46,13 +44,13 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
* Defines the end targets of a gesture and the associated state.
*/
public enum GestureEndTarget {
HOME(true, LAUNCHER_STATE_HOME, false),
HOME(true, ContainerType.WORKSPACE, false),
RECENTS(true, LAUNCHER_STATE_OVERVIEW, true),
RECENTS(true, ContainerType.TASKSWITCHER, true),
NEW_TASK(false, LAUNCHER_STATE_BACKGROUND, true),
NEW_TASK(false, ContainerType.APP, true),
LAST_TASK(false, LAUNCHER_STATE_BACKGROUND, true);
LAST_TASK(false, ContainerType.APP, true);
GestureEndTarget(boolean isLauncher, int containerType,
boolean recentsAttachedToAppWindow) {

View File

@ -44,6 +44,7 @@ import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
@ -207,6 +208,10 @@ public final class LauncherActivityInterface extends
return false;
}
launcher.getUserEventDispatcher().logActionCommand(
LauncherLogProto.Action.Command.RECENTS_BUTTON,
getContainerType(),
LauncherLogProto.ContainerType.TASKSWITCHER);
launcher.getStateManager().goToState(OVERVIEW,
launcher.getStateManager().shouldAnimateStateChange(), onCompleteCallback);
return true;
@ -247,6 +252,13 @@ public final class LauncherActivityInterface extends
return true;
}
@Override
public int getContainerType() {
final Launcher launcher = getVisibleLauncher();
return launcher != null ? launcher.getStateManager().getState().containerType
: LauncherLogProto.ContainerType.APP;
}
@Override
public boolean isInLiveTileMode() {
Launcher launcher = getCreatedActivity();

View File

@ -30,6 +30,7 @@ import android.view.ViewConfiguration;
import androidx.annotation.BinderThread;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.views.RecentsView;
@ -46,6 +47,7 @@ public class OverviewCommandHelper {
private final Context mContext;
private final RecentsAnimationDeviceState mDeviceState;
private final RecentsModel mRecentsModel;
private final OverviewComponentObserver mOverviewComponentObserver;
private long mLastToggleTime;
@ -54,6 +56,7 @@ public class OverviewCommandHelper {
OverviewComponentObserver observer) {
mContext = context;
mDeviceState = deviceState;
mRecentsModel = RecentsModel.INSTANCE.get(mContext);
mOverviewComponentObserver = observer;
}
@ -147,6 +150,7 @@ public class OverviewCommandHelper {
private final AppToOverviewAnimationProvider<T> mAnimationProvider;
private final long mToggleClickedTime = SystemClock.uptimeMillis();
private boolean mUserEventLogged;
private ActivityInitListener mListener;
public RecentsActivityCommand() {
@ -156,7 +160,7 @@ public class OverviewCommandHelper {
ActivityManagerWrapper.getInstance().getRunningTask(), mDeviceState);
// Preload the plan
RecentsModel.INSTANCE.get(mContext).getTasks(null);
mRecentsModel.getTasks(null);
}
@Override
@ -208,6 +212,13 @@ public class OverviewCommandHelper {
private boolean onActivityReady(Boolean wasVisible) {
final T activity = mActivityInterface.getCreatedActivity();
if (!mUserEventLogged) {
activity.getUserEventDispatcher().logActionCommand(
LauncherLogProto.Action.Command.RECENTS_BUTTON,
mActivityInterface.getContainerType(),
LauncherLogProto.ContainerType.TASKSWITCHER);
mUserEventLogged = true;
}
return mAnimationProvider.onActivityReady(activity, wasVisible);
}

View File

@ -41,10 +41,7 @@ import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAnimationRunner;
import com.android.launcher3.LauncherAnimationRunner.AnimationResult;
import com.android.launcher3.R;
import com.android.launcher3.WrappedAnimationRunnerImpl;
import com.android.launcher3.WrappedLauncherAnimationRunner;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@ -90,9 +87,6 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
private StateManager<RecentsState> mStateManager;
// Strong refs to runners which are cleared when the activity is destroyed
private WrappedAnimationRunnerImpl mActivityLaunchAnimationRunner;
/**
* Init drag layer and overview panel views.
*/
@ -124,6 +118,7 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
* etc.)
*/
protected void onHandleConfigChanged() {
mUserEventDispatcher = null;
initDeviceProfile();
AbstractFloatingView.closeOpenViews(this, true,
@ -175,11 +170,8 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
}
final TaskView taskView = (TaskView) v;
mActivityLaunchAnimationRunner = new WrappedAnimationRunnerImpl() {
@Override
public Handler getHandler() {
return mUiHandler;
}
RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mUiHandler,
true /* startAtFrontOfQueue */) {
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
@ -190,10 +182,8 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
result.setAnimation(anim, RecentsActivity.this);
}
};
final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner<>(
mActivityLaunchAnimationRunner, true /* startAtFrontOfQueue */);
return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
wrapper, RECENTS_LAUNCH_DURATION,
runner, RECENTS_LAUNCH_DURATION,
RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION
- STATUS_BAR_TRANSITION_PRE_DELAY));
}
@ -298,7 +288,6 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
protected void onDestroy() {
super.onDestroy();
ACTIVITY_TRACKER.onActivityDestroyed(this);
mActivityLaunchAnimationRunner = null;
}
@Override

View File

@ -18,6 +18,7 @@ package com.android.quickstep;
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.createAndStartNewLooper;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
import android.annotation.TargetApi;
@ -25,11 +26,11 @@ import android.app.ActivityManager;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.os.Build;
import android.os.Looper;
import android.os.Process;
import android.os.UserHandle;
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.util.Executors.SimpleThreadFactory;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@ -39,8 +40,6 @@ import com.android.systemui.shared.system.TaskStackChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
/**
@ -53,9 +52,6 @@ public class RecentsModel extends TaskStackChangeListener {
public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
new MainThreadInitializedObject<>(RecentsModel::new);
private static final Executor RECENTS_MODEL_EXECUTOR = Executors.newSingleThreadExecutor(
new SimpleThreadFactory("TaskThumbnailIconCache-", THREAD_PRIORITY_BACKGROUND));
private final List<TaskVisualsChangeListener> mThumbnailChangeListeners = new ArrayList<>();
private final Context mContext;
@ -65,10 +61,12 @@ public class RecentsModel extends TaskStackChangeListener {
private RecentsModel(Context context) {
mContext = context;
Looper looper =
createAndStartNewLooper("TaskThumbnailIconCache", THREAD_PRIORITY_BACKGROUND);
mTaskList = new RecentTasksList(MAIN_EXECUTOR,
new KeyguardManagerCompat(context), ActivityManagerWrapper.getInstance());
mIconCache = new TaskIconCache(context, RECENTS_MODEL_EXECUTOR);
mThumbnailCache = new TaskThumbnailCache(context, RECENTS_MODEL_EXECUTOR);
mIconCache = new TaskIconCache(context, looper);
mThumbnailCache = new TaskThumbnailCache(context, looper);
ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
IconProvider.registerIconChangeListener(context,

View File

@ -17,6 +17,7 @@ package com.android.quickstep;
import static com.android.launcher3.FastBitmapDrawable.newIcon;
import static com.android.launcher3.uioverrides.QuickstepLauncher.GO_LOW_RAM_RECENTS_ENABLED;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.app.ActivityManager.TaskDescription;
import android.content.Context;
@ -26,6 +27,8 @@ import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.util.SparseArray;
import android.view.accessibility.AccessibilityManager;
@ -34,11 +37,12 @@ import androidx.annotation.WorkerThread;
import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.util.Preconditions;
import com.android.quickstep.util.CancellableTask;
import com.android.quickstep.util.TaskKeyLruCache;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
@ -46,7 +50,6 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.TaskDescriptionCompat;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
/**
@ -54,7 +57,7 @@ import java.util.function.Consumer;
*/
public class TaskIconCache {
private final Executor mBgExecutor;
private final Handler mBackgroundHandler;
private final AccessibilityManager mAccessibilityManager;
private final Context mContext;
@ -62,9 +65,9 @@ public class TaskIconCache {
private final SparseArray<BitmapInfo> mDefaultIcons = new SparseArray<>();
private final IconProvider mIconProvider;
public TaskIconCache(Context context, Executor bgExecutor) {
public TaskIconCache(Context context, Looper backgroundLooper) {
mContext = context;
mBgExecutor = bgExecutor;
mBackgroundHandler = new Handler(backgroundLooper);
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
Resources res = context.getResources();
@ -80,27 +83,31 @@ public class TaskIconCache {
* @param callback The callback to receive the task after its data has been populated.
* @return A cancelable handle to the request
*/
public CancellableTask updateIconInBackground(Task task, Consumer<Task> callback) {
public IconLoadRequest updateIconInBackground(Task task, Consumer<Task> callback) {
Preconditions.assertUIThread();
if (task.icon != null) {
// Nothing to load, the icon is already loaded
callback.accept(task);
return null;
}
CancellableTask<TaskCacheEntry> request = new CancellableTask<TaskCacheEntry>() {
@Override
public TaskCacheEntry getResultOnBg() {
return getCacheEntry(task);
}
IconLoadRequest request = new IconLoadRequest(mBackgroundHandler) {
@Override
public void handleResult(TaskCacheEntry result) {
task.icon = result.icon;
task.titleDescription = result.contentDescription;
callback.accept(task);
public void run() {
TaskCacheEntry entry = getCacheEntry(task);
if (isCanceled()) {
// We don't call back to the provided callback in this case
return;
}
MAIN_EXECUTOR.execute(() -> {
task.icon = entry.icon;
task.titleDescription = entry.contentDescription;
callback.accept(task);
onEnd();
});
}
};
mBgExecutor.execute(request);
Utilities.postAsyncCallback(mBackgroundHandler, request);
return request;
}
@ -113,8 +120,9 @@ public class TaskIconCache {
}
void invalidateCacheEntries(String pkg, UserHandle handle) {
mBgExecutor.execute(() -> mIconCache.removeAll(key ->
pkg.equals(key.getPackageName()) && handle.getIdentifier() == key.userId));
Utilities.postAsyncCallback(mBackgroundHandler,
() -> mIconCache.removeAll(key ->
pkg.equals(key.getPackageName()) && handle.getIdentifier() == key.userId));
}
@WorkerThread
@ -200,6 +208,12 @@ public class TaskIconCache {
}
}
public static abstract class IconLoadRequest extends HandlerRunnable {
IconLoadRequest(Handler handler) {
super(handler, null);
}
}
private static class TaskCacheEntry {
public Drawable icon;
public String contentDescription = "";

View File

@ -21,6 +21,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SELECTIONS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
import android.app.Activity;
import android.app.ActivityOptions;
@ -38,6 +39,7 @@ import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.popup.SystemShortcut.AppInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.InstantAppResolver;
import com.android.quickstep.views.RecentsView;
@ -226,6 +228,8 @@ public interface TaskShortcutFactory {
@Override
protected boolean onActivityStarted(BaseDraggingActivity activity) {
activity.getUserEventDispatcher().logActionOnControl(TAP,
LauncherLogProto.ControlType.SPLIT_SCREEN_TARGET);
return true;
}
};

View File

@ -15,12 +15,17 @@
*/
package com.android.quickstep;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.content.Context;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Looper;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.util.Preconditions;
import com.android.quickstep.util.CancellableTask;
import com.android.quickstep.util.TaskKeyLruCache;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
@ -28,12 +33,11 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import java.util.ArrayList;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
public class TaskThumbnailCache {
private final Executor mBgExecutor;
private final Handler mBackgroundHandler;
private final int mCacheSize;
private final TaskKeyLruCache<ThumbnailData> mCache;
@ -90,8 +94,8 @@ public class TaskThumbnailCache {
}
}
public TaskThumbnailCache(Context context, Executor bgExecutor) {
mBgExecutor = bgExecutor;
public TaskThumbnailCache(Context context, Looper backgroundLooper) {
mBackgroundHandler = new Handler(backgroundLooper);
mHighResLoadingState = new HighResLoadingState(context);
Resources res = context.getResources();
@ -126,7 +130,7 @@ public class TaskThumbnailCache {
* @param callback The callback to receive the task after its data has been populated.
* @return A cancelable handle to the request
*/
public CancellableTask updateThumbnailInBackground(
public ThumbnailLoadRequest updateThumbnailInBackground(
Task task, Consumer<ThumbnailData> callback) {
Preconditions.assertUIThread();
@ -138,13 +142,14 @@ public class TaskThumbnailCache {
return null;
}
return updateThumbnailInBackground(task.key, !mHighResLoadingState.isEnabled(), t -> {
task.thumbnail = t;
callback.accept(t);
});
}
private CancellableTask updateThumbnailInBackground(TaskKey key, boolean lowResolution,
private ThumbnailLoadRequest updateThumbnailInBackground(TaskKey key, boolean lowResolution,
Consumer<ThumbnailData> callback) {
Preconditions.assertUIThread();
@ -155,20 +160,26 @@ public class TaskThumbnailCache {
return null;
}
CancellableTask<ThumbnailData> request = new CancellableTask<ThumbnailData>() {
ThumbnailLoadRequest request = new ThumbnailLoadRequest(mBackgroundHandler,
lowResolution) {
@Override
public ThumbnailData getResultOnBg() {
return ActivityManagerWrapper.getInstance().getTaskThumbnail(
public void run() {
ThumbnailData thumbnail = ActivityManagerWrapper.getInstance().getTaskThumbnail(
key.id, lowResolution);
}
@Override
public void handleResult(ThumbnailData result) {
mCache.put(key, result);
callback.accept(result);
MAIN_EXECUTOR.execute(() -> {
if (isCanceled()) {
// We don't call back to the provided callback in this case
return;
}
mCache.put(key, thumbnail);
callback.accept(thumbnail);
onEnd();
});
}
};
mBgExecutor.execute(request);
Utilities.postAsyncCallback(mBackgroundHandler, request);
return request;
}
@ -207,6 +218,15 @@ public class TaskThumbnailCache {
return mEnableTaskSnapshotPreloading && mHighResLoadingState.mVisible;
}
public static abstract class ThumbnailLoadRequest extends HandlerRunnable {
public final boolean mLowResolution;
ThumbnailLoadRequest(Handler handler, boolean lowResolution) {
super(handler, null);
mLowResolution = lowResolution;
}
}
/**
* @return Whether device supports low-res thumbnails. Low-res files are an optimization
* for faster load times of snapshots. Devices can optionally disable low-res files so that

View File

@ -20,7 +20,6 @@ import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.GestureState.DEFAULT_STATE;
@ -688,7 +687,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
gestureState, shouldDefer, this::onConsumerInactive,
mInputMonitorCompat, mInputEventReceiver, disableHorizontalSwipe, factory);
mInputMonitorCompat, disableHorizontalSwipe, factory);
}
private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState) {
@ -710,10 +709,8 @@ public class TouchInteractionService extends Service implements PluginListener<O
if (activity.getRootView().hasWindowFocus()
|| previousGestureState.isRunningAnimationToLauncher()
|| (ASSISTANT_GIVES_LAUNCHER_FOCUS.get()
&& forceOverviewInputConsumer)
|| (ENABLE_QUICKSTEP_LIVE_TILE.get())
&& gestureState.getActivityInterface().isInLiveTileMode()) {
|| (FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS.get()
&& forceOverviewInputConsumer)) {
return new OverviewInputConsumer(gestureState, activity, mInputMonitorCompat,
false /* startingInActivityBounds */);
} else {
@ -737,8 +734,6 @@ public class TouchInteractionService extends Service implements PluginListener<O
private void reset() {
mConsumer = mUncheckedConsumer = mResetGestureInputConsumer;
mGestureState = DEFAULT_STATE;
// By default, use batching of the input events
mInputEventReceiver.setBatchingEnabled(true);
}
private void preloadOverview(boolean fromInit) {

View File

@ -15,7 +15,6 @@
*/
package com.android.quickstep.fallback;
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.fallback.RecentsState.MODAL_TASK;
@ -28,7 +27,6 @@ import android.util.AttributeSet;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.quickstep.FallbackActivityInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
@ -76,14 +74,14 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity>
}
/**
* When the gesture ends and we're going to recents view, we also remove the temporary
* When the gesture ends and recents view become interactive, we also remove the temporary
* invisible tile added for the home task. This also pushes the remaining tiles back
* to the center.
*/
@Override
public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) {
super.onGestureEndTargetCalculated(endTarget);
if (mHomeTaskInfo != null && endTarget == RECENTS) {
public void onGestureAnimationEnd() {
super.onGestureAnimationEnd();
if (mHomeTaskInfo != null) {
TaskView tv = getTaskView(mHomeTaskInfo.taskId);
if (tv != null) {
PendingAnimation pa = createTaskDismissAnimation(tv, true, false, 150);

View File

@ -25,6 +25,12 @@ import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPLEFT;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPRIGHT;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.FLING;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.SWIPE;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.SWIPE_NOOP;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.NAVBAR;
import android.animation.ValueAnimator;
import android.content.Context;
@ -41,6 +47,7 @@ import android.view.ViewConfiguration;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.quickstep.BaseActivityInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.InputConsumer;
@ -73,6 +80,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer {
private float mTimeFraction;
private long mDragTime;
private float mLastProgress;
private int mDirection;
private BaseActivityInterface mActivityInterface;
private final float mDragDistThreshold;
@ -189,6 +197,8 @@ public class AssistantInputConsumer extends DelegateInputConsumer {
if (mState != STATE_DELEGATE_ACTIVE && !mLaunchedAssistant) {
ValueAnimator animator = ValueAnimator.ofFloat(mLastProgress, 0)
.setDuration(RETRACT_ANIMATION_DURATION_MS);
UserEventDispatcher.newInstance(mContext).logActionOnContainer(
SWIPE_NOOP, mDirection, NAVBAR);
animator.addUpdateListener(valueAnimator -> {
float progress = (float) valueAnimator.getAnimatedValue();
SystemUiProxy.INSTANCE.get(mContext).onAssistantProgress(progress);
@ -213,7 +223,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer {
mLastProgress = Math.min(mDistance * 1f / mDragDistThreshold, 1) * mTimeFraction;
if (mDistance >= mDragDistThreshold && mTimeFraction >= 1) {
SystemUiProxy.INSTANCE.get(mContext).onAssistantGestureCompletion(0);
startAssistantInternal();
startAssistantInternal(SWIPE);
Bundle args = new Bundle();
args.putInt(OPA_BUNDLE_TRIGGER, OPA_BUNDLE_TRIGGER_DIAG_SWIPE_GESTURE);
@ -226,7 +236,10 @@ public class AssistantInputConsumer extends DelegateInputConsumer {
}
}
private void startAssistantInternal() {
private void startAssistantInternal(int gestureType) {
UserEventDispatcher.newInstance(mContext)
.logActionOnContainer(gestureType, mDirection, NAVBAR);
BaseDraggingActivity launcherActivity = mActivityInterface.getCreatedActivity();
if (launcherActivity != null) {
launcherActivity.getRootView().performHapticFeedback(
@ -240,6 +253,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer {
*/
private boolean isValidAssistantGestureAngle(float deltaX, float deltaY) {
float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
mDirection = angle > 90 ? UPLEFT : UPRIGHT;
// normalize so that angle is measured clockwise from horizontal in the bottom right corner
// and counterclockwise from horizontal in the bottom left corner
@ -258,7 +272,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer {
mLastProgress = 1;
SystemUiProxy.INSTANCE.get(mContext).onAssistantGestureCompletion(
(float) Math.sqrt(velocityX * velocityX + velocityY * velocityY));
startAssistantInternal();
startAssistantInternal(FLING);
Bundle args = new Bundle();
args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE);

View File

@ -67,7 +67,6 @@ import com.android.quickstep.util.CachedEventDispatcher;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.util.NavBarPosition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
import com.android.systemui.shared.system.InputMonitorCompat;
import java.util.function.Consumer;
@ -93,7 +92,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
private RecentsAnimationCallbacks mActiveCallbacks;
private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher();
private final InputMonitorCompat mInputMonitorCompat;
private final InputEventReceiver mInputEventReceiver;
private final BaseActivityInterface mActivityInterface;
private final AbsSwipeUpHandler.Factory mHandlerFactory;
@ -137,8 +135,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState,
boolean isDeferredDownTarget, Consumer<OtherActivityInputConsumer> onCompleteCallback,
InputMonitorCompat inputMonitorCompat, InputEventReceiver inputEventReceiver,
boolean disableHorizontalSwipe, Factory handlerFactory) {
InputMonitorCompat inputMonitorCompat, boolean disableHorizontalSwipe,
Factory handlerFactory) {
super(base);
mDeviceState = deviceState;
mNavBarPosition = mDeviceState.getNavBarPosition();
@ -156,7 +154,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
mOnCompleteCallback = onCompleteCallback;
mVelocityTracker = VelocityTracker.obtain();
mInputMonitorCompat = inputMonitorCompat;
mInputEventReceiver = inputEventReceiver;
boolean continuingPreviousGesture = mTaskAnimationManager.isRecentsAnimationRunning();
mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget;
@ -218,9 +215,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
switch (ev.getActionMasked()) {
case ACTION_DOWN: {
// Until we detect the gesture, handle events as we receive them
mInputEventReceiver.setBatchingEnabled(false);
Object traceToken = TraceHelper.INSTANCE.beginSection(DOWN_EVT,
FLAG_CHECK_FOR_RACE_CONDITIONS);
mActivePointerId = ev.getPointerId(0);
@ -357,8 +351,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
}
TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
mInputMonitorCompat.pilferPointers();
// Once we detect the gesture, we can enable batching to reduce further updates
mInputEventReceiver.setBatchingEnabled(true);
mActivityInterface.closeOverlay();
ActivityManagerWrapper.getInstance().closeSystemWindows(

View File

@ -15,7 +15,6 @@
*/
package com.android.quickstep.inputconsumers;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE;
@ -28,6 +27,9 @@ import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.quickstep.GestureState;
import com.android.quickstep.InputConsumer;
import com.android.quickstep.RecentsAnimationDeviceState;
@ -80,12 +82,17 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer,
mContext.startActivity(mGestureState.getHomeIntent());
ActiveGestureLog.INSTANCE.addLog("startQuickstep");
BaseActivity activity = BaseDraggingActivity.fromContext(mContext);
int state = (mGestureState != null && mGestureState.getEndTarget() != null)
int pageIndex = -1; // This number doesn't reflect workspace page index.
// It only indicates that launcher client screen was shown.
int containerType = (mGestureState != null && mGestureState.getEndTarget() != null)
? mGestureState.getEndTarget().containerType
: LAUNCHER_STATE_HOME;
: LauncherLogProto.ContainerType.WORKSPACE;
activity.getUserEventDispatcher().logActionOnContainer(
wasFling ? Touch.FLING : Touch.SWIPE, Direction.UP, containerType, pageIndex);
activity.getUserEventDispatcher().setPreviousHomeGesture(true);
activity.getStatsLogManager().logger()
.withSrcState(LAUNCHER_STATE_BACKGROUND)
.withDstState(state)
.withSrcState(LAUNCHER_STATE_HOME)
.withDstState(LAUNCHER_STATE_HOME)
.withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
.setWorkspace(
LauncherAtom.WorkspaceContainer.newBuilder()

View File

@ -24,7 +24,7 @@ import com.android.quickstep.interaction.TutorialController.TutorialType;
/** Shows the Home gesture interactive tutorial. */
public class AssistantGestureTutorialFragment extends TutorialFragment {
@Override
Integer getHandAnimationResId() {
int getHandAnimationResId() {
return R.drawable.assistant_gesture;
}

View File

@ -24,7 +24,7 @@ import com.android.quickstep.interaction.TutorialController.TutorialType;
/** Shows the Back gesture interactive tutorial. */
public class BackGestureTutorialFragment extends TutorialFragment {
@Override
Integer getHandAnimationResId() {
int getHandAnimationResId() {
return R.drawable.back_gesture;
}

View File

@ -143,10 +143,6 @@ public class EdgeBackGestureHandler implements OnTouchListener {
return false;
}
boolean onInterceptTouch(MotionEvent motionEvent) {
return isWithinTouchRegion((int) motionEvent.getX(), (int) motionEvent.getY());
}
private boolean isWithinTouchRegion(int x, int y) {
// Disallow if too far from the edge
if (x > mEdgeWidth + mLeftInset && x < (mDisplaySize.x - mEdgeWidth - mRightInset)) {

View File

@ -21,7 +21,7 @@ import com.android.quickstep.interaction.TutorialController.TutorialType;
/** Shows the Home gesture interactive tutorial. */
public class HomeGestureTutorialFragment extends TutorialFragment {
@Override
Integer getHandAnimationResId() {
int getHandAnimationResId() {
return R.drawable.home_gesture;
}

View File

@ -250,12 +250,6 @@ public class NavBarGestureHandler implements OnTouchListener,
return intercepted;
}
boolean onInterceptTouch(MotionEvent event) {
return mAssistantLeftRegion.contains(event.getX(), event.getY())
|| mAssistantRightRegion.contains(event.getX(), event.getY())
|| event.getY() >= mDisplaySize.y - mBottomGestureHeight;
}
protected void onMotionPauseDetected() {
VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
}

View File

@ -21,7 +21,7 @@ import com.android.quickstep.interaction.TutorialController.TutorialType;
/** Shows the Overview gesture interactive tutorial. */
public class OverviewGestureTutorialFragment extends TutorialFragment {
@Override
Integer getHandAnimationResId() {
int getHandAnimationResId() {
return R.drawable.overview_gesture;
}

View File

@ -1,44 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.interaction;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
import androidx.fragment.app.FragmentManager;
/** Root layout that TutorialFragment uses to intercept motion events. */
public class RootSandboxLayout extends RelativeLayout {
public RootSandboxLayout(Context context) {
super(context);
}
public RootSandboxLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RootSandboxLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent motionEvent) {
return ((TutorialFragment) FragmentManager.findFragment(this))
.onInterceptTouch(motionEvent);
}
}

View File

@ -1,44 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.interaction;
import android.content.Context;
import android.view.View;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.graphics.LauncherPreviewRenderer;
/** Renders a fake Launcher for use in the Sandbox. */
class SandboxLauncherRenderer extends LauncherPreviewRenderer {
SandboxLauncherRenderer(Context context, InvariantDeviceProfile idp, boolean migrated) {
super(context, idp, migrated);
}
@Override
public boolean shouldShowRealLauncherPreview() {
return false;
}
@Override
public boolean shouldShowQsb() {
return false;
}
@Override
public View.OnLongClickListener getWorkspaceChildOnLongClickListener() {
return null;
}
}

View File

@ -1,102 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.interaction;
import android.graphics.PointF;
import android.view.View;
import androidx.annotation.Nullable;
import com.android.launcher3.R;
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
/** A {@link TutorialController} for the Sandbox Mode. */
public class SandboxModeTutorialController extends SwipeUpGestureTutorialController {
SandboxModeTutorialController(SandboxModeTutorialFragment fragment, TutorialType tutorialType) {
super(fragment, tutorialType);
}
@Nullable
@Override
Integer getTitleStringId() {
return R.string.sandbox_mode_title;
}
@Nullable
@Override
Integer getSubtitleStringId() {
return R.string.sandbox_mode_subtitle;
}
@Nullable
@Override
Integer getActionButtonStringId() {
return R.string.gesture_tutorial_action_button_label_done;
}
@Override
void onActionButtonClicked(View button) {
mTutorialFragment.closeTutorial();
}
@Override
public void onBackGestureAttempted(BackGestureResult result) {
switch (result) {
case BACK_COMPLETED_FROM_LEFT:
case BACK_COMPLETED_FROM_RIGHT:
showRippleEffect(null);
showFeedback(R.string.sandbox_mode_back_gesture_feedback_successful);
break;
case BACK_CANCELLED_FROM_RIGHT:
showFeedback(R.string.back_gesture_feedback_cancelled_right_edge);
break;
case BACK_CANCELLED_FROM_LEFT:
showFeedback(R.string.back_gesture_feedback_cancelled_left_edge);
break;
case BACK_NOT_STARTED_TOO_FAR_FROM_EDGE:
showFeedback(R.string.sandbox_mode_back_gesture_feedback_swipe_too_far_from_edge);
break;
}
}
@Override
public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
switch (result) {
case ASSISTANT_COMPLETED:
showRippleEffect(null);
showFeedback(R.string.sandbox_mode_assistant_gesture_feedback_successful);
break;
case HOME_GESTURE_COMPLETED:
animateFakeTaskViewHome(finalVelocity, () -> {
showFeedback(R.string.sandbox_mode_home_gesture_feedback_successful);
});
break;
case OVERVIEW_GESTURE_COMPLETED:
fadeOutFakeTaskView(true, () -> {
showFeedback(R.string.sandbox_mode_overview_gesture_feedback_successful);
});
break;
case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
case HOME_OR_OVERVIEW_CANCELLED:
case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
break;
}
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.interaction;
import android.view.MotionEvent;
import android.view.View;
import com.android.quickstep.interaction.TutorialController.TutorialType;
/** Shows the general navigation gesture sandbox environment. */
public class SandboxModeTutorialFragment extends TutorialFragment {
@Override
TutorialController createController(TutorialType type) {
return new SandboxModeTutorialController(this, type);
}
@Override
Class<? extends TutorialController> 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);
}
}

View File

@ -47,12 +47,11 @@ abstract class TutorialController implements BackGestureAttemptCallback,
final TextView mTitleTextView;
final TextView mSubtitleTextView;
final TextView mFeedbackView;
final View mLauncherView;
final ClipIconView mFakeIconView;
final View mFakeTaskView;
final View mRippleView;
final RippleDrawable mRippleDrawable;
@Nullable final TutorialHandAnimation mHandCoachingAnimation;
final TutorialHandAnimation mHandCoachingAnimation;
final ImageView mHandCoachingView;
final Button mActionTextButton;
final Button mActionButton;
@ -69,7 +68,6 @@ abstract class TutorialController implements BackGestureAttemptCallback,
mTitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_title_view);
mSubtitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_subtitle_view);
mFeedbackView = rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_view);
mLauncherView = tutorialFragment.getLauncherView();
mFakeIconView = rootView.findViewById(R.id.gesture_tutorial_fake_icon_view);
mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view);
mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
@ -145,16 +143,13 @@ abstract class TutorialController implements BackGestureAttemptCallback,
void onActionTextButtonClicked(View button) {}
void showHandCoachingAnimation() {
if (isComplete() || mHandCoachingAnimation == null) {
if (isComplete()) {
return;
}
mHandCoachingAnimation.startLoopedAnimation(mTutorialType);
}
void hideHandCoachingAnimation() {
if (mHandCoachingAnimation == null) {
return;
}
mHandCoachingAnimation.stop();
mHandCoachingView.setVisibility(View.INVISIBLE);
}
@ -167,10 +162,8 @@ abstract class TutorialController implements BackGestureAttemptCallback,
if (isComplete()) {
hideHandCoachingAnimation();
mLauncherView.setVisibility(View.INVISIBLE);
} else {
showHandCoachingAnimation();
mLauncherView.setVisibility(View.VISIBLE);
}
}
@ -213,8 +206,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
return mTutorialType == TutorialType.BACK_NAVIGATION_COMPLETE
|| mTutorialType == TutorialType.HOME_NAVIGATION_COMPLETE
|| mTutorialType == TutorialType.OVERVIEW_NAVIGATION_COMPLETE
|| mTutorialType == TutorialType.ASSISTANT_COMPLETE
|| mTutorialType == TutorialType.SANDBOX_MODE;
|| mTutorialType == TutorialType.ASSISTANT_COMPLETE;
}
/** Denotes the type of the tutorial. */
@ -227,7 +219,6 @@ abstract class TutorialController implements BackGestureAttemptCallback,
OVERVIEW_NAVIGATION,
OVERVIEW_NAVIGATION_COMPLETE,
ASSISTANT,
ASSISTANT_COMPLETE,
SANDBOX_MODE
ASSISTANT_COMPLETE
}
}

View File

@ -31,7 +31,6 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
import com.android.quickstep.interaction.TutorialController.TutorialType;
@ -43,10 +42,9 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
TutorialType mTutorialType;
@Nullable TutorialController mTutorialController = null;
View mRootView;
@Nullable TutorialHandAnimation mHandCoachingAnimation = null;
TutorialHandAnimation mHandCoachingAnimation;
EdgeBackGestureHandler mEdgeBackGestureHandler;
NavBarGestureHandler mNavBarGestureHandler;
private View mLauncherView;
public static TutorialFragment newInstance(TutorialType tutorialType) {
TutorialFragment fragment = getFragmentForTutorialType(tutorialType);
@ -76,17 +74,13 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
case ASSISTANT:
case ASSISTANT_COMPLETE:
return new AssistantGestureTutorialFragment();
case SANDBOX_MODE:
return new SandboxModeTutorialFragment();
default:
Log.e(LOG_TAG, "Failed to find an appropriate fragment for " + tutorialType.name());
}
return null;
}
@Nullable Integer getHandAnimationResId() {
return null;
}
abstract int getHandAnimationResId();
abstract TutorialController createController(TutorialType type);
@ -120,14 +114,8 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
return insets;
});
mRootView.setOnTouchListener(this);
Integer handAnimationResId = getHandAnimationResId();
if (handAnimationResId != null) {
mHandCoachingAnimation =
new TutorialHandAnimation(getContext(), mRootView, handAnimationResId);
}
InvariantDeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(getContext());
mLauncherView = new SandboxLauncherRenderer(getContext(), dp, true).getRenderedView();
((ViewGroup) mRootView).addView(mLauncherView, 0);
mHandCoachingAnimation = new TutorialHandAnimation(getContext(), mRootView,
getHandAnimationResId());
return mRootView;
}
@ -140,25 +128,16 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
@Override
public void onPause() {
super.onPause();
if (mHandCoachingAnimation != null) {
mHandCoachingAnimation.stop();
}
mHandCoachingAnimation.stop();
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
// Note: Using logical-or to ensure both functions get called.
// Note: Using logical or to ensure both functions get called.
return mEdgeBackGestureHandler.onTouch(view, motionEvent)
| mNavBarGestureHandler.onTouch(view, motionEvent);
}
boolean onInterceptTouch(MotionEvent motionEvent) {
// Note: Using logical-or to ensure both functions get called.
return mEdgeBackGestureHandler.onInterceptTouch(motionEvent)
| mNavBarGestureHandler.onInterceptTouch(motionEvent);
}
void onAttachedToWindow() {
mEdgeBackGestureHandler.setViewGroupParent((ViewGroup) getRootView());
}
@ -189,11 +168,7 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
return mRootView;
}
View getLauncherView() {
return mLauncherView;
}
@Nullable TutorialHandAnimation getHandAnimation() {
TutorialHandAnimation getHandAnimation() {
return mHandCoachingAnimation;
}

View File

@ -1,68 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.util;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import androidx.annotation.UiThread;
import androidx.annotation.WorkerThread;
/**
* Utility class to executore a task on background and post the result on UI thread
*/
public abstract class CancellableTask<T> 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;
}
}

View File

@ -18,10 +18,8 @@ package com.android.quickstep.util;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
@ -112,7 +110,7 @@ public class OverviewToHomeAnim {
boolean isLayoutNaturalToLauncher = recentsView.getPagedOrientationHandler()
.isLayoutNaturalToLauncher();
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, isLayoutNaturalToLauncher
? clampToProgress(FAST_OUT_SLOW_IN, 0, 0.75f) : FINAL_FRAME);
? DEACCEL : FINAL_FRAME);
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, FINAL_FRAME);
config.setInterpolator(ANIM_OVERVIEW_SCALE, FINAL_FRAME);
config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, INSTANT);

View File

@ -23,6 +23,7 @@ import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static com.android.launcher3.logging.LoggerUtils.extractObjectNameAndAddress;
import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
@ -71,7 +72,6 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
private static final String TAG = "RecentsOrientedState";
private static final boolean DEBUG = false;
private static final String DELIMITER_DOT = "\\.";
private ContentObserver mSystemAutoRotateObserver = new ContentObserver(new Handler()) {
@Override
@ -534,13 +534,4 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
? idp.landscapeProfile
: idp.portraitProfile;
}
/**
* String conversion for only the helpful parts of {@link Object#toString()} method
* @param stringToExtract "foo.bar.baz.MyObject@1234"
* @return "MyObject@1234"
*/
private static String extractObjectNameAndAddress(String stringToExtract) {
return stringToExtract.substring(stringToExtract.lastIndexOf(DELIMITER_DOT));
}
}

View File

@ -21,8 +21,6 @@ import android.content.Context;
import android.os.Handler;
import com.android.launcher3.LauncherAnimationRunner;
import com.android.launcher3.LauncherAnimationRunner.AnimationResult;
import com.android.launcher3.WrappedAnimationRunnerImpl;
import com.android.launcher3.WrappedLauncherAnimationRunner;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
@ -30,17 +28,14 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
public abstract class RemoteAnimationProvider {
WrappedAnimationRunnerImpl mAnimationRunner;
LauncherAnimationRunner mAnimationRunner;
public abstract AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets);
ActivityOptions toActivityOptions(Handler handler, long duration, Context context) {
mAnimationRunner = new WrappedAnimationRunnerImpl() {
@Override
public Handler getHandler() {
return handler;
}
mAnimationRunner = new LauncherAnimationRunner(handler,
false /* startAtFrontOfQueue */) {
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
@ -50,6 +45,7 @@ public abstract class RemoteAnimationProvider {
};
final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner(
mAnimationRunner, false /* startAtFrontOfQueue */);
return ActivityOptionsCompat.makeRemoteAnimation(
new RemoteAnimationAdapterCompat(wrapper, duration, 0));
}

View File

@ -278,6 +278,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
int start = mOrientationState.getOrientationHandler()
.getPrimaryValue(mTaskRect.left, mTaskRect.top);
mScrollState.screenCenter = start + mScrollState.scroll + mScrollState.halfPageSize;
mScrollState.pageParentScale = recentsViewScale.value;
mScrollState.updateInterpolation(start);
mCurveScale = TaskView.getCurveScaleForInterpolation(mScrollState.linearInterpolation);
}
@ -296,9 +297,9 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
mMatrix.postTranslate(insets.left, insets.top);
mMatrix.postScale(scale, scale);
// Apply TaskView matrix: scale, translate, scroll
mMatrix.postScale(mCurveScale, mCurveScale, taskWidth / 2, taskHeight / 2);
// Apply TaskView matrix: translate, scale, scroll
mMatrix.postTranslate(mTaskRect.left, mTaskRect.top + mOffsetY);
mMatrix.postScale(mCurveScale, mCurveScale, taskWidth / 2, taskHeight / 2);
mOrientationState.getOrientationHandler().set(
mMatrix, MATRIX_POST_TRANSLATE, mScrollState.scroll);

View File

@ -42,6 +42,7 @@ import androidx.annotation.StringRes;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.systemui.shared.recents.model.Task;
import java.time.Duration;
@ -216,8 +217,8 @@ public final class DigitalWellBeingToast {
view, 0, 0,
view.getWidth(), view.getHeight());
activity.startActivity(intent, options.toBundle());
// TODO: add WW logging on the app usage settings click.
activity.getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.Touch.TAP,
LauncherLogProto.ControlType.APP_USAGE_SETTINGS, view);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "Failed to open app usage settings for task "
+ mTask.getTopComponent().getPackageName(), e);

View File

@ -36,6 +36,7 @@ import android.view.Surface;
import android.widget.FrameLayout;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager.StateListener;
@ -176,8 +177,14 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
@Override
protected boolean shouldStealTouchFromSiblingsBelow(MotionEvent ev) {
return mActivity.getStateManager().getState().overviewUi
&& super.shouldStealTouchFromSiblingsBelow(ev);
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
// Allow touches to go through to the hotseat.
Hotseat hotseat = mActivity.getHotseat();
boolean touchingHotseat = hotseat.isShown()
&& mActivity.getDragLayer().isEventOverView(hotseat, ev, this);
return !touchingHotseat;
}
return super.shouldStealTouchFromSiblingsBelow(ev);
}
@Override

View File

@ -54,6 +54,7 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
HIDDEN_UNSUPPORTED_NAVIGATION,
HIDDEN_NON_ZERO_ROTATION,
HIDDEN_NO_TASKS,
HIDDEN_GESTURE_RUNNING,
HIDDEN_NO_RECENTS})
@Retention(RetentionPolicy.SOURCE)
public @interface ActionsHiddenFlags { }
@ -61,7 +62,8 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
public static final int HIDDEN_UNSUPPORTED_NAVIGATION = 1 << 0;
public static final int HIDDEN_NON_ZERO_ROTATION = 1 << 1;
public static final int HIDDEN_NO_TASKS = 1 << 2;
public static final int HIDDEN_NO_RECENTS = 1 << 3;
public static final int HIDDEN_GESTURE_RUNNING = 1 << 3;
public static final int HIDDEN_NO_RECENTS = 1 << 4;
@IntDef(flag = true, value = {
DISABLED_SCROLLING,

View File

@ -35,14 +35,16 @@ import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.CLEAR_ALL_BUTTON;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_GESTURE_RUNNING;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_RECENTS;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS;
@ -107,6 +109,7 @@ import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.touch.PagedOrientationHandler.CurveProperties;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DynamicResource;
import com.android.launcher3.util.MultiValueAlpha;
@ -115,7 +118,6 @@ import com.android.launcher3.util.ResourceBasedOverride.Overrides;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.ViewPool;
import com.android.quickstep.BaseActivityInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.RecentsAnimationController;
import com.android.quickstep.RecentsAnimationTargets;
import com.android.quickstep.RecentsModel;
@ -1127,6 +1129,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
setEnableDrawingLiveTile(false);
setRunningTaskHidden(true);
setRunningTaskIconScaledDown(true);
mActionsView.updateHiddenFlags(HIDDEN_GESTURE_RUNNING, true);
}
/**
@ -1180,14 +1183,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
}
/**
* Called when a gesture from an app has finished, and an end target has been determined.
*/
public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) {
}
/**
* Called when a gesture from an app has finished, and the animation to the target has ended.
* Called when a gesture from an app has finished.
*/
public void onGestureAnimationEnd() {
if (mOrientationState.setGestureActive(false)) {
@ -1326,6 +1322,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
}
private void animateActionsViewIn() {
mActionsView.updateHiddenFlags(HIDDEN_GESTURE_RUNNING, false);
ObjectAnimator anim = ObjectAnimator.ofFloat(
mActionsView.getVisibilityAlpha(), MultiValueAlpha.VALUE, 0, 1);
anim.setDuration(TaskView.SCALE_ICON_DURATION);
@ -1410,12 +1407,13 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
* Updates linearInterpolation for the provided child position
*/
public void updateInterpolation(float childStart) {
float pageCenter = childStart + halfPageSize;
float scaledHalfPageSize = halfPageSize / pageParentScale;
float pageCenter = childStart + scaledHalfPageSize;
float distanceFromScreenCenter = screenCenter - pageCenter;
// How far the page has to move from the center to be offscreen, taking into account
// the EDGE_SCALE_DOWN_FACTOR that will be applied at that position.
float distanceToReachEdge = halfScreenSize
+ halfPageSize * (1 - TaskView.EDGE_SCALE_DOWN_FACTOR);
+ scaledHalfPageSize * (1 - TaskView.EDGE_SCALE_DOWN_FACTOR);
linearInterpolation = Math.min(1,
Math.abs(distanceFromScreenCenter) / distanceToReachEdge);
}
@ -1461,7 +1459,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
public PendingAnimation createTaskDismissAnimation(TaskView taskView, boolean animateTaskView,
boolean shouldRemoveTask, long duration) {
if (mPendingAnimation != null) {
mPendingAnimation.finish(false);
mPendingAnimation.finish(false, Touch.SWIPE);
}
PendingAnimation anim = new PendingAnimation(duration);
@ -1623,7 +1621,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
protected void runDismissAnimation(PendingAnimation pendingAnim) {
AnimatorPlaybackController controller = pendingAnim.createPlaybackController();
controller.dispatchOnStart();
controller.setEndAction(() -> pendingAnim.finish(true));
controller.setEndAction(() -> pendingAnim.finish(true, Touch.SWIPE));
controller.getAnimationPlayer().setInterpolator(FAST_OUT_SLOW_IN);
controller.start();
}
@ -1636,7 +1634,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
@SuppressWarnings("unused")
private void dismissAllTasks(View view) {
runDismissAnimation(createAllTasksDismissAnimation(DISMISS_TASK_DURATION));
mActivity.getStatsLogManager().logger().log(LAUNCHER_TASK_CLEAR_ALL);
mActivity.getUserEventDispatcher().logActionOnControl(TAP, CLEAR_ALL_BUTTON);
}
private void dismissCurrentTask() {
@ -2161,12 +2159,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
tv.notifyTaskLaunchFailed(TAG);
}
};
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
finishRecentsAnimation(false /* toRecents */, null);
onLaunchResult.accept(true /* success */);
} else {
tv.launchTask(false, onLaunchResult, getHandler());
}
tv.launchTask(false, onLaunchResult, getHandler());
Task task = tv.getTask();
if (task != null) {
mActivity.getStatsLogManager().logger().withItemInfo(tv.getItemInfo())

View File

@ -16,7 +16,6 @@
package com.android.quickstep.views;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
import android.animation.Animator;
@ -230,16 +229,7 @@ public class TaskMenuView extends AbstractFloatingView {
menuOptionView.findViewById(R.id.icon), menuOptionView.findViewById(R.id.text));
LayoutParams lp = (LayoutParams) menuOptionView.getLayoutParams();
mTaskView.getPagedOrientationHandler().setLayoutParamsForTaskMenuOptionItem(lp);
menuOptionView.setOnClickListener(view -> {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
RecentsView recentsView = mTaskView.getRecentsView();
recentsView.switchToScreenshot(null,
() -> recentsView.finishRecentsAnimation(true /* toRecents */,
() -> menuOption.onClick(view)));
} else {
menuOption.onClick(view);
}
});
menuOptionView.setOnClickListener(menuOption);
mOptionLayout.addView(menuOptionView);
}

View File

@ -73,11 +73,15 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.TransformingTouchDelegate;
import com.android.launcher3.util.ViewPool.Reusable;
@ -86,7 +90,6 @@ import com.android.quickstep.TaskIconCache;
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.util.CancellableTask;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.TaskCornerRadius;
import com.android.quickstep.views.RecentsView.PageCallbacks;
@ -186,8 +189,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private boolean mShowScreenshot;
// The current background requests to load the task thumbnail and icon
private CancellableTask mThumbnailLoadRequest;
private CancellableTask mIconLoadRequest;
private TaskThumbnailCache.ThumbnailLoadRequest mThumbnailLoadRequest;
private TaskIconCache.IconLoadRequest mIconLoadRequest;
// Order in which the footers appear. Lower order appear below higher order.
public static final int INDEX_DIGITAL_WELLBEING_TOAST = 0;
@ -217,7 +220,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (isRunningTask()) {
// TODO: Replace this animation with createRecentsWindowAnimator
createLaunchAnimationForRunningTask().start();
} else {
launchTask(true /* animate */);
@ -363,7 +365,10 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
final PendingAnimation pendingAnimation = getRecentsView().createTaskLaunchAnimation(
this, RECENTS_LAUNCH_DURATION, TOUCH_RESPONSE_INTERPOLATOR);
AnimatorPlaybackController currentAnimation = pendingAnimation.createPlaybackController();
currentAnimation.setEndAction(() -> pendingAnimation.finish(true));
currentAnimation.setEndAction(() -> {
pendingAnimation.finish(true, Touch.SWIPE);
launchTask(false);
});
return currentAnimation;
}
@ -386,6 +391,20 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
public void launchTask(boolean animate, boolean freezeTaskList, Consumer<Boolean> 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<Boolean> resultCallback, Handler resultCallbackHandler) {
if (mTask != null) {
final ActivityOptions opts;
TestLogging.recordEvent(
@ -462,13 +481,15 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
}
}
private boolean showTaskMenu() {
private boolean showTaskMenu(int action) {
if (!getRecentsView().isClearAllHidden()) {
getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
} else {
mMenuView = TaskMenuView.showForTask(this);
mActivity.getStatsLogManager().logger().withItemInfo(getItemInfo())
.log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS);
UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE,
LauncherLogProto.ItemType.TASK_ICON);
if (mMenuView != null) {
mMenuView.addOnAttachStateChangeListener(mTaskMenuStateListener);
}
@ -479,10 +500,10 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private void setIcon(Drawable icon) {
if (icon != null) {
mIconView.setDrawable(icon);
mIconView.setOnClickListener(v -> showTaskMenu());
mIconView.setOnClickListener(v -> showTaskMenu(Touch.TAP));
mIconView.setOnLongClickListener(v -> {
requestDisallowInterceptTouchEvent(true);
return showTaskMenu();
return showTaskMenu(Touch.LONGPRESS);
});
} else {
mIconView.setDrawable(null);

View File

@ -3,8 +3,6 @@ package com.android.quickstep;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static com.android.launcher3.util.rule.TestStabilityRule.UNBUNDLED_POSTSUBMIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -13,12 +11,12 @@ import static org.junit.Assert.assertTrue;
import android.app.PendingIntent;
import android.app.usage.UsageStatsManager;
import android.content.Intent;
import android.os.Build;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.Launcher;
import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.quickstep.views.DigitalWellBeingToast;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@ -36,6 +34,9 @@ public class DigitalWellBeingToastTest extends AbstractQuickStepTest {
@Test
public void testToast() throws Exception {
// b/150303529
if (Build.MODEL.contains("Cuttlefish")) return;
startAppFast(CALCULATOR_PACKAGE);
final UsageStatsManager usageStatsManager =

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<com.android.launcher3.views.SearchResultIconRow xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
style="@style/BaseIcon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:drawablePadding="@dimen/dynamic_grid_icon_drawable_padding"
android:gravity="start|center_vertical"
android:textAlignment="viewStart"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp"
android:padding="@dimen/dynamic_grid_edge_margin"
launcher:iconDisplay="hero_app"
launcher:layoutHorizontal="true"
>
</com.android.launcher3.views.SearchResultIconRow>

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<com.android.launcher3.views.SearchResultShortcut xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="@dimen/dynamic_grid_edge_margin">
<com.android.launcher3.BubbleTextView
android:id="@+id/bubble_text"
style="@style/BaseIcon"
android:drawablePadding="@dimen/dynamic_grid_icon_drawable_padding"
android:gravity="start|center_vertical"
android:textAlignment="viewStart"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp"
android:layout_height="wrap_content"
launcher:iconDisplay="hero_app"
launcher:layoutHorizontal="true" />
<View
android:id="@+id/icon"
android:layout_width="@dimen/deep_shortcut_icon_size"
android:layout_height="@dimen/deep_shortcut_icon_size"
android:layout_gravity="start|center_vertical"
android:background="@drawable/ic_deepshortcut_placeholder" />
</com.android.launcher3.views.SearchResultShortcut>

View File

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<com.android.launcher3.views.SearchResultSuggestRow xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/TextHeadline"
android:id="@+id/section_title"
android:background="?android:attr/selectableItemBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_vertical"
android:padding="4dp"
android:minHeight="48dp"
android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp">
<TextView
android:id="@+id/title"
style="@style/TextTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:layout_marginBottom="4dp"
android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp" />
</com.android.launcher3.views.SearchResultSuggestRow>

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<com.android.launcher3.views.ThumbnailSearchResultView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="125dp"
android:layout_height="125dp"/>

View File

@ -59,6 +59,7 @@
<bool name="hotseat_transpose_layout_with_orientation">true</bool>
<!-- Various classes overriden by projects/build flavors. -->
<string name="user_event_dispatcher_class" translatable="false"></string>
<string name="folder_name_provider_class" translatable="false"></string>
<string name="stats_log_manager_class" translatable="false"></string>
<string name="app_transition_manager_class" translatable="false"></string>

View File

@ -21,6 +21,7 @@ import static com.android.launcher3.util.Preconditions.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import android.content.Context;
import android.os.UserManager;
@ -29,6 +30,8 @@ import android.provider.Settings;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.allapps.AllAppsPagedView;
import com.android.launcher3.allapps.AllAppsRecyclerView;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.shadows.ShadowOverrides;
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.LauncherModelHelper;
@ -66,6 +69,8 @@ public class SDWorkModeTest {
mModelHelper = new LauncherModelHelper();
mTargetContext = RuntimeEnvironment.application;
mIdp = InvariantDeviceProfile.INSTANCE.get(mTargetContext);
ShadowOverrides.setProvider(UserEventDispatcher.class,
c -> mock(UserEventDispatcher.class));
Settings.Global.putFloat(mTargetContext.getContentResolver(),
Settings.Global.WINDOW_ANIMATION_SCALE, 0);

View File

@ -20,6 +20,7 @@ import static com.android.launcher3.util.LauncherUIHelper.doLayout;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.Mockito.mock;
import android.content.Context;
import android.os.SystemClock;
@ -35,6 +36,8 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.FolderPagedView;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.shadows.ShadowOverrides;
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.LauncherLayoutBuilder.FolderBuilder;
import com.android.launcher3.util.LauncherModelHelper;
@ -67,6 +70,8 @@ public class LauncherUIScrollTest {
mModelHelper = new LauncherModelHelper();
mTargetContext = RuntimeEnvironment.application;
mIdp = InvariantDeviceProfile.INSTANCE.get(mTargetContext);
ShadowOverrides.setProvider(UserEventDispatcher.class,
c -> mock(UserEventDispatcher.class));
Settings.Global.putFloat(mTargetContext.getContentResolver(),
Settings.Global.WINDOW_ANIMATION_SCALE, 0);

View File

@ -37,6 +37,8 @@ import androidx.annotation.IntDef;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.ViewCache;
import com.android.launcher3.views.ActivityContext;
@ -80,6 +82,7 @@ public abstract class BaseActivity extends Activity implements ActivityContext {
new ArrayList<>();
protected DeviceProfile mDeviceProfile;
protected UserEventDispatcher mUserEventDispatcher;
protected StatsLogManager mStatsLogManager;
protected SystemUiController mSystemUiController;
@ -141,6 +144,8 @@ public abstract class BaseActivity extends Activity implements ActivityContext {
return mDeviceProfile;
}
public void modifyUserEvent(LauncherLogProto.LauncherEvent event) {}
public final StatsLogManager getStatsLogManager() {
if (mStatsLogManager == null) {
mStatsLogManager = StatsLogManager.newInstance(this);
@ -148,6 +153,13 @@ public abstract class BaseActivity extends Activity implements ActivityContext {
return mStatsLogManager;
}
public final UserEventDispatcher getUserEventDispatcher() {
if (mUserEventDispatcher == null) {
mUserEventDispatcher = UserEventDispatcher.newInstance(this);
}
return mUserEventDispatcher;
}
public SystemUiController getSystemUiController() {
if (mSystemUiController == null) {
mSystemUiController = new SystemUiController(getWindow());

View File

@ -23,7 +23,6 @@ import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
@ -31,8 +30,6 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@ -46,8 +43,6 @@ import android.view.View;
import android.view.ViewDebug;
import android.widget.TextView;
import androidx.core.graphics.ColorUtils;
import com.android.launcher3.Launcher.OnResumeCallback;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.dot.DotInfo;
@ -55,7 +50,6 @@ import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.graphics.PlaceHolderIconDrawable;
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.icons.IconCache.IconLoadRequest;
@ -65,7 +59,6 @@ import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.model.data.PromiseAppInfo;
import com.android.launcher3.model.data.RemoteActionItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.views.ActivityContext;
@ -91,8 +84,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
private final PointF mTranslationForReorderBounce = new PointF(0, 0);
private final PointF mTranslationForReorderPreview = new PointF(0, 0);
private static final int ICON_UPDATE_ANIMATION_DURATION = 375;
private float mScaleForReorderBounce = 1f;
private static final Property<BubbleTextView, Float> DOT_SCALE_PROPERTY
@ -301,14 +292,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
verifyHighRes();
}
/**
* Apply label and tag using a {@link RemoteActionItemInfo}
*/
public void applyFromRemoteActionInfo(RemoteActionItemInfo remoteActionItemInfo) {
applyIconAndLabel(remoteActionItemInfo);
setTag(remoteActionItemInfo);
}
private void applyIconAndLabel(ItemInfoWithIcon info) {
FastBitmapDrawable iconDrawable = newIcon(getContext(), info);
mDotParams.color = IconPalette.getMutedColor(info.bitmap.color, 0.54f);
@ -653,14 +636,11 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
mDisableRelayout = mIcon != null;
icon.setBounds(0, 0, mIconSize, mIconSize);
updateIcon(icon);
// If the current icon is a placeholder color, animate its update.
if (mIcon != null && mIcon instanceof PlaceHolderIconDrawable) {
animateIconUpdate((PlaceHolderIconDrawable) mIcon, icon);
if (mLayoutHorizontal) {
setCompoundDrawablesRelative(icon, null, null, null);
} else {
setCompoundDrawables(null, icon, null, null);
}
mDisableRelayout = false;
}
@ -690,8 +670,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
mActivity.invalidateParent(info);
} else if (info instanceof PackageItemInfo) {
applyFromItemInfoWithIcon((PackageItemInfo) info);
} else if (info instanceof RemoteActionItemInfo) {
applyFromRemoteActionInfo((RemoteActionItemInfo) info);
}
mDisableRelayout = false;
@ -798,33 +776,4 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
((FastBitmapDrawable) mIcon).setScale(1f);
}
}
private void updateIcon(Drawable newIcon) {
if (mLayoutHorizontal) {
setCompoundDrawablesRelative(newIcon, null, null, null);
} else {
setCompoundDrawables(null, newIcon, null, null);
}
}
private static void animateIconUpdate(PlaceHolderIconDrawable oldIcon, Drawable newIcon) {
int placeholderColor = oldIcon.mPaint.getColor();
int originalAlpha = Color.alpha(placeholderColor);
ValueAnimator iconUpdateAnimation = ValueAnimator.ofInt(originalAlpha, 0);
iconUpdateAnimation.setDuration(ICON_UPDATE_ANIMATION_DURATION);
iconUpdateAnimation.addUpdateListener(valueAnimator -> {
int newAlpha = (int) valueAnimator.getAnimatedValue();
int newColor = ColorUtils.setAlphaComponent(placeholderColor, newAlpha);
newIcon.setColorFilter(new PorterDuffColorFilter(newColor, Mode.SRC_ATOP));
});
iconUpdateAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
newIcon.setColorFilter(null);
}
});
iconUpdateAnimation.start();
}
}

View File

@ -47,6 +47,7 @@ import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
@ -394,4 +395,6 @@ public abstract class ButtonDropTarget extends TextView
TextUtils.TruncateAt.END);
return !mText.equals(displayedText);
}
public abstract Target getDropTargetForLogging();
}

View File

@ -323,8 +323,11 @@ public class CellLayout extends ViewGroup {
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mTouchHelper != null
|| (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev));
if (mTouchHelper != null
|| (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev))) {
return true;
}
return false;
}
public void enableHardwareLayer(boolean hasLayer) {

View File

@ -18,7 +18,8 @@ package com.android.launcher3;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_CANCEL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_REMOVE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNDO;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.UNDO;
import android.content.Context;
import android.text.TextUtils;
@ -27,19 +28,22 @@ import android.view.View;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.LoggerUtils;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.views.Snackbar;
public class DeleteDropTarget extends ButtonDropTarget {
private final StatsLogManager mStatsLogManager;
private StatsLogManager.LauncherEvent mLauncherEvent;
private int mControlType = ControlType.DEFAULT_CONTROLTYPE;
public DeleteDropTarget(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@ -111,8 +115,8 @@ public class DeleteDropTarget extends ButtonDropTarget {
* Set mControlType depending on the drag item.
*/
private void setControlTypeBasedOnDragSource(ItemInfo item) {
mLauncherEvent = item.id != ItemInfo.NO_ID ? LAUNCHER_ITEM_DROPPED_ON_REMOVE
: LAUNCHER_ITEM_DROPPED_ON_CANCEL;
mControlType = item.id != ItemInfo.NO_ID ? ControlType.REMOVE_TARGET
: ControlType.CANCEL_TARGET;
}
@Override
@ -123,7 +127,8 @@ public class DeleteDropTarget extends ButtonDropTarget {
}
super.onDrop(d, options);
mStatsLogManager.logger().withInstanceId(d.logInstanceId)
.log(mLauncherEvent);
.log(mControlType == ControlType.REMOVE_TARGET ? LAUNCHER_ITEM_DROPPED_ON_REMOVE
: LAUNCHER_ITEM_DROPPED_ON_CANCEL);
}
@Override
@ -136,7 +141,7 @@ public class DeleteDropTarget extends ButtonDropTarget {
Runnable onUndoClicked = () -> {
mLauncher.setPageToBindSynchronously(itemPage);
modelWriter.abortDelete();
mLauncher.getStatsLogManager().logger().log(LAUNCHER_UNDO);
mLauncher.getUserEventDispatcher().logActionOnControl(TAP, UNDO);
};
Snackbar.show(mLauncher, R.string.item_removed, R.string.undo,
modelWriter::commitDelete, onUndoClicked);
@ -156,4 +161,11 @@ public class DeleteDropTarget extends ButtonDropTarget {
mLauncher.getDragLayer()
.announceForAccessibility(getContext().getString(R.string.item_removed));
}
@Override
public Target getDropTargetForLogging() {
Target t = LoggerUtils.newTarget(Target.Type.CONTROL);
t.controlType = mControlType;
return t;
}
}

View File

@ -33,8 +33,6 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.Property;
import androidx.annotation.Nullable;
import com.android.launcher3.graphics.PlaceHolderIconDrawable;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
@ -56,8 +54,6 @@ public class FastBitmapDrawable extends Drawable {
protected Bitmap mBitmap;
protected final int mIconColor;
@Nullable private ColorFilter mColorFilter;
private boolean mIsPressed;
private boolean mIsDisabled;
private float mDisabledAlpha = 1f;
@ -119,8 +115,7 @@ public class FastBitmapDrawable extends Drawable {
@Override
public void setColorFilter(ColorFilter cf) {
mColorFilter = cf;
updateFilter();
// No op
}
@Override
@ -270,7 +265,7 @@ public class FastBitmapDrawable extends Drawable {
* Updates the paint to reflect the current brightness and saturation.
*/
protected void updateFilter() {
mPaint.setColorFilter(mIsDisabled ? getDisabledColorFilter() : mColorFilter);
mPaint.setColorFilter(mIsDisabled ? getDisabledColorFilter() : null);
invalidateSelf();
}

View File

@ -16,6 +16,8 @@
package com.android.launcher3;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
@ -25,10 +27,14 @@ import android.view.ViewDebug;
import android.view.ViewGroup;
import android.widget.FrameLayout;
/**
* View class that represents the bottom row of the home screen.
*/
public class Hotseat extends CellLayout implements Insettable {
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import java.util.ArrayList;
public class Hotseat extends CellLayout implements LogContainerProvider, Insettable {
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mHasVerticalHotseat;
@ -72,6 +78,15 @@ public class Hotseat extends CellLayout implements Insettable {
}
}
@Override
public void fillInLogContainerData(ItemInfo childInfo, Target child,
ArrayList<Target> 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();

View File

@ -18,7 +18,6 @@ package com.android.launcher3;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
@ -37,10 +36,11 @@ import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONRESUME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONSTOP;
import static com.android.launcher3.logging.StatsLogManager.containerTypeToAtomState;
import static com.android.launcher3.model.ItemInstallQueue.FLAG_ACTIVITY_PAUSED;
import static com.android.launcher3.model.ItemInstallQueue.FLAG_DRAG_AND_DROP;
import static com.android.launcher3.model.ItemInstallQueue.FLAG_LOADER_RUNNING;
@ -70,7 +70,6 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
@ -89,10 +88,9 @@ import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.CallSuper;
@ -119,13 +117,13 @@ import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.folder.FolderGridOrganizer;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.keyboard.CustomActionsPopup;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.model.ModelUtils;
@ -153,6 +151,9 @@ import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.AllAppsSwipeController;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.ActivityResultInfo;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.ComponentKey;
@ -268,8 +269,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
private static final int APPS_VIEW_ALPHA_CHANNEL_INDEX = 1;
private static final int SCRIM_VIEW_ALPHA_CHANNEL_INDEX = 0;
private static final int THEME_CROSS_FADE_ANIMATION_DURATION = 375;
private LauncherAppTransitionManager mAppTransitionManager;
private Configuration mOldConfig;
@ -401,7 +400,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
inflateRootView(R.layout.launcher);
setupViews();
crossFadeWithPreviousAppearance();
mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots);
mAppTransitionManager = LauncherAppTransitionManager.newInstance(this);
@ -478,7 +476,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
() -> getStateManager().goToState(NORMAL));
if (Utilities.ATLEAST_R) {
getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
}
mLifecycleRegistry = new LifecycleRegistry(this);
@ -556,6 +554,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
}
private void onIdpChanged(InvariantDeviceProfile idp) {
mUserEventDispatcher = null;
initDeviceProfile(idp);
dispatchDeviceProfileChanged();
@ -911,7 +910,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
mOverlayManager.onActivityStopped(this);
}
logStopAndResume(false /* isResume */);
logStopAndResume(Action.Command.STOP);
mAppWidgetHost.setListenIfResumed(false);
NotificationListener.removeNotificationsChangedListener();
}
@ -933,7 +932,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
@Override
@CallSuper
protected void onDeferredResumed() {
logStopAndResume(true /* isResume */);
logStopAndResume(Action.Command.RESUME);
// Process any items that were added while Launcher was away.
ItemInstallQueue.INSTANCE.get(this)
@ -950,28 +949,32 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
protected void handlePendingActivityRequest() { }
private void logStopAndResume(boolean isResume) {
private void logStopAndResume(int command) {
if (mPendingExecutor != null) return;
int pageIndex = mWorkspace.isOverlayShown() ? -1 : mWorkspace.getCurrentPage();
int statsLogOrdinal = mStateManager.getState().statsLogOrdinal;
int containerType = mStateManager.getState().containerType;
StatsLogManager.EventEnum event;
StatsLogManager.StatsLogger logger = getStatsLogManager().logger();
if (isResume) {
if (command == Action.Command.RESUME) {
logger.withSrcState(LAUNCHER_STATE_BACKGROUND)
.withDstState(mStateManager.getState().statsLogOrdinal);
.withDstState(containerTypeToAtomState(mStateManager.getState().containerType));
event = LAUNCHER_ONRESUME;
} else { /* command == Action.Command.STOP */
logger.withSrcState(mStateManager.getState().statsLogOrdinal)
logger.withSrcState(containerTypeToAtomState(mStateManager.getState().containerType))
.withDstState(LAUNCHER_STATE_BACKGROUND);
event = LAUNCHER_ONSTOP;
}
if (statsLogOrdinal == LAUNCHER_STATE_HOME && mWorkspace != null) {
if (containerType == ContainerType.WORKSPACE && mWorkspace != null) {
getUserEventDispatcher().logActionCommand(command,
containerType, -1, pageIndex);
logger.withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
.setWorkspace(
LauncherAtom.WorkspaceContainer.newBuilder()
.setPageIndex(pageIndex)).build());
} else {
getUserEventDispatcher().logActionCommand(command, containerType, -1);
}
logger.log(event);
}
@ -1361,18 +1364,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
closeContextMenu();
}
@Override
public Object onRetainNonConfigurationInstance() {
int width = mDragLayer.getWidth();
int height = mDragLayer.getHeight();
if (width <= 0 || height <= 0) {
return null;
}
return BitmapRenderer.createHardwareBitmap(width, height, mDragLayer::draw);
}
public AllAppsTransitionController getAllAppsController() {
return mAllAppsController;
}
@ -1473,6 +1464,11 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
}
// Handle HOME_INTENT
UserEventDispatcher ued = getUserEventDispatcher();
Target target = newContainerTarget(mStateManager.getState().containerType);
target.pageIndex = mWorkspace.getCurrentPage();
ued.logActionCommand(Action.Command.HOME_INTENT, target,
newContainerTarget(ContainerType.WORKSPACE));
hideKeyboard();
if (mLauncherCallbacks != null) {
@ -2762,40 +2758,4 @@ public class Launcher extends StatefulActivity<LauncherState> 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();
}
}

View File

@ -105,7 +105,7 @@ public class LauncherAppState {
new Handler().post( () -> mInvariantDeviceProfile.verifyConfigChangedInBackground(context));
mInstallSessionTracker = InstallSessionHelper.INSTANCE.get(context)
.registerInstallTracker(mModel);
.registerInstallTracker(mModel, MODEL_EXECUTOR);
// Register an observer to rebind the notification listener when dots are re-enabled.
mNotificationDotsObserver =

View File

@ -16,7 +16,6 @@
package com.android.launcher3;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL;
@ -36,6 +35,7 @@ import com.android.launcher3.states.SpringLoadedState;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.uioverrides.states.AllAppsState;
import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import java.util.Arrays;
@ -97,7 +97,7 @@ public abstract class LauncherState implements BaseState<LauncherState> {
* TODO: Create a separate class for NORMAL state.
*/
public static final LauncherState NORMAL = new LauncherState(NORMAL_STATE_ORDINAL,
LAUNCHER_STATE_HOME,
ContainerType.WORKSPACE,
FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED | FLAG_HIDE_BACK_BUTTON |
FLAG_HAS_SYS_UI_SCRIM) {
@Override
@ -126,9 +126,9 @@ public abstract class LauncherState implements BaseState<LauncherState> {
public final int ordinal;
/**
* Used for {@link com.android.launcher3.logging.StatsLogManager}
* Used for containerType in {@link com.android.launcher3.logging.UserEventDispatcher}
*/
public final int statsLogOrdinal;
public final int containerType;
/**
* True if the state has overview panel visible.
@ -137,8 +137,8 @@ public abstract class LauncherState implements BaseState<LauncherState> {
private final int mFlags;
public LauncherState(int id, int statsLogOrdinal, int flags) {
this.statsLogOrdinal = statsLogOrdinal;
public LauncherState(int id, int containerType, int flags) {
this.containerType = containerType;
this.mFlags = flags;
this.overviewUi = (flags & FLAG_OVERVIEW_UI) != 0;
this.ordinal = id;

View File

@ -37,11 +37,14 @@ import com.android.launcher3.Launcher.OnResumeCallback;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.logging.LoggerUtils;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Themes;
@ -131,6 +134,19 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
return mCurrentAccessibilityAction;
}
@Override
public Target getDropTargetForLogging() {
Target t = LoggerUtils.newTarget(Target.Type.CONTROL);
if (mCurrentAccessibilityAction == UNINSTALL) {
t.controlType = ControlType.UNINSTALL_TARGET;
} else if (mCurrentAccessibilityAction == DISMISS_PREDICTION) {
t.controlType = ControlType.DISMISS_PREDICTION;
} else {
t.controlType = ControlType.SETTINGS_BUTTON;
}
return t;
}
@Override
protected boolean supportsDrop(ItemInfo info) {
return supportsAccessibilityDrop(info, getViewUnderDrag(info));

View File

@ -25,11 +25,8 @@ import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.text.TextUtils;
import androidx.annotation.WorkerThread;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.util.Executors;
/**
* BroadcastReceiver to handle session commit intent.
@ -41,11 +38,6 @@ public class SessionCommitReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Executors.MODEL_EXECUTOR.execute(() -> processIntent(context, intent));
}
@WorkerThread
private static void processIntent(Context context, Intent intent) {
if (!isEnabled(context)) {
// User has decided to not add icons on homescreen.
return;

View File

@ -133,10 +133,6 @@ public final class Utilities {
public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET";
public static final String EXTRA_WALLPAPER_FLAVOR = "com.android.launcher3.WALLPAPER_FLAVOR";
// An intent extra to indicate the launch source by launcher.
public static final String EXTRA_WALLPAPER_LAUNCH_SOURCE =
"com.android.wallpaper.LAUNCH_SOURCE";
public static boolean IS_RUNNING_IN_TEST_HARNESS =
ActivityManager.isRunningInTestHarness();

View File

@ -85,6 +85,7 @@ import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
@ -96,6 +97,8 @@ import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.WorkspaceTouchListener;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSparseArrayMap;
@ -1001,6 +1004,8 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
public void onOverlayScrollChanged(float scroll) {
if (Float.compare(scroll, 1f) == 0) {
if (!mOverlayShown) {
mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
Action.Direction.LEFT, ContainerType.WORKSPACE, 0);
mLauncher.getStatsLogManager().logger()
.withSrcState(LAUNCHER_STATE_HOME)
.withDstState(LAUNCHER_STATE_HOME)
@ -1015,16 +1020,20 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
// Not announcing the overlay page for accessibility since it announces itself.
} else if (Float.compare(scroll, 0f) == 0) {
if (mOverlayShown) {
// TODO: this is logged unnecessarily on home gesture.
mLauncher.getStatsLogManager().logger()
.withSrcState(LAUNCHER_STATE_HOME)
.withDstState(LAUNCHER_STATE_HOME)
.withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
.setWorkspace(
LauncherAtom.WorkspaceContainer.newBuilder()
.setPageIndex(-1))
.build())
.log(LAUNCHER_SWIPERIGHT);
UserEventDispatcher ued = mLauncher.getUserEventDispatcher();
if (!ued.isPreviousHomeGesture()) {
mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
Action.Direction.RIGHT, ContainerType.WORKSPACE, -1);
mLauncher.getStatsLogManager().logger()
.withSrcState(LAUNCHER_STATE_HOME)
.withDstState(LAUNCHER_STATE_HOME)
.withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
.setWorkspace(
LauncherAtom.WorkspaceContainer.newBuilder()
.setPageIndex(-1))
.build())
.log(LAUNCHER_SWIPERIGHT);
}
} else if (Float.compare(mOverlayTranslation, 0f) != 0) {
// When arriving to 0 overscroll from non-zero overscroll, announce page for
// accessibility since default announcements were disabled while in overscroll
@ -1115,8 +1124,12 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
protected void notifyPageSwitchListener(int prevPage) {
super.notifyPageSwitchListener(prevPage);
if (prevPage != mCurrentPage) {
int swipeDirection = (prevPage < mCurrentPage)
? Action.Direction.RIGHT : Action.Direction.LEFT;
StatsLogManager.EventEnum event = (prevPage < mCurrentPage)
? LAUNCHER_SWIPERIGHT : LAUNCHER_SWIPELEFT;
mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
swipeDirection, ContainerType.WORKSPACE, prevPage);
mLauncher.getStatsLogManager().logger()
.withSrcState(LAUNCHER_STATE_HOME)
.withDstState(LAUNCHER_STATE_HOME)
@ -1162,6 +1175,13 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
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.

View File

@ -130,16 +130,12 @@ public interface WorkspaceLayoutManager {
}
child.setHapticFeedbackEnabled(false);
child.setOnLongClickListener(getWorkspaceChildOnLongClickListener());
child.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE);
if (child instanceof DropTarget) {
onAddDropTarget((DropTarget) child);
}
}
default View.OnLongClickListener getWorkspaceChildOnLongClickListener() {
return ItemLongClickListener.INSTANCE_WORKSPACE;
}
Hotseat getHotseat();
CellLayout getScreenWithId(int screenId);

View File

@ -92,14 +92,10 @@ public class AllAppsGridAdapter extends
public static final int VIEW_TYPE_SEARCH_SLICE = 1 << 9;
public static final int VIEW_TYPE_SEARCH_ICON_ROW = 1 << 10;
public static final int VIEW_TYPE_SEARCH_SHORTCUT = 1 << 10;
public static final int VIEW_TYPE_SEARCH_PEOPLE = 1 << 11;
public static final int VIEW_TYPE_SEARCH_THUMBNAIL = 1 << 12;
public static final int VIEW_TYPE_SEARCH_SUGGEST = 1 << 13;
// Common view type masks
public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
@ -190,9 +186,7 @@ public class AllAppsGridAdapter extends
|| viewType == VIEW_TYPE_SEARCH_SLICE
|| viewType == VIEW_TYPE_SEARCH_ROW
|| viewType == VIEW_TYPE_SEARCH_PEOPLE
|| viewType == VIEW_TYPE_SEARCH_THUMBNAIL
|| viewType == VIEW_TYPE_SEARCH_ICON_ROW
|| viewType == VIEW_TYPE_SEARCH_SUGGEST;
|| viewType == VIEW_TYPE_SEARCH_SHORTCUT;
}
}
@ -203,7 +197,6 @@ public class AllAppsGridAdapter extends
*/
public static class AdapterItemWithPayload<T> extends AdapterItem {
private T mPayload;
private String mSearchSessionId;
private AllAppsSearchPlugin mPlugin;
private IntConsumer mSelectionHandler;
@ -225,14 +218,6 @@ public class AllAppsGridAdapter extends
mSelectionHandler = runnable;
}
public void setSearchSessionId(String searchSessionId) {
mSearchSessionId = searchSessionId;
}
public String getSearchSessionId() {
return mSearchSessionId;
}
public IntConsumer getSelectionHandler() {
return mSelectionHandler;
}
@ -240,8 +225,6 @@ public class AllAppsGridAdapter extends
public T getPayload() {
return mPayload;
}
}
/**
@ -324,21 +307,15 @@ public class AllAppsGridAdapter extends
@Override
public int getSpanSize(int position) {
int viewType = mApps.getAdapterItems().get(position).viewType;
if (isIconViewType(viewType)) {
return 1 * SPAN_MULTIPLIER;
} else if (viewType == VIEW_TYPE_SEARCH_THUMBNAIL) {
return mAppsPerRow;
if (isIconViewType(mApps.getAdapterItems().get(position).viewType)) {
return 1;
} else {
// Section breaks span the full width
return mAppsPerRow * SPAN_MULTIPLIER;
return mAppsPerRow;
}
}
}
// multiplier to support adapter item column count that is not mAppsPerRow.
public static final int SPAN_MULTIPLIER = 3;
private final BaseDraggingActivity mLauncher;
private final LayoutInflater mLayoutInflater;
private final AlphabeticalAppsList mApps;
@ -375,7 +352,7 @@ public class AllAppsGridAdapter extends
public void setAppsPerRow(int appsPerRow) {
mAppsPerRow = appsPerRow;
mGridLayoutMgr.setSpanCount(mAppsPerRow * SPAN_MULTIPLIER);
mGridLayoutMgr.setSpanCount(mAppsPerRow);
}
/**
@ -461,18 +438,12 @@ public class AllAppsGridAdapter extends
case VIEW_TYPE_SEARCH_SLICE:
return new ViewHolder(mLayoutInflater.inflate(
R.layout.search_result_slice, parent, false));
case VIEW_TYPE_SEARCH_ICON_ROW:
case VIEW_TYPE_SEARCH_SHORTCUT:
return new ViewHolder(mLayoutInflater.inflate(
R.layout.search_result_icon_row, parent, false));
R.layout.search_result_shortcut, parent, false));
case VIEW_TYPE_SEARCH_PEOPLE:
return new ViewHolder(mLayoutInflater.inflate(
R.layout.search_result_people_item, parent, false));
case VIEW_TYPE_SEARCH_THUMBNAIL:
return new ViewHolder(mLayoutInflater.inflate(
R.layout.search_result_thumbnail, parent, false));
case VIEW_TYPE_SEARCH_SUGGEST:
return new ViewHolder(mLayoutInflater.inflate(
R.layout.search_result_suggest, parent, false));
default:
throw new RuntimeException("Unexpected view type");
}
@ -493,27 +464,24 @@ public class AllAppsGridAdapter extends
//TODO: replace with custom TopHitBubbleTextView with support for both shortcut
// and apps
if (adapterItem instanceof AdapterItemWithPayload) {
AdapterItemWithPayload item = (AdapterItemWithPayload) adapterItem;
item.setSelectionHandler(type -> {
AdapterItemWithPayload withPayload = (AdapterItemWithPayload) adapterItem;
IntConsumer selectionHandler = type -> {
SearchTargetEvent e = new SearchTargetEvent(SearchTarget.ItemType.APP,
type, item.position, item.getSearchSessionId());
type);
e.bundle = HeroSearchResultView.getAppBundle(info);
if (item.getPlugin() != null) {
item.getPlugin().notifySearchTargetEvent(e);
if (withPayload.getPlugin() != null) {
withPayload.getPlugin().notifySearchTargetEvent(e);
}
});
};
icon.setOnClickListener(view -> {
item.getSelectionHandler().accept(SearchTargetEvent.SELECT);
selectionHandler.accept(SearchTargetEvent.SELECT);
mOnIconClickListener.onClick(view);
});
icon.setOnLongClickListener(view -> {
item.getSelectionHandler().accept(SearchTargetEvent.SELECT);
selectionHandler.accept(SearchTargetEvent.LONG_PRESS);
return mOnIconLongClickListener.onLongClick(view);
});
}
else {
icon.setOnClickListener(mOnIconClickListener);
icon.setOnLongClickListener(mOnIconLongClickListener);
withPayload.setSelectionHandler(selectionHandler);
}
break;
case VIEW_TYPE_EMPTY_SEARCH:
@ -532,22 +500,20 @@ public class AllAppsGridAdapter extends
break;
case VIEW_TYPE_SEARCH_SLICE:
SliceView sliceView = (SliceView) holder.itemView;
AdapterItemWithPayload<Uri> slicePayload =
AdapterItemWithPayload<Uri> item =
(AdapterItemWithPayload<Uri>) mApps.getAdapterItems().get(position);
sliceView.setOnSliceActionListener((info1, s) -> {
if (slicePayload.getPlugin() != null) {
if (item.getPlugin() != null) {
SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
SearchTarget.ItemType.SETTINGS_SLICE,
SearchTargetEvent.CHILD_SELECT, slicePayload.position,
slicePayload.getSearchSessionId());
SearchTargetEvent.CHILD_SELECT);
searchTargetEvent.bundle = new Bundle();
searchTargetEvent.bundle.putParcelable("uri", slicePayload.getPayload());
slicePayload.getPlugin().notifySearchTargetEvent(searchTargetEvent);
searchTargetEvent.bundle.putParcelable("uri", item.getPayload());
item.getPlugin().notifySearchTargetEvent(searchTargetEvent);
}
});
try {
LiveData<Slice> liveData = SliceLiveData.fromUri(mLauncher,
slicePayload.getPayload());
LiveData<Slice> liveData = SliceLiveData.fromUri(mLauncher, item.getPayload());
liveData.observe((Launcher) mLauncher, sliceView);
sliceView.setTag(liveData);
} catch (Exception ignored) {
@ -557,14 +523,11 @@ public class AllAppsGridAdapter extends
case VIEW_TYPE_SEARCH_ROW_WITH_BUTTON:
case VIEW_TYPE_SEARCH_HERO_APP:
case VIEW_TYPE_SEARCH_ROW:
case VIEW_TYPE_SEARCH_ICON_ROW:
case VIEW_TYPE_SEARCH_SHORTCUT:
case VIEW_TYPE_SEARCH_PEOPLE:
case VIEW_TYPE_SEARCH_THUMBNAIL:
case VIEW_TYPE_SEARCH_SUGGEST:
AdapterItemWithPayload item =
(AdapterItemWithPayload) mApps.getAdapterItems().get(position);
PayloadResultHandler payloadResultView = (PayloadResultHandler) holder.itemView;
payloadResultView.setup(item);
payloadResultView.applyAdapterInfo(
(AdapterItemWithPayload) mApps.getAdapterItems().get(position));
break;
case VIEW_TYPE_ALL_APPS_DIVIDER:
// nothing to do
@ -578,8 +541,8 @@ public class AllAppsGridAdapter extends
if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) return;
if (holder.itemView instanceof BubbleTextView) {
BubbleTextView icon = (BubbleTextView) holder.itemView;
icon.setOnClickListener(null);
icon.setOnLongClickListener(null);
icon.setOnClickListener(mOnIconClickListener);
icon.setOnLongClickListener(mOnIconLongClickListener);
} else if (holder.itemView instanceof SliceView) {
SliceView sliceView = (SliceView) holder.itemView;
sliceView.setOnSliceActionListener(null);
@ -590,6 +553,7 @@ public class AllAppsGridAdapter extends
}
}
@Override
public boolean onFailedToRecycleView(ViewHolder holder) {
// Always recycle and we will reset the view when it is bound

View File

@ -19,6 +19,8 @@ import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.UNSPECIFIED;
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
@ -36,6 +38,10 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsGridAdapter.AppsGridLayoutManager;
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.views.RecyclerViewFastScroller;
import java.util.ArrayList;
@ -44,7 +50,7 @@ import java.util.List;
/**
* A RecyclerView with custom fast scroll support for the all apps view.
*/
public class AllAppsRecyclerView extends BaseRecyclerView {
public class AllAppsRecyclerView extends BaseRecyclerView implements LogContainerProvider {
private AlphabeticalAppsList mApps;
private final int mNumAppsPerRow;
@ -170,6 +176,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
mAutoSizedOverlays.clear();
}
@Override
public void fillInLogContainerData(ItemInfo childInfo, Target child,
ArrayList<Target> 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();

View File

@ -18,6 +18,8 @@ package com.android.launcher3.allapps;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.HOTSEAT;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.PREDICTION;
import android.animation.Animator;
import android.animation.AnimatorInflater;
@ -118,10 +120,10 @@ public class DiscoveryBounce extends AbstractFloatingView {
return (type & TYPE_DISCOVERY_BOUNCE) != 0;
}
private void show() {
private void show(int containerType) {
mIsOpen = true;
mLauncher.getDragLayer().addView(this);
// TODO: add WW log for discovery bounce tip show event.
mLauncher.getUserEventDispatcher().logActionBounceTip(containerType);
}
public static void showForHomeIfNeeded(Launcher launcher) {
@ -144,7 +146,7 @@ public class DiscoveryBounce extends AbstractFloatingView {
}
onboardingPrefs.incrementEventCount(OnboardingPrefs.HOME_BOUNCE_COUNT);
new DiscoveryBounce(launcher, 0).show();
new DiscoveryBounce(launcher, 0).show(HOTSEAT);
}
public static void showForOverviewIfNeeded(Launcher launcher,
@ -177,7 +179,7 @@ public class DiscoveryBounce extends AbstractFloatingView {
onboardingPrefs.incrementEventCount(OnboardingPrefs.SHELF_BOUNCE_COUNT);
new DiscoveryBounce(launcher, (1 - OVERVIEW.getVerticalProgress(launcher)))
.show();
.show(PREDICTION);
}
/**

View File

@ -35,8 +35,6 @@ import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.systemui.plugins.AllAppsSearchPlugin;
import com.android.systemui.plugins.shared.SearchTarget;
import com.android.systemui.plugins.shared.SearchTargetEvent;
import java.util.ArrayList;
import java.util.List;
@ -215,44 +213,6 @@ public class AllAppsSearchBarController
/**
* Updates View using Adapter's payload
*/
default void setup(AdapterItemWithPayload<T> adapterItemWithPayload) {
Object[] targetInfo = getTargetInfo();
if (targetInfo != null) {
targetInfo[0] = adapterItemWithPayload.getSearchSessionId();
targetInfo[1] = adapterItemWithPayload.position;
}
applyAdapterInfo(adapterItemWithPayload);
}
void applyAdapterInfo(AdapterItemWithPayload<T> 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);
}
}
}

View File

@ -73,9 +73,9 @@ public class PendingAnimation implements PropertySetter {
addAnimationHoldersRecur(a, mDuration, springProperty, mAnimHolders);
}
public void finish(boolean isSuccess) {
public void finish(boolean isSuccess, int logAction) {
for (Consumer<EndState> listeners : mEndListeners) {
listeners.accept(new EndState(isSuccess));
listeners.accept(new EndState(isSuccess, logAction));
}
mEndListeners.clear();
}
@ -164,7 +164,7 @@ public class PendingAnimation implements PropertySetter {
/**
* Add a listener of receiving the end state.
* Note that the listeners are called as a result of calling {@link #finish(boolean)}
* Note that the listeners are called as a result of calling {@link #finish(boolean, int)}
* and not automatically
*/
public void addEndListener(Consumer<EndState> listener) {
@ -173,9 +173,11 @@ public class PendingAnimation implements PropertySetter {
public static class EndState {
public boolean isSuccess;
public int logAction;
public EndState(boolean isSuccess) {
public EndState(boolean isSuccess, int logAction) {
this.isSuccess = isSuccess;
this.logAction = logAction;
}
}
}

View File

@ -16,11 +16,10 @@
package com.android.launcher3.dragndrop;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_EXTERNAL_ITEM_BACK;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_EXTERNAL_ITEM_CANCELLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_EXTERNAL_ITEM_DRAGGED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_EXTERNAL_ITEM_START;
import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.logging.LoggerUtils.newItemTarget;
import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.annotation.TargetApi;
@ -50,10 +49,11 @@ import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetHost;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.R;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.pm.PinRequestHelper;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.PendingAddShortcutInfo;
@ -125,7 +125,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
// savedInstanceState is null when the activity is created the first time (i.e., avoids
// duplicate logging during rotation)
if (savedInstanceState == null) {
logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_START);
logCommand(Action.Command.ENTRY);
}
}
@ -178,7 +178,6 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
startActivity(homeIntent,
ActivityOptions.makeCustomAnimation(this, 0, android.R.anim.fade_out)
.toBundle());
logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_DRAGGED);
mFinishOnPause = true;
return false;
}
@ -241,7 +240,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
* Called when the cancel button is clicked.
*/
public void onCancelClick(View v) {
logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_CANCELLED);
logCommand(Action.Command.CANCEL);
finish();
}
@ -251,7 +250,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
public void onPlaceAutomaticallyClick(View v) {
if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
ItemInstallQueue.INSTANCE.get(this).queueItem(mRequest.getShortcutInfo());
logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY);
logCommand(Action.Command.CONFIRM);
mRequest.accept();
finish();
return;
@ -275,13 +274,13 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
.queueItem(mRequest.getAppWidgetProviderInfo(this), widgetId);
mWidgetOptions.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
mRequest.accept(mWidgetOptions);
logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY);
logCommand(Action.Command.CONFIRM);
finish();
}
@Override
public void onBackPressed() {
logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_BACK);
logCommand(Action.Command.BACK);
super.onBackPressed();
}
@ -321,7 +320,10 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
throw new UnsupportedOperationException();
}
private void logCommand(StatsLogManager.EventEnum command) {
getStatsLogManager().logger().log(command);
private void logCommand(int command) {
getUserEventDispatcher().dispatchUserEvent(newLauncherEvent(
newCommandAction(command),
newItemTarget(mWidgetCell.getWidgetView(), mInstantAppResolver),
newContainerTarget(ContainerType.PINITEM)), null);
}
}

View File

@ -206,6 +206,7 @@ public class DragController implements DragDriver.EventListener, TouchController
}
handleMoveEvent(mLastTouch.x, mLastTouch.y);
mLauncher.getUserEventDispatcher().resetActionDurationMillis();
if (!mLauncher.isTouchInProgress() && options.simulatedDndStartPoint == null) {
// If it is an internal drag and the touch is already complete, cancel immediately
@ -543,6 +544,7 @@ public class DragController implements DragDriver.EventListener, TouchController
}
}
final View dropTargetAsView = dropTarget instanceof View ? (View) dropTarget : null;
mLauncher.getUserEventDispatcher().logDragNDrop(mDragObject, dropTargetAsView);
dispatchDropComplete(dropTargetAsView, accepted);
}

View File

@ -23,6 +23,7 @@ import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import static com.android.launcher3.config.FeatureFlags.ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_LABEL_UPDATED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED;
@ -94,6 +95,7 @@ import com.android.launcher3.model.data.FolderInfo.FolderListener;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pageindicators.PageIndicatorDots;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.views.ClipPathView;
@ -597,6 +599,15 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
* is played.
*/
private void animateOpen(List<WorkspaceItemInfo> 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<WorkspaceItemInfo> items, int pageNo, boolean skipUserEventLog) {
Folder openFolder = getOpen(mLauncher);
if (openFolder != null && openFolder != this) {
// Close any open folder before opening a folder.
@ -646,6 +657,14 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
mState = STATE_OPEN;
announceAccessibilityChanges();
if (!skipUserEventLog) {
mLauncher.getUserEventDispatcher().logActionOnItem(
LauncherLogProto.Action.Touch.TAP,
LauncherLogProto.Action.Direction.NONE,
LauncherLogProto.ItemType.FOLDER_ICON, mInfo.cellX, mInfo.cellY);
}
mContent.setFocusOnFirstChild();
}
});
@ -1494,6 +1513,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
}
statsLogger.log(LAUNCHER_FOLDER_LABEL_UPDATED);
logFolderLabelState(mFromLabelState, toLabelState);
mFolderName.dispatchBackKey();
}
}
@ -1624,7 +1644,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
return true;
}
} else {
// TODO: add ww log if need to gather tap outside to close folder
mLauncher.getUserEventDispatcher().logActionTapOutside(
newContainerTarget(LauncherLogProto.ContainerType.FOLDER));
close(true);
return true;
}
@ -1659,6 +1680,17 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
return mContent;
}
/**
* Logs current folder label info.
*
* @deprecated This method is only used for log validation and soon will be removed.
*/
@Deprecated
public void logFolderLabelState(FromState fromState, ToState toState) {
mLauncher.getUserEventDispatcher()
.logLauncherEvent(mInfo.getFolderLabelStateLauncherEvent(fromState, toState));
}
/** Returns the height of the current folder's bottom edge from the bottom of the screen. */
private int getHeightFromBottom() {
DragLayer.LayoutParams layoutParams = (DragLayer.LayoutParams) getLayoutParams();

View File

@ -478,6 +478,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
// event is assumed to be folder creation on the server side.
.withEditText(newTitle.toString())
.log(LAUNCHER_FOLDER_AUTO_LABELED);
mFolder.logFolderLabelState(fromState, ToState.TO_SUGGESTION0);
}

View File

@ -513,7 +513,8 @@ public class LauncherPreviewRenderer extends ContextThemeWrapper
}
// Setup search view
SearchUiManager searchUiManager = mRootView.findViewById(R.id.search_container_all_apps);
SearchUiManager searchUiManager =
mRootView.findViewById(R.id.search_container_all_apps);
mRootView.findViewById(R.id.apps_view).setTranslationY(
mDp.heightPx - searchUiManager.getScrollRangeDelta(mInsets));
ViewGroup searchView = (ViewGroup) searchUiManager;

View File

@ -0,0 +1,190 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.logging;
import android.util.ArrayMap;
import android.util.SparseArray;
import android.view.View;
import com.android.launcher3.ButtonDropTarget;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.userevent.nano.LauncherLogExtensions.TargetExtension;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.InstantAppResolver;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
/**
* Helper methods for logging.
*/
public class LoggerUtils {
private static final ArrayMap<Class, SparseArray<String>> 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<String> 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<Target> 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];
}
}

View File

@ -27,6 +27,7 @@ import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
import com.android.launcher3.logger.LauncherAtom.FromState;
import com.android.launcher3.logger.LauncherAtom.ToState;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.userevent.LauncherLogProto;
import com.android.launcher3.util.ResourceBasedOverride;
import java.util.List;
@ -50,22 +51,40 @@ public class StatsLogManager implements ResourceBasedOverride {
public static final int LAUNCHER_STATE_UNCHANGED = 5;
/**
* Returns event enum based on the two state transition information when swipe
* Returns proper launcher state enum for {@link StatsLogManager}(to be removed during
* UserEventDispatcher cleanup)
*/
public static int containerTypeToAtomState(int containerType) {
switch (containerType) {
case LauncherLogProto.ContainerType.ALLAPPS_VALUE:
return LAUNCHER_STATE_ALLAPPS;
case LauncherLogProto.ContainerType.OVERVIEW_VALUE:
return LAUNCHER_STATE_OVERVIEW;
case LauncherLogProto.ContainerType.WORKSPACE_VALUE:
return LAUNCHER_STATE_HOME;
case LauncherLogProto.ContainerType.APP_VALUE:
return LAUNCHER_STATE_BACKGROUND;
}
return LAUNCHER_STATE_UNSPECIFIED;
}
/**
* Returns event enum based on the two {@link ContainerType} transition information when swipe
* gesture happens(to be removed during UserEventDispatcher cleanup).
*/
public static EventEnum getLauncherAtomEvent(int startState,
int targetState, EventEnum fallbackEvent) {
if (startState == LAUNCHER_STATE_HOME
&& targetState == LAUNCHER_STATE_HOME) {
public static EventEnum getLauncherAtomEvent(int startContainerType,
int targetContainerType, EventEnum fallbackEvent) {
if (startContainerType == LauncherLogProto.ContainerType.WORKSPACE.getNumber()
&& targetContainerType == LauncherLogProto.ContainerType.WORKSPACE.getNumber()) {
return LAUNCHER_HOME_GESTURE;
} else if (startState != LAUNCHER_STATE_OVERVIEW
&& targetState == LAUNCHER_STATE_OVERVIEW) {
} else if (startContainerType != LauncherLogProto.ContainerType.TASKSWITCHER.getNumber()
&& targetContainerType == LauncherLogProto.ContainerType.TASKSWITCHER.getNumber()) {
return LAUNCHER_OVERVIEW_GESTURE;
} else if (startState != LAUNCHER_STATE_ALLAPPS
&& targetState == LAUNCHER_STATE_ALLAPPS) {
} else if (startContainerType != LauncherLogProto.ContainerType.ALLAPPS.getNumber()
&& targetContainerType == LauncherLogProto.ContainerType.ALLAPPS.getNumber()) {
return LAUNCHER_ALLAPPS_OPEN_UP;
} else if (startState == LAUNCHER_STATE_ALLAPPS
&& targetState != LAUNCHER_STATE_ALLAPPS) {
} else if (startContainerType == LauncherLogProto.ContainerType.ALLAPPS.getNumber()
&& targetContainerType != LauncherLogProto.ContainerType.ALLAPPS.getNumber()) {
return LAUNCHER_ALLAPPS_CLOSE_DOWN;
}
return fallbackEvent; // TODO fix
@ -303,38 +322,7 @@ public class StatsLogManager implements ResourceBasedOverride {
LAUNCHER_FOLDER_CONVERTED_TO_ICON(628),
@UiEvent(doc = "A hotseat prediction item was pinned")
LAUNCHER_HOTSEAT_PREDICTION_PINNED(629),
@UiEvent(doc = "Activity to add external item was started")
LAUNCHER_ADD_EXTERNAL_ITEM_START(641),
@UiEvent(doc = "Activity to add external item was cancelled")
LAUNCHER_ADD_EXTERNAL_ITEM_CANCELLED(642),
@UiEvent(doc = "Activity to add external item was backed out")
LAUNCHER_ADD_EXTERNAL_ITEM_BACK(643),
@UiEvent(doc = "Item was placed automatically in external item addition flow")
LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY(644),
@UiEvent(doc = "Item was dragged in external item addition flow")
LAUNCHER_ADD_EXTERNAL_ITEM_DRAGGED(645),
@UiEvent(doc = "Undo event was tapped.")
LAUNCHER_UNDO(648),
@UiEvent(doc = "Task switcher clear all target was tapped.")
LAUNCHER_TASK_CLEAR_ALL(649),
@UiEvent(doc = "Task preview was long pressed.")
LAUNCHER_TASK_PREVIEW_LONGPRESS(650),
@UiEvent(doc = "User swiped down on workspace (triggering noti shade to open).")
LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN(651),
@UiEvent(doc = "Notification dismissed by swiping right.")
LAUNCHER_NOTIFICATION_DISMISSED(652),
;
LAUNCHER_HOTSEAT_PREDICTION_PINNED(629);
// ADD MORE

View File

@ -0,0 +1,49 @@
package com.android.launcher3.logging;
import android.view.View;
import android.view.ViewParent;
import androidx.annotation.Nullable;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import java.util.ArrayList;
public class StatsLogUtils {
private final static int MAXIMUM_VIEW_HIERARCHY_LEVEL = 5;
/**
* Implemented by containers to provide a container source for a given child.
*/
public interface LogContainerProvider {
/**
* Populates parent container targets for an item
*/
void fillInLogContainerData(ItemInfo childInfo, Target child, ArrayList<Target> 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;
}
}

View File

@ -0,0 +1,373 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.logging;
import static com.android.launcher3.logging.LoggerUtils.newAction;
import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.logging.LoggerUtils.newDropTarget;
import static com.android.launcher3.logging.LoggerUtils.newItemTarget;
import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
import static com.android.launcher3.logging.LoggerUtils.newTarget;
import static com.android.launcher3.logging.LoggerUtils.newTouchAction;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
import static com.android.launcher3.userevent.nano.LauncherLogProto.TipType;
import static java.util.Optional.ofNullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.DropTarget;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.userevent.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.util.LogConfig;
import com.android.launcher3.util.ResourceBasedOverride;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
import com.google.protobuf.nano.MessageNano;
import java.util.ArrayList;
import java.util.UUID;
/**
* Manages the creation of {@link LauncherEvent}.
* To debug this class, execute following command before side loading a new apk.
* <p>
* $ 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<Target> 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<Target> 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<Target> 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<Target> 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<Target> srcTargets = makeTargetsList(srcChild);
Target destChild = newItemTarget(dragObj.originalDragInfo, mInstantAppResolver);
ArrayList<Target> 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<Target> makeTargetsList(Target... targets) {
ArrayList<Target> result = new ArrayList<>();
for (Target target : targets) {
result.add(target);
}
return result;
}
}

Some files were not shown because too many files have changed in this diff Show More