Merge "Move the cursor to the end after accepting gboard selection Bug: 146909183" into ub-launcher3-master
diff --git a/proguard.flags b/proguard.flags
index 272ab7a..3e12283 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -23,7 +23,10 @@
# support jar.
-keep class androidx.recyclerview.widget.RecyclerView { *; }
-# Preference fragments
+# Fragments
+-keep class ** extends androidx.fragment.app.Fragment {
+ public <init>(...);
+}
-keep class ** extends android.app.Fragment {
public <init>(...);
}
@@ -50,4 +53,4 @@
-dontwarn android.app.**
-dontwarn android.view.**
-dontwarn android.os.**
--dontwarn android.graphics.**
\ No newline at end of file
+-dontwarn android.graphics.**
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index 055ade5..0560d68 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -57,6 +57,7 @@
optional TargetExtension extension = 16;
optional TipType tip_type = 17;
optional int32 search_query_length = 18;
+ optional bool is_work_app = 19;
}
// Used to define what type of item a Target would represent.
@@ -92,7 +93,7 @@
TASKSWITCHER = 12; // Recents UI Container (QuickStep)
APP = 13; // Foreground activity is another app (QuickStep)
TIP = 14; // Onboarding texts (QuickStep)
- SIDELOADED_LAUNCHER = 15;
+ OTHER_LAUNCHER_APP = 15;
}
// Used to define what type of control a Target would represent.
diff --git a/quickstep/recents_ui_overrides/res/drawable/predicted_icon_background.xml b/quickstep/recents_ui_overrides/res/drawable/predicted_icon_background.xml
deleted file mode 100644
index cfc6d48..0000000
--- a/quickstep/recents_ui_overrides/res/drawable/predicted_icon_background.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:inset="@dimen/predicted_icon_background_inset">
- <shape>
- <solid android:color="?attr/folderFillColor" />
- <corners android:radius="@dimen/predicted_icon_background_corner_radius" />
- </shape>
-</inset>
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java
index f7e71f3..b94142a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java
@@ -44,6 +44,7 @@
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -61,7 +62,7 @@
public class HotseatPredictionController implements DragController.DragListener,
View.OnAttachStateChangeListener, SystemShortcut.Factory<QuickstepLauncher>,
InvariantDeviceProfile.OnIDPChangeListener, AllAppsStore.OnUpdateListener,
- IconCache.ItemInfoUpdateReceiver {
+ IconCache.ItemInfoUpdateReceiver, DragSource {
private static final String TAG = "PredictiveHotseat";
private static final boolean DEBUG = false;
@@ -72,6 +73,9 @@
private static final String APP_LOCATION_HOTSEAT = "hotseat";
private static final String APP_LOCATION_WORKSPACE = "workspace";
+ private static final String BUNDLE_KEY_HOTSEAT = "hotseat_apps";
+ private static final String BUNDLE_KEY_WORKSPACE = "workspace_apps";
+
private static final String PREDICTION_CLIENT = "hotseat";
private DropTarget.DragObject mDragObject;
@@ -79,7 +83,7 @@
private int mPredictedSpotsCount = 0;
private Launcher mLauncher;
- private Hotseat mHotseat;
+ private final Hotseat mHotseat;
private List<ComponentKeyMapper> mComponentKeyMappers = new ArrayList<>();
@@ -87,10 +91,18 @@
private AppPredictor mAppPredictor;
private AllAppsStore mAllAppsStore;
+ private AnimatorSet mIconRemoveAnimators;
+
private List<PredictedAppIcon.PredictedIconOutlineDrawing> mOutlineDrawings = new ArrayList<>();
- private static HotseatPredictionController sInstance;
+ private final View.OnLongClickListener mPredictionLongClickListener = v -> {
+ if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
+ if (mLauncher.getWorkspace().isSwitchingState()) return false;
+ // Start the drag
+ mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions());
+ return false;
+ };
public HotseatPredictionController(Launcher launcher) {
mLauncher = launcher;
@@ -101,7 +113,9 @@
mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons;
launcher.getDeviceProfile().inv.addOnChangeListener(this);
mHotseat.addOnAttachStateChangeListener(this);
- sInstance = this;
+ if (mHotseat.isAttachedToWindow()) {
+ onViewAttachedToWindow(mHotseat);
+ }
}
@Override
@@ -125,6 +139,17 @@
List<WorkspaceItemInfo> predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers);
int predictionIndex = 0;
ArrayList<WorkspaceItemInfo> newItems = new ArrayList<>();
+ // make sure predicted icon removal and filling predictions don't step on each other
+ if (mIconRemoveAnimators != null && mIconRemoveAnimators.isRunning()) {
+ mIconRemoveAnimators.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ fillGapsWithPrediction(animate, callback);
+ mIconRemoveAnimators.removeListener(this);
+ }
+ });
+ return;
+ }
for (int rank = 0; rank < mHotSeatItemsCount; rank++) {
View child = mHotseat.getChildAt(
mHotseat.getCellXFromOrder(rank),
@@ -140,12 +165,11 @@
}
continue;
}
-
WorkspaceItemInfo predictedItem = predictedApps.get(predictionIndex++);
if (isPredictedIcon(child) && child.isEnabled()) {
PredictedAppIcon icon = (PredictedAppIcon) child;
icon.applyFromWorkspaceItem(predictedItem);
- icon.finishBinding();
+ icon.finishBinding(mPredictionLongClickListener);
} else {
newItems.add(predictedItem);
}
@@ -160,7 +184,7 @@
for (WorkspaceItemInfo item : itemsToAdd) {
PredictedAppIcon icon = PredictedAppIcon.createIcon(mHotseat, item);
mLauncher.getWorkspace().addInScreenFromBind(icon, item);
- icon.finishBinding();
+ icon.finishBinding(mPredictionLongClickListener);
if (animate) {
animationSet.play(ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0.2f, 1));
}
@@ -215,9 +239,9 @@
private Bundle getAppPredictionContextExtra() {
Bundle bundle = new Bundle();
- bundle.putParcelableArrayList(APP_LOCATION_HOTSEAT,
+ bundle.putParcelableArrayList(BUNDLE_KEY_HOTSEAT,
getPinnedAppTargetsInViewGroup((mHotseat.getShortcutsAndWidgets())));
- bundle.putParcelableArrayList(APP_LOCATION_WORKSPACE, getPinnedAppTargetsInViewGroup(
+ bundle.putParcelableArrayList(BUNDLE_KEY_WORKSPACE, getPinnedAppTargetsInViewGroup(
mLauncher.getWorkspace().getScreenWithId(
Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets()));
return bundle;
@@ -285,9 +309,12 @@
ItemInfoWithIcon info = mapper.getApp(allAppsStore);
if (info instanceof AppInfo) {
WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((AppInfo) info);
+ predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
predictedApps.add(predictedApp);
} else if (info instanceof WorkspaceItemInfo) {
- predictedApps.add(new WorkspaceItemInfo((WorkspaceItemInfo) info));
+ WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((WorkspaceItemInfo) info);
+ predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
+ predictedApps.add(predictedApp);
} else {
if (DEBUG) {
Log.e(TAG, "Predicted app not found: " + mapper);
@@ -313,13 +340,27 @@
return icons;
}
- private void removePredictedApps(List<PredictedAppIcon.PredictedIconOutlineDrawing> outlines) {
+ private void removePredictedApps(List<PredictedAppIcon.PredictedIconOutlineDrawing> outlines,
+ ItemInfo draggedInfo) {
+ if (mIconRemoveAnimators != null) {
+ mIconRemoveAnimators.end();
+ }
+ mIconRemoveAnimators = new AnimatorSet();
+ removeOutlineDrawings();
for (PredictedAppIcon icon : getPredictedIcons()) {
+ if (!icon.isEnabled()) {
+ continue;
+ }
+ if (icon.getTag().equals(draggedInfo)) {
+ mHotseat.removeView(icon);
+ continue;
+ }
int rank = ((WorkspaceItemInfo) icon.getTag()).rank;
outlines.add(new PredictedAppIcon.PredictedIconOutlineDrawing(
mHotseat.getCellXFromOrder(rank), mHotseat.getCellYFromOrder(rank), icon));
icon.setEnabled(false);
- icon.animate().scaleY(0).scaleX(0).setListener(new AnimationSuccessListener() {
+ ObjectAnimator animator = ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0);
+ animator.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
if (icon.getParent() != null) {
@@ -327,10 +368,11 @@
}
}
});
+ mIconRemoveAnimators.play(animator);
}
+ mIconRemoveAnimators.start();
}
-
private void notifyItemAction(AppTarget target, String location, int action) {
if (mAppPredictor != null) {
mAppPredictor.notifyAppTargetEvent(new AppTargetEvent.Builder(target,
@@ -340,7 +382,7 @@
@Override
public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
- removePredictedApps(mOutlineDrawings);
+ removePredictedApps(mOutlineDrawings, dragObject.dragInfo);
mDragObject = dragObject;
if (mOutlineDrawings.isEmpty()) return;
for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) {
@@ -354,14 +396,25 @@
if (mDragObject == null) {
return;
}
+
ItemInfo dragInfo = mDragObject.dragInfo;
- if (dragInfo instanceof WorkspaceItemInfo && dragInfo.getTargetComponent() != null) {
+ ViewGroup hotseatVG = mHotseat.getShortcutsAndWidgets();
+ ViewGroup firstScreenVG = mLauncher.getWorkspace().getScreenWithId(
+ Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets();
+
+ if (dragInfo instanceof WorkspaceItemInfo
+ && dragInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+ && dragInfo.getTargetComponent() != null) {
AppTarget appTarget = getAppTargetFromItemInfo(dragInfo);
if (!isInHotseat(dragInfo) && isInHotseat(mDragObject.originalDragInfo)) {
- notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, APPTARGET_ACTION_UNPIN);
+ if (!getPinnedAppTargetsInViewGroup(hotseatVG).contains(appTarget)) {
+ notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, APPTARGET_ACTION_UNPIN);
+ }
}
if (!isInFirstPage(dragInfo) && isInFirstPage(mDragObject.originalDragInfo)) {
- notifyItemAction(appTarget, APP_LOCATION_WORKSPACE, APPTARGET_ACTION_UNPIN);
+ if (!getPinnedAppTargetsInViewGroup(firstScreenVG).contains(appTarget)) {
+ notifyItemAction(appTarget, APP_LOCATION_WORKSPACE, APPTARGET_ACTION_UNPIN);
+ }
}
if (isInHotseat(dragInfo) && !isInHotseat(mDragObject.originalDragInfo)) {
notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, AppTargetEvent.ACTION_PIN);
@@ -371,14 +424,7 @@
}
}
mDragObject = null;
- fillGapsWithPrediction(true, () -> {
- if (mOutlineDrawings.isEmpty()) return;
- for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) {
- mHotseat.removeDelegatedCellDrawing(outlineDrawing);
- }
- mHotseat.invalidate();
- mOutlineDrawings.clear();
- });
+ fillGapsWithPrediction(true, this::removeOutlineDrawings);
}
@Nullable
@@ -394,11 +440,20 @@
private void preparePredictionInfo(WorkspaceItemInfo itemInfo, int rank) {
itemInfo.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
itemInfo.rank = rank;
- itemInfo.cellX = rank;
- itemInfo.cellY = mHotSeatItemsCount - rank - 1;
+ itemInfo.cellX = mHotseat.getCellXFromOrder(rank);
+ itemInfo.cellY = mHotseat.getCellYFromOrder(rank);
itemInfo.screenId = rank;
}
+ private void removeOutlineDrawings() {
+ if (mOutlineDrawings.isEmpty()) return;
+ for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) {
+ mHotseat.removeDelegatedCellDrawing(outlineDrawing);
+ }
+ mHotseat.invalidate();
+ mOutlineDrawings.clear();
+ }
+
@Override
public void onIdpChanged(int changeFlags, InvariantDeviceProfile profile) {
this.mHotSeatItemsCount = profile.numHotseatIcons;
@@ -415,6 +470,17 @@
}
+ @Override
+ public void onDropCompleted(View target, DropTarget.DragObject d, boolean success) {
+ //Does nothing
+ }
+
+ @Override
+ public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target,
+ LauncherLogProto.Target targetParent) {
+ mHotseat.fillInLogContainerData(v, info, target, targetParent);
+ }
+
private class PinPrediction extends SystemShortcut<QuickstepLauncher> {
private PinPrediction(QuickstepLauncher target, ItemInfo itemInfo) {
@@ -435,18 +501,22 @@
*/
public static void fillInHybridHotseatRank(
@NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) {
- if (sInstance == null || itemInfo.getTargetComponent() == null
+ QuickstepLauncher launcher = QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
+ if (launcher == null || launcher.getHotseatPredictionController() == null
+ || itemInfo.getTargetComponent() == null
|| itemInfo.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) {
return;
}
+ HotseatPredictionController controller = launcher.getHotseatPredictionController();
+
final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user);
- final List<ComponentKeyMapper> predictedApps = sInstance.mComponentKeyMappers;
+ final List<ComponentKeyMapper> predictedApps = controller.mComponentKeyMappers;
IntStream.range(0, predictedApps.size())
.filter((i) -> k.equals(predictedApps.get(i).getComponentKey()))
.findFirst()
.ifPresent((rank) -> target.predictedRank =
- Integer.parseInt(sInstance.mPredictedSpotsCount + "0" + rank));
+ Integer.parseInt(controller.mPredictedSpotsCount + "0" + rank));
}
private static boolean isPredictedIcon(View view) {
@@ -461,8 +531,7 @@
}
ItemInfo info = (ItemInfo) view.getTag();
return info.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION && (
- info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
- || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
+ info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION);
}
private static boolean isInHotseat(ItemInfo itemInfo) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index 1dcbffb..27ac284 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -29,7 +29,6 @@
import androidx.core.graphics.ColorUtils;
-import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
@@ -37,7 +36,6 @@
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.icons.IconNormalizer;
-import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.views.DoubleShadowBubbleTextView;
@@ -47,14 +45,13 @@
*/
public class PredictedAppIcon extends DoubleShadowBubbleTextView {
- private static final float RING_EFFECT_RATIO = 0.12f;
+ private static final float RING_EFFECT_RATIO = 0.11f;
private DeviceProfile mDeviceProfile;
private final Paint mIconRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private boolean mIsPinned = false;
private int mNormalizedIconRadius;
-
public PredictedAppIcon(Context context) {
this(context, null, 0);
}
@@ -105,14 +102,8 @@
/**
* prepares prediction icon for usage after bind
*/
- public void finishBinding() {
- setOnLongClickListener((v) -> {
- PopupContainerWithArrow.showForIcon((BubbleTextView) v);
- if (getParent() != null) {
- getParent().requestDisallowInterceptTouchEvent(true);
- }
- return true;
- });
+ public void finishBinding(OnLongClickListener longClickListener) {
+ setOnLongClickListener(longClickListener);
((CellLayout.LayoutParams) getLayoutParams()).canReorder = false;
setTextVisibility(false);
verifyHighRes();
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 37a3929..cae01ae 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -178,6 +178,13 @@
}
/**
+ * Returns Prediction controller for hybrid hotseat
+ */
+ public HotseatPredictionController getHotseatPredictionController() {
+ return mHotseatPredictionController;
+ }
+
+ /**
* Recents logic that triggers when launcher state changes or launcher activity stops/resumes.
*/
private void onStateOrResumeChanged() {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
index f889bc1..6574d22 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
@@ -226,7 +226,7 @@
RecentsActivity activity = getCreatedActivity();
boolean visible = activity != null && activity.isStarted() && activity.hasWindowFocus();
return visible
- ? LauncherLogProto.ContainerType.SIDELOADED_LAUNCHER
+ ? LauncherLogProto.ContainerType.OTHER_LAUNCHER_APP
: LauncherLogProto.ContainerType.APP;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
index 888ea9c..700feef 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -453,8 +453,10 @@
@Override
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
- super.onRecentsAnimationCanceled(thumbnailData);
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
+
+ // Defer clearing the controller and the targets until after we've updated the state
+ super.onRecentsAnimationCanceled(thumbnailData);
}
/**
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
index 8f75c79..1b60404 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
@@ -610,10 +610,12 @@
@Override
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
- super.onRecentsAnimationCanceled(thumbnailData);
+ ActiveGestureLog.INSTANCE.addLog("cancelRecentsAnimation");
mActivityInitListener.unregister();
mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
- ActiveGestureLog.INSTANCE.addLog("cancelRecentsAnimation");
+
+ // Defer clearing the controller and the targets until after we've updated the state
+ super.onRecentsAnimationCanceled(thumbnailData);
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewActionsFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewActionsFactory.java
deleted file mode 100644
index 6d17b27..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewActionsFactory.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
-
-import android.view.View;
-
-import com.android.launcher3.R;
-import com.android.launcher3.util.MainThreadInitializedObject;
-import com.android.launcher3.util.ResourceBasedOverride;
-
-/**
- * Overview actions are shown in overview underneath the task snapshot. This factory class is
- * overrideable in an overlay. The {@link OverviewActions} class provides the view that should be
- * shown in the Overview.
- */
-public class OverviewActionsFactory implements ResourceBasedOverride {
-
- public static final MainThreadInitializedObject<OverviewActionsFactory> INSTANCE =
- forOverride(OverviewActionsFactory.class, R.string.overview_actions_factory_class);
-
- /** Create a new Overview Actions for interacting between the actions and overview. */
- public OverviewActions createOverviewActions() {
- return new OverviewActions();
- }
-
- /** Overlay overrideable, base class does nothing. */
- public static class OverviewActions {
- /** Get the view to show in the overview. */
- public View getView() {
- return null;
- }
- }
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
index b5441df..ec7cddf 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
@@ -19,6 +19,9 @@
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
import android.graphics.Matrix;
+import android.view.View;
+
+import androidx.annotation.Nullable;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
@@ -75,6 +78,11 @@
*/
public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix) { }
+ @Nullable
+ public View getActionsView() {
+ return null;
+ }
+
/**
* Called when the overlay is no longer used.
*/
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 bafb2ef..29df5cc 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -484,7 +484,9 @@
base = new AssistantInputConsumer(this, newGestureState, base, mInputMonitorCompat);
}
- if (mOverscrollPlugin != null) {
+ if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()
+ && (mOverscrollPlugin != null)
+ && mOverscrollPlugin.isActive()) {
// Put the overscroll gesture as higher priority than the Assistant or base gestures
base = new OverscrollInputConsumer(this, newGestureState, base, mInputMonitorCompat,
mOverscrollPlugin);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
index e3da98b..0a21413 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
@@ -26,14 +26,17 @@
import android.content.Context;
import android.graphics.PointF;
+import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import androidx.annotation.Nullable;
import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.R;
import com.android.quickstep.GestureState;
import com.android.quickstep.InputConsumer;
+import com.android.quickstep.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.plugins.OverscrollPlugin;
import com.android.systemui.shared.system.InputMonitorCompat;
@@ -47,12 +50,12 @@
private static final String TAG = "OverscrollInputConsumer";
- private static final int ANGLE_THRESHOLD = 35; // Degrees
-
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private final PointF mStartDragPos = new PointF();
+ private final int mAngleThreshold;
+ private final float mFlingThresholdPx;
private int mActivePointerId = -1;
private boolean mPassedSlop = false;
@@ -60,19 +63,28 @@
private final Context mContext;
private final GestureState mGestureState;
- @Nullable private final OverscrollPlugin mPlugin;
+ @Nullable
+ private final OverscrollPlugin mPlugin;
+ private final GestureDetector mGestureDetector;
private RecentsView mRecentsView;
public OverscrollInputConsumer(Context context, GestureState gestureState,
InputConsumer delegate, InputMonitorCompat inputMonitor, OverscrollPlugin plugin) {
super(delegate, inputMonitor);
+
+ mAngleThreshold = context.getResources()
+ .getInteger(R.integer.assistant_gesture_corner_deg_threshold);
+ mFlingThresholdPx = context.getResources()
+ .getDimension(R.dimen.gestures_overscroll_fling_threshold);
mContext = context;
mGestureState = gestureState;
mPlugin = plugin;
float slop = ViewConfiguration.get(context).getScaledTouchSlop();
+
mSquaredSlop = slop * slop;
+ mGestureDetector = new GestureDetector(context, new FlingGestureListener());
gestureState.getActivityInterface().createActivityInitListener(this::onActivityInit)
.register();
@@ -139,21 +151,29 @@
mPassedSlop = true;
mStartDragPos.set(mLastPos.x, mLastPos.y);
-
if (isOverscrolled()) {
setActive(ev);
+
+ if (mPlugin != null) {
+ mPlugin.onTouchStart(getDeviceState(), getUnderlyingActivity());
+ }
} else {
mState = STATE_DELEGATE_ACTIVE;
}
}
}
+ if (mPassedSlop && mState != STATE_DELEGATE_ACTIVE && isOverscrolled()
+ && mPlugin != null) {
+ mPlugin.onTouchTraveled(getDistancePx());
+ }
+
break;
}
case ACTION_CANCEL:
case ACTION_UP:
if (mState != STATE_DELEGATE_ACTIVE && mPassedSlop && mPlugin != null) {
- mPlugin.onOverscroll(getDeviceState());
+ mPlugin.onTouchEnd(getDistancePx());
}
mPassedSlop = false;
@@ -161,6 +181,10 @@
break;
}
+ if (mState != STATE_DELEGATE_ACTIVE) {
+ mGestureDetector.onTouchEvent(ev);
+ }
+
if (mState != STATE_ACTIVE) {
mDelegate.onMotionEvent(ev);
}
@@ -168,12 +192,19 @@
private boolean isOverscrolled() {
// Make sure there isn't an app to quick switch to on our right
- boolean atRightMostApp = (mRecentsView == null || mRecentsView.getRunningTaskIndex() <= 0);
+ int maxIndex = 0;
+ if ((mRecentsView instanceof LauncherRecentsView)
+ && ((LauncherRecentsView) mRecentsView).hasRecentsExtraCard()) {
+ maxIndex = 1;
+ }
+
+ boolean atRightMostApp = (mRecentsView == null
+ || mRecentsView.getRunningTaskIndex() <= maxIndex);
// Check if the gesture is within our angle threshold of horizontal
float deltaY = Math.abs(mLastPos.y - mDownPos.y);
float deltaX = mDownPos.x - mLastPos.x; // Positive if this is a gesture to the left
- boolean angleInBounds = Math.toDegrees(Math.atan2(deltaY, deltaX)) < ANGLE_THRESHOLD;
+ boolean angleInBounds = Math.toDegrees(Math.atan2(deltaY, deltaX)) < mAngleThreshold;
return atRightMostApp && angleInBounds;
}
@@ -193,4 +224,36 @@
return deviceState;
}
+
+ private int getDistancePx() {
+ return (int) Math.hypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y);
+ }
+
+ private String getUnderlyingActivity() {
+ return mGestureState.getRunningTask().topActivity.flattenToString();
+ }
+
+ private class FlingGestureListener extends GestureDetector.SimpleOnGestureListener {
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ if (isValidAngle(velocityX, -velocityY)
+ && getDistancePx() >= mFlingThresholdPx
+ && mState != STATE_DELEGATE_ACTIVE) {
+
+ if (mPlugin != null) {
+ mPlugin.onFling(-velocityX);
+ }
+ }
+ return true;
+ }
+
+ private boolean isValidAngle(float deltaX, float deltaY) {
+ float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
+ // normalize so that angle is measured clockwise from horizontal in the bottom right
+ // corner and counterclockwise from horizontal in the bottom left corner
+
+ angle = angle > 90 ? 180 - angle : angle;
+ return (angle < mAngleThreshold);
+ }
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index 82fbbc6..1bbb3f5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -378,6 +378,11 @@
}
@Override
+ public boolean hasRecentsExtraCard() {
+ return mRecentsExtraViewContainer != null;
+ }
+
+ @Override
public void setContentAlpha(float alpha) {
super.setContentAlpha(alpha);
if (mRecentsExtraViewContainer != null) {
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 0f0fda9..47bc31a 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
@@ -830,6 +830,11 @@
public abstract void startHome();
+ /** `true` if there is a +1 space available in overview. */
+ public boolean hasRecentsExtraCard() {
+ return false;
+ }
+
public void reset() {
setCurrentTask(-1);
mIgnoreResetTaskId = -1;
@@ -1310,7 +1315,7 @@
}
private void dismissCurrentTask() {
- TaskView taskView = getTaskView(getNextPage());
+ TaskView taskView = getNextPageTaskView();
if (taskView != null) {
dismissTask(taskView, true /*animateTaskView*/, true /*removeTask*/);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
index 4e0fdea..3bc1509 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -197,6 +197,10 @@
updateThumbnailPaintFilter();
}
+ public TaskOverlay getTaskOverlay() {
+ return mOverlay;
+ }
+
public float getDimAlpha() {
return mDimAlpha;
}
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 94cec72..6e1b24a 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
@@ -62,7 +62,6 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.PendingAnimation;
import com.android.launcher3.util.ViewPool.Reusable;
-import com.android.quickstep.OverviewActionsFactory;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.TaskIconCache;
import com.android.quickstep.TaskOverlayFactory;
@@ -164,7 +163,6 @@
private final float mWindowCornerRadius;
private final BaseDraggingActivity mActivity;
- private OverviewActionsFactory.OverviewActions mOverviewActions;
@Nullable private View mActionsView;
private ObjectAnimator mIconAndDimAnimator;
@@ -222,7 +220,6 @@
mCurrentFullscreenParams = new FullscreenDrawParams(mCornerRadius);
mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
- mOverviewActions = OverviewActionsFactory.INSTANCE.get(context).createOverviewActions();
mOutlineProvider = new TaskOutlineProvider(getResources(), mCurrentFullscreenParams);
setOutlineProvider(mOutlineProvider);
}
@@ -239,7 +236,7 @@
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
- mActionsView = mOverviewActions.getView();
+ mActionsView = mSnapshotView.getTaskOverlay().getActionsView();
if (mActionsView != null) {
TaskView.LayoutParams params = new TaskView.LayoutParams(LayoutParams.MATCH_PARENT,
getResources().getDimensionPixelSize(R.dimen.overview_actions_height),
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 24ab487..327bb14 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -15,8 +15,6 @@
-->
<resources>
<string name="task_overlay_factory_class" translatable="false"></string>
- <!-- Class name for factory object that creates the overview actions UI when enabled. -->
- <string name="overview_actions_factory_class" translatable="false" />
<!-- Activity which blocks home gesture -->
<string name="gesture_blocking_activity" translatable="false"></string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 9ff1350..24be859 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -77,4 +77,7 @@
<!-- Distance to move elements when swiping up to go home from launcher -->
<dimen name="home_pullback_distance">28dp</dimen>
+
+ <!-- Overscroll Gesture -->
+ <dimen name="gestures_overscroll_fling_threshold">40dp</dimen>
</resources>
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 8e5ed1a..a466f12 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -17,30 +17,34 @@
package com.android.quickstep.logging;
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.DISMISS_TASK;
-import static android.stats.launcher.nano.Launcher.BACKGROUND;
import static android.stats.launcher.nano.Launcher.OVERVIEW;
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.ItemInfo;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogUtils;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
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.StatsLogCompat;
+
import com.google.protobuf.nano.MessageNano;
/**
@@ -60,7 +64,7 @@
public StatsLogCompatManager(Context context) { }
@Override
- public void logAppLaunch(View v, Intent intent) {
+ 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();
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index 5606ac2..b786c8b 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -35,6 +35,7 @@
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.tapl.TestHelpers;
+import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.FailureWatcher;
import com.android.systemui.shared.system.QuickStepContract;
@@ -57,6 +58,8 @@
static final String TAG = "QuickStepOnOffRule";
+ public static final int WAIT_TIME_MS = 10000;
+
public enum Mode {
THREE_BUTTON, TWO_BUTTON, ZERO_BUTTON, ALL
}
@@ -118,8 +121,8 @@
if (mode == THREE_BUTTON || mode == ALL) {
evaluateWithThreeButtons();
}
- } catch (Exception e) {
- Log.e(TAG, "Exception", e);
+ } catch (Throwable e) {
+ Log.e(TAG, "Error", e);
throw e;
} finally {
assertTrue("Couldn't set overlay",
@@ -195,19 +198,14 @@
currentSysUiNavigationMode() == expectedMode);
}
- for (int i = 0; i != 100; ++i) {
- if (mLauncher.getNavigationModel() == expectedMode) break;
- Thread.sleep(100);
- }
- assertTrue("Couldn't switch to " + overlayPackage,
- mLauncher.getNavigationModel() == expectedMode);
+ Wait.atMost("Couldn't switch to " + overlayPackage,
+ () -> mLauncher.getNavigationModel() == expectedMode, WAIT_TIME_MS,
+ mLauncher);
- for (int i = 0; i != 100; ++i) {
- if (mLauncher.getNavigationModeMismatchError() == null) break;
- Thread.sleep(100);
- }
- final String error = mLauncher.getNavigationModeMismatchError();
- assertTrue("Switching nav mode: " + error, error == null);
+ Wait.atMost(() -> "Switching nav mode: "
+ + mLauncher.getNavigationModeMismatchError(),
+ () -> mLauncher.getNavigationModeMismatchError() == null, WAIT_TIME_MS,
+ mLauncher);
return true;
}
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 893f64a..21c819a 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -174,8 +174,8 @@
AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(), user,
sourceContainer);
}
- getUserEventDispatcher().logAppLaunch(v, intent);
- getStatsLogManager().logAppLaunch(v, intent);
+ getUserEventDispatcher().logAppLaunch(v, intent, user);
+ getStatsLogManager().logAppLaunch(v, intent, user);
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/Launcher.java b/src/com/android/launcher3/Launcher.java
index 7265a1a..d8c4c5c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1429,6 +1429,9 @@
@Override
protected void onNewIntent(Intent intent) {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.PERMANENT_DIAG_TAG, "Launcher.onNewIntent: " + intent);
+ }
Object traceToken = TraceHelper.INSTANCE.beginSection(ON_NEW_INTENT_EVT);
super.onNewIntent(intent);
diff --git a/src/com/android/launcher3/ResourceUtils.java b/src/com/android/launcher3/ResourceUtils.java
index 73e705b..7f327a5 100644
--- a/src/com/android/launcher3/ResourceUtils.java
+++ b/src/com/android/launcher3/ResourceUtils.java
@@ -29,7 +29,7 @@
return getDimenByName(resName, res, 48);
}
- private static int getDimenByName(String resName, Resources res, int defaultValue) {
+ public static int getDimenByName(String resName, Resources res, int defaultValue) {
final int frameSize;
final int frameSizeResID = res.getIdentifier(resName, "dimen", "android");
if (frameSizeResID != 0) {
@@ -40,6 +40,17 @@
return frameSize;
}
+ public static boolean getBoolByName(String resName, Resources res, boolean defaultValue) {
+ final boolean val;
+ final int resId = res.getIdentifier(resName, "bool", "android");
+ if (resId != 0) {
+ val = res.getBoolean(resId);
+ } else {
+ val = defaultValue;
+ }
+ return val;
+ }
+
public static int pxFromDp(float size, DisplayMetrics metrics) {
return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, metrics));
}
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index d47a40e..28579c1 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.os.Bundle;
+import android.util.Log;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -57,6 +58,7 @@
parcel.putInt(TestProtocol.STATE_FIELD, stateOrdinal);
sendEventToTest(accessibilityManager, TestProtocol.SWITCHED_TO_STATE_MESSAGE, parcel);
+ Log.d(TestProtocol.PERMANENT_DIAG_TAG, "sendStateEventToTest: " + stateOrdinal);
}
public static void sendScrollFinishedEventToTest(Context context) {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 80c7056..003ca82 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -95,7 +95,7 @@
"ENABLE_QUICKSTEP_LIVE_TILE", false, "Enable live tile in Quickstep overview");
public static final TogglableFlag ENABLE_HINTS_IN_OVERVIEW = new TogglableFlag(
- "ENABLE_HINTS_IN_OVERVIEW", true,
+ "ENABLE_HINTS_IN_OVERVIEW", false,
"Show chip hints and gleams on the overview screen");
public static final TogglableFlag FAKE_LANDSCAPE_UI = new TogglableFlag(
@@ -114,7 +114,7 @@
"ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list");
public static final TogglableFlag ENABLE_QUICK_CAPTURE_GESTURE = new TogglableFlag(
- "ENABLE_QUICK_CAPTURE_GESTURE", false, "Swipe from right to left to quick capture");
+ "ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture");
public static final TogglableFlag ASSISTANT_GIVES_LAUNCHER_FOCUS = new TogglableFlag(
"ASSISTANT_GIVES_LAUNCHER_FOCUS", false,
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index b72fd98..dcdf5d6 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.Utilities.ATLEAST_Q;
import android.animation.ValueAnimator;
import android.content.ComponentName;
@@ -56,6 +57,12 @@
public class DragController implements DragDriver.EventListener, TouchController {
private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
+ /**
+ * When a drag is started from a deep press, you need to drag this much farther than normal to
+ * end a pre-drag. See {@link DragOptions.PreDragCondition#shouldStartDrag(double)}.
+ */
+ private static final int DEEP_PRESS_DISTANCE_FACTOR = 3;
+
@Thunk Launcher mLauncher;
private FlingToDeleteHelper mFlingToDeleteHelper;
@@ -91,9 +98,10 @@
private DropTarget mLastDropTarget;
- @Thunk int mLastTouch[] = new int[2];
- @Thunk long mLastTouchUpTime = -1;
- @Thunk int mDistanceSinceScroll = 0;
+ private final int[] mLastTouch = new int[2];
+ private long mLastTouchUpTime = -1;
+ private int mLastTouchClassification;
+ private int mDistanceSinceScroll = 0;
private int mTmpPoint[] = new int[2];
private Rect mDragLayerRect = new Rect();
@@ -204,7 +212,7 @@
}
mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- dragView.show(mMotionDownX, mMotionDownY);
+ dragView.show(mLastTouch[0], mLastTouch[1]);
mDistanceSinceScroll = 0;
if (!mIsInPreDrag) {
@@ -213,9 +221,7 @@
mOptions.preDragCondition.onPreDragStart(mDragObject);
}
- mLastTouch[0] = mMotionDownX;
- mLastTouch[1] = mMotionDownY;
- handleMoveEvent(mMotionDownX, mMotionDownY);
+ handleMoveEvent(mLastTouch[0], mLastTouch[1]);
mLauncher.getUserEventDispatcher().resetActionDurationMillis();
return dragView;
}
@@ -430,6 +436,11 @@
final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());
final int dragLayerX = dragLayerPos[0];
final int dragLayerY = dragLayerPos[1];
+ mLastTouch[0] = dragLayerX;
+ mLastTouch[1] = dragLayerY;
+ if (ATLEAST_Q) {
+ mLastTouchClassification = ev.getClassification();
+ }
switch (action) {
case MotionEvent.ACTION_DOWN:
@@ -488,8 +499,12 @@
mLastTouch[0] = x;
mLastTouch[1] = y;
+ int distanceDragged = mDistanceSinceScroll;
+ if (ATLEAST_Q && mLastTouchClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS) {
+ distanceDragged /= DEEP_PRESS_DISTANCE_FACTOR;
+ }
if (mIsInPreDrag && mOptions.preDragCondition != null
- && mOptions.preDragCondition.shouldStartDrag(mDistanceSinceScroll)) {
+ && mOptions.preDragCondition.shouldStartDrag(distanceDragged)) {
callOnDragStart();
}
}
diff --git a/src/com/android/launcher3/logging/DumpTargetWrapper.java b/src/com/android/launcher3/logging/DumpTargetWrapper.java
index 365e8f2..067bdfd 100644
--- a/src/com/android/launcher3/logging/DumpTargetWrapper.java
+++ b/src/com/android/launcher3/logging/DumpTargetWrapper.java
@@ -15,17 +15,22 @@
*/
package com.android.launcher3.logging;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+
+import android.content.ComponentName;
import android.os.Process;
import android.text.TextUtils;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.model.nano.LauncherDumpProto;
import com.android.launcher3.model.nano.LauncherDumpProto.ContainerType;
import com.android.launcher3.model.nano.LauncherDumpProto.DumpTarget;
import com.android.launcher3.model.nano.LauncherDumpProto.ItemType;
import com.android.launcher3.model.nano.LauncherDumpProto.UserType;
+import com.android.launcher3.util.ShortcutUtil;
import java.util.ArrayList;
import java.util.List;
@@ -73,20 +78,23 @@
public DumpTarget newItemTarget(ItemInfo info) {
DumpTarget dt = new DumpTarget();
dt.type = DumpTarget.Type.ITEM;
-
+ if (info == null) {
+ return dt;
+ }
switch (info.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
dt.itemType = ItemType.APP_ICON;
break;
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- dt.itemType = ItemType.UNKNOWN_ITEMTYPE;
- break;
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
dt.itemType = ItemType.WIDGET;
break;
- case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
+ case ITEM_TYPE_DEEP_SHORTCUT:
+ case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
dt.itemType = ItemType.SHORTCUT;
break;
+ default:
+ dt.itemType = ItemType.UNKNOWN_ITEMTYPE;
+ break;
}
return dt;
}
@@ -120,6 +128,9 @@
}
private static String getItemStr(DumpTarget t) {
+ if (t == null) {
+ return "";
+ }
String typeStr = LoggerUtils.getFieldName(t.itemType, ItemType.class);
if (!TextUtils.isEmpty(t.packageName)) {
typeStr += ", package=" + t.packageName;
@@ -132,8 +143,15 @@
}
public DumpTarget writeToDumpTarget(ItemInfo info) {
- node.component = info.getTargetComponent() == null? "":
- info.getTargetComponent().flattenToString();
+ if (info == null) {
+ return node;
+ }
+ if (ShortcutUtil.isDeepShortcut(info)) {
+ node.component = ((WorkspaceItemInfo) info).getDeepShortcutId();
+ } else {
+ ComponentName cmp = info.getTargetComponent();
+ node.component = cmp == null ? "" : cmp.flattenToString();
+ }
node.packageName = info.getTargetComponent() == null? "":
info.getTargetComponent().getPackageName();
if (info instanceof LauncherAppWidgetInfo) {
diff --git a/src/com/android/launcher3/logging/FileLog.java b/src/com/android/launcher3/logging/FileLog.java
index 04cf20a..2c972a0 100644
--- a/src/com/android/launcher3/logging/FileLog.java
+++ b/src/com/android/launcher3/logging/FileLog.java
@@ -42,6 +42,8 @@
private static Handler sHandler = null;
private static File sLogsDirectory = null;
+ private static final int LOG_DAYS = 2;
+
public static void setDir(File logsDir) {
if (ENABLED) {
synchronized (DATE_FORMAT) {
@@ -147,7 +149,7 @@
case MSG_WRITE: {
Calendar cal = Calendar.getInstance();
// suffix with 0 or 1 based on the day of the year.
- String fileName = FILE_NAME_PREFIX + (cal.get(Calendar.DAY_OF_YEAR) & 1);
+ String fileName = FILE_NAME_PREFIX + (cal.get(Calendar.DAY_OF_YEAR) % LOG_DAYS);
if (!fileName.equals(mCurrentFileName)) {
closeWriter();
@@ -195,8 +197,9 @@
(Pair<PrintWriter, CountDownLatch>) msg.obj;
if (p.first != null) {
- dumpFile(p.first, FILE_NAME_PREFIX + 0);
- dumpFile(p.first, FILE_NAME_PREFIX + 1);
+ for (int i = 0; i < LOG_DAYS; i++) {
+ dumpFile(p.first, FILE_NAME_PREFIX + i);
+ }
}
p.second.countDown();
return true;
@@ -226,4 +229,15 @@
}
}
}
+
+ /**
+ * Gets files used for FileLog
+ */
+ public static File[] getLogFiles() {
+ File[] files = new File[LOG_DAYS];
+ for (int i = 0; i < LOG_DAYS; i++) {
+ files[i] = new File(sLogsDirectory, FILE_NAME_PREFIX + i);
+ }
+ return files;
+ }
}
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index 598792a..f352b46 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -142,8 +142,10 @@
typeStr += ", grid(" + t.gridX + "," + t.gridY + ")";
} else if ((t.packageNameHash != 0 || t.componentHash != 0 || t.intentHash != 0)
&& t.itemType != ItemType.TASK) {
- typeStr += ", predictiveRank=" + t.predictedRank + ", grid(" + t.gridX + "," + t.gridY
- + "), span(" + t.spanX + "," + t.spanY + "), pageIdx=" + t.pageIndex;
+ typeStr +=
+ ", isWorkApp=" + t.isWorkApp + ", predictiveRank=" + t.predictedRank + ", grid("
+ + t.gridX + "," + t.gridY + "), span(" + t.spanX + "," + t.spanY
+ + "), pageIdx=" + t.pageIndex;
}
if (t.searchQueryLength != 0) {
typeStr += ", searchQueryLength=" + t.searchQueryLength;
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index cad95b0..9dfd7ab 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -17,12 +17,15 @@
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.logging.StatsLogUtils.LogStateProvider;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ResourceBasedOverride;
-import com.android.launcher3.logging.StatsLogUtils.LogStateProvider;
/**
* Handles the user event logging in Q.
@@ -38,7 +41,10 @@
return mgr;
}
- public void logAppLaunch(View v, Intent intent) { }
+ /**
+ * Logs app launches
+ */
+ 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) { }
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 99906fe..8289da9 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -33,7 +33,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.os.Process;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.util.Log;
import android.view.View;
@@ -135,7 +137,7 @@
// --------------------------------------------------------------
@Deprecated
- public void logAppLaunch(View v, Intent intent) {
+ public void logAppLaunch(View v, Intent intent, @Nullable UserHandle userHandle) {
LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP),
newItemTarget(v, mInstantAppResolver), newTarget(Target.Type.CONTAINER));
@@ -143,7 +145,13 @@
if (mDelegate != null) {
mDelegate.modifyUserEvent(event);
}
- fillIntentInfo(event.srcTarget[0], intent);
+ fillIntentInfo(event.srcTarget[0], intent, userHandle);
+ }
+ ItemInfo info = (ItemInfo) v.getTag();
+ if (Utilities.IS_DEBUG_DEVICE && FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) {
+ FileLog.d(TAG, "appLaunch: packageName:" + info.getTargetComponent().getPackageName()
+ + ",isWorkApp:" + (info.user != null && !Process.myUserHandle().equals(
+ userHandle)) + ",launchLocation:" + info.container);
}
dispatchUserEvent(event, intent);
mAppOrTaskLaunch = true;
@@ -171,8 +179,9 @@
mAppOrTaskLaunch = true;
}
- protected void fillIntentInfo(Target target, Intent intent) {
+ protected void fillIntentInfo(Target target, Intent intent, @Nullable UserHandle userHandle) {
target.intentHash = intent.hashCode();
+ target.isWorkApp = userHandle != null && !userHandle.equals(Process.myUserHandle());
fillComponentInfo(target, intent.getComponent());
}
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index 521f511..2a102d2 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.widget;
+import static com.android.launcher3.testing.TestProtocol.NORMAL_STATE_ORDINAL;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -37,6 +39,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.R;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.TopRoundedCornerView;
@@ -247,4 +250,10 @@
anim.play(ObjectAnimator.ofFloat(mRecyclerView, ALPHA, 0.5f));
return anim;
}
+
+ @Override
+ protected void onCloseComplete() {
+ super.onCloseComplete();
+ AccessibilityManagerCompat.sendStateEventToTest(getContext(), NORMAL_STATE_ORDINAL);
+ }
}
diff --git a/src_plugins/com/android/systemui/plugins/OverscrollPlugin.java b/src_plugins/com/android/systemui/plugins/OverscrollPlugin.java
index 60eb304..28a9193 100644
--- a/src_plugins/com/android/systemui/plugins/OverscrollPlugin.java
+++ b/src_plugins/com/android/systemui/plugins/OverscrollPlugin.java
@@ -24,11 +24,11 @@
* the user to a more recent app).
*/
@ProvidesInterface(action = com.android.systemui.plugins.OverscrollPlugin.ACTION,
- version = com.android.systemui.plugins.OverlayPlugin.VERSION)
+ version = com.android.systemui.plugins.OverscrollPlugin.VERSION)
public interface OverscrollPlugin extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_LAUNCHER_OVERSCROLL";
- int VERSION = 1;
+ int VERSION = 3;
String DEVICE_STATE_LOCKED = "Locked";
String DEVICE_STATE_LAUNCHER = "Launcher";
@@ -36,9 +36,38 @@
String DEVICE_STATE_UNKNOWN = "Unknown";
/**
- * Called when the user completed a right to left swipe in the gesture area.
- *
- * @param deviceState One of the DEVICE_STATE_* constants.
+ * @return true if the plugin is active and will accept overscroll gestures
*/
- void onOverscroll(String deviceState);
+ boolean isActive();
+
+ /**
+ * Called when a touch is down and has been recognized as an overscroll gesture.
+ * A call of this method will always result in `onTouchUp` being called, and possibly
+ * `onFling` as well.
+ *
+ * @param deviceState String representing the current device state
+ * @param underlyingActivity String representing the currently active Activity
+ */
+ void onTouchStart(String deviceState, String underlyingActivity);
+
+ /**
+ * Called when a touch that was previously recognized has moved.
+ *
+ * @param px distance between the position of touch on this update and the position of the
+ * touch when it was initially recognized.
+ */
+ void onTouchTraveled(int px);
+
+ /**
+ * Called when a touch that was previously recognized has ended.
+ *
+ * @param px distance between the position of touch on this update and the position of the
+ * touch when it was initially recognized.
+ */
+ void onTouchEnd(int px);
+
+ /**
+ * Called when the user starts Compose with a fling. `onTouchUp` will also be called.
+ */
+ void onFling(float velocity);
}
diff --git a/tests/Android.mk b/tests/Android.mk
index 83fdddc..d1a6c06 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -57,7 +57,7 @@
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES += launcher-aosp-tapl
else
- LOCAL_SDK_VERSION := 28
+ LOCAL_SDK_VERSION := system_28
LOCAL_MIN_SDK_VERSION := 21
LOCAL_STATIC_JAVA_LIBRARIES += ub-launcher-aosp-tapl
endif
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 4243ed0..60dad12 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -92,7 +92,7 @@
public static final long DEFAULT_ACTIVITY_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 5;
- public static final long DEFAULT_UI_TIMEOUT = 60000; // b/136278866
+ public static final long DEFAULT_UI_TIMEOUT = 10000;
private static final String TAG = "AbstractLauncherUiTest";
protected LooperExecutor mMainThreadExecutor = MAIN_EXECUTOR;
@@ -259,7 +259,7 @@
protected <T> T getOnUiThread(final Callable<T> callback) {
try {
return mMainThreadExecutor.submit(callback).get();
- } catch (Exception e) {
+ } catch (Throwable e) {
throw new RuntimeException(e);
}
}
diff --git a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
index 80bb3ed..1a68122 100644
--- a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
+++ b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -38,8 +38,8 @@
evaluateInPortrait();
evaluateInLandscape();
- } catch (Exception e) {
- Log.e(TAG, "Exception", e);
+ } catch (Throwable e) {
+ Log.e(TAG, "Error", e);
throw e;
} finally {
mTest.mDevice.setOrientationNatural();
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 0472ce1..62e2a53 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -103,11 +103,11 @@
setResult(acceptConfig);
if (acceptConfig) {
- Wait.atMost(null, new WidgetSearchCondition(), DEFAULT_ACTIVITY_TIMEOUT, mLauncher);
+ Wait.atMost("", new WidgetSearchCondition(), DEFAULT_ACTIVITY_TIMEOUT, mLauncher);
assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
} else {
// Verify that the widget id is deleted.
- Wait.atMost(null, () -> mAppWidgetManager.getAppWidgetInfo(mWidgetId) == null,
+ Wait.atMost("", () -> mAppWidgetManager.getAppWidgetInfo(mWidgetId) == null,
DEFAULT_ACTIVITY_TIMEOUT, mLauncher);
}
}
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index d909ad7..59b861c 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -170,7 +170,7 @@
// Go back to home
mLauncher.pressHome();
- Wait.atMost(null, new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT,
+ Wait.atMost("", new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT,
mLauncher);
}
diff --git a/tests/src/com/android/launcher3/util/Wait.java b/tests/src/com/android/launcher3/util/Wait.java
index 2663d02..2ab1e00 100644
--- a/tests/src/com/android/launcher3/util/Wait.java
+++ b/tests/src/com/android/launcher3/util/Wait.java
@@ -7,6 +7,8 @@
import org.junit.Assert;
+import java.util.function.Supplier;
+
/**
* A utility class for waiting for a condition to be true.
*/
@@ -16,10 +18,16 @@
public static void atMost(String message, Condition condition, long timeout,
LauncherInstrumentation launcher) {
+ atMost(() -> message, condition, timeout, DEFAULT_SLEEP_MS, launcher);
+ }
+
+ public static void atMost(Supplier<String> message, Condition condition, long timeout,
+ LauncherInstrumentation launcher) {
atMost(message, condition, timeout, DEFAULT_SLEEP_MS, launcher);
}
- public static void atMost(String message, Condition condition, long timeout, long sleepMillis,
+ public static void atMost(Supplier<String> message, Condition condition, long timeout,
+ long sleepMillis,
LauncherInstrumentation launcher) {
final long startTime = SystemClock.uptimeMillis();
long endTime = startTime + timeout;
@@ -45,6 +53,6 @@
}
Log.d("Wait", "atMost: timed out: " + SystemClock.uptimeMillis());
launcher.checkForAnomaly();
- Assert.fail(message);
+ Assert.fail(message.get());
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 18f33a2..b715de0 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -308,13 +308,22 @@
}
}
+ private String getVisiblePackages() {
+ return mDevice.findObjects(By.textStartsWith(""))
+ .stream()
+ .map(object -> object.getApplicationPackage())
+ .distinct()
+ .filter(pkg -> !"com.android.systemui".equals(pkg))
+ .collect(Collectors.joining(", "));
+ }
+
private String getVisibleStateMessage() {
if (hasLauncherObject(CONTEXT_MENU_RES_ID)) return "Context Menu";
if (hasLauncherObject(WIDGETS_RES_ID)) return "Widgets";
if (hasLauncherObject(OVERVIEW_RES_ID)) return "Overview";
if (hasLauncherObject(WORKSPACE_RES_ID)) return "Workspace";
if (hasLauncherObject(APPS_RES_ID)) return "AllApps";
- return "Background";
+ return "Background (" + getVisiblePackages() + ")";
}
public void setSystemHealthSupplier(Function<Long, String> supplier) {
@@ -429,12 +438,6 @@
assertEquals("Unexpected display rotation",
mExpectedRotation, mDevice.getDisplayRotation());
- // b/136278866
- for (int i = 0; i != 100; ++i) {
- if (getNavigationModeMismatchError() == null) break;
- sleep(100);
- }
-
final String error = getNavigationModeMismatchError();
assertTrue(error, error == null);
log("verifyContainerType: " + containerType);
@@ -519,7 +522,9 @@
mInstrumentation.getUiAutomation().executeAndWaitForEvent(
command, eventFilter, WAIT_TIME_MS);
assertNotNull("executeAndWaitForEvent returned null (this can't happen)", event);
- return event.getParcelableData();
+ final Parcelable parcelableData = event.getParcelableData();
+ event.recycle();
+ return parcelableData;
} catch (TimeoutException e) {
fail(message.get());
return null;
@@ -557,7 +562,7 @@
if (hasLauncherObject(WORKSPACE_RES_ID)) {
log(action = "already at home");
} else {
- log("Hierarchy before swiping up to home");
+ log("Hierarchy before swiping up to home:");
dumpViewHierarchy();
log(action = "swiping up to home from " + getVisibleStateMessage());
@@ -569,15 +574,19 @@
}
}
} else {
- log(action = "clicking home button");
- executeAndWaitForEvent(
- () -> {
- log("LauncherInstrumentation.pressHome before clicking");
- waitForSystemUiObject("home").click();
- },
- event -> true,
- () -> "Pressing Home didn't produce any events");
- mDevice.waitForIdle();
+ log("Hierarchy before clicking home:");
+ dumpViewHierarchy();
+ log(action = "clicking home button from " + getVisibleStateMessage());
+ try (LauncherInstrumentation.Closable c = addContextLayer(action)) {
+ mDevice.waitForIdle();
+ runToState(
+ () -> waitForSystemUiObject("home").click(),
+ NORMAL_STATE_ORDINAL,
+ !hasLauncherObject(WORKSPACE_RES_ID)
+ && (hasLauncherObject(APPS_RES_ID)
+ || hasLauncherObject(OVERVIEW_RES_ID)));
+ mDevice.waitForIdle();
+ }
}
try (LauncherInstrumentation.Closable c = addContextLayer(
"performed action to switch to Home - " + action)) {
@@ -781,12 +790,20 @@
+ "]";
}
+ void runToState(Runnable command, int expectedState, boolean requireEvent) {
+ if (requireEvent) {
+ runToState(command, expectedState);
+ } else {
+ command.run();
+ }
+ }
+
void runToState(Runnable command, int expectedState) {
final List<Integer> actualEvents = new ArrayList<>();
executeAndWaitForEvent(
command,
event -> isSwitchToStateEvent(event, expectedState, actualEvents),
- () -> "Failed to receive an event for the swipe end: expected "
+ () -> "Failed to receive an event for the state change: expected "
+ TestProtocol.stateOrdinalToString(expectedState)
+ ", actual: " + eventListToString(actualEvents));
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 8a53ef1..3299d5d 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -22,6 +22,7 @@
import static junit.framework.TestCase.assertTrue;
+import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemClock;
@@ -49,6 +50,34 @@
mHotseat = launcher.waitForLauncherObject("hotseat");
}
+ private static boolean supportsRoundedCornersOnWindows(Resources resources) {
+ return ResourceUtils.getBoolByName(
+ "config_supportsRoundedCornersOnWindows", resources, false);
+ }
+
+ private static float getWindowCornerRadius(Resources resources) {
+ if (!supportsRoundedCornersOnWindows(resources)) {
+ return 0f;
+ }
+
+ // Radius that should be used in case top or bottom aren't defined.
+ float defaultRadius = ResourceUtils.getDimenByName("rounded_corner_radius", resources, 0);
+
+ float topRadius = ResourceUtils.getDimenByName("rounded_corner_radius_top", resources, 0);
+ if (topRadius == 0f) {
+ topRadius = defaultRadius;
+ }
+ float bottomRadius = ResourceUtils.getDimenByName(
+ "rounded_corner_radius_bottom", resources, 0);
+ if (bottomRadius == 0f) {
+ bottomRadius = defaultRadius;
+ }
+
+ // Always use the smallest radius to make sure the rounded corners will
+ // completely cover the display.
+ return Math.min(topRadius, bottomRadius);
+ }
+
/**
* Swipes up to All Apps.
*
@@ -59,13 +88,12 @@
try (LauncherInstrumentation.Closable c =
mLauncher.addContextLayer("want to switch from workspace to all apps")) {
verifyActiveContainer();
- final UiObject2 hotseat = mHotseat;
- final Point start = hotseat.getVisibleCenter();
- int deviceHeight = mLauncher.getDevice().getDisplayHeight();
- int bottomGestureMargin = ResourceUtils.getNavbarSize(
+ final int deviceHeight = mLauncher.getDevice().getDisplayHeight();
+ final int bottomGestureMargin = ResourceUtils.getNavbarSize(
ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources());
- int displayBottom = deviceHeight - bottomGestureMargin;
- start.y = displayBottom - 1;
+ final int windowCornerRadius = (int) Math.ceil(getWindowCornerRadius(
+ mLauncher.getResources()));
+ final int startY = deviceHeight - Math.max(bottomGestureMargin, windowCornerRadius) - 1;
final int swipeHeight = mLauncher.getTestInfo(
TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT).
getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
@@ -74,10 +102,10 @@
+ mLauncher.getTouchSlop());
mLauncher.swipeToState(
- start.x,
- start.y,
- start.x,
- start.y - swipeHeight - mLauncher.getTouchSlop(),
+ 0,
+ startY,
+ 0,
+ startY - swipeHeight - mLauncher.getTouchSlop(),
12,
ALL_APPS_STATE_ORDINAL);