Merge "Re-enable orientation sensor for Overview animation" 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/res/values/dimens.xml b/quickstep/recents_ui_overrides/res/values/dimens.xml
index 20b1485..363840a 100644
--- a/quickstep/recents_ui_overrides/res/values/dimens.xml
+++ b/quickstep/recents_ui_overrides/res/values/dimens.xml
@@ -31,9 +31,6 @@
<dimen name="all_apps_label_top_padding">16dp</dimen>
<dimen name="all_apps_label_bottom_padding">8dp</dimen>
<dimen name="all_apps_label_text_size">14sp</dimen>
- <dimen name="all_apps_tip_bottom_margin">8dp</dimen>
- <!-- The size of corner radius of the arrow in the arrow toast. -->
- <dimen name="arrow_toast_corner_radius">2dp</dimen>
<!-- Minimum distance to swipe to trigger accessibility gesture -->
<dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java
index b3bb850..079a738 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java
@@ -24,13 +24,13 @@
import android.os.UserManager;
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.ArrowTipView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.FloatingHeaderView;
+import com.android.launcher3.views.ArrowTipView;
import com.android.systemui.shared.system.LauncherEventUtil;
/**
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
index 5b01185..773c6c8 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
@@ -26,7 +26,6 @@
import androidx.core.app.NotificationCompat;
-import com.android.launcher3.ArrowTipView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.FolderInfo;
import com.android.launcher3.Hotseat;
@@ -43,6 +42,7 @@
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.Snackbar;
import java.util.ArrayDeque;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 496a3d8..61fe6cb 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -444,9 +444,12 @@
GestureState newGestureState;
if (mDeviceState.isInSwipeUpTouchRegion(event)) {
+ // Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger
+ // onConsumerInactive and wipe the previous gesture state
+ GestureState prevGestureState = new GestureState(mGestureState);
newGestureState = createGestureState();
mConsumer.onConsumerAboutToBeSwitched();
- mConsumer = newConsumer(mGestureState, newGestureState, event);
+ mConsumer = newConsumer(prevGestureState, newGestureState, event);
ActiveGestureLog.INSTANCE.addLog("setInputConsumer", mConsumer.getType());
mUncheckedConsumer = mConsumer;
@@ -686,7 +689,7 @@
* To be called by the consumer when it's no longer active.
*/
private void onConsumerInactive(InputConsumer caller) {
- if (mConsumer == caller) {
+ if (mConsumer != null && mConsumer.isInConsumerHierarchy(caller)) {
mConsumer = mUncheckedConsumer = mResetGestureInputConsumer;
mGestureState = new GestureState();
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java
index 71465eb..bcc9707 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java
@@ -30,6 +30,11 @@
}
@Override
+ public boolean isInConsumerHierarchy(InputConsumer candidate) {
+ return this == candidate || mDelegate.isInConsumerHierarchy(candidate);
+ }
+
+ @Override
public boolean allowInterceptByParent() {
return mDelegate.allowInterceptByParent() && mState != STATE_ACTIVE;
}
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 4a36f54..c73b3ee 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;
@@ -1241,13 +1243,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());
}
}
@@ -1342,7 +1344,7 @@
private void onEnd(EndState endState) {
if (endState.isSuccess) {
if (shouldRemoveTask) {
- removeTask(taskView.getTask(), draggedIndex, endState);
+ removeTask(taskView, draggedIndex, endState);
}
int pageToSnapTo = mCurrentPage;
@@ -1791,6 +1793,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 56e3632..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();
@@ -812,8 +826,8 @@
super.onInitializeAccessibilityNodeInfo(info);
info.addAction(
- new AccessibilityNodeInfo.AccessibilityAction(R.string.accessibility_close_task,
- getContext().getText(R.string.accessibility_close_task)));
+ new AccessibilityNodeInfo.AccessibilityAction(R.string.accessibility_close,
+ getContext().getText(R.string.accessibility_close)));
final Context context = getContext();
for (SystemShortcut s : TaskOverlayFactory.getEnabledShortcuts(this)) {
@@ -837,7 +851,7 @@
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
- if (action == R.string.accessibility_close_task) {
+ if (action == R.string.accessibility_close) {
getRecentsView().dismissTask(this, true /*animateTaskView*/,
true /*removeTask*/);
return true;
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 40d7c7a..9ef38c0 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -32,9 +32,6 @@
<!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
<string name="recents_empty_message">No recent items</string>
- <!-- Content description for the recent apps's accessibility option that closes it. [CHAR LIMIT=NONE] -->
- <string name="accessibility_close_task">Close</string>
-
<!-- Content description for the recent apps's accessibility option that opens its usage settings. [CHAR LIMIT=NONE] -->
<string name="accessibility_app_usage_settings">App usage settings</string>
@@ -116,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/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 631df4c..5118906 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -130,6 +130,17 @@
mGestureId = gestureId;
}
+ public GestureState(GestureState other) {
+ mHomeIntent = other.mHomeIntent;
+ mOverviewIntent = other.mOverviewIntent;
+ mActivityInterface = other.mActivityInterface;
+ mStateCallback = other.mStateCallback;
+ mGestureId = other.mGestureId;
+ mRunningTask = other.mRunningTask;
+ mEndTarget = other.mEndTarget;
+ mFinishingRecentsAnimationTaskId = other.mFinishingRecentsAnimationTaskId;
+ }
+
public GestureState() {
// Do nothing, only used for initializing the gesture state prior to user unlock
mHomeIntent = new Intent();
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index 8efaeb9..818d836 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -70,6 +70,13 @@
}
/**
+ * Returns true if the given input consumer is in the hierarchy of this input consumer.
+ */
+ default boolean isInConsumerHierarchy(InputConsumer candidate) {
+ return this == candidate;
+ }
+
+ /**
* Called by the event queue when the consumer is about to be switched to a new consumer.
* Consumers should update the state accordingly here before the state is passed to the new
* consumer.
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/quickstep/recents_ui_overrides/res/drawable/arrow_toast_rounded_background.xml b/res/drawable/arrow_toast_rounded_background.xml
similarity index 100%
rename from quickstep/recents_ui_overrides/res/drawable/arrow_toast_rounded_background.xml
rename to res/drawable/arrow_toast_rounded_background.xml
diff --git a/quickstep/recents_ui_overrides/res/layout/arrow_toast.xml b/res/layout/arrow_toast.xml
similarity index 99%
rename from quickstep/recents_ui_overrides/res/layout/arrow_toast.xml
rename to res/layout/arrow_toast.xml
index 980bb5a..087e45a 100644
--- a/quickstep/recents_ui_overrides/res/layout/arrow_toast.xml
+++ b/res/layout/arrow_toast.xml
@@ -50,7 +50,7 @@
android:src="@drawable/ic_remove_no_shadow"
android:tint="@android:color/white"
android:background="?android:attr/selectableItemBackgroundBorderless"
- android:contentDescription="@string/accessibility_close_task"/>
+ android:contentDescription="@string/accessibility_close"/>
</LinearLayout>
<View
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/res/values/dimens.xml b/res/values/dimens.xml
index 871651d..271511e 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -85,6 +85,10 @@
<dimen name="all_apps_tabs_side_padding">12dp</dimen>
<dimen name="all_apps_divider_height">1dp</dimen>
+ <dimen name="all_apps_tip_bottom_margin">8dp</dimen>
+ <!-- The size of corner radius of the arrow in the arrow toast. -->
+ <dimen name="arrow_toast_corner_radius">2dp</dimen>
+
<dimen name="all_apps_work_profile_tab_footer_padding">20dp</dimen>
<!-- Search bar in All Apps -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b1077be..ac04262 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -316,6 +316,9 @@
<!-- Accessibility action to dismiss a notification in the shortcuts menu for an icon. [CHAR_LIMIT=30] -->
<string name="action_dismiss_notification">Dismiss</string>
+ <!-- Content description for arrow tip close button. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_close">Close</string>
+
<!-- Accessibility confirmation for notification being dismissed. -->
<string name="notification_dismissed">Notification dismissed</string>
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..f45c0b1 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 PopupContainerWithArrow.canShow(host, info)
+ || new CustomActionsPopup(mLauncher, host).canShow();
+ }
+
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 (PopupContainerWithArrow.canShow(host, 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/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index f935e4d..05db18e 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -17,8 +17,6 @@
import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Rect;
@@ -27,7 +25,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.util.AttributeSet;
-import android.view.MotionEvent;
import android.widget.Switch;
import com.android.launcher3.Insettable;
@@ -35,6 +32,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.views.ArrowTipView;
import java.lang.ref.WeakReference;
@@ -43,27 +41,21 @@
*/
public class WorkModeSwitch extends Switch implements Insettable {
- private Rect mInsets = new Rect();
- protected ObjectAnimator mOpenCloseAnimator;
+ private static final int WORK_TIP_THRESHOLD = 2;
+ public static final String KEY_WORK_TIP_COUNTER = "worked_tip_counter";
+ private Rect mInsets = new Rect();
public WorkModeSwitch(Context context) {
super(context);
- init();
}
public WorkModeSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
- init();
}
public WorkModeSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- init();
- }
-
- private void init() {
- mOpenCloseAnimator = ObjectAnimator.ofPropertyValuesHolder(this);
}
@Override
@@ -73,6 +65,9 @@
@Override
public void toggle() {
+ Launcher launcher = Launcher.getLauncher(getContext());
+ // don't show tip if user uses toggle
+ launcher.getSharedPrefs().edit().putInt(KEY_WORK_TIP_COUNTER, -1).apply();
trySetQuietModeEnabledToAllProfilesAsync(isChecked());
}
@@ -95,11 +90,6 @@
this.setVisibility(shouldShowWorkSwitch() ? VISIBLE : GONE);
}
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- return ev.getActionMasked() == MotionEvent.ACTION_MOVE || super.onTouchEvent(ev);
- }
-
private void trySetQuietModeEnabledToAllProfilesAsync(boolean enabled) {
new SetQuietModeEnabledAsyncTask(enabled, new WeakReference<>(this)).execute();
}
@@ -117,9 +107,15 @@
*/
public void setWorkTabVisible(boolean workTabVisible) {
if (!shouldShowWorkSwitch()) return;
-
- mOpenCloseAnimator.setValues(PropertyValuesHolder.ofFloat(ALPHA, workTabVisible ? 1 : 0));
- mOpenCloseAnimator.start();
+ clearAnimation();
+ if (workTabVisible) {
+ setVisibility(VISIBLE);
+ setAlpha(0);
+ animate().alpha(1).start();
+ showTipifNeeded();
+ } else {
+ animate().alpha(0).withEndAction(() -> this.setVisibility(GONE)).start();
+ }
}
private static final class SetQuietModeEnabledAsyncTask
@@ -179,4 +175,17 @@
|| launcher.checkSelfPermission("android.permission.MODIFY_QUIET_MODE")
== PackageManager.PERMISSION_GRANTED);
}
+
+ /**
+ * Shows a work tip on the Nth work tab open
+ */
+ public void showTipifNeeded() {
+ Launcher launcher = Launcher.getLauncher(getContext());
+ int tipCounter = launcher.getSharedPrefs().getInt(KEY_WORK_TIP_COUNTER, WORK_TIP_THRESHOLD);
+ if (tipCounter < 0) return;
+ if (tipCounter == 0) {
+ new ArrowTipView(launcher).show(launcher.getString(R.string.work_switch_tip), getTop());
+ }
+ launcher.getSharedPrefs().edit().putInt(KEY_WORK_TIP_COUNTER, tipCounter - 1).apply();
+ }
}
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/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 9bac259..406e1b2 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -185,6 +185,13 @@
}
/**
+ * Returns true if we can show the container.
+ */
+ public static boolean canShow(View icon, ItemInfo item) {
+ return icon instanceof BubbleTextView && ShortcutUtil.supportsShortcuts(item);
+ }
+
+ /**
* Shows the notifications and deep shortcuts associated with {@param icon}.
* @return the container if shown or null.
*/
@@ -196,7 +203,7 @@
return null;
}
ItemInfo item = (ItemInfo) icon.getTag();
- if (!ShortcutUtil.supportsShortcuts(item)) {
+ if (!canShow(icon, item)) {
return null;
}
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/quickstep/recents_ui_overrides/src/com/android/launcher3/ArrowTipView.java b/src/com/android/launcher3/views/ArrowTipView.java
similarity index 96%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/ArrowTipView.java
rename to src/com/android/launcher3/views/ArrowTipView.java
index a5ea523..60470dc 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/ArrowTipView.java
+++ b/src/com/android/launcher3/views/ArrowTipView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.launcher3;
+package com.android.launcher3.views;
import android.content.Context;
import android.graphics.CornerPathEffect;
@@ -31,6 +31,9 @@
import androidx.core.content.ContextCompat;
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.graphics.TriangleShape;
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/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index a3c70ec..001a88f 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -275,8 +275,10 @@
}
private void verifyPendingWidgetPresent() {
+ final Widget widget = mLauncher.getWorkspace().tryGetPendingWidget(DEFAULT_UI_TIMEOUT);
+ if (widget == null) mLauncher.dumpViewHierarchy(); // b/152645831
assertTrue("Pending widget is not present",
- mLauncher.getWorkspace().tryGetPendingWidget(DEFAULT_UI_TIMEOUT) != null);
+ widget != null);
}
/**
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 4a2d699..808be66 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -43,7 +43,7 @@
AllApps(LauncherInstrumentation launcher) {
super(launcher);
final UiObject2 allAppsContainer = verifyActiveContainer();
- mHeight = allAppsContainer.getVisibleBounds().height();
+ mHeight = mLauncher.getVisibleBounds(allAppsContainer).height();
final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer,
"apps_list_view");
// Wait for the recycler to populate.
@@ -66,7 +66,7 @@
LauncherInstrumentation.log("hasClickableIcon: icon not visible");
return false;
}
- final Rect iconBounds = icon.getVisibleBounds();
+ final Rect iconBounds = mLauncher.getVisibleBounds(icon);
LauncherInstrumentation.log("hasClickableIcon: icon bounds: " + iconBounds);
if (iconBounds.height() < mIconHeight / 2) {
LauncherInstrumentation.log("hasClickableIcon: icon has insufficient height");
@@ -86,7 +86,7 @@
private boolean iconCenterInSearchBox(UiObject2 allAppsContainer, UiObject2 icon) {
final Point iconCenter = icon.getVisibleCenter();
- return getSearchBox(allAppsContainer).getVisibleBounds().contains(
+ return mLauncher.getVisibleBounds(getSearchBox(allAppsContainer)).contains(
iconCenter.x, iconCenter.y);
}
@@ -125,11 +125,11 @@
mLauncher.getObjectsInContainer(allAppsContainer, "icon")
.stream()
.filter(icon ->
- icon.getVisibleBounds().bottom
+ mLauncher.getVisibleBounds(icon).bottom
<= displayBottom)
.collect(Collectors.toList()),
- searchBox.getVisibleBounds().bottom
- - allAppsContainer.getVisibleBounds().top);
+ mLauncher.getVisibleBounds(searchBox).bottom
+ - mLauncher.getVisibleBounds(allAppsContainer).top);
final int newScroll = getAllAppsScroll();
mLauncher.assertTrue(
"Scrolled in a wrong direction in AllApps: from " + scroll + " to "
@@ -166,7 +166,8 @@
final UiObject2 searchBox = getSearchBox(allAppsContainer);
int attempts = 0;
- final Rect margins = new Rect(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
+ final Rect margins =
+ new Rect(0, mLauncher.getVisibleBounds(searchBox).bottom + 1, 0, 5);
for (int scroll = getAllAppsScroll();
scroll != 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/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index a769acf..69afcc4 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -117,8 +117,8 @@
// part) one in the center, and parts of its right and left siblings. Find the
// main task view by its width.
final UiObject2 widestTask = Collections.max(taskViews,
- (t1, t2) -> Integer.compare(t1.getVisibleBounds().width(),
- t2.getVisibleBounds().width()));
+ (t1, t2) -> Integer.compare(mLauncher.getVisibleBounds(t1).width(),
+ mLauncher.getVisibleBounds(t2).width()));
return new OverviewTask(mLauncher, widestTask, this);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index d1a1254..2922acf 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -57,7 +57,7 @@
private Background launch(BySelector selector) {
LauncherInstrumentation.log("Launchable.launch before click " +
- mObject.getVisibleCenter() + " in " + mObject.getVisibleBounds());
+ mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(mObject));
mLauncher.executeAndWaitForEvent(
() -> mLauncher.clickLauncherObject(mObject),
@@ -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 d7374a4..710ce9e 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";
@@ -971,7 +977,7 @@
int getBottomGestureMarginInContainer(UiObject2 container) {
final int bottomGestureStartOnScreen = getRealDisplaySize().y - getBottomGestureSize();
- return container.getVisibleBounds().bottom - bottomGestureStartOnScreen;
+ return getVisibleBounds(container).bottom - bottomGestureStartOnScreen;
}
void clickLauncherObject(UiObject2 object) {
@@ -989,10 +995,10 @@
Collection<UiObject2> items,
int topPaddingInContainer) {
final UiObject2 lowestItem = Collections.max(items, (i1, i2) ->
- Integer.compare(i1.getVisibleBounds().top, i2.getVisibleBounds().top));
+ Integer.compare(getVisibleBounds(i1).top, getVisibleBounds(i2).top));
- final int itemRowCurrentTopOnScreen = lowestItem.getVisibleBounds().top;
- final Rect containerRect = container.getVisibleBounds();
+ final int itemRowCurrentTopOnScreen = getVisibleBounds(lowestItem).top;
+ final Rect containerRect = getVisibleBounds(container);
final int itemRowNewTopOnScreen = containerRect.top + topPaddingInContainer;
final int distance = itemRowCurrentTopOnScreen - itemRowNewTopOnScreen + getTouchSlop();
@@ -1011,7 +1017,7 @@
void scroll(
UiObject2 container, Direction direction, Rect margins, int steps, boolean slowDown) {
- final Rect rect = container.getVisibleBounds();
+ final Rect rect = getVisibleBounds(container);
if (margins != null) {
rect.left += margins.left;
rect.top += margins.top;
@@ -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);
@@ -1326,4 +1334,13 @@
void expectEvent(String sequence, Pattern expected) {
if (sCheckingEvents) sEventChecker.expectPattern(sequence, expected);
}
+
+ Rect getVisibleBounds(UiObject2 object) {
+ try {
+ return object.getVisibleBounds();
+ } catch (Throwable t) {
+ fail(t.toString());
+ return null;
+ }
+ }
}
\ No newline at end of file
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/OptionsPopupMenuItem.java b/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
index b8e6c0e..63a97f4 100644
--- a/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
+++ b/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
@@ -41,7 +41,7 @@
public void launch(@NonNull String expectedPackageName) {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
LauncherInstrumentation.log("OptionsPopupMenuItem before click "
- + mObject.getVisibleCenter() + " in " + mObject.getVisibleBounds());
+ + mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(mObject));
mLauncher.clickLauncherObject(mObject);
if (!Build.MODEL.contains("Cuttlefish") ||
Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q &&
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 5c51782..fae5f19 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -56,7 +56,7 @@
"want to dismiss a task")) {
verifyActiveContainer();
// Dismiss the task via flinging it up.
- final Rect taskBounds = mTask.getVisibleBounds();
+ final Rect taskBounds = mLauncher.getVisibleBounds(mTask);
final int centerX = taskBounds.centerX();
final int centerY = taskBounds.centerY();
mLauncher.linearGesture(centerX, centerY, centerX, 0, 10, false,
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/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index a14d2f0..5be57c6 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -73,7 +73,7 @@
mLauncher.scroll(
widgetsContainer,
Direction.UP,
- new Rect(0, 0, widgetsContainer.getVisibleBounds().width(), 0),
+ new Rect(0, 0, mLauncher.getVisibleBounds(widgetsContainer).width(), 0),
FLING_STEPS, false);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
verifyActiveContainer();
@@ -111,19 +111,19 @@
int maxWidth = 0;
for (UiObject2 sibling : widget.getParent().getChildren()) {
- maxWidth = Math.max(sibling.getVisibleBounds().width(), maxWidth);
+ maxWidth = Math.max(mLauncher.getVisibleBounds(sibling).width(), maxWidth);
}
- int visibleDelta = maxWidth - widget.getVisibleBounds().width();
+ int visibleDelta = maxWidth - mLauncher.getVisibleBounds(widget).width();
if (visibleDelta > 0) {
- Rect parentBounds = cell.getVisibleBounds();
+ Rect parentBounds = mLauncher.getVisibleBounds(cell);
mLauncher.linearGesture(parentBounds.centerX() + visibleDelta
+ mLauncher.getTouchSlop(),
parentBounds.centerY(), parentBounds.centerX(),
parentBounds.centerY(), 10, true, GestureScope.INSIDE);
}
- if (widget.getVisibleBounds().bottom
+ if (mLauncher.getVisibleBounds(widget).bottom
<= displaySize.y - mLauncher.getBottomGestureSize()) {
return new Widget(mLauncher, widget);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 9ef6476..b3b5e32 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;
@@ -176,9 +177,11 @@
mLauncher,
getHotseatAppIcon("Chrome"),
new Point(mLauncher.getDevice().getDisplayWidth(),
- workspace.getVisibleBounds().centerY()),
+ mLauncher.getVisibleBounds(workspace).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,