diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto index 6dfb84ea2f..ca9f0631f1 100644 --- a/protos/launcher_atom.proto +++ b/protos/launcher_atom.proto @@ -241,6 +241,7 @@ message FolderContainer { oneof ParentContainer { WorkspaceContainer workspace = 4; HotseatContainer hotseat = 5; + TaskBarContainer taskbar = 6; } } diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 764b0d3c7b..3dd7f5dd81 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -16,6 +16,8 @@ package com.android.launcher3.taskbar; import static com.android.launcher3.LauncherState.HOTSEAT_ICONS; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP; import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME; @@ -36,7 +38,10 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.logging.InstanceId; +import com.android.launcher3.logging.InstanceIdSequence; import com.android.launcher3.model.data.ItemInfoWithIcon; +import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.MultiValueAlpha; import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.launcher3.util.OnboardingPrefs; @@ -262,6 +267,11 @@ public class LauncherTaskbarUIController extends TaskbarUIController { @Override protected void onStashedInAppChanged() { onStashedInAppChanged(mLauncher.getDeviceProfile()); + if (mControllers.taskbarStashController.isStashedInApp()) { + mContext.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_LONGPRESS_HIDE); + } else { + mContext.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_LONGPRESS_SHOW); + } } private void onStashedInAppChanged(DeviceProfile deviceProfile) { @@ -306,6 +316,12 @@ public class LauncherTaskbarUIController extends TaskbarUIController { mControllers.taskbarEduController.hideEdu(); } + @Override + public void onTaskbarIconLaunched(WorkspaceItemInfo item) { + InstanceId instanceId = new InstanceIdSequence().newInstanceId(); + mLauncher.logAppLaunch(mContext.getStatsLogManager(), item, instanceId); + } + private final class TaskBarRecentsAnimationListener implements RecentsAnimationListener { private final RecentsAnimationCallbacks mCallbacks; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 0d684a04d4..b93251e4d7 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -19,6 +19,7 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN; import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT; import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR; @@ -52,6 +53,7 @@ import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.taskbar.contextual.RotationButtonController; @@ -229,6 +231,60 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ return false; } + /** + * Change from hotseat/predicted hotseat to taskbar container. + */ + @Override + public void applyOverwritesToLogItem(LauncherAtom.ItemInfo.Builder itemInfoBuilder) { + if (!itemInfoBuilder.hasContainerInfo()) { + return; + } + LauncherAtom.ContainerInfo oldContainer = itemInfoBuilder.getContainerInfo(); + + if (oldContainer.hasPredictedHotseatContainer()) { + LauncherAtom.PredictedHotseatContainer predictedHotseat = + oldContainer.getPredictedHotseatContainer(); + LauncherAtom.TaskBarContainer.Builder taskbarBuilder = + LauncherAtom.TaskBarContainer.newBuilder(); + + if (predictedHotseat.hasIndex()) { + taskbarBuilder.setIndex(predictedHotseat.getIndex()); + } + if (predictedHotseat.hasCardinality()) { + taskbarBuilder.setCardinality(predictedHotseat.getCardinality()); + } + + itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder() + .setTaskBarContainer(taskbarBuilder)); + } else if (oldContainer.hasHotseat()) { + LauncherAtom.HotseatContainer hotseat = oldContainer.getHotseat(); + LauncherAtom.TaskBarContainer.Builder taskbarBuilder = + LauncherAtom.TaskBarContainer.newBuilder(); + + if (hotseat.hasIndex()) { + taskbarBuilder.setIndex(hotseat.getIndex()); + } + + itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder() + .setTaskBarContainer(taskbarBuilder)); + } else if (oldContainer.hasFolder() && oldContainer.getFolder().hasHotseat()) { + LauncherAtom.FolderContainer.Builder folderBuilder = oldContainer.getFolder() + .toBuilder(); + LauncherAtom.HotseatContainer hotseat = folderBuilder.getHotseat(); + LauncherAtom.TaskBarContainer.Builder taskbarBuilder = + LauncherAtom.TaskBarContainer.newBuilder(); + + if (hotseat.hasIndex()) { + taskbarBuilder.setIndex(hotseat.getIndex()); + } + + folderBuilder.setTaskbar(taskbarBuilder); + folderBuilder.clearHotseat(); + itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder() + .setFolder(folderBuilder)); + } + } + /** * Sets a new data-source for this taskbar instance */ @@ -326,6 +382,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ getDragLayer().post(() -> { folder.animateOpen(); + getStatsLogManager().logger().withItemInfo(folder.mInfo).log(LAUNCHER_FOLDER_OPEN); folder.iterateOverItems((itemInfo, itemView) -> { mControllers.taskbarViewController @@ -363,6 +420,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ getSystemService(LauncherApps.class).startMainActivity( intent.getComponent(), info.user, intent.getSourceBounds(), null); } + + mControllers.uiController.onTaskbarIconLaunched(info); } catch (NullPointerException | ActivityNotFoundException | SecurityException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT) .show(); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index b89032e704..1afbd177e7 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -34,6 +34,8 @@ import android.view.View; import androidx.annotation.Nullable; +import com.android.internal.logging.InstanceId; +import com.android.internal.logging.InstanceIdSequence; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DragSource; @@ -48,6 +50,7 @@ import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.graphics.DragPreviewProvider; import com.android.launcher3.icons.FastBitmapDrawable; +import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.systemui.shared.recents.model.Task; @@ -284,10 +287,22 @@ public class TaskbarDragController extends DragController getAppIconsForEdu() { return Stream.empty(); } + + public void onTaskbarIconLaunched(WorkspaceItemInfo item) { } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 2009cd75d9..3738dce123 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -51,6 +51,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.appprediction.PredictionRowView; import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.logging.InstanceId; +import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.StatsLogManager.StatsLogger; import com.android.launcher3.model.BgDataModel.FixedContainerItems; import com.android.launcher3.model.data.ItemInfo; @@ -104,7 +105,8 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { } @Override - protected void logAppLaunch(ItemInfo info, InstanceId instanceId) { + public void logAppLaunch(StatsLogManager statsLogManager, ItemInfo info, + InstanceId instanceId) { // If the app launch is from any of the surfaces in AllApps then add the InstanceId from // LiveSearchManager to recreate the AllApps session on the server side. if (mAllAppsSessionLogId != null && ALL_APPS.equals( @@ -112,8 +114,7 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { instanceId = mAllAppsSessionLogId; } - StatsLogger logger = getStatsLogManager() - .logger().withItemInfo(info).withInstanceId(instanceId); + StatsLogger logger = statsLogManager.logger().withItemInfo(info).withInstanceId(instanceId); if (mAllAppsPredictions != null && (info.itemType == ITEM_TYPE_APPLICATION diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index 38c299e493..09113d8ede 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -56,6 +56,7 @@ import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.Executors; import com.android.launcher3.util.LogConfig; +import com.android.launcher3.views.ActivityContext; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.systemui.shared.system.SysUiStatsLog; @@ -97,7 +98,7 @@ public class StatsLogCompatManager extends StatsLogManager { @Override protected StatsLogger createLogger() { - return new StatsCompatLogger(mContext); + return new StatsCompatLogger(mContext, mActivityContext); } /** @@ -141,7 +142,8 @@ public class StatsLogCompatManager extends StatsLogManager { private static final ItemInfo DEFAULT_ITEM_INFO = new ItemInfo(); - private Context mContext; + private final Context mContext; + private final Optional mActivityContext; private ItemInfo mItemInfo = DEFAULT_ITEM_INFO; private InstanceId mInstanceId = DEFAULT_INSTANCE_ID; private OptionalInt mRank = OptionalInt.empty(); @@ -154,8 +156,9 @@ public class StatsLogCompatManager extends StatsLogManager { private SliceItem mSliceItem; private LauncherAtom.Slice mSlice; - StatsCompatLogger(Context context) { + StatsCompatLogger(Context context, ActivityContext activityContext) { mContext = context; + mActivityContext = Optional.ofNullable(activityContext); } @Override @@ -307,6 +310,9 @@ public class StatsLogCompatManager extends StatsLogManager { mRank.ifPresent(itemInfoBuilder::setRank); mContainerInfo.ifPresent(itemInfoBuilder::setContainerInfo); + mActivityContext.ifPresent(activityContext -> + activityContext.applyOverwritesToLogItem(itemInfoBuilder)); + if (mFromState.isPresent() || mToState.isPresent() || mEditText.isPresent()) { FolderIcon.Builder folderIconBuilder = itemInfoBuilder .getFolderIcon() diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index 2c76e52c61..7954011e93 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -55,6 +55,7 @@ import com.android.launcher3.allapps.search.DefaultSearchAdapterProvider; import com.android.launcher3.allapps.search.SearchAdapterProvider; import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.InstanceIdSequence; +import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.touch.ItemClickHandler; @@ -224,7 +225,7 @@ public abstract class BaseDraggingActivity extends BaseActivity } if (item != null) { InstanceId instanceId = new InstanceIdSequence().newInstanceId(); - logAppLaunch(item, instanceId); + logAppLaunch(getStatsLogManager(), item, instanceId); } return true; } catch (NullPointerException | ActivityNotFoundException | SecurityException e) { @@ -234,8 +235,12 @@ public abstract class BaseDraggingActivity extends BaseActivity return false; } - protected void logAppLaunch(ItemInfo info, InstanceId instanceId) { - getStatsLogManager().logger().withItemInfo(info).withInstanceId(instanceId) + /** + * Creates and logs a new app launch event. + */ + public void logAppLaunch(StatsLogManager statsLogManager, ItemInfo info, + InstanceId instanceId) { + statsLogManager.logger().withItemInfo(info).withInstanceId(instanceId) .log(LAUNCHER_APP_LAUNCH_TAP); } diff --git a/src/com/android/launcher3/logging/InstanceId.java b/src/com/android/launcher3/logging/InstanceId.java index e720d758b4..3c4a644053 100644 --- a/src/com/android/launcher3/logging/InstanceId.java +++ b/src/com/android/launcher3/logging/InstanceId.java @@ -36,10 +36,10 @@ import androidx.annotation.VisibleForTesting; */ public final class InstanceId implements Parcelable { // At most 20 bits: ~1m possibilities, ~0.5% probability of collision in 100 values - static final int INSTANCE_ID_MAX = 1 << 20; + public static final int INSTANCE_ID_MAX = 1 << 20; private final int mId; - InstanceId(int id) { + public InstanceId(int id) { mId = min(max(0, id), INSTANCE_ID_MAX); } diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 5ed651f5a9..d987212e22 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -33,6 +33,7 @@ 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.util.ResourceBasedOverride; +import com.android.launcher3.views.ActivityContext; /** * Handles the user event logging in R+. @@ -53,6 +54,9 @@ public class StatsLogManager implements ResourceBasedOverride { public static final int LAUNCHER_STATE_UNCHANGED = 5; private InstanceId mInstanceId; + + protected @Nullable ActivityContext mActivityContext = null; + /** * Returns event enum based on the two state transition information when swipe * gesture happens(to be removed during UserEventDispatcher cleanup). @@ -281,6 +285,9 @@ public class StatsLogManager implements ResourceBasedOverride { @UiEvent(doc = "User tapped on the share button on overview") LAUNCHER_OVERVIEW_ACTIONS_SHARE(582), + @UiEvent(doc = "User tapped on the split screen button on overview") + LAUNCHER_OVERVIEW_ACTIONS_SPLIT(895), + @UiEvent(doc = "User tapped on the close button in select mode") LAUNCHER_SELECT_MODE_CLOSE(583), @@ -505,7 +512,13 @@ public class StatsLogManager implements ResourceBasedOverride { LAUNCHER_TURN_OFF_WORK_APPS_TAP(839), @UiEvent(doc = "Launcher item drop failed since there was not enough room on the screen.") - LAUNCHER_ITEM_DROP_FAILED_INSUFFICIENT_SPACE(872); + LAUNCHER_ITEM_DROP_FAILED_INSUFFICIENT_SPACE(872), + + @UiEvent(doc = "User long pressed on the taskbar background to hide the taskbar") + LAUNCHER_TASKBAR_LONGPRESS_HIDE(896), + + @UiEvent(doc = "User long pressed on the taskbar gesture handle to show the taskbar") + LAUNCHER_TASKBAR_LONGPRESS_SHOW(897); // ADD MORE @@ -645,7 +658,7 @@ public class StatsLogManager implements ResourceBasedOverride { public StatsLogger logger() { StatsLogger logger = createLogger(); if (mInstanceId != null) { - return logger.withInstanceId(mInstanceId); + logger.withInstanceId(mInstanceId); } return logger; } @@ -668,7 +681,9 @@ public class StatsLogManager implements ResourceBasedOverride { * Creates a new instance of {@link StatsLogManager} based on provided context. */ public static StatsLogManager newInstance(Context context) { - return Overrides.getObject(StatsLogManager.class, + StatsLogManager manager = Overrides.getObject(StatsLogManager.class, context.getApplicationContext(), R.string.stats_log_manager_class); + manager.mActivityContext = ActivityContext.lookupContextNoThrow(context); + return manager; } } diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java index dc5fe06450..ebcd379f74 100644 --- a/src/com/android/launcher3/views/ActivityContext.java +++ b/src/com/android/launcher3/views/ActivityContext.java @@ -27,6 +27,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.dot.DotInfo; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.ViewCache; @@ -122,15 +123,33 @@ public interface ActivityContext { } /** - * Returns the ActivityContext associated with the given Context. + * Called just before logging the given item. + */ + default void applyOverwritesToLogItem(LauncherAtom.ItemInfo.Builder itemInfoBuilder) { } + + /** + * Returns the ActivityContext associated with the given Context, or throws an exception if + * the Context is not associated with any ActivityContext. */ static T lookupContext(Context context) { + T activityContext = lookupContextNoThrow(context); + if (activityContext == null) { + throw new IllegalArgumentException("Cannot find ActivityContext in parent tree"); + } + return activityContext; + } + + /** + * Returns the ActivityContext associated with the given Context, or null if + * the Context is not associated with any ActivityContext. + */ + static T lookupContextNoThrow(Context context) { if (context instanceof ActivityContext) { return (T) context; } else if (context instanceof ContextWrapper) { - return lookupContext(((ContextWrapper) context).getBaseContext()); + return lookupContextNoThrow(((ContextWrapper) context).getBaseContext()); } else { - throw new IllegalArgumentException("Cannot find ActivityContext in parent tree"); + return null; } } }