Merge "Add ImpressionLogger to StatsLogManager" into tm-qpr-dev
diff --git a/quickstep/Android.bp b/quickstep/Android.bp
index 7292c44..f5a8253 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -38,6 +38,7 @@
name: "launcher3-quickstep-oop-tests-src",
path: "tests",
srcs: [
+ "tests/src/com/android/quickstep/TaskbarModeSwitchRule.java",
"tests/src/com/android/quickstep/NavigationModeSwitchRule.java",
"tests/src/com/android/quickstep/AbstractQuickStepTest.java",
"tests/src/com/android/quickstep/TaplTestsQuickstep.java",
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index c0d52a4..1a801b5 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -187,6 +187,8 @@
<string name="allset_title">All set!</string>
<!-- Hint string at the bottom of "All Set" page [CHAR LIMIT=NONE] -->
<string name="allset_hint">Swipe up to go Home</string>
+ <!-- Hint string at the bottom of "All Set" page for button navigation [CHAR LIMIT=NONE] -->
+ <string name="allset_button_hint">Tap the home button to go to your home screen</string>
<!-- Description of "All Set" page on phones [CHAR LIMIT=NONE] -->
<string name="allset_description">You\u2019re ready to start using your phone</string>
<!-- Description of "All Set" page on tablets [CHAR LIMIT=NONE] -->
@@ -204,7 +206,7 @@
<!-- Label for toast with instructions for split screen selection mode. [CHAR_LIMIT=50] -->
<string name="toast_split_select_app">Tap another app to use splitscreen</string>
<!-- Label for toast when app selected for split isn't supported. [CHAR_LIMIT=50] -->
- <string name="toast_split_app_unsupported">App does not support split-screen.</string>
+ <string name="toast_split_app_unsupported">Choose another app to use split screen</string>
<!-- Message shown when an action is blocked by a policy enforced by the app or the organization managing the device. [CHAR_LIMIT=NONE] -->
<string name="blocked_by_policy">This action isn\'t allowed by the app or your organization</string>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 9175226..27159d3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
+import static com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN;
@@ -308,7 +309,8 @@
int windowFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_SLIPPERY
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
- if (DisplayController.isTransientTaskbar(this)) {
+ if (DisplayController.isTransientTaskbar(this)
+ && !IS_RUNNING_IN_TEST_HARNESS) {
windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
}
@@ -897,12 +899,25 @@
}
/**
+ * Enables the auto timeout for taskbar stashing. This method should only be used for taskbar
+ * testing.
+ */
+ @VisibleForTesting
+ public void enableBlockingTimeoutDuringTests(boolean enableBlockingTimeout) {
+ mControllers.taskbarStashController.enableBlockingTimeoutDuringTests(enableBlockingTimeout);
+ }
+
+ /**
* Unstashes the Taskbar if it is stashed. This method should only be used to unstash the
* taskbar at the end of a test.
*/
@VisibleForTesting
public void unstashTaskbarIfStashed() {
- mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
+ if (DisplayController.isTransientTaskbar(this)) {
+ mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
+ } else {
+ mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
+ }
}
protected boolean isUserSetupComplete() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index d7bb16e..3045eca 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
@@ -301,7 +302,12 @@
protected void callOnDragStart() {
super.callOnDragStart();
// Pre-drag has ended, start the global system drag.
- AbstractFloatingView.closeAllOpenViews(mActivity);
+ if (mDisallowGlobalDrag) {
+ AbstractFloatingView.closeAllOpenViewsExcept(mActivity, TYPE_TASKBAR_ALL_APPS);
+ } else {
+ AbstractFloatingView.closeAllOpenViews(mActivity);
+ }
+
startSystemDrag((BubbleTextView) mDragObject.originalView);
}
@@ -536,10 +542,15 @@
private View findTaskbarTargetForIconView(@NonNull View iconView) {
Object tag = iconView.getTag();
+ TaskbarViewController taskbarViewController = mControllers.taskbarViewController;
+
if (tag instanceof ItemInfo) {
ItemInfo item = (ItemInfo) tag;
- TaskbarViewController taskbarViewController = mControllers.taskbarViewController;
if (item.container == CONTAINER_ALL_APPS || item.container == CONTAINER_PREDICTION) {
+ if (mDisallowGlobalDrag) {
+ // We're dragging in taskbarAllApps, we don't have folders or shortcuts
+ return iconView;
+ }
// Since all apps closes when the drag starts, target the all apps button instead.
return taskbarViewController.getAllAppsButtonView();
} else if (item.container >= 0) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index fc26f5f..ea5df87 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -119,10 +119,13 @@
mLauncherState = finalState;
updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, false);
applyState();
- mControllers.taskbarDragController.setDisallowGlobalDrag(
- (finalState instanceof OverviewState));
- mControllers.taskbarDragController.setDisallowLongClick(
- finalState == LauncherState.OVERVIEW_SPLIT_SELECT);
+ boolean disallowGlobalDrag = finalState instanceof OverviewState;
+ boolean disallowLongClick = finalState == LauncherState.OVERVIEW_SPLIT_SELECT;
+ mControllers.taskbarDragController.setDisallowGlobalDrag(disallowGlobalDrag);
+ mControllers.taskbarDragController.setDisallowLongClick(disallowLongClick);
+ mControllers.taskbarAllAppsController.setDisallowGlobalDrag(disallowGlobalDrag);
+ mControllers.taskbarAllAppsController.setDisallowLongClick(disallowLongClick);
+ mControllers.taskbarPopupController.setHideSplitOptions(disallowGlobalDrag);
}
};
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index da6dab1..9b27c9d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -75,6 +75,7 @@
// Initialized in init.
private TaskbarControllers mControllers;
+ private boolean mHideSplitOptions;
public TaskbarPopupController(TaskbarActivityContext context) {
mContext = context;
@@ -100,6 +101,10 @@
mPopupDataProvider.setDeepShortcutMap(deepShortcutMapCopy);
}
+ public void setHideSplitOptions(boolean hideSplitOptions) {
+ mHideSplitOptions = hideSplitOptions;
+ }
+
private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
final PackageUserKey packageUserKey = new PackageUserKey(null, null);
Predicate<ItemInfo> matcher = info -> !packageUserKey.updateFromItemInfo(info)
@@ -186,11 +191,16 @@
// TODO(b/227800345): Add "Split bottom" option when tablet is in portrait mode.
private Stream<SystemShortcut.Factory> getSystemShortcuts() {
// concat a Stream of split options with a Stream of APP_INFO
+ Stream<SystemShortcut.Factory> appInfo = Stream.of(APP_INFO);
+ if (mHideSplitOptions) {
+ return appInfo;
+ }
+
return Stream.concat(
Utilities.getSplitPositionOptions(mContext.getDeviceProfile())
.stream()
.map(this::createSplitShortcutFactory),
- Stream.of(APP_INFO)
+ appInfo
);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 72ae1d1..b53e9c5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -37,6 +37,7 @@
import android.view.ViewConfiguration;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.launcher3.Alarm;
@@ -169,6 +170,7 @@
private boolean mEnableManualStashingDuringTests = false;
private final Alarm mTimeoutAlarm = new Alarm();
+ private boolean mEnableBlockingTimeoutDuringTests = false;
// Evaluate whether the handle should be stashed
private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
@@ -267,11 +269,21 @@
* Enables support for manual stashing. This should only be used to add this functionality
* to Launcher specific tests.
*/
+ @VisibleForTesting
public void enableManualStashingDuringTests(boolean enableManualStashing) {
mEnableManualStashingDuringTests = enableManualStashing;
}
/**
+ * Enables the auto timeout for taskbar stashing. This method should only be used for taskbar
+ * testing.
+ */
+ @VisibleForTesting
+ public void enableBlockingTimeoutDuringTests(boolean enableBlockingTimeout) {
+ mEnableBlockingTimeoutDuringTests = enableBlockingTimeout;
+ }
+
+ /**
* Sets the flag indicating setup UI is visible
*/
protected void setSetupUIVisible(boolean isVisible) {
@@ -846,12 +858,12 @@
* Attempts to start timer to auto hide the taskbar based on time.
*/
public void tryStartTaskbarTimeout() {
- if (!DisplayController.isTransientTaskbar(mActivity)) {
+ if (!DisplayController.isTransientTaskbar(mActivity)
+ || mIsStashed
+ || mEnableBlockingTimeoutDuringTests) {
return;
}
- if (mIsStashed) {
- return;
- }
+
cancelTimeoutIfExists();
mTimeoutAlarm.setOnAlarmListener(this::onTaskbarTimeout);
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
index 85c6318..4dc8d47 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
@@ -48,6 +48,8 @@
private AppInfo[] mApps;
private int mAppsModelFlags;
private List<ItemInfo> mPredictedApps;
+ private boolean mDisallowGlobalDrag;
+ private boolean mDisallowLongClick;
/** Initialize the controller. */
public void init(TaskbarControllers controllers, boolean allAppsVisible) {
@@ -78,6 +80,14 @@
}
}
+ public void setDisallowGlobalDrag(boolean disableDragForOverviewState) {
+ mDisallowGlobalDrag = disableDragForOverviewState;
+ }
+
+ public void setDisallowLongClick(boolean disallowLongClick) {
+ mDisallowLongClick = disallowLongClick;
+ }
+
/** Updates the current predictions. */
public void setPredictedApps(List<ItemInfo> predictedApps) {
if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
@@ -123,6 +133,12 @@
mAppsView.getFloatingHeaderView()
.findFixedRowByType(PredictionRowView.class)
.setPredictedApps(mPredictedApps);
+ // 1 alternative that would be more work:
+ // Create a shared drag layer between taskbar and taskbarAllApps so that when dragging
+ // starts and taskbarAllApps can close, but the drag layer that the view is being dragged in
+ // doesn't also close
+ overlayContext.getDragController().setDisallowGlobalDrag(mDisallowGlobalDrag);
+ overlayContext.getDragController().setDisallowLongClick(mDisallowLongClick);
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 875b72c..5a09e02 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -116,7 +116,7 @@
*/
@BinderThread
public void addCommand(int type) {
- if (mPendingCommands.size() > MAX_QUEUE_SIZE) {
+ if (mPendingCommands.size() >= MAX_QUEUE_SIZE) {
return;
}
CommandInfo cmd = new CommandInfo(type);
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 9621ce6..6f124b8 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -11,9 +11,11 @@
import androidx.annotation.Nullable;
import com.android.launcher3.R;
+import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.testing.TestInformationHandler;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.util.DisplayController;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.TISBindHelper;
@@ -120,6 +122,30 @@
.getCurrentActivityContext()
.getTaskbarAllAppsTopPadding());
}
+
+ case TestProtocol.REQUEST_ENABLE_BLOCK_TIMEOUT:
+ runOnTISBinder(tisBinder -> {
+ enableBlockingTimeout(tisBinder, true);
+ });
+ return response;
+
+ case TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT:
+ runOnTISBinder(tisBinder -> {
+ enableBlockingTimeout(tisBinder, false);
+ });
+ return response;
+
+ case TestProtocol.REQUEST_ENABLE_TRANSIENT_TASKBAR:
+ runOnTISBinder(tisBinder -> {
+ enableTransientTaskbar(tisBinder, true);
+ });
+ return response;
+
+ case TestProtocol.REQUEST_DISABLE_TRANSIENT_TASKBAR:
+ runOnTISBinder(tisBinder -> {
+ enableTransientTaskbar(tisBinder, false);
+ });
+ return response;
}
return super.call(method, arg, extras);
@@ -149,6 +175,20 @@
enable);
}
+ private void enableBlockingTimeout(
+ TouchInteractionService.TISBinder tisBinder, boolean enable) {
+ // Allow null-pointer to catch illegal states.
+ tisBinder.getTaskbarManager().getCurrentActivityContext().enableBlockingTimeoutDuringTests(
+ enable);
+ }
+
+ private void enableTransientTaskbar(
+ TouchInteractionService.TISBinder tisBinder, boolean enable) {
+ // Allow null-pointer to catch illegal states.
+ TaskbarActivityContext context = tisBinder.getTaskbarManager().getCurrentActivityContext();
+ DisplayController.INSTANCE.get(context).enableTransientTaskbarForTests(enable);
+ }
+
/**
* Runs the given command on the UI thread, after ensuring we are connected to
* TouchInteractionService.
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index acf597b..ef7c6dc 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -548,15 +548,13 @@
}
}
- public void startIntentAndTask(PendingIntent pendingIntent, Intent fillInIntent,
- Bundle options1, int taskId, Bundle options2,
- @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio,
- RemoteTransition remoteTransition, InstanceId instanceId) {
+ public void startIntentAndTask(PendingIntent pendingIntent, Bundle options1, int taskId,
+ Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition,
+ float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) {
if (mSystemUiProxy != null) {
try {
- mSplitScreen.startIntentAndTask(pendingIntent, fillInIntent, options1,
- taskId, options2, splitPosition, splitRatio,
- remoteTransition, instanceId);
+ mSplitScreen.startIntentAndTask(pendingIntent, options1, taskId, options2,
+ splitPosition, splitRatio, remoteTransition, instanceId);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startIntentAndTask");
}
@@ -593,13 +591,13 @@
}
public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent,
- Intent fillInIntent, Bundle options1, int taskId, Bundle options2,
+ Bundle options1, int taskId, Bundle options2,
@SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio,
RemoteAnimationAdapter adapter, InstanceId instanceId) {
if (mSystemUiProxy != null) {
try {
- mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, fillInIntent,
- options1, taskId, options2, splitPosition, splitRatio, adapter, instanceId);
+ mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, options1, taskId,
+ options2, splitPosition, splitRatio, adapter, instanceId);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startIntentAndTaskWithLegacyTransition");
}
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 8986c05..897b559 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -53,6 +53,7 @@
import androidx.annotation.Nullable;
import androidx.core.graphics.ColorUtils;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -120,10 +121,9 @@
mContentView = findViewById(R.id.content_view);
mSwipeUpShift = getResources().getDimension(R.dimen.allset_swipe_up_shift);
- boolean isTablet = InvariantDeviceProfile.INSTANCE.get(getApplicationContext())
- .getDeviceProfile(this).isTablet;
+ DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
TextView subtitle = findViewById(R.id.subtitle);
- subtitle.setText(isTablet
+ subtitle.setText(dp.isTablet
? R.string.allset_description_tablet : R.string.allset_description);
TextView tv = findViewById(R.id.navigation_settings);
@@ -137,7 +137,11 @@
}
});
- findViewById(R.id.hint).setAccessibilityDelegate(new SkipButtonAccessibilityDelegate());
+ TextView hintTextView = findViewById(R.id.hint);
+ if (!dp.isGestureMode) {
+ hintTextView.setText(R.string.allset_button_hint);
+ }
+ hintTextView.setAccessibilityDelegate(new SkipButtonAccessibilityDelegate());
mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
mVibrator = getSystemService(Vibrator.class);
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 08f9fa6..4a74ac6 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -37,7 +37,6 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.RemoteAnimationAdapter;
@@ -88,10 +87,8 @@
private ItemInfo mItemInfo;
private Intent mInitialTaskIntent;
private int mInitialTaskId = INVALID_TASK_ID;
- private String mInitialTaskPackageName;
private Intent mSecondTaskIntent;
private int mSecondTaskId = INVALID_TASK_ID;
- private String mSecondTaskPackageName;
private boolean mRecentsAnimationRunning;
@Nullable
private UserHandle mUser;
@@ -119,7 +116,6 @@
public void setInitialTaskSelect(Task task, @StagePosition int stagePosition,
StatsLogManager.EventEnum splitEvent, ItemInfo itemInfo) {
mInitialTaskId = task.key.id;
- mInitialTaskPackageName = task.getTopComponent().getPackageName();
setInitialData(stagePosition, splitEvent, itemInfo);
}
@@ -131,7 +127,6 @@
mInitialTaskIntent = intent;
mUser = itemInfo.user;
mItemInfo = itemInfo;
- mInitialTaskPackageName = intent.getComponent().getPackageName();
setInitialData(stagePosition, splitEvent, itemInfo);
}
@@ -143,7 +138,6 @@
@StagePosition int stagePosition, @NonNull ItemInfo itemInfo,
StatsLogManager.EventEnum splitEvent) {
mInitialTaskId = info.taskId;
- mInitialTaskPackageName = info.topActivity.getPackageName();
setInitialData(stagePosition, splitEvent, itemInfo);
}
@@ -161,9 +155,9 @@
public void launchSplitTasks(Consumer<Boolean> callback) {
Pair<InstanceId, com.android.launcher3.logging.InstanceId> instanceIds =
LogUtils.getShellShareableInstanceId();
- launchTasks(mInitialTaskId, mInitialTaskIntent, mInitialTaskPackageName, mSecondTaskId,
- mSecondTaskIntent, mSecondTaskPackageName, mStagePosition, callback,
- false /* freezeTaskList */, DEFAULT_SPLIT_RATIO, instanceIds.first);
+ launchTasks(mInitialTaskId, mInitialTaskIntent, mSecondTaskId, mSecondTaskIntent,
+ mStagePosition, callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO,
+ instanceIds.first);
mStatsLogManager.logger()
.withItemInfo(mItemInfo)
@@ -177,12 +171,10 @@
*/
public void setSecondTask(Task task) {
mSecondTaskId = task.key.id;
- mSecondTaskPackageName = task.getTopComponent().getPackageName();
}
public void setSecondTask(Intent intent) {
mSecondTaskIntent = intent;
- mSecondTaskPackageName = intent.getComponent().getPackageName();
}
/**
@@ -205,9 +197,8 @@
*/
public void launchTasks(int taskId1, int taskId2, @StagePosition int stagePosition,
Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {
- launchTasks(taskId1, null /* intent1 */, null /* packageName1 */, taskId2,
- null /* intent2 */, null /* packageName2 */, stagePosition, callback,
- freezeTaskList, splitRatio, null);
+ launchTasks(taskId1, null /* intent1 */, taskId2, null /* intent2 */, stagePosition,
+ callback, freezeTaskList, splitRatio, null);
}
/**
@@ -220,8 +211,8 @@
* a split instance, null for cases that bring existing instaces to the
* foreground (quickswitch, launching previous pairs from overview)
*/
- public void launchTasks(int taskId1, @Nullable Intent intent1, String packageName1, int taskId2,
- @Nullable Intent intent2, String packageName2, @StagePosition int stagePosition,
+ public void launchTasks(int taskId1, @Nullable Intent intent1, int taskId2,
+ @Nullable Intent intent2, @StagePosition int stagePosition,
Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio,
@Nullable InstanceId shellInstanceId) {
TestLogging.recordEvent(
@@ -240,10 +231,10 @@
null /* options2 */, stagePosition, splitRatio, remoteTransition,
shellInstanceId);
} else if (intent2 == null) {
- launchIntentOrShortcut(intent1, packageName2, options1, taskId2, stagePosition,
- splitRatio, remoteTransition, shellInstanceId);
+ launchIntentOrShortcut(intent1, options1, taskId2, stagePosition, splitRatio,
+ remoteTransition, shellInstanceId);
} else if (intent1 == null) {
- launchIntentOrShortcut(intent2, packageName1, options1, taskId1,
+ launchIntentOrShortcut(intent2, options1, taskId1,
getOppositeStagePosition(stagePosition), splitRatio, remoteTransition,
shellInstanceId);
} else {
@@ -261,10 +252,10 @@
taskId2, null /* options2 */, stagePosition, splitRatio, adapter,
shellInstanceId);
} else if (intent2 == null) {
- launchIntentOrShortcutLegacy(intent1, packageName2, options1, taskId2,
- stagePosition, splitRatio, adapter, shellInstanceId);
+ launchIntentOrShortcutLegacy(intent1, options1, taskId2, stagePosition, splitRatio,
+ adapter, shellInstanceId);
} else if (intent1 == null) {
- launchIntentOrShortcutLegacy(intent2, packageName1, options1, taskId1,
+ launchIntentOrShortcutLegacy(intent2, options1, taskId1,
getOppositeStagePosition(stagePosition), splitRatio, adapter,
shellInstanceId);
} else {
@@ -273,9 +264,8 @@
}
}
- private void launchIntentOrShortcut(Intent intent, String otherTaskPackageName,
- ActivityOptions options1, int taskId, @StagePosition int stagePosition,
- float splitRatio, RemoteTransition remoteTransition,
+ private void launchIntentOrShortcut(Intent intent, ActivityOptions options1, int taskId,
+ @StagePosition int stagePosition, float splitRatio, RemoteTransition remoteTransition,
@Nullable InstanceId shellInstanceId) {
PendingIntent pendingIntent = getPendingIntent(intent);
final ShortcutInfo shortcutInfo = getShortcutInfo(intent,
@@ -285,16 +275,14 @@
options1.toBundle(), taskId, null /* options2 */, stagePosition,
splitRatio, remoteTransition, shellInstanceId);
} else {
- mSystemUiProxy.startIntentAndTask(pendingIntent,
- getFillInIntent(intent, otherTaskPackageName), options1.toBundle(), taskId,
+ mSystemUiProxy.startIntentAndTask(pendingIntent, options1.toBundle(), taskId,
null /* options2 */, stagePosition, splitRatio, remoteTransition,
shellInstanceId);
}
}
- private void launchIntentOrShortcutLegacy(Intent intent, String otherTaskPackageName,
- ActivityOptions options1, int taskId, @StagePosition int stagePosition,
- float splitRatio, RemoteAnimationAdapter adapter,
+ private void launchIntentOrShortcutLegacy(Intent intent, ActivityOptions options1, int taskId,
+ @StagePosition int stagePosition, float splitRatio, RemoteAnimationAdapter adapter,
@Nullable InstanceId shellInstanceId) {
PendingIntent pendingIntent = getPendingIntent(intent);
final ShortcutInfo shortcutInfo = getShortcutInfo(intent,
@@ -305,9 +293,8 @@
splitRatio, adapter, shellInstanceId);
} else {
mSystemUiProxy.startIntentAndTaskWithLegacyTransition(pendingIntent,
- getFillInIntent(intent, otherTaskPackageName), options1.toBundle(), taskId,
- null /* options2 */, stagePosition, splitRatio, adapter,
- shellInstanceId);
+ options1.toBundle(), taskId, null /* options2 */, stagePosition, splitRatio,
+ adapter, shellInstanceId);
}
}
@@ -318,18 +305,6 @@
: PendingIntent.getActivity(mContext, 0, intent, FLAG_MUTABLE));
}
- private Intent getFillInIntent(Intent intent, String otherTaskPackageName) {
- if (intent == null) {
- return null;
- }
-
- Intent fillInIntent = new Intent();
- if (TextUtils.equals(intent.getComponent().getPackageName(), otherTaskPackageName)) {
- fillInIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- }
- return fillInIntent;
- }
-
public @StagePosition int getActiveSplitStagePosition() {
return mStagePosition;
@@ -464,10 +439,8 @@
public void resetState() {
mInitialTaskId = INVALID_TASK_ID;
mInitialTaskIntent = null;
- mInitialTaskPackageName = null;
mSecondTaskId = INVALID_TASK_ID;
mSecondTaskIntent = null;
- mSecondTaskPackageName = null;
mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
mRecentsAnimationRunning = false;
mLaunchingTaskView = null;
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 2abd715..8c43fd1 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -288,7 +288,7 @@
public RunnableList launchTasks() {
SystemUiProxy.INSTANCE.get(getContext()).showDesktopApps();
getRecentsView().startHome();
- return new RunnableList();
+ return null;
}
@Nullable
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 6286374..ff0c984 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -3544,7 +3544,8 @@
mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SELECT_ACTIVE, isSplitSelectionActive());
mActionsView.updateSplitButtonHiddenFlags(FLAG_IS_NOT_TABLET,
!mActivity.getDeviceProfile().isTablet);
- mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK, getTaskViewCount() <= 1);
+ mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK,
+ !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get() && getTaskViewCount() <= 1);
}
/**
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 583771e..c428c64 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -726,13 +726,14 @@
/**
* Launch of the current task (both live and inactive tasks) with an animation.
*/
+ @Nullable
public RunnableList launchTasks() {
RecentsView recentsView = getRecentsView();
RemoteTargetHandle[] remoteTargetHandles = recentsView.mRemoteTargetHandles;
- RunnableList runnableList = new RunnableList();
if (isRunningTask() && remoteTargetHandles != null) {
if (!mIsClickableAsLiveTile) {
- return runnableList;
+ Log.e(TAG, "TaskView is not clickable as a live tile; returning to home.");
+ return null;
}
mIsClickableAsLiveTile = false;
@@ -757,11 +758,16 @@
if (targets == null) {
// If the recents animation is cancelled somehow between the parent if block and
// here, try to launch the task as a non live tile task.
- launchTaskAnimated();
+ RunnableList runnableList = launchTaskAnimated();
+ if (runnableList == null) {
+ Log.e(TAG, "Recents animation cancelled and cannot launch task as non-live tile"
+ + "; returning to home");
+ }
mIsClickableAsLiveTile = true;
return runnableList;
}
+ RunnableList runnableList = new RunnableList();
AnimatorSet anim = new AnimatorSet();
TaskViewUtils.composeRecentsLaunchAnimator(
anim, this, targets.apps,
@@ -798,10 +804,10 @@
});
anim.start();
recentsView.onTaskLaunchedInLiveTileMode();
+ return runnableList;
} else {
return launchTaskAnimated();
}
- return runnableList;
}
/**
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
index e2774c0..2c5825f 100644
--- a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
+++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
@@ -39,6 +39,7 @@
protected TestRule getRulesInsideActivityMonitor() {
return RuleChain.
outerRule(new NavigationModeSwitchRule(mLauncher)).
+ around(new TaskbarModeSwitchRule(mLauncher)).
around(super.getRulesInsideActivityMonitor());
}
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index e5e2cf3..eded1c9 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -51,7 +51,7 @@
/**
* Test rule that allows executing a test with Quickstep on and then Quickstep off.
- * The test should be annotated with @QuickstepOnOff.
+ * The test should be annotated with @NavigationModeSwitch.
*/
public class NavigationModeSwitchRule implements TestRule {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index 9337cb5..0b8bc10 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -17,6 +17,8 @@
import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
+
import static junit.framework.TestCase.assertEquals;
import android.content.Intent;
@@ -27,6 +29,7 @@
import com.android.launcher3.tapl.Taskbar;
import com.android.launcher3.ui.TaplTestsLauncher3;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
import org.junit.After;
import org.junit.Assume;
@@ -53,21 +56,25 @@
TaplTestsLauncher3.initialize(this);
startAppFast(CALCULATOR_APP_PACKAGE);
+ mLauncher.enableBlockTimeout(true);
mLauncher.showTaskbarIfHidden();
}
@After
public void tearDown() {
mLauncher.useDefaultWorkspaceLayoutOnReload();
+ mLauncher.enableBlockTimeout(false);
}
@Test
+ @TaskbarModeSwitch(mode = PERSISTENT)
public void testHideShowTaskbar() {
getTaskbar().hide();
mLauncher.getLaunchedAppState().showTaskbar();
}
@Test
+ @TaskbarModeSwitch(mode = PERSISTENT)
public void testHideTaskbarPersistsOnRecreate() {
getTaskbar().hide();
mLauncher.recreateTaskbar();
@@ -75,16 +82,19 @@
}
@Test
+ @TaskbarModeSwitch
public void testLaunchApp() throws Exception {
getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
}
@Test
+ @TaskbarModeSwitch
public void testOpenMenu() throws Exception {
getTaskbar().getAppIcon(TEST_APP_NAME).openMenu();
}
@Test
+ @TaskbarModeSwitch
public void testLaunchShortcut() throws Exception {
getTaskbar().getAppIcon(TEST_APP_NAME)
.openDeepShortcutMenu()
@@ -95,6 +105,7 @@
@Test
@ScreenRecord // b/231615831
@PortraitLandscape
+ @TaskbarModeSwitch
public void testLaunchAppInSplitscreen() throws Exception {
getTaskbar().getAppIcon(TEST_APP_NAME).dragToSplitscreen(
TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
@@ -103,6 +114,7 @@
@Test
@ScreenRecord // b/231615831
@PortraitLandscape
+ @TaskbarModeSwitch
public void testLaunchShortcutInSplitscreen() throws Exception {
getTaskbar().getAppIcon(TEST_APP_NAME)
.openDeepShortcutMenu()
@@ -111,16 +123,19 @@
}
@Test
+ @TaskbarModeSwitch
public void testLaunchApp_FromTaskbarAllApps() throws Exception {
getTaskbar().openAllApps().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
}
@Test
+ @TaskbarModeSwitch
public void testOpenMenu_FromTaskbarAllApps() throws Exception {
getTaskbar().openAllApps().getAppIcon(TEST_APP_NAME).openMenu();
}
@Test
+ @TaskbarModeSwitch
public void testLaunchShortcut_FromTaskbarAllApps() throws Exception {
getTaskbar().openAllApps()
.getAppIcon(TEST_APP_NAME)
@@ -132,6 +147,7 @@
@Test
@ScreenRecord // b/231615831
@PortraitLandscape
+ @TaskbarModeSwitch
public void testLaunchAppInSplitscreen_FromTaskbarAllApps() throws Exception {
getTaskbar().openAllApps()
.getAppIcon(TEST_APP_NAME)
@@ -141,6 +157,7 @@
@Test
@ScreenRecord // b/231615831
@PortraitLandscape
+ @TaskbarModeSwitch
public void testLaunchShortcutInSplitscreen_FromTaskbarAllApps() throws Exception {
getTaskbar().openAllApps()
.getAppIcon(TEST_APP_NAME)
diff --git a/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java
new file mode 100644
index 0000000..9e41f74
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 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 androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.quickstep.TaskbarModeSwitchRule.Mode.ALL;
+import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
+import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.tapl.TestHelpers;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.rule.FailureWatcher;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Test rule that allows executing a test multiple times with different conditions
+ * ie. with transient taskbar enabled and disabled.
+ * The test should be annotated with @TaskbarModeSwitch.
+ */
+public class TaskbarModeSwitchRule implements TestRule {
+
+ static final String TAG = "TaskbarModeSwitchRule";
+
+ public static final int WAIT_TIME_MS = 10000;
+
+ public enum Mode {
+ TRANSIENT, PERSISTENT, ALL
+ }
+
+ // Annotation for tests that need to be run with quickstep enabled and disabled.
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ public @interface TaskbarModeSwitch {
+ Mode mode() default ALL;
+ }
+
+ private final LauncherInstrumentation mLauncher;
+
+ public TaskbarModeSwitchRule(LauncherInstrumentation launcher) {
+ mLauncher = launcher;
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ if (TestHelpers.isInLauncherProcess()
+ && description.getAnnotation(TaskbarModeSwitch.class) != null) {
+ Mode mode = description.getAnnotation(TaskbarModeSwitch.class).mode();
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ mLauncher.enableDebugTracing();
+ final boolean wasTransientTaskbarMode =
+ isTaskbarTransientMode(getInstrumentation().getTargetContext());
+ try {
+ if (mode == TRANSIENT || mode == ALL) {
+ evaluateWithTransientTaskbar();
+ }
+ if (mode == PERSISTENT || mode == ALL) {
+ evaluateWithPersistentTaskbar();
+ }
+ } catch (Throwable e) {
+ Log.e(TAG, "Error", e);
+ throw e;
+ } finally {
+ Log.d(TAG, "In Finally block");
+ setTaskbarMode(mLauncher, wasTransientTaskbarMode, description);
+ }
+ }
+
+ private void evaluateWithPersistentTaskbar() throws Throwable {
+ setTaskbarMode(mLauncher, false, description);
+ base.evaluate();
+ }
+
+ private void evaluateWithTransientTaskbar() throws Throwable {
+ setTaskbarMode(mLauncher, true, description);
+ base.evaluate();
+ }
+ };
+ } else {
+ return base;
+ }
+ }
+
+ private static boolean isTaskbarTransientMode(Context context) {
+ return DisplayController.isTransientTaskbar(context);
+ }
+
+ public static void setTaskbarMode(LauncherInstrumentation launcher,
+ boolean expectTransientTaskbar, Description description) throws Exception {
+ launcher.enableTransientTaskbar(expectTransientTaskbar);
+ launcher.recreateTaskbar();
+
+ Context context = getInstrumentation().getTargetContext();
+ assertTrue(launcher, "Couldn't set taskbar=" + expectTransientTaskbar,
+ isTaskbarTransientMode(context) == expectTransientTaskbar, description);
+
+ AbstractLauncherUiTest.checkDetectedLeaks(launcher);
+ }
+
+ private static void assertTrue(LauncherInstrumentation launcher, String message,
+ boolean condition, Description description) {
+ launcher.checkForAnomaly(true, true);
+ if (!condition) {
+ final AssertionError assertionError = new AssertionError(message);
+ if (description != null) {
+ FailureWatcher.onError(launcher, description, assertionError);
+ }
+ throw assertionError;
+ }
+ }
+}
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 033346a..3b92ac4 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -333,7 +333,7 @@
<!-- Snackbar -->
<dimen name="snackbar_height">48dp</dimen>
- <dimen name="snackbar_content_height">32dp</dimen>
+ <dimen name="snackbar_content_height">48dp</dimen>
<dimen name="snackbar_padding">8dp</dimen>
<dimen name="snackbar_min_margin_left_right">6dp</dimen>
<dimen name="snackbar_max_margin_left_right">72dp</dimen>
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 27e1ba1..a8def69 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2350,7 +2350,7 @@
}
mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
- (int) mDragViewVisualCenter[1], minSpanX, minSpanY,
+ (int) mDragViewVisualCenter[1], item.spanX, item.spanY,
mDragTargetLayout, mTargetCell);
int reorderX = mTargetCell[0];
int reorderY = mTargetCell[1];
@@ -2366,7 +2366,8 @@
mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX,
item.spanY, child, mTargetCell);
- manageReorderOnDragOver(d, targetCellDistance, nearestDropOccupied, minSpanX, minSpanY);
+ manageReorderOnDragOver(d, targetCellDistance, nearestDropOccupied, minSpanX, minSpanY,
+ reorderX, reorderY);
if (mDragMode == DRAG_MODE_CREATE_FOLDER || mDragMode == DRAG_MODE_ADD_TO_FOLDER ||
!nearestDropOccupied) {
@@ -2378,26 +2379,23 @@
}
protected void manageReorderOnDragOver(DragObject d, float targetCellDistance,
- boolean nearestDropOccupied, int minSpanX, int minSpanY) {
+ boolean nearestDropOccupied, int minSpanX, int minSpanY, int reorderX, int reorderY) {
ItemInfo item = d.dragInfo;
final View child = (mDragInfo == null) ? null : mDragInfo.cell;
- int reorderX = mTargetCell[0];
- int reorderY = mTargetCell[1];
- if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
- && (mLastReorderX != reorderX || mLastReorderY != reorderY)
- && targetCellDistance < mDragTargetLayout.getReorderRadius(mTargetCell, item.spanX,
- item.spanY)) {
- mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0],
- (int) mDragViewVisualCenter[1], minSpanX, minSpanY, item.spanX, item.spanY,
- child, mTargetCell, new int[2], CellLayout.MODE_SHOW_REORDER_HINT);
- }
-
if (!nearestDropOccupied) {
mDragTargetLayout.visualizeDropLocation(mTargetCell[0], mTargetCell[1],
item.spanX, item.spanY, d);
} else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
- && !mReorderAlarm.alarmPending()) {
+ && !mReorderAlarm.alarmPending()
+ && (mLastReorderX != reorderX || mLastReorderY != reorderY)
+ && targetCellDistance < mDragTargetLayout.getReorderRadius(mTargetCell, item.spanX,
+ item.spanY)) {
+ mLastReorderX = reorderX;
+ mLastReorderY = reorderY;
+ mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0],
+ (int) mDragViewVisualCenter[1], minSpanX, minSpanY, item.spanX, item.spanY,
+ child, mTargetCell, new int[2], CellLayout.MODE_SHOW_REORDER_HINT);
// Otherwise, if we aren't adding to or creating a folder and there's no pending
// reorder, then we schedule a reorder
ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter,
@@ -2602,8 +2600,6 @@
mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
(int) mDragViewVisualCenter[1], minSpanX, minSpanY, mDragTargetLayout,
mTargetCell);
- mLastReorderX = mTargetCell[0];
- mLastReorderY = mTargetCell[1];
mTargetCell = mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0],
(int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index dd47592..063b82e 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -1,5 +1,7 @@
package com.android.launcher3.accessibility;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -172,7 +174,11 @@
mContext.getDragLayer().getDescendantRectRelativeToSelf(host, pos);
ArrowPopup popup = OptionsPopupView.show(mContext, new RectF(pos), actions, false);
popup.requestFocus();
- popup.setOnCloseCallback(host::requestFocus);
+ popup.setOnCloseCallback(() -> {
+ host.requestFocus();
+ host.sendAccessibilityEvent(TYPE_VIEW_FOCUSED);
+ host.performAccessibilityAction(ACTION_ACCESSIBILITY_FOCUS, null);
+ });
return true;
} else if (action == DEEP_SHORTCUTS || action == SHORTCUTS_AND_NOTIFICATIONS) {
BubbleTextView btv = host instanceof BubbleTextView ? (BubbleTextView) host
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 08b42cd..c86f08d 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -102,6 +102,16 @@
}
}
+ /**
+ * Sets results list for search.
+ *
+ * @param searchResultCode indicates if the result is final or intermediate for a given query
+ * since we can get search results from multiple sources.
+ */
+ public void setSearchResults(ArrayList<AdapterItem> results, int searchResultCode) {
+ setSearchResults(results);
+ }
+
private void animateToSearchState(boolean goingToSearch) {
animateToSearchState(goingToSearch, DEFAULT_SEARCH_TRANSITION_DURATION_MS);
}
@@ -311,7 +321,7 @@
layoutParams.topMargin =
includeTabsMargin
? getContext().getResources().getDimensionPixelSize(
- R.dimen.all_apps_header_pill_height)
+ R.dimen.all_apps_header_pill_height)
: 0;
}
diff --git a/src/com/android/launcher3/allapps/SearchTransitionController.java b/src/com/android/launcher3/allapps/SearchTransitionController.java
index 9c3dab4..495f5c3 100644
--- a/src/com/android/launcher3/allapps/SearchTransitionController.java
+++ b/src/com/android/launcher3/allapps/SearchTransitionController.java
@@ -32,6 +32,7 @@
import android.util.FloatProperty;
import android.util.Log;
import android.view.View;
+import android.view.ViewGroup;
import android.view.animation.Interpolator;
import com.android.launcher3.BubbleTextView;
@@ -39,6 +40,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.ItemInfo;
/** Coordinates the transition between Search and A-Z in All Apps. */
@@ -225,16 +227,35 @@
numSearchResultsAnimated++;
}
- searchResultView.setAlpha(contentAlpha);
- // Apply background alpha to decorator if possible.
- if (adapterPosition != NO_POSITION) {
- searchRecyclerView.getApps().getAdapterItems()
- .get(adapterPosition).setDecorationFillAlpha((int) (255 * backgroundAlpha));
- }
- // Apply background alpha to view's background (e.g. for Search Edu card).
+
Drawable background = searchResultView.getBackground();
- if (background != null) {
+ if (background != null
+ && searchResultView instanceof ViewGroup
+ && FeatureFlags.ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES.get()) {
+ searchResultView.setAlpha(1f);
+
+ // Apply content alpha to each child, since the view needs to be fully opaque for
+ // the background to show properly.
+ ViewGroup searchResultViewGroup = (ViewGroup) searchResultView;
+ for (int j = 0; j < searchResultViewGroup.getChildCount(); j++) {
+ searchResultViewGroup.getChildAt(j).setAlpha(contentAlpha);
+ }
+
+ // Apply background alpha to the background drawable directly.
background.setAlpha((int) (255 * backgroundAlpha));
+ } else {
+ searchResultView.setAlpha(contentAlpha);
+
+ // Apply background alpha to decorator if possible.
+ if (adapterPosition != NO_POSITION) {
+ searchRecyclerView.getApps().getAdapterItems().get(adapterPosition)
+ .setDecorationFillAlpha((int) (255 * backgroundAlpha));
+ }
+
+ // Apply background alpha to view's background (e.g. for Search Edu card).
+ if (background != null) {
+ background.setAlpha((int) (255 * backgroundAlpha));
+ }
}
float scaleY = 1;
@@ -304,6 +325,13 @@
getSearchRecyclerView().getApps().getAdapterItems().get(adapterPosition)
.setDecorationFillAlpha(255);
}
+ if (child instanceof ViewGroup
+ && FeatureFlags.ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES.get()) {
+ ViewGroup childGroup = (ViewGroup) child;
+ for (int i = 0; i < childGroup.getChildCount(); i++) {
+ childGroup.getChildAt(i).setAlpha(1f);
+ }
+ }
if (child.getBackground() != null) {
child.getBackground().setAlpha(255);
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 3a58020..9484fff 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -264,6 +264,10 @@
public static final BooleanFlag ENABLE_ONE_SEARCH_MOTION = new DeviceFlag(
"ENABLE_ONE_SEARCH_MOTION", true, "Enables animations in OneSearch.");
+ public static final BooleanFlag ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES = new DeviceFlag(
+ "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", false,
+ "Enable option to replace decorator-based search result backgrounds with drawables");
+
public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = new DeviceFlag(
"ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", true,
"Enable option to show keyboard when going to all-apps");
@@ -323,6 +327,14 @@
public static final BooleanFlag SHOW_DOT_PAGINATION = getDebugFlag(
"SHOW_DOT_PAGINATION", false, "Enable showing dot pagination in workspace");
+ public static final BooleanFlag LARGE_SCREEN_WIDGET_PICKER = getDebugFlag(
+ "LARGE_SCREEN_WIDGET_PICKER", false, "Enable new widget picker that takes "
+ + "advantage of large screen format");
+
+ public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(
+ "ENABLE_NEW_GESTURE_NAV_TUTORIAL", false,
+ "Enable the redesigned gesture navigation tutorial");
+
public static final BooleanFlag ENABLE_TOAST_IMPRESSION_LOGGING = getDebugFlag(
"ENABLE_TOAST_IMPRESSION_LOGGING", false, "Enable toast impression logging");
diff --git a/src/com/android/launcher3/search/SearchCallback.java b/src/com/android/launcher3/search/SearchCallback.java
index 495a303..cf7ab10 100644
--- a/src/com/android/launcher3/search/SearchCallback.java
+++ b/src/com/android/launcher3/search/SearchCallback.java
@@ -24,6 +24,11 @@
*/
public interface SearchCallback<T> {
+ // Search Result Codes
+ int UNKNOWN = 0;
+ int INTERMEDIATE = 1;
+ int FINAL = 2;
+
/**
* Called when the search from primary source is complete.
*
@@ -32,6 +37,17 @@
void onSearchResult(String query, ArrayList<T> items);
/**
+ * Called when the search from primary source is complete.
+ *
+ * @param items list of search results
+ * @param searchResultCode indicates if the result is final or intermediate for a given query
+ * since we can get search results from multiple sources.
+ */
+ default void onSearchResult(String query, ArrayList<T> items, int searchResultCode) {
+ onSearchResult(query, items);
+ }
+
+ /**
* Called when the search results should be cleared.
*/
void clearSearchResult();
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
index 5eac01e..c8455b8 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
@@ -38,12 +38,14 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.util.ShortcutUtil;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
/**
* DragLayer for Secondary launcher
@@ -194,15 +196,21 @@
return false;
}
+ List<SystemShortcut> systemShortcuts = new ArrayList<>();
+
+ // Hide redundant pin shortcut for app drawer icons if drag-n-drop is enabled.
+ if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
+ systemShortcuts.add(mPinnedAppsAdapter.getSystemShortcut(item, v));
+ }
+ systemShortcuts.add(APP_INFO.getShortcut(mActivity, item, v));
+
final PopupContainerWithArrow container =
(PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
R.layout.popup_container, mActivity.getDragLayer(), false);
container.populateAndShow((BubbleTextView) v,
popupDataProvider.getShortcutCountForItem(item),
- Collections.emptyList(),
- Arrays.asList(mPinnedAppsAdapter.getSystemShortcut(item, v),
- APP_INFO.getShortcut(mActivity, item, v)));
+ Collections.emptyList(), systemShortcuts);
container.requestFocus();
if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
diff --git a/src/com/android/launcher3/testing/shared/TestProtocol.java b/src/com/android/launcher3/testing/shared/TestProtocol.java
index 3fbce88..7586d0b 100644
--- a/src/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/src/com/android/launcher3/testing/shared/TestProtocol.java
@@ -84,6 +84,10 @@
public static final String REQUEST_UNFREEZE_APP_LIST = "unfreeze-app-list";
public static final String REQUEST_ENABLE_MANUAL_TASKBAR_STASHING = "enable-taskbar-stashing";
public static final String REQUEST_DISABLE_MANUAL_TASKBAR_STASHING = "disable-taskbar-stashing";
+ public static final String REQUEST_ENABLE_BLOCK_TIMEOUT = "enable-block-timeout";
+ public static final String REQUEST_DISABLE_BLOCK_TIMEOUT = "disable-block-timeout";
+ public static final String REQUEST_ENABLE_TRANSIENT_TASKBAR = "enable-transient-taskbar";
+ public static final String REQUEST_DISABLE_TRANSIENT_TASKBAR = "disable-transient-taskbar";
public static final String REQUEST_UNSTASH_TASKBAR_IF_STASHED = "unstash-taskbar-if-stashed";
public static final String REQUEST_STASHED_TASKBAR_HEIGHT = "stashed-taskbar-height";
public static final String REQUEST_RECREATE_TASKBAR = "recreate-taskbar";
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index f9f7ac0..226f2d9 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -42,6 +42,7 @@
import androidx.annotation.AnyThread;
import androidx.annotation.UiThread;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.window.CachedDisplayInfo;
@@ -63,6 +64,7 @@
private static final String TAG = "DisplayController";
private static final boolean DEBUG = false;
+ private static boolean sTransientTaskbarStatusForTests;
public static final MainThreadInitializedObject<DisplayController> INSTANCE =
new MainThreadInitializedObject<>(DisplayController::new);
@@ -128,8 +130,18 @@
* Returns whether taskbar is transient.
*/
public static boolean isTransientTaskbar(Context context) {
- return ENABLE_TRANSIENT_TASKBAR.get()
- && getNavigationMode(context) == NavigationMode.NO_BUTTON;
+ return getNavigationMode(context) == NavigationMode.NO_BUTTON
+ && (Utilities.IS_RUNNING_IN_TEST_HARNESS
+ ? sTransientTaskbarStatusForTests
+ : ENABLE_TRANSIENT_TASKBAR.get());
+ }
+
+ /**
+ * Enables transient taskbar status for tests.
+ */
+ @VisibleForTesting
+ public static void enableTransientTaskbarForTests(boolean enable) {
+ sTransientTaskbarStatusForTests = enable;
}
@Override
diff --git a/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java b/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
index 93fa705..082e243 100644
--- a/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
+++ b/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
@@ -15,39 +15,273 @@
*/
package com.android.launcher3.secondarydisplay;
-import static androidx.test.core.app.ActivityScenario.launch;
+import static android.content.Context.MODE_PRIVATE;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.view.MotionEvent.ACTION_DOWN;
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.espresso.intent.Intents;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Point;
+import android.os.SystemClock;
+import android.view.MotionEvent;
+import android.widget.TextView;
+
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.MediumTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.util.LauncherModelHelper;
import org.junit.After;
-import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
- * Tests for {@link SecondaryDisplayLauncher}
+ * Tests for {@link SecondaryDisplayLauncher}.
+ * TODO (b/242776943): Remove anti-patterns & migrate prediction row tests to Quickstep directory
*/
-@MediumTest
+@LargeTest
@RunWith(AndroidJUnit4.class)
-public class SecondaryDisplayLauncherTest {
+public final class SecondaryDisplayLauncherTest extends AbstractLauncherUiTest {
+ private static final int WAIT_TIME_MS = 5000;
+ private static final int LONG_PRESS_DURATION_MS = 1000;
+ private static final int DRAG_TIME_MS = 160;
- @Before
- public void setUp() {
- Intents.init();
+ private static final String PINNED_APPS_KEY = "pinned_apps";
+
+ // Variables required to coordinate drag steps.
+ private Point mStartPoint;
+ private Point mEndPoint;
+ private long mDownTime;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ setDragNDropFlag(true);
}
@After
public void tearDown() {
- Intents.release();
+ mTargetContext.getSharedPreferences(PINNED_APPS_KEY, MODE_PRIVATE)
+ .edit().clear().commit();
}
@Test
- public void testAllAppsListOpens() {
- ActivityScenario<SecondaryDisplayLauncher> launcher =
- launch(SecondaryDisplayLauncher.class);
- launcher.onActivity(l -> l.showAppDrawer(true));
+ @Ignore
+ public void initializeSecondaryDisplayLauncher_allAppsButtonVisible() {
+ assertThat(findObjectByResourceName("all_apps_button")).isNotNull();
+ }
+
+ @Test
+ @Ignore
+ public void allAppsButtonTap_opensAppDrawer() {
+ openAppDrawer();
+ assertThat(findObjectByResourceName("search_container_all_apps")).isNotNull();
+ }
+
+ @Test
+ @Ignore("Launcher3 without quickstep doesn't have a predictions row.")
+ public void appDrawerOpened_predictionRowAppDividerVisible() {
+ openAppDrawer();
+ assertThat(findObjectByResourceName("apps_divider_view")).isNotNull();
+ }
+
+ @Test
+ @Ignore
+ public void dragNDropDisabled_pinIconAddsToWorkspace() {
+ setDragNDropFlag(false);
+ openAppDrawer();
+ UiObject2 app = findDescendantByResourceName(
+ findObjectByResourceName("apps_list_view"), "icon");
+ app.click(LONG_PRESS_DURATION_MS);
+ UiObject2 popupContainer = findObjectByResourceName("popup_container");
+ assertThat(popupContainer).isNotNull();
+ UiObject2 pinIcon = findDescendantByTextOrDesc(popupContainer, "Add to home screen");
+ assertThat(pinIcon).isNotNull();
+ pinIcon.click();
+ String appName = app.getContentDescription();
+ assertThat(findAppInWorkspace(appName)).isNotNull();
+ }
+
+ @Test
+ @Ignore
+ public void pressBackFromAllApps_popupMenuOpen_returnsToWorkspace() {
+ openAppDrawer();
+ assertThat(findObjectByResourceName("search_container_all_apps")).isNotNull();
+
+ findDescendantByResourceName(findObjectByResourceName("apps_list_view"), "icon")
+ .click(LONG_PRESS_DURATION_MS);
+ assertThat(findObjectByResourceName("popup_container")).isNotNull();
+
+ // First back press should close only popup menu.
+ mDevice.pressBack();
+ assertThat(findObjectByResourceName("search_container_all_apps")).isNotNull();
+ assertThat(findObjectByResourceName("popup_container")).isNull();
+
+ // Second back press should close app drawer.
+ mDevice.pressBack();
+ assertThat(findObjectByResourceName("popup_container")).isNull();
+ assertThat(findObjectByResourceName("search_container_all_apps")).isNull();
+ }
+
+ @Test
+ @Ignore("Launcher3 without quickstep doesn't have a predictions row.")
+ public void dragNDropFromPredictionsRow_pinToGrid() {
+ openAppDrawer();
+ assertThat(findObjectByResourceName("prediction_row")).isNotNull();
+ String appName = startDragFromPredictionRow();
+ moveAppToCenterOfScreen();
+ dropApp();
+
+ // Ensure app was added.
+ assertThat(findAppInWorkspace(appName)).isNotNull();
+ }
+
+ @Test
+ @Ignore
+ public void dragNDropFromAppDrawer_pinToGrid() {
+ openAppDrawer();
+ String draggedAppName = startDragFromAllApps();
+ moveAppToCenterOfScreen();
+ dropApp();
+
+ // Ensure app was added.
+ assertThat(findAppInWorkspace(draggedAppName)).isNotNull();
+ }
+
+ @Test
+ @Ignore
+ public void tapRemoveButton_unpinApp() {
+ openAppDrawer();
+ String draggedAppName = startDragFromAllApps();
+ moveAppToCenterOfScreen();
+ dropApp();
+ removeAppByName(draggedAppName);
+ assertThat(findAppInWorkspace(draggedAppName)).isNull();
+ }
+
+ private void openAppDrawer() {
+ UiObject2 allAppsButton = findObjectByResourceName("all_apps_button");
+ assertThat(allAppsButton).isNotNull();
+ allAppsButton.click();
+ }
+
+ private String startDragFromAllApps() {
+ // Find app from app drawer.
+ UiObject2 allApps = findObjectByResourceName("apps_list_view");
+ assertThat(allApps).isNotNull();
+ UiObject2 icon = findDescendantByResourceName(allApps, "icon");
+ assertThat(icon).isNotNull();
+ String appName = icon.getContentDescription();
+
+ // Start drag action.
+ mDownTime = SystemClock.uptimeMillis();
+ mStartPoint = icon.getVisibleCenter();
+ mEndPoint = new Point(mStartPoint.x, mStartPoint.y);
+ mLauncher.sendPointer(mDownTime, mDownTime, ACTION_DOWN, mStartPoint,
+ LauncherInstrumentation.GestureScope.INSIDE);
+ assertThat(findObjectByResourceName("popup_container")).isNotNull();
+ return appName;
+ }
+
+ private String startDragFromPredictionRow() {
+ // Find app from predictions.
+ UiObject2 predictionRow = findObjectByResourceName("prediction_row");
+ assertThat(predictionRow).isNotNull();
+
+ UiObject2 icon = findDescendantByResourceName(predictionRow, "icon");
+ assertThat(icon).isNotNull();
+
+ String appName = icon.getContentDescription();
+ UiObject2 app = findDescendantByAppName(predictionRow, appName);
+ assertThat(app).isNotNull();
+
+ // Start drag action.
+ mDownTime = SystemClock.uptimeMillis();
+ mStartPoint = icon.getVisibleCenter();
+ mEndPoint = new Point(mStartPoint.x, mStartPoint.y);
+ mLauncher.sendPointer(mDownTime, mDownTime, ACTION_DOWN, mStartPoint,
+ LauncherInstrumentation.GestureScope.INSIDE);
+ assertThat(findObjectByResourceName("popup_container")).isNotNull();
+ return appName;
+ }
+
+ private void moveAppToCenterOfScreen() {
+ mEndPoint.set(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight() / 2);
+ mLauncher.movePointer(mDownTime, SystemClock.uptimeMillis(), DRAG_TIME_MS, true,
+ mStartPoint, mEndPoint, LauncherInstrumentation.GestureScope.INSIDE);
+ }
+
+ private void dropApp() {
+ mLauncher.sendPointer(mDownTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP,
+ mEndPoint, LauncherInstrumentation.GestureScope.INSIDE);
+ }
+
+ private void removeAppByName(String appName) {
+ // Find app within home screen.
+ UiObject2 app = findDescendantByAppName(findObjectByResourceName("workspace_grid"),
+ appName);
+ if (app == null) return;
+
+ // Open app's popup container.
+ app.click(LONG_PRESS_DURATION_MS);
+ UiObject2 popupContainer = findObjectByResourceName("popup_container");
+ assertThat(popupContainer).isNotNull();
+
+ // Grab & click remove button.
+ UiObject2 removeButton = findDescendantByTextOrDesc(popupContainer, "Remove");
+ assertThat(removeButton).isNotNull();
+ removeButton.click();
+ }
+
+ private UiObject2 findAppInWorkspace(String appName) {
+ UiObject2 workspace = findObjectByResourceName("workspace_grid");
+ return findDescendantByAppName(workspace, appName);
+ }
+
+ private UiObject2 findObjectByResourceName(String resourceName) {
+ return mDevice.wait(Until.findObject(By.res(mTargetPackage, resourceName)), WAIT_TIME_MS);
+ }
+
+ private UiObject2 findDescendantByResourceName(UiObject2 outerObject,
+ String resourceName) {
+ assertThat(outerObject).isNotNull();
+ return outerObject.findObject(By.res(mTargetPackage, resourceName));
+ }
+
+ private UiObject2 findDescendantByAppName(UiObject2 outerObject, String appName) {
+ assertThat(outerObject).isNotNull();
+ return outerObject.findObject(By.clazz(TextView.class).text(appName)
+ .pkg(mDevice.getLauncherPackageName()));
+ }
+
+ private UiObject2 findDescendantByTextOrDesc(UiObject2 outerObject, String content) {
+ assertThat(outerObject).isNotNull();
+ UiObject2 innerObject = outerObject.findObject(By.desc(content));
+ if (innerObject == null) innerObject = outerObject.findObject(By.text(content));
+ return innerObject;
+ }
+
+ private void startSecondaryDisplayActivity() {
+ mTargetContext.startActivity((
+ new Intent(mTargetContext, SecondaryDisplayLauncher.class).addFlags(
+ FLAG_ACTIVITY_NEW_TASK)));
+ }
+
+ private void setDragNDropFlag(Boolean status) {
+ Context context = new LauncherModelHelper().sandboxContext;
+ context.getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE).edit()
+ .putBoolean(FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.key, status)
+ .commit();
+ FeatureFlags.initialize(context);
+ startSecondaryDisplayActivity();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index f23a38c..4a3507e 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -17,7 +17,9 @@
package com.android.launcher3.tapl;
import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
+import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING;
+import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_BLOCK_TIMEOUT;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT;
@@ -88,6 +90,7 @@
*/
public Taskbar showTaskbar() {
mLauncher.getTestInfo(REQUEST_ENABLE_MANUAL_TASKBAR_STASHING);
+ mLauncher.getTestInfo(REQUEST_ENABLE_BLOCK_TIMEOUT);
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
@@ -114,6 +117,7 @@
}
} finally {
mLauncher.getTestInfo(REQUEST_DISABLE_MANUAL_TASKBAR_STASHING);
+ mLauncher.getTestInfo(REQUEST_DISABLE_BLOCK_TIMEOUT);
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 1212c3d..c3ea14a 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1850,6 +1850,20 @@
getTestInfo(TestProtocol.REQUEST_UNSTASH_TASKBAR_IF_STASHED);
}
+ /** Blocks the taskbar from automatically stashing based on time. */
+ public void enableBlockTimeout(boolean enable) {
+ getTestInfo(enable
+ ? TestProtocol.REQUEST_ENABLE_BLOCK_TIMEOUT
+ : TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT);
+ }
+
+ /** Enables transient taskbar for testing purposes only. */
+ public void enableTransientTaskbar(boolean enable) {
+ getTestInfo(enable
+ ? TestProtocol.REQUEST_ENABLE_TRANSIENT_TASKBAR
+ : TestProtocol.REQUEST_DISABLE_TRANSIENT_TASKBAR);
+ }
+
/**
* Recreates the taskbar (outside of tests this is done for certain configuration changes).
* The expected behavior is that the taskbar retains its current state after being recreated.