Merge "Show work switch tip" into ub-launcher3-master
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
new file mode 100644
index 0000000..a89fe5c
--- /dev/null
+++ b/protos/launcher_atom.proto
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+syntax = "proto2";
+
+option java_package = "com.android.launcher3.logger";
+option java_outer_classname = "LauncherAtom";
+
+//
+// ItemInfos
+message ItemInfo {
+ oneof Item {
+ Application application = 1;
+ Task task= 2;
+ Shortcut shortcut = 3;
+ Widget widget = 4;
+ }
+ // When used for launch event, stores the global predictive rank
+ optional int32 rank = 5;
+
+ // Stores whether the Item belows to non primary user
+ optional bool is_work = 6;
+
+ // Item can be child node to parent container or parent containers (nested)
+ oneof Container {
+ WorkspaceContainer workspace = 7;
+ HotseatContainer hotseat = 8;
+ FolderContainer folder = 9;
+ }
+ // Stores the origin of the Item
+ optional Origin source = 10;
+}
+
+enum Origin {
+ UNKNOWN = 0;
+ DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat
+ BACKUP_RESTORE = 2; // icon layout restored from backup
+ PINITEM = 3; // from another app (e.g., Chrome's "Add to Home screen")
+ ALLAPPS_ATOZ = 4; // within launcher surface, all aps a-z
+ WIDGETS = 5; // within launcher, widgets tray
+ ADD_TO_HOMESCREEN = 6; // play install + launcher home setting
+ ALLAPPS_PREDICTION = 7; // from prediction bar in all apps container
+ HOTSEAT_PREDICTION = 8; // from prediction bar in hotseat container
+}
+
+// Main app icons
+message Application {
+ optional string package_name = 1;
+ optional string component_name = 2;
+}
+
+// Legacy shortcuts and shortcuts handled by ShortcutManager
+message Shortcut {
+ optional string shortcut_name = 1;
+}
+
+// AppWidgets handled by AppWidgetManager
+message Widget {
+ optional int32 span_x = 1;
+ optional int32 span_y = 2;
+ optional int32 app_widget_id = 3;
+ optional string package_name = 4; // only populated during snapshot if from workspace
+ optional string component_name = 5; // only populated during snapshot if from workspace
+}
+
+// Tasks handled by PackageManager
+message Task {
+ optional string package_name = 1;
+ optional string component_name = 2;
+ optional int32 index = 3;
+}
+
+//////////////////////////////////////////////
+// Containers
+
+message WorkspaceContainer {
+ optional int32 page_index = 1; // range [-1, l], 0 is the index of the main homescreen
+ optional int32 grid_x = 2; // [0, m], m varies based on the display density and resolution
+ optional int32 grid_y = 3; // [0, n], n varies based on the display density and resolution
+}
+
+message HotseatContainer {
+ optional int32 index = 1;
+}
+
+message FolderContainer {
+ optional int32 page_index = 1;
+ optional int32 grid_x = 2;
+ optional int32 grid_y = 3;
+ oneof Container {
+ WorkspaceContainer workspace = 4;
+ HotseatContainer hotseat = 5;
+ }
+}
+
+
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 57a9940..1c95a9e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -30,6 +30,8 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_DISMISS_SWIPE_UP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.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;
@@ -1183,13 +1185,13 @@
verticalFactor * secondaryTaskDimension).setDuration(duration), LINEAR, sp);
}
- private void removeTask(Task task, int index, EndState endState) {
- if (task != null) {
- ActivityManagerWrapper.getInstance().removeTask(task.key.id);
- ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(task.key);
+ private void removeTask(TaskView taskView, int index, EndState endState) {
+ if (taskView.getTask() != null) {
+ ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
+ ComponentKey compKey = TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key);
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
- endState.logAction, Direction.UP, index, componentKey);
- mActivity.getStatsLogManager().logTaskDismiss(this, componentKey);
+ endState.logAction, Direction.UP, index, compKey);
+ mActivity.getStatsLogManager().log(TASK_DISMISS_SWIPE_UP, taskView.buildProto());
}
}
@@ -1284,7 +1286,7 @@
private void onEnd(EndState endState) {
if (endState.isSuccess) {
if (shouldRemoveTask) {
- removeTask(taskView.getTask(), draggedIndex, endState);
+ removeTask(taskView, draggedIndex, endState);
}
int pageToSnapTo = mCurrentPage;
@@ -1733,6 +1735,8 @@
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
endState.logAction, Direction.DOWN, indexOfChild(tv),
TaskUtils.getLaunchComponentKeyForTask(task.key));
+ mActivity.getStatsLogManager().log(TASK_LAUNCH_SWIPE_DOWN, tv.buildProto()
+ );
}
} else {
onTaskLaunched(false);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 71aaef1..7010f9a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -29,6 +29,7 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_TAP;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -43,6 +44,7 @@
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Process;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Log;
@@ -59,6 +61,7 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.states.RotationHelper;
@@ -68,6 +71,7 @@
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.ViewPool.Reusable;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.TaskIconCache;
@@ -217,8 +221,7 @@
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this),
TaskUtils.getLaunchComponentKeyForTask(getTask().key));
- mActivity.getStatsLogManager().logTaskLaunch(getRecentsView(),
- TaskUtils.getLaunchComponentKeyForTask(getTask().key));
+ mActivity.getStatsLogManager().log(TASK_LAUNCH_TAP, buildProto());
});
mCornerRadius = TaskCornerRadius.get(context);
mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources());
@@ -229,6 +232,17 @@
setOutlineProvider(mOutlineProvider);
}
+ /* Builds proto for logging */
+ protected LauncherAtom.ItemInfo buildProto() {
+ ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(getTask().key);
+ LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
+ itemBuilder.setIsWork(componentKey.user != Process.myUserHandle());
+ itemBuilder.setTask(LauncherAtom.Task.newBuilder()
+ .setComponentName(componentKey.componentName.flattenToShortString())
+ .setIndex(getRecentsView().indexOfChild(this)));
+ return itemBuilder.build();
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 32e07af..9ef38c0 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -113,7 +113,7 @@
<!-- ******* Overview ******* -->
<!-- Label for a button that causes the current overview app to be shared. [CHAR_LIMIT=40] -->
- <string translatable="false" name="action_share">Share</string>
+ <string name="action_share">Share</string>
<!-- Label for a button that causes a screen shot of the current app to be taken. [CHAR_LIMIT=40] -->
- <string translatable="false" name="action_screenshot">Screenshot</string>
+ <string name="action_screenshot">Screenshot</string>
</resources>
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 22fe2e1..58bb980 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -18,36 +18,22 @@
import static android.stats.launcher.nano.Launcher.ALLAPPS;
import static android.stats.launcher.nano.Launcher.BACKGROUND;
-import static android.stats.launcher.nano.Launcher.DISMISS_TASK;
import static android.stats.launcher.nano.Launcher.HOME;
-import static android.stats.launcher.nano.Launcher.LAUNCH_APP;
-import static android.stats.launcher.nano.Launcher.LAUNCH_TASK;
import static android.stats.launcher.nano.Launcher.OVERVIEW;
-import static com.android.launcher3.logging.UserEventDispatcher.makeTargetsList;
-
import android.content.Context;
-import android.content.Intent;
-import android.os.UserHandle;
-import android.stats.launcher.nano.Launcher;
-import android.stats.launcher.nano.LauncherExtension;
-import android.stats.launcher.nano.LauncherTarget;
-import android.util.Log;
-import android.view.View;
-import androidx.annotation.Nullable;
-
+import com.android.launcher3.FolderInfo;
import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogUtils;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-import com.android.launcher3.util.ComponentKey;
-import com.android.systemui.shared.system.SysUiStatsLog;
-
-import com.google.protobuf.nano.MessageNano;
+import com.android.launcher3.model.AllAppsList;
+import com.android.launcher3.model.BaseModelUpdateTask;
+import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.util.IntSparseArrayMap;
import java.util.ArrayList;
@@ -62,186 +48,17 @@
public class StatsLogCompatManager extends StatsLogManager {
private static final int SUPPORTED_TARGET_DEPTH = 2;
- private static final String TAG = "StatsLogCompatManager";
+ private static final String TAG = "StatsLog";
private static final boolean DEBUG = false;
+ private static Context sContext;
public StatsLogCompatManager(Context context) {
+ sContext = context;
}
@Override
- public void logAppLaunch(View v, Intent intent, @Nullable UserHandle userHandle) {
- LauncherExtension ext = new LauncherExtension();
- ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH];
- int srcState = mStateProvider.getCurrentState();
- fillInLauncherExtension(v, ext);
- if (ext.srcTarget[0] != null) {
- ext.srcTarget[0].item = LauncherTarget.APP_ICON;
- }
- SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT, LAUNCH_APP, srcState,
- BACKGROUND /* dstState */, MessageNano.toByteArray(ext), true);
- }
-
- @Override
- public void logTaskLaunch(View v, ComponentKey componentKey) {
- LauncherExtension ext = new LauncherExtension();
- ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH];
- int srcState = OVERVIEW;
- fillInLauncherExtension(v, ext);
- SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT, LAUNCH_TASK, srcState,
- BACKGROUND /* dstState */, MessageNano.toByteArray(ext), true);
- }
-
- @Override
- public void logTaskDismiss(View v, ComponentKey componentKey) {
- LauncherExtension ext = new LauncherExtension();
- ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH];
- int srcState = OVERVIEW;
- fillInLauncherExtension(v, ext);
- SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT, DISMISS_TASK, srcState,
- BACKGROUND /* dstState */, MessageNano.toByteArray(ext), true);
- }
-
- @Override
- public void logSwipeOnContainer(boolean isSwipingToLeft, int pageId) {
- LauncherExtension ext = new LauncherExtension();
- ext.srcTarget = new LauncherTarget[1];
- int srcState = mStateProvider.getCurrentState();
- fillInLauncherExtensionWithPageId(ext, pageId);
- int launcherAction = isSwipingToLeft ? Launcher.SWIPE_LEFT : Launcher.SWIPE_RIGHT;
- SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT, launcherAction, srcState, srcState,
- MessageNano.toByteArray(ext), true);
- }
-
- public static boolean fillInLauncherExtension(View v, LauncherExtension extension) {
- if (DEBUG) {
- Log.d(TAG, "fillInLauncherExtension");
- }
-
- StatsLogUtils.LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(v);
- if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) {
- if (DEBUG) {
- Log.d(TAG, "View or provider is null, or view doesn't have an ItemInfo tag.");
- }
-
- return false;
- }
- Target child = new Target();
- ArrayList<Target> targets = makeTargetsList(child);
- targets.add(child);
- provider.fillInLogContainerData((ItemInfo) v.getTag(), child, targets);
-
- int maxDepth = Math.min(SUPPORTED_TARGET_DEPTH, targets.size());
- extension.srcTarget = new LauncherTarget[maxDepth];
- for (int i = 0; i < maxDepth; i++) {
- extension.srcTarget[i] = new LauncherTarget();
- copy(targets.get(i), extension.srcTarget[i]);
- }
- return true;
- }
-
- public static boolean fillInLauncherExtensionWithPageId(LauncherExtension ext, int pageId) {
- if (DEBUG) {
- Log.d(TAG, "fillInLauncherExtensionWithPageId, pageId = " + pageId);
- }
-
- Target target = new Target();
- target.pageIndex = pageId;
- ext.srcTarget[0] = new LauncherTarget();
- copy(target, ext.srcTarget[0]);
- return true;
- }
-
- private static void copy(Target src, LauncherTarget dst) {
- if (DEBUG) {
- Log.d(TAG, "copy target information from clearcut Target to LauncherTarget.");
- }
-
- // Fill in type
- switch (src.type) {
- case Target.Type.ITEM:
- dst.type = LauncherTarget.ITEM_TYPE;
- break;
- case Target.Type.CONTROL:
- dst.type = LauncherTarget.CONTROL_TYPE;
- break;
- case Target.Type.CONTAINER:
- dst.type = LauncherTarget.CONTAINER_TYPE;
- break;
- default:
- dst.type = LauncherTarget.NONE;
- break;
- }
-
- // Fill in item
- switch (src.itemType) {
- case ItemType.APP_ICON:
- dst.item = LauncherTarget.APP_ICON;
- break;
- case ItemType.SHORTCUT:
- dst.item = LauncherTarget.SHORTCUT;
- break;
- case ItemType.WIDGET:
- dst.item = LauncherTarget.WIDGET;
- break;
- case ItemType.FOLDER_ICON:
- dst.item = LauncherTarget.FOLDER_ICON;
- break;
- case ItemType.DEEPSHORTCUT:
- dst.item = LauncherTarget.DEEPSHORTCUT;
- break;
- case ItemType.SEARCHBOX:
- dst.item = LauncherTarget.SEARCHBOX;
- break;
- case ItemType.EDITTEXT:
- dst.item = LauncherTarget.EDITTEXT;
- break;
- case ItemType.NOTIFICATION:
- dst.item = LauncherTarget.NOTIFICATION;
- break;
- case ItemType.TASK:
- dst.item = LauncherTarget.TASK;
- break;
- default:
- dst.item = LauncherTarget.DEFAULT_ITEM;
- break;
- }
-
- // Fill in container
- switch (src.containerType) {
- case ContainerType.HOTSEAT:
- dst.container = LauncherTarget.HOTSEAT;
- break;
- case ContainerType.FOLDER:
- dst.container = LauncherTarget.FOLDER;
- break;
- case ContainerType.PREDICTION:
- dst.container = LauncherTarget.PREDICTION;
- break;
- case ContainerType.SEARCHRESULT:
- dst.container = LauncherTarget.SEARCHRESULT;
- break;
- default:
- dst.container = LauncherTarget.DEFAULT_CONTAINER;
- break;
- }
-
- // Fill in control
- switch (src.controlType) {
- case ControlType.UNINSTALL_TARGET:
- dst.control = LauncherTarget.UNINSTALL;
- break;
- case ControlType.REMOVE_TARGET:
- dst.control = LauncherTarget.REMOVE;
- break;
- default:
- dst.control = LauncherTarget.DEFAULT_CONTROL;
- break;
- }
-
- // Fill in other fields
- dst.pageId = src.pageIndex;
- dst.gridX = src.gridX;
- dst.gridY = src.gridY;
+ public void log(LauncherEvent eventId, LauncherAtom.ItemInfo item) {
+ // Call StatsLog method
}
@Override
@@ -254,4 +71,36 @@
"StatsLogUtil constants doesn't match enums in launcher.proto");
}
}
+
+ /**
+ * Logs the workspace layout information on the model thread.
+ */
+ public void logSnapshot() {
+ LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask(
+ new SnapshotWorker());
+ }
+
+ private class SnapshotWorker extends BaseModelUpdateTask {
+ @Override
+ public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
+ IntSparseArrayMap<FolderInfo> folders = dataModel.folders.clone();
+ ArrayList<ItemInfo> workspaceItems = (ArrayList) dataModel.workspaceItems.clone();
+ ArrayList<LauncherAppWidgetInfo> appWidgets = (ArrayList) dataModel.appWidgets.clone();
+
+ for (ItemInfo info : workspaceItems) {
+ LauncherAtom.ItemInfo atomInfo = info.buildProto(null, null);
+ // call StatsLog method
+ }
+ for (FolderInfo fInfo : folders) {
+ for (ItemInfo info : fInfo.contents) {
+ LauncherAtom.ItemInfo atomInfo = info.buildProto(null, fInfo);
+ // call StatsLog method
+ }
+ }
+ for (ItemInfo info : appWidgets) {
+ LauncherAtom.ItemInfo atomInfo = info.buildProto(null, null);
+ // call StatsLog method
+ }
+ }
+ }
}
diff --git a/res/layout/search_container_all_apps.xml b/res/layout/search_container_all_apps.xml
index fd9cb60..e1646ba 100644
--- a/res/layout/search_container_all_apps.xml
+++ b/res/layout/search_container_all_apps.xml
@@ -34,5 +34,4 @@
android:singleLine="true"
android:textColor="?android:attr/textColorSecondary"
android:textColorHint="@drawable/all_apps_search_hint"
- android:textSize="16sp"
- android:translationY="24dp" />
\ No newline at end of file
+ android:textSize="16sp" />
\ No newline at end of file
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 9f3b48f..6fa3c28 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.APP_LAUNCH_TAP;
import static com.android.launcher3.util.DefaultDisplay.CHANGE_ROTATION;
import android.app.ActivityOptions;
@@ -181,7 +182,7 @@
sourceContainer);
}
getUserEventDispatcher().logAppLaunch(v, intent, user);
- getStatsLogManager().logAppLaunch(v, intent, user);
+ getStatsLogManager().log(APP_LAUNCH_TAP, item.buildProto(null, null));
return true;
} catch (NullPointerException|ActivityNotFoundException|SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index c99465c..8c4e4a0 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -16,6 +16,13 @@
package com.android.launcher3;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Intent;
@@ -24,13 +31,17 @@
import androidx.annotation.Nullable;
+import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.util.ContentWriter;
+
+
/**
* Represents an item in the launcher.
*/
public class ItemInfo {
+ public static final boolean DEBUG = true;
public static final int NO_ID = -1;
/**
@@ -190,6 +201,7 @@
return "id=" + id
+ " type=" + LauncherSettings.Favorites.itemTypeToString(itemType)
+ " container=" + LauncherSettings.Favorites.containerToString((int)container)
+ + " targetComponent=" + getTargetComponent()
+ " screen=" + screenId
+ " cell(" + cellX + "," + cellY + ")"
+ " span(" + spanX + "," + spanY + ")"
@@ -221,4 +233,70 @@
return container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION
|| container == LauncherSettings.Favorites.CONTAINER_PREDICTION;
}
+
+ /**
+ * Can be overridden by inherited classes to fill in {@link LauncherAtom.ItemInfo}
+ */
+ public void setItemBuilder(LauncherAtom.ItemInfo.Builder builder) {
+ }
+
+ /**
+ * Creates {@link LauncherAtom.ItemInfo} with important fields and parent container info.
+ */
+ public LauncherAtom.ItemInfo buildProto(Intent intent, FolderInfo fInfo) {
+
+ LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
+ itemBuilder.setIsWork(user != Process.myUserHandle());
+ ComponentName cn = getTargetComponent();
+ switch (itemType) {
+ case ITEM_TYPE_APPLICATION:
+ itemBuilder.setApplication(LauncherAtom.Application.newBuilder()
+ .setComponentName(cn.flattenToShortString())
+ .setPackageName(cn.getPackageName()));
+ break;
+ case ITEM_TYPE_DEEP_SHORTCUT:
+ case ITEM_TYPE_SHORTCUT:
+ itemBuilder.setShortcut(LauncherAtom.Shortcut.newBuilder()
+ .setShortcutName(cn.flattenToShortString()));
+ break;
+ case ITEM_TYPE_APPWIDGET:
+ setItemBuilder(itemBuilder);
+ break;
+ default:
+ break;
+
+ }
+ if (fInfo != null) {
+ LauncherAtom.FolderContainer.Builder folderBuilder =
+ LauncherAtom.FolderContainer.newBuilder();
+ folderBuilder.setGridX(cellX).setGridY(cellY).setPageIndex(screenId);
+
+ switch (fInfo.container) {
+ case CONTAINER_HOTSEAT:
+ folderBuilder.setHotseat(LauncherAtom.HotseatContainer.newBuilder()
+ .setIndex(fInfo.screenId));
+ break;
+ case CONTAINER_DESKTOP:
+ folderBuilder.setWorkspace(LauncherAtom.WorkspaceContainer.newBuilder()
+ .setPageIndex(fInfo.screenId)
+ .setGridX(fInfo.cellX).setGridY(fInfo.cellY));
+ break;
+ }
+ itemBuilder.setFolder(folderBuilder);
+ } else {
+ switch (container) {
+ case CONTAINER_HOTSEAT:
+ itemBuilder.setHotseat(LauncherAtom.HotseatContainer.newBuilder()
+ .setIndex(screenId));
+ break;
+ case CONTAINER_DESKTOP:
+ itemBuilder.setWorkspace(LauncherAtom.WorkspaceContainer.newBuilder()
+ .setGridX(cellX)
+ .setGridY(cellY)
+ .setPageIndex(screenId));
+ break;
+ }
+ }
+ return itemBuilder.build();
+ }
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index b824301..3a478dd 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.os.Process;
+import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.util.ContentWriter;
@@ -162,7 +163,9 @@
@Override
protected String dumpProperties() {
- return super.dumpProperties() + " appWidgetId=" + appWidgetId;
+ return super.dumpProperties()
+ + " providerName=" + providerName
+ + " appWidgetId=" + appWidgetId;
}
public final boolean isWidgetIdAllocated() {
@@ -182,4 +185,13 @@
public final boolean hasOptionFlag(int option) {
return (options & option) != 0;
}
+
+ @Override
+ public void setItemBuilder(LauncherAtom.ItemInfo.Builder builder) {
+ builder.setWidget(LauncherAtom.Widget.newBuilder()
+ .setSpanX(spanX)
+ .setSpanY(spanY)
+ .setComponentName(providerName.toString())
+ .setPackageName(providerName.getPackageName()));
+ }
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index ee9c099..8bc0242 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -991,7 +991,6 @@
if (!mOverlayShown) {
mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
Action.Direction.LEFT, ContainerType.WORKSPACE, 0);
- mLauncher.getStatsLogManager().logSwipeOnContainer(true, 0);
}
mOverlayShown = true;
// Not announcing the overlay page for accessibility since it announces itself.
@@ -1001,7 +1000,6 @@
if (!ued.isPreviousHomeGesture()) {
mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
Action.Direction.RIGHT, ContainerType.WORKSPACE, -1);
- mLauncher.getStatsLogManager().logSwipeOnContainer(false, -1);
}
} else if (Float.compare(mOverlayTranslation, 0f) != 0) {
// When arriving to 0 overscroll from non-zero overscroll, announce page for
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 6f7f8e6..24c846c 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -146,11 +146,21 @@
}
}
+ if (!fromKeyboard && !itemSupportsLongClick(host, item)) {
+ info.setLongClickable(false);
+ info.removeAction(AccessibilityAction.ACTION_LONG_CLICK);
+ }
+
if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
info.addAction(mActions.get(ADD_TO_WORKSPACE));
}
}
+ private boolean itemSupportsLongClick(View host, ItemInfo info) {
+ return new CustomActionsPopup(mLauncher, host).canShow()
+ || ShortcutUtil.supportsShortcuts(info);
+ }
+
private boolean itemSupportsAccessibleDrag(ItemInfo item) {
if (item instanceof WorkspaceItemInfo) {
// Support the action unless the item is in a context menu.
@@ -171,18 +181,18 @@
public boolean performAction(final View host, final ItemInfo item, int action) {
if (action == ACTION_LONG_CLICK) {
- if (ShortcutUtil.isDeepShortcut(item)) {
- CustomActionsPopup popup = new CustomActionsPopup(mLauncher, host);
- if (popup.canShow()) {
- popup.show();
- return true;
- }
- } else if (host instanceof BubbleTextView) {
+ if (ShortcutUtil.supportsShortcuts(item)) {
// Long press should be consumed for workspace items, and it should invoke the
// Shortcuts / Notifications / Actions pop-up menu, and not start a drag as the
// standard long press path does.
PopupContainerWithArrow.showForIcon((BubbleTextView) host);
return true;
+ } else {
+ CustomActionsPopup popup = new CustomActionsPopup(mLauncher, host);
+ if (popup.canShow()) {
+ popup.show();
+ return true;
+ }
}
}
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index d497c3a..9e3a862 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -62,9 +62,8 @@
private AlphabeticalAppsList mApps;
private AllAppsContainerView mAppsView;
- // This value was used to position the QSB. We store it here for translationY animations.
- private final float mFixedTranslationY;
- private final float mMarginTopAdjusting;
+ // The amount of pixels to shift down and overlap with the rest of the content.
+ private final int mContentOverlap;
public AppsSearchContainerLayout(Context context) {
this(context, null);
@@ -82,11 +81,10 @@
mSearchQueryBuilder = new SpannableStringBuilder();
Selection.setSelection(mSearchQueryBuilder, 0);
-
- mFixedTranslationY = getTranslationY();
- mMarginTopAdjusting = mFixedTranslationY - getPaddingTop();
-
setHint(prefixTextWithIcon(getContext(), R.drawable.ic_allapps_search, getHint()));
+
+ mContentOverlap =
+ getResources().getDimensionPixelSize(R.dimen.all_apps_search_bar_field_height) / 2;
}
@Override
@@ -128,6 +126,8 @@
int expectedLeft = parent.getPaddingLeft() + (availableWidth - myWidth) / 2;
int shift = expectedLeft - left;
setTranslationX(shift);
+
+ offsetTopAndBottom(mContentOverlap);
}
@Override
@@ -196,7 +196,7 @@
@Override
public void setInsets(Rect insets) {
MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
- mlp.topMargin = Math.round(Math.max(-mFixedTranslationY, insets.top - mMarginTopAdjusting));
+ mlp.topMargin = insets.top;
requestLayout();
}
@@ -205,9 +205,7 @@
if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
return 0;
} else {
- int topMargin = Math.round(Math.max(
- -mFixedTranslationY, insets.top - mMarginTopAdjusting));
- return insets.bottom + topMargin + mFixedTranslationY;
+ return insets.bottom + insets.top;
}
}
diff --git a/src/com/android/launcher3/logging/LauncherUiEvent.java b/src/com/android/launcher3/logging/LauncherUiEvent.java
new file mode 100644
index 0000000..4507ff7
--- /dev/null
+++ b/src/com/android/launcher3/logging/LauncherUiEvent.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.logging;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Retention(SOURCE)
+@Target(FIELD)
+public @interface LauncherUiEvent {
+ /** An explanation, suitable for Android analysts, of the UI event that this log represents. */
+ String doc();
+}
+
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 9dfd7ab..2829951 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -16,23 +16,44 @@
package com.android.launcher3.logging;
import android.content.Context;
-import android.content.Intent;
-import android.os.UserHandle;
-import android.view.View;
-
-import androidx.annotation.Nullable;
import com.android.launcher3.R;
+import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logger.LauncherAtom.ItemInfo;
import com.android.launcher3.logging.StatsLogUtils.LogStateProvider;
-import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ResourceBasedOverride;
/**
- * Handles the user event logging in Q.
+ * Handles the user event logging in R+.
*/
public class StatsLogManager implements ResourceBasedOverride {
+ interface EventEnum {
+ int getId();
+ }
+
+ public enum LauncherEvent implements EventEnum {
+ @LauncherUiEvent(doc = "App launched from workspace, hotseat or folder in launcher")
+ APP_LAUNCH_TAP(1),
+ @LauncherUiEvent(doc = "Task launched from overview using TAP")
+ TASK_LAUNCH_TAP(2),
+ @LauncherUiEvent(doc = "Task launched from overview using SWIPE DOWN")
+ TASK_LAUNCH_SWIPE_DOWN(2),
+ @LauncherUiEvent(doc = "TASK dismissed from overview using SWIPE UP")
+ TASK_DISMISS_SWIPE_UP(3);
+ // ADD MORE
+
+ private final int mId;
+ LauncherEvent(int id) {
+ mId = id;
+ }
+ public int getId() {
+ return mId;
+ }
+ }
+
protected LogStateProvider mStateProvider;
+
public static StatsLogManager newInstance(Context context, LogStateProvider stateProvider) {
StatsLogManager mgr = Overrides.getObject(StatsLogManager.class,
context.getApplicationContext(), R.string.stats_log_manager_class);
@@ -42,11 +63,14 @@
}
/**
- * Logs app launches
+ * Logs an event and accompanying {@link ItemInfo}
*/
- public void logAppLaunch(View v, Intent intent, @Nullable UserHandle userHandle) { }
- public void logTaskLaunch(View v, ComponentKey key) { }
- public void logTaskDismiss(View v, ComponentKey key) { }
- public void logSwipeOnContainer(boolean isSwipingToLeft, int pageId) { }
+ public void log(LauncherEvent eventId, LauncherAtom.ItemInfo itemInfo) { }
+
+ /**
+ * Logs snapshot, or impression of the current workspace.
+ */
+ public void logSnapshot() { }
+
public void verify() {} // TODO: should move into robo tests
}
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 2311dcc..695d2a6 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -35,6 +35,8 @@
import android.util.Log;
import android.util.LongSparseArray;
+import androidx.annotation.VisibleForTesting;
+
import com.android.launcher3.AppInfo;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
@@ -150,8 +152,10 @@
}
}
+ @VisibleForTesting
public WorkspaceItemInfo loadSimpleWorkspaceItem() {
final WorkspaceItemInfo info = new WorkspaceItemInfo();
+ info.intent = new Intent();
// Non-app shortcuts are only supported for current user.
info.user = user;
info.itemType = itemType;
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index fae0fe2..d28fcf6 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -15,10 +15,12 @@
*/
package com.android.launcher3.states;
+import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
import static com.android.launcher3.config.FeatureFlags.FLAG_ENABLE_FIXED_ROTATION_TRANSFORM;
@@ -37,7 +39,6 @@
import android.view.WindowManager;
import com.android.launcher3.Launcher;
-import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
@@ -142,9 +143,12 @@
if (setValueFromPrefs) {
mForcedRotation = isForcedRotation;
}
- UI_HELPER_EXECUTOR.execute(
- () -> Settings.Global.putInt(mContentResolver, FIXED_ROTATION_TRANSFORM_SETTING_NAME,
- mForcedRotation ? 1 : 0));
+ UI_HELPER_EXECUTOR.execute(() -> {
+ if (mLauncher.checkSelfPermission(WRITE_SECURE_SETTINGS) == PERMISSION_GRANTED) {
+ Settings.Global.putInt(mContentResolver, FIXED_ROTATION_TRANSFORM_SETTING_NAME,
+ mForcedRotation ? 1 : 0);
+ }
+ });
for (ForcedRotationChangedListener listener : mForcedRotationChangedListeners) {
listener.onForcedRotationChanged(mForcedRotation);
}
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index ba1bfa5..8537bdf 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -33,6 +33,8 @@
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.folder.Folder;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
/**
* Class to handle long-clicks on workspace items and start drag as a result.
@@ -46,6 +48,7 @@
ItemLongClickListener::onAllAppsItemLongClick;
private static boolean onWorkspaceItemLongClick(View v) {
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onWorkspaceItemLongClick");
Launcher launcher = Launcher.getLauncher(v.getContext());
if (!canStartDrag(launcher)) return false;
if (!launcher.isInState(NORMAL) && !launcher.isInState(OVERVIEW)) return false;
@@ -75,6 +78,8 @@
}
private static boolean onAllAppsItemLongClick(View v) {
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onAllAppsItemLongClick");
+ v.cancelLongPress();
Launcher launcher = Launcher.getLauncher(v.getContext());
if (!canStartDrag(launcher)) return false;
// When we have exited all apps or are in transition, disregard long clicks
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 310d598..da631bd 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -38,6 +38,8 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.Workspace;
import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.views.OptionsPopupView;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -165,6 +167,7 @@
@Override
public void onLongPress(MotionEvent event) {
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Workspace.longPress");
if (mLongPressState == STATE_REQUESTED) {
if (canHandleLongPress()) {
mLongPressState = STATE_PENDING_PARENT_INFORM;
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 868c91d..2fc3eaf 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -33,6 +33,7 @@
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.Property;
import android.view.MotionEvent;
import android.view.View;
@@ -48,6 +49,7 @@
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.SimpleBroadcastReceiver;
@@ -273,6 +275,9 @@
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "BaseDragLayer: " + ev);
+ }
switch (ev.getAction()) {
case ACTION_DOWN: {
mTouchDispatchState |= TOUCH_DISPATCHING_VIEW;
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 73a0615..23c2160 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -33,6 +33,8 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -92,6 +94,8 @@
@Override
public boolean onLongClick(View v) {
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Widgets.onLongClick");
+ v.cancelLongPress();
if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
if (v instanceof WidgetCell) {
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index b07a4f4..aaebedd 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -38,8 +39,10 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.TopRoundedCornerView;
@@ -68,6 +71,14 @@
}
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "WidgetsFullSheet: " + ev);
+ }
+ return super.dispatchTouchEvent(ev);
+ }
+
public WidgetsFullSheet(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index 8932291..bdfd563 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -32,6 +32,7 @@
public final class AppIcon extends Launchable {
private static final Pattern START_EVENT = Pattern.compile("start:");
+ private static final Pattern LONG_CLICK_EVENT = Pattern.compile("onAllAppsItemLongClick");
AppIcon(LauncherInstrumentation launcher, UiObject2 icon) {
super(launcher, icon);
@@ -47,11 +48,16 @@
public AppIconMenu openMenu() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
return new AppIconMenu(mLauncher, mLauncher.clickAndGet(
- mObject, "deep_shortcuts_container"));
+ mObject, "deep_shortcuts_container", LONG_CLICK_EVENT));
}
}
@Override
+ protected void addExpectedEventsForLongClick() {
+ mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT);
+ }
+
+ @Override
protected String getLongPressIndicator() {
return "deep_shortcuts_container";
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
index f8dd89c..37a7b91 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
@@ -41,6 +41,10 @@
}
@Override
+ protected void addExpectedEventsForLongClick() {
+ }
+
+ @Override
protected String getLongPressIndicator() {
return "drop_target_bar";
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index d1a1254..2177032 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -92,9 +92,12 @@
: launchableCenter.x + width / 2,
displaySize.y / 2),
getLongPressIndicator(),
- startsActivity);
+ startsActivity,
+ () -> addExpectedEventsForLongClick());
}
}
+ protected abstract void addExpectedEventsForLongClick();
+
protected abstract String getLongPressIndicator();
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index d171a69..1861ad1 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -334,15 +334,21 @@
private String getSystemAnomalyMessage() {
try {
+ final StringBuilder sb = new StringBuilder();
+
UiObject2 object = mDevice.findObject(By.res("android", "alertTitle"));
if (object != null) {
- return "System alert popup is visible: " + object.getText();
+ sb.append("TITLE: ").append(object.getText());
}
object = mDevice.findObject(By.res("android", "message"));
if (object != null) {
- return "Message popup by " + object.getApplicationPackage() + " is visible: "
- + object.getText();
+ sb.append(" PACKAGE: ").append(object.getApplicationPackage())
+ .append(" MESSAGE: ").append(object.getText());
+ }
+
+ if (sb.length() != 0) {
+ return "System alert popup is visible: " + sb;
}
if (hasSystemUiObject("keyguard_status_view")) return "Phone is locked";
@@ -1173,10 +1179,12 @@
}
@NonNull
- UiObject2 clickAndGet(@NonNull final UiObject2 target, @NonNull String resName) {
+ UiObject2 clickAndGet(
+ @NonNull final UiObject2 target, @NonNull String resName, Pattern longClickEvent) {
final Point targetCenter = target.getVisibleCenter();
final long downTime = SystemClock.uptimeMillis();
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetCenter, GestureScope.INSIDE);
+ expectEvent(TestProtocol.SEQUENCE_MAIN, longClickEvent);
final UiObject2 result = waitForLauncherObject(resName);
sendPointer(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, targetCenter,
GestureScope.INSIDE);
diff --git a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
index 0fc88ee..49901ea 100644
--- a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
+++ b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
@@ -149,23 +149,24 @@
finishSync(waitForExpectedCountMs);
final StringBuilder sb = new StringBuilder();
+ boolean hasMismatches = false;
for (Map.Entry<String, List<Pattern>> expectedEvents : mExpectedEvents.entrySet()) {
String sequence = expectedEvents.getKey();
List<String> actual = new ArrayList<>(mEvents.getNonNull(sequence));
final int mismatchPosition = getMismatchPosition(expectedEvents.getValue(), actual);
- if (mismatchPosition != -1) {
- formatSequenceWithMismatch(
- sb,
- sequence,
- expectedEvents.getValue(),
- actual,
- mismatchPosition);
- }
+ hasMismatches = hasMismatches || mismatchPosition != -1;
+ formatSequenceWithMismatch(
+ sb,
+ sequence,
+ expectedEvents.getValue(),
+ actual,
+ mismatchPosition);
}
// Check for unexpected event sequences in the actual data.
for (String actualNamedSequence : mEvents.keySet()) {
if (!mExpectedEvents.containsKey(actualNamedSequence)) {
+ hasMismatches = true;
formatSequenceWithMismatch(
sb,
actualNamedSequence,
@@ -175,7 +176,7 @@
}
}
- return sb.length() != 0 ? "mismatching events: " + sb.toString() : null;
+ return hasMismatches ? "mismatching events: " + sb.toString() : null;
}
// If the list of actual events matches the list of expected events, returns -1, otherwise
@@ -199,10 +200,11 @@
List<Pattern> expected,
List<String> actualEvents,
int mismatchPosition) {
- sb.append("\n>> Sequence " + sequenceName);
- sb.append("\n Expected:");
+ sb.append("\n>> SEQUENCE " + sequenceName + " - "
+ + (mismatchPosition == -1 ? "MATCH" : "MISMATCH"));
+ sb.append("\n EXPECTED:");
formatEventListWithMismatch(sb, expected, mismatchPosition);
- sb.append("\n Actual:");
+ sb.append("\n ACTUAL:");
formatEventListWithMismatch(sb, actualEvents, mismatchPosition);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widget.java b/tests/tapl/com/android/launcher3/tapl/Widget.java
index a658f16..53ef796 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widget.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widget.java
@@ -18,11 +18,17 @@
import androidx.test.uiautomator.UiObject2;
+import com.android.launcher3.testing.TestProtocol;
+
+import java.util.regex.Pattern;
+
/**
* Widget in workspace or a widget list.
*/
public final class Widget extends Launchable {
+ private static final Pattern LONG_CLICK_EVENT = Pattern.compile("Widgets.onLongClick");
+
Widget(LauncherInstrumentation launcher, UiObject2 icon) {
super(launcher, icon);
}
@@ -35,4 +41,9 @@
@Override
protected void expectActivityStartEvents() {
}
+
+ @Override
+ protected void addExpectedEventsForLongClick() {
+ mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT);
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 9ef6476..86aafc2 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -52,6 +52,7 @@
static final Pattern EVENT_CTRL_W_UP = Pattern.compile(
"Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_W"
+ ".*?metaState=META_CTRL_ON");
+ private static final Pattern LONG_CLICK_EVENT = Pattern.compile("onWorkspaceItemLongClick");
private final UiObject2 mHotseat;
@@ -178,7 +179,9 @@
new Point(mLauncher.getDevice().getDisplayWidth(),
workspace.getVisibleBounds().centerY()),
"deep_shortcuts_container",
- false);
+ false,
+ () -> mLauncher.expectEvent(
+ TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT));
verifyActiveContainer();
}
}
@@ -199,7 +202,7 @@
static void dragIconToWorkspace(
LauncherInstrumentation launcher, Launchable launchable, Point dest,
- String longPressIndicator, boolean startsActivity) {
+ String longPressIndicator, boolean startsActivity, Runnable expectLongClickEvents) {
LauncherInstrumentation.log("dragIconToWorkspace: begin");
final Point launchableCenter = launchable.getObject().getVisibleCenter();
final long downTime = SystemClock.uptimeMillis();
@@ -208,6 +211,7 @@
launcher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
launchableCenter, LauncherInstrumentation.GestureScope.INSIDE);
LauncherInstrumentation.log("dragIconToWorkspace: sent down");
+ expectLongClickEvents.run();
launcher.waitForLauncherObject(longPressIndicator);
LauncherInstrumentation.log("dragIconToWorkspace: indicator");
launcher.movePointer(launchableCenter, dest, 10, downTime, true,