Merge "Ensure starting split animation scale is always 1"
diff --git a/quickstep/res/layout/taskbar_all_apps.xml b/quickstep/res/layout/taskbar_all_apps.xml
index 1ad20cc..11d75c7 100644
--- a/quickstep/res/layout/taskbar_all_apps.xml
+++ b/quickstep/res/layout/taskbar_all_apps.xml
@@ -46,6 +46,8 @@
android:paddingTop="@dimen/all_apps_header_top_padding"
android:orientation="vertical">
+ <include layout="@layout/floating_header_content" />
+
<include layout="@layout/all_apps_personal_work_tabs" />
</com.android.launcher3.allapps.FloatingHeaderView>
diff --git a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
index 4f987d2..d37e530 100644
--- a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -16,7 +16,7 @@
package com.android.launcher3.appprediction;
-import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;
import android.annotation.TargetApi;
import android.content.Context;
@@ -34,23 +34,17 @@
import androidx.core.content.ContextCompat;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.allapps.FloatingHeaderRow;
import com.android.launcher3.allapps.FloatingHeaderView;
-import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.ActivityContext;
/**
* A view which shows a horizontal divider
*/
@TargetApi(Build.VERSION_CODES.O)
-public class AppsDividerView extends View implements StateListener<LauncherState>,
- FloatingHeaderRow {
-
- private static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count";
- private static final int SHOW_ALL_APPS_LABEL_ON_ALL_APPS_VISITED_COUNT = 20;
+public class AppsDividerView extends View implements FloatingHeaderRow {
public enum DividerType {
NONE,
@@ -58,7 +52,6 @@
ALL_APPS_LABEL
}
- private final Launcher mLauncher;
private final TextPaint mPaint = new TextPaint();
private DividerType mDividerType = DividerType.NONE;
@@ -86,7 +79,6 @@
public AppsDividerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mLauncher = Launcher.getLauncher(context);
boolean isMainColorDark = Themes.getAttrBoolean(context, R.attr.isMainColorDark);
mDividerSize = new int[]{
@@ -101,6 +93,9 @@
mAllAppsLabelTextColor = ContextCompat.getColor(context, isMainColorDark
? R.color.all_apps_label_text_dark
: R.color.all_apps_label_text);
+
+ mShowAllAppsLabel = !ActivityContext.lookupContext(
+ getContext()).getOnboardingPrefs().hasReachedMaxCount(ALL_APPS_VISITED_COUNT);
}
public void setup(FloatingHeaderView parent, FloatingHeaderRow[] rows, boolean tabsHidden) {
@@ -110,6 +105,14 @@
updateDividerType();
}
+ /** {@code true} if all apps label should be shown in place of divider. */
+ public void setShowAllAppsLabel(boolean showAllAppsLabel) {
+ if (showAllAppsLabel != mShowAllAppsLabel) {
+ mShowAllAppsLabel = showAllAppsLabel;
+ updateDividerType();
+ }
+ }
+
@Override
public int getExpectedHeight() {
return getPaddingTop() + getPaddingBottom();
@@ -236,51 +239,6 @@
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- if (shouldShowAllAppsLabel()) {
- mShowAllAppsLabel = true;
- mLauncher.getStateManager().addStateListener(this);
- updateDividerType();
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mLauncher.getStateManager().removeStateListener(this);
- }
-
- @Override
- public void onStateTransitionComplete(LauncherState finalState) {
- if (finalState == ALL_APPS) {
- setAllAppsVisitedCount(getAllAppsVisitedCount() + 1);
- } else {
- if (mShowAllAppsLabel != shouldShowAllAppsLabel()) {
- mShowAllAppsLabel = !mShowAllAppsLabel;
- updateDividerType();
- }
-
- if (!mShowAllAppsLabel) {
- mLauncher.getStateManager().removeStateListener(this);
- }
- }
- }
-
- private void setAllAppsVisitedCount(int count) {
- mLauncher.getSharedPrefs().edit().putInt(ALL_APPS_VISITED_COUNT, count).apply();
- }
-
- private int getAllAppsVisitedCount() {
- return mLauncher.getSharedPrefs().getInt(ALL_APPS_VISITED_COUNT, 0);
- }
-
- private boolean shouldShowAllAppsLabel() {
- return getAllAppsVisitedCount() < SHOW_ALL_APPS_LABEL_ON_ALL_APPS_VISITED_COUNT;
- }
-
- @Override
public void setInsets(Rect insets, DeviceProfile grid) {
int leftRightPadding = grid.allAppsLeftRightPadding;
setPadding(leftRightPadding, getPaddingTop(), leftRightPadding, getPaddingBottom());
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index 9ad8bb2..1dec737 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -31,8 +31,8 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.allapps.FloatingHeaderRow;
import com.android.launcher3.allapps.FloatingHeaderView;
@@ -43,18 +43,18 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener;
+import com.android.launcher3.views.ActivityContext;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@TargetApi(Build.VERSION_CODES.P)
-public class PredictionRowView extends LinearLayout implements
- OnDeviceProfileChangeListener, FloatingHeaderRow {
+public class PredictionRowView<T extends Context & ActivityContext & DeviceProfileListenable>
+ extends LinearLayout implements OnDeviceProfileChangeListener, FloatingHeaderRow {
- private final Launcher mLauncher;
+ private final T mActivityContext;
private int mNumPredictedAppsPerRow;
// Helper to drawing the focus indicator.
@@ -64,12 +64,10 @@
private final List<WorkspaceItemInfo> mPredictedApps = new ArrayList<>();
private FloatingHeaderView mParent;
- private boolean mScrolledOut;
private boolean mPredictionsEnabled = false;
-
- @Nullable
- private List<ItemInfo> mPendingPredictedItems;
+ private @Nullable List<ItemInfo> mPendingPredictedItems;
+ private OnLongClickListener mOnIconLongClickListener = ItemLongClickListener.INSTANCE_ALL_APPS;
public PredictionRowView(@NonNull Context context) {
this(context, null);
@@ -80,9 +78,9 @@
setOrientation(LinearLayout.HORIZONTAL);
mFocusHelper = new SimpleFocusIndicatorHelper(this);
- mLauncher = Launcher.getLauncher(context);
- mLauncher.addOnDeviceProfileChangeListener(this);
- mNumPredictedAppsPerRow = mLauncher.getDeviceProfile().numShownAllAppsColumns;
+ mActivityContext = ActivityContext.lookupContext(context);
+ mActivityContext.addOnDeviceProfileChangeListener(this);
+ mNumPredictedAppsPerRow = mActivityContext.getDeviceProfile().numShownAllAppsColumns;
updateVisibility();
}
@@ -97,11 +95,11 @@
private void updateVisibility() {
setVisibility(mPredictionsEnabled ? VISIBLE : GONE);
- if (mLauncher.getAppsView() != null) {
+ if (mActivityContext.getAppsView() != null) {
if (mPredictionsEnabled) {
- mLauncher.getAppsView().getAppsStore().registerIconContainer(this);
+ mActivityContext.getAppsView().getAppsStore().registerIconContainer(this);
} else {
- mLauncher.getAppsView().getAppsStore().unregisterIconContainer(this);
+ mActivityContext.getAppsView().getAppsStore().unregisterIconContainer(this);
}
}
}
@@ -120,9 +118,9 @@
@Override
public int getExpectedHeight() {
- return getVisibility() == GONE ? 0 :
- Launcher.getLauncher(getContext()).getDeviceProfile().allAppsCellHeightPx
- + getPaddingTop() + getPaddingBottom();
+ return getVisibility() == GONE ? 0
+ : mActivityContext.getDeviceProfile().allAppsCellHeightPx + getPaddingTop()
+ + getPaddingBottom();
}
@Override
@@ -158,13 +156,12 @@
*/
public void setPredictedApps(List<ItemInfo> items) {
if (!FeatureFlags.ENABLE_APP_PREDICTIONS_WHILE_VISIBLE.get()
- && !mLauncher.isWorkspaceLoading()
+ && !mActivityContext.isBindingItems()
&& isShown()
&& getWindowVisibility() == View.VISIBLE) {
mPendingPredictedItems = items;
return;
}
-
applyPredictedApps(items);
}
@@ -177,6 +174,15 @@
applyPredictionApps();
}
+ /**
+ * Sets the long click listener for predictions for any future predictions.
+ *
+ * Existing predictions in the container are not updated with this new callback.
+ */
+ public void setOnIconLongClickListener(OnLongClickListener onIconLongClickListener) {
+ mOnIconLongClickListener = onIconLongClickListener;
+ }
+
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
mNumPredictedAppsPerRow = dp.numShownAllAppsColumns;
@@ -189,18 +195,18 @@
while (getChildCount() > mNumPredictedAppsPerRow) {
removeViewAt(0);
}
- LayoutInflater inflater = mLauncher.getAppsView().getLayoutInflater();
+ LayoutInflater inflater = mActivityContext.getAppsView().getLayoutInflater();
while (getChildCount() < mNumPredictedAppsPerRow) {
BubbleTextView icon = (BubbleTextView) inflater.inflate(
R.layout.all_apps_icon, this, false);
- icon.setOnClickListener(ItemClickHandler.INSTANCE);
- icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS);
+ icon.setOnClickListener(mActivityContext.getItemOnClickListener());
+ icon.setOnLongClickListener(mOnIconLongClickListener);
icon.setLongPressTimeoutFactor(1f);
icon.setOnFocusChangeListener(mFocusHelper);
LayoutParams lp = (LayoutParams) icon.getLayoutParams();
// Ensure the all apps icon height matches the workspace icons in portrait mode.
- lp.height = mLauncher.getDeviceProfile().allAppsCellHeightPx;
+ lp.height = mActivityContext.getDeviceProfile().allAppsCellHeightPx;
lp.width = 0;
lp.weight = 1;
addView(icon);
@@ -223,7 +229,6 @@
boolean predictionsEnabled = predictionCount > 0;
if (predictionsEnabled != mPredictionsEnabled) {
mPredictionsEnabled = predictionsEnabled;
- mLauncher.reapplyUi(false /* cancelCurrentAnimation */);
updateVisibility();
}
mParent.onHeightUpdated();
@@ -237,11 +242,10 @@
@Override
public void setVerticalScroll(int scroll, boolean isScrolledOut) {
- mScrolledOut = isScrolledOut;
if (!isScrolledOut) {
setTranslationY(scroll);
}
- setAlpha(mScrolledOut ? 0 : 1);
+ setAlpha(isScrolledOut ? 0 : 1);
if (getVisibility() != GONE) {
AlphaUpdateListener.updateVisibility(this);
}
@@ -263,6 +267,7 @@
return getChildAt(0);
}
+
@Override
public void onVisibilityAggregated(boolean isVisible) {
super.onVisibilityAggregated(isVisible);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 78e39bb..fe091ef 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -58,8 +58,11 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
@@ -70,6 +73,7 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.touch.ItemClickHandler;
+import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.Themes;
@@ -85,13 +89,16 @@
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
/**
* The {@link ActivityContext} with which we inflate Taskbar-related Views. This allows UI elements
* that are used by both Launcher and Taskbar (such as Folder) to reference a generic
* ActivityContext and BaseDragLayer instead of the Launcher activity and its DragLayer.
*/
-public class TaskbarActivityContext extends ContextThemeWrapper implements ActivityContext {
+public class TaskbarActivityContext extends ContextThemeWrapper implements ActivityContext,
+ DeviceProfileListenable {
private static final boolean ENABLE_THREE_BUTTON_TASKBAR =
SystemProperties.getBoolean("persist.debug.taskbar_three_button", false);
@@ -103,6 +110,7 @@
private final TaskbarDragLayer mDragLayer;
private final TaskbarAllAppsContainerView mAppsView;
private final TaskbarControllers mControllers;
+ private final List<OnDeviceProfileChangeListener> mDPChangeListeners = new ArrayList<>();
private DeviceProfile mDeviceProfile;
@@ -124,14 +132,17 @@
private boolean mIsDestroyed = false;
// The flag to know if the window is excluded from magnification region computation.
private boolean mIsExcludeFromMagnificationRegion = false;
+ private boolean mBindingItems = false;
private final TaskbarShortcutMenuAccessibilityDelegate mAccessibilityDelegate;
+ private final OnboardingPrefs<TaskbarActivityContext> mOnboardingPrefs;
public TaskbarActivityContext(Context windowContext, DeviceProfile dp,
TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
unfoldTransitionProgressProvider) {
super(windowContext, Themes.getActivityThemeRes(windowContext));
mDeviceProfile = dp;
+ mOnboardingPrefs = new OnboardingPrefs<>(this, Utilities.getPrefs(this));
mNavMode = SysUINavigationMode.getMode(windowContext);
mImeDrawsImeNavBar = SysUINavigationMode.getImeDrawsImeNavBar(windowContext);
@@ -229,6 +240,7 @@
public void updateDeviceProfile(DeviceProfile dp) {
mDeviceProfile = dp;
updateIconSize(getResources());
+ dispatchDeviceProfileChanged();
}
private void updateIconSize(Resources resources) {
@@ -305,6 +317,11 @@
}
@Override
+ public List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners() {
+ return mDPChangeListeners;
+ }
+
+ @Override
public Rect getFolderBoundingBox() {
return mControllers.taskbarDragLayerController.getFolderBoundingBox();
}
@@ -394,6 +411,20 @@
return mAccessibilityDelegate;
}
+ @Override
+ public OnboardingPrefs<TaskbarActivityContext> getOnboardingPrefs() {
+ return mOnboardingPrefs;
+ }
+
+ @Override
+ public boolean isBindingItems() {
+ return mBindingItems;
+ }
+
+ public void setBindingItems(boolean bindingItems) {
+ mBindingItems = bindingItems;
+ }
+
/**
* Sets a new data-source for this taskbar instance
*/
@@ -738,6 +769,8 @@
"%s\tmIsUserSetupComplete=%b", prefix, mIsUserSetupComplete));
pw.println(String.format(
"%s\tmWindowLayoutParams.height=%dpx", prefix, mWindowLayoutParams.height));
+ pw.println(String.format(
+ "%s\tmBindInProgress=%b", prefix, mBindingItems));
mControllers.dumpLogs(prefix + "\t", pw);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java
index 62125fe..2670200 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java
@@ -15,8 +15,15 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;
+
+import com.android.launcher3.appprediction.AppsDividerView;
+import com.android.launcher3.appprediction.PredictionRowView;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.ItemInfo;
+
+import java.util.List;
/** Handles the {@link TaskbarAllAppsContainerView} initialization and updates. */
public final class TaskbarAllAppsViewController {
@@ -40,6 +47,9 @@
mAppsView.setOnIconLongClickListener(
controllers.taskbarDragController::startDragOnLongClick);
+ mAppsView.getFloatingHeaderView().findFixedRowByType(
+ PredictionRowView.class).setOnIconLongClickListener(
+ controllers.taskbarDragController::startDragOnLongClick);
}
/** Binds the current {@link AppInfo} instances to the {@link TaskbarAllAppsContainerView}. */
@@ -49,11 +59,26 @@
}
}
+ /** Binds the current app predictions to all apps {@link PredictionRowView}. */
+ public void setPredictedApps(List<ItemInfo> predictedApps) {
+ if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
+ PredictionRowView<?> predictionRowView =
+ mAppsView.getFloatingHeaderView().findFixedRowByType(PredictionRowView.class);
+ predictionRowView.setPredictedApps(predictedApps);
+ }
+ }
+
/** Opens the {@link TaskbarAllAppsContainerView}. */
public void show() {
- if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
- mContext.setTaskbarWindowFullscreen(true);
- mSlideInView.show();
+ if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
+ return;
}
+
+ mAppsView.getFloatingHeaderView().findFixedRowByType(AppsDividerView.class)
+ .setShowAllAppsLabel(
+ !mContext.getOnboardingPrefs().hasReachedMaxCount(ALL_APPS_VISITED_COUNT));
+ mContext.getOnboardingPrefs().incrementEventCount(ALL_APPS_VISITED_COUNT);
+ mContext.setTaskbarWindowFullscreen(true);
+ mSlideInView.show();
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 2bafccd..2e18a40 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -52,8 +52,6 @@
// Initialized in init.
private TaskbarControllers mControllers;
- private boolean mBindInProgress = false;
-
public TaskbarModelCallbacks(
TaskbarActivityContext context, TaskbarView container) {
mContext = context;
@@ -66,14 +64,14 @@
@Override
public void startBinding() {
- mBindInProgress = true;
+ mContext.setBindingItems(true);
mHotseatItems.clear();
mPredictedItems = Collections.emptyList();
}
@Override
public void finishBindingItems(IntSet pagesBoundFirst) {
- mBindInProgress = false;
+ mContext.setBindingItems(false);
commitItemsToUI();
}
@@ -159,11 +157,13 @@
if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION) {
mPredictedItems = item.items;
commitItemsToUI();
+ } else if (item.containerId == Favorites.CONTAINER_PREDICTION) {
+ mControllers.taskbarAllAppsViewController.setPredictedApps(item.items);
}
}
private void commitItemsToUI() {
- if (mBindInProgress) {
+ if (mContext.isBindingItems()) {
return;
}
@@ -212,6 +212,5 @@
pw.println(
String.format("%s\tpredicted items count=%s", prefix, mPredictedItems.size()));
}
- pw.println(String.format("%s\tmBindInProgress=%b", prefix, mBindInProgress));
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 9050ddc..1073d76 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -69,7 +69,6 @@
import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.PendingRequestArgs;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.UiThreadHelper;
@@ -162,7 +161,7 @@
}
@Override
- protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) {
+ protected QuickstepOnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) {
return new QuickstepOnboardingPrefs(this, sharedPrefs);
}
@@ -235,8 +234,10 @@
public void bindExtraContainerItems(FixedContainerItems item) {
if (item.containerId == Favorites.CONTAINER_PREDICTION) {
mAllAppsPredictions = item;
- getAppsView().getFloatingHeaderView().findFixedRowByType(PredictionRowView.class)
- .setPredictedApps(item.items);
+ PredictionRowView<?> predictionRowView =
+ getAppsView().getFloatingHeaderView().findFixedRowByType(
+ PredictionRowView.class);
+ predictionRowView.setPredictedApps(item.items);
} else if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION) {
mHotseatPredictionController.setPredictedItems(item);
} else if (item.containerId == Favorites.CONTAINER_WIDGETS_PREDICTION) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 59ade49..099915a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -221,13 +221,9 @@
* @return true if the event is over the hotseat
*/
static boolean isTouchOverHotseat(Launcher launcher, MotionEvent ev) {
- return (ev.getY() >= getHotseatTop(launcher));
- }
-
- public static int getHotseatTop(Launcher launcher) {
DeviceProfile dp = launcher.getDeviceProfile();
int hotseatHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
- return launcher.getDragLayer().getHeight() - hotseatHeight;
+ return (ev.getY() >= (launcher.getDragLayer().getHeight() - hotseatHeight));
}
@Override
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 4c570f1..ef81449 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -7,11 +7,9 @@
import androidx.annotation.Nullable;
-import com.android.launcher3.LauncherState;
import com.android.launcher3.testing.TestInformationHandler;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler;
-import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
import com.android.quickstep.util.LayoutUtils;
public class QuickstepTestInformationHandler extends TestInformationHandler {
@@ -26,15 +24,6 @@
public Bundle call(String method, String arg, @Nullable Bundle extras) {
final Bundle response = new Bundle();
switch (method) {
- case TestProtocol.REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT: {
- return getLauncherUIProperty(Bundle::putInt, l -> {
- final float progress = LauncherState.OVERVIEW.getVerticalProgress(l)
- - LauncherState.ALL_APPS.getVerticalProgress(l);
- final float distance = l.getAllAppsController().getShiftRange() * progress;
- return (int) distance;
- });
- }
-
case TestProtocol.REQUEST_HOME_TO_OVERVIEW_SWIPE_HEIGHT: {
final float swipeHeight =
LayoutUtils.getDefaultSwipeHeight(mContext, mDeviceProfile);
@@ -50,11 +39,6 @@
return response;
}
- case TestProtocol.REQUEST_HOTSEAT_TOP: {
- return getLauncherUIProperty(
- Bundle::putInt, PortraitStatesTouchController::getHotseatTop);
- }
-
case TestProtocol.REQUEST_GET_FOCUSED_TASK_HEIGHT_FOR_TABLET: {
if (!mDeviceProfile.isTablet) {
return null;
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 4aa69d1..d28796c 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -609,14 +609,13 @@
}
public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent,
- Intent fillInIntent, int taskId, boolean intentFirst, Bundle mainOptions,
- Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition,
- float splitRatio, RemoteAnimationAdapter adapter) {
+ Intent fillInIntent, int taskId, Bundle mainOptions, Bundle sideOptions,
+ @SplitConfigurationOptions.StagePosition int sidePosition, float splitRatio,
+ RemoteAnimationAdapter adapter) {
if (mSystemUiProxy != null) {
try {
mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, fillInIntent,
- taskId, intentFirst, mainOptions, sideOptions, sidePosition, splitRatio,
- adapter);
+ taskId, mainOptions, sideOptions, sidePosition, splitRatio, adapter);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startTasksWithLegacyTransition");
}
diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
index 6b6bd6a..333df10 100644
--- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
+++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
@@ -15,9 +15,14 @@
*/
package com.android.quickstep.util;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_UNFOLD_ANIMATION;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY_FACTORY;
import static com.android.launcher3.Utilities.comp;
import android.annotation.Nullable;
+import android.util.FloatProperty;
+import android.util.MathUtils;
+import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
@@ -39,6 +44,8 @@
// Percentage of the width of the quick search bar that will be reduced
// from the both sides of the bar when progress is 0
private static final float MAX_WIDTH_INSET_FRACTION = 0.15f;
+ private static final FloatProperty<View> UNFOLD_SCALE_PROPERTY =
+ SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_UNFOLD_ANIMATION);
private final Launcher mLauncher;
@@ -62,6 +69,8 @@
// Animated in all orientations
mProgressProvider.addCallback(new UnfoldMoveFromCenterWorkspaceAnimator(launcher,
windowManager));
+ mProgressProvider
+ .addCallback(new LauncherScaleAnimationListener());
// Animated only in natural orientation
mNaturalOrientationProgressProvider
@@ -120,4 +129,26 @@
}
}
}
+
+ private class LauncherScaleAnimationListener implements TransitionProgressListener {
+
+ @Override
+ public void onTransitionStarted() {
+ }
+
+ @Override
+ public void onTransitionFinished() {
+ setScale(1);
+ }
+
+ @Override
+ public void onTransitionProgress(float progress) {
+ setScale(MathUtils.constrainedMap(0.85f, 1, 0, 1, progress));
+ }
+
+ private void setScale(float value) {
+ UNFOLD_SCALE_PROPERTY.setValue(mLauncher.getWorkspace(), value);
+ UNFOLD_SCALE_PROPERTY.setValue(mLauncher.getHotseat(), value);
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index 6d6e802..54642a2 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -28,6 +28,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
+import com.android.launcher3.appprediction.AppsDividerView;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
import com.android.launcher3.statemanager.StateManager;
@@ -132,5 +133,24 @@
}
});
}
+
+ if (!hasReachedMaxCount(ALL_APPS_VISITED_COUNT)) {
+ mLauncher.getStateManager().addStateListener(new StateListener<LauncherState>() {
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ if (finalState == ALL_APPS) {
+ incrementEventCount(ALL_APPS_VISITED_COUNT);
+ return;
+ }
+
+ boolean hasReachedMaxCount = hasReachedMaxCount(ALL_APPS_VISITED_COUNT);
+ mLauncher.getAppsView().getFloatingHeaderView().findFixedRowByType(
+ AppsDividerView.class).setShowAllAppsLabel(!hasReachedMaxCount);
+ if (hasReachedMaxCount) {
+ mLauncher.getStateManager().removeStateListener(this);
+ }
+ }
+ });
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index e856d8a..fff55a1 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -156,9 +156,8 @@
splitRatio, adapter);
} else {
mSystemUiProxy.startIntentAndTaskWithLegacyTransition(taskPendingIntent,
- new Intent(), taskId2, stagePosition == STAGE_POSITION_TOP_OR_LEFT,
- mainOpts.toBundle(), null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
- splitRatio, adapter);
+ new Intent(), taskId2, mainOpts.toBundle(), null /* sideOptions */,
+ stagePosition, splitRatio, adapter);
}
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index a534450..ee35adc 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -278,7 +278,7 @@
private RotatedPosition getRotatedPosition(float progress) {
final float degree, positionX, positionY;
- if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+ if (TaskAnimationManager.SHELL_TRANSITIONS_ROTATION) {
if (mFromRotation == Surface.ROTATION_90) {
degree = -90 * (1 - progress);
positionX = progress * (mDestinationBoundsTransformed.left - mStartBounds.left)
diff --git a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
index 7ae6cb7..8659b68 100644
--- a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
+++ b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
@@ -15,7 +15,8 @@
*/
package com.android.quickstep.util;
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_REVEAL_ANIM;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY_FACTORY;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
@@ -27,6 +28,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.util.FloatProperty;
import android.view.View;
import com.android.launcher3.BaseQuickstepLauncher;
@@ -49,6 +51,8 @@
// Should be used for animations running alongside this WorkspaceRevealAnim.
public static final int DURATION_MS = 350;
+ private static final FloatProperty<View> REVEAL_SCALE_PROPERTY =
+ SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_REVEAL_ANIM);
private final float mScaleStart;
private final AnimatorSet mAnimators = new AnimatorSet();
@@ -90,7 +94,7 @@
}
private void addRevealAnimatorsForView(View v) {
- ObjectAnimator scale = ObjectAnimator.ofFloat(v, SCALE_PROPERTY, mScaleStart, 1f);
+ ObjectAnimator scale = ObjectAnimator.ofFloat(v, REVEAL_SCALE_PROPERTY, mScaleStart, 1f);
scale.setDuration(DURATION_MS);
scale.setInterpolator(Interpolators.DECELERATED_EASE);
mAnimators.play(scale);
@@ -103,7 +107,7 @@
mAnimators.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- SCALE_PROPERTY.set(v, 1f);
+ REVEAL_SCALE_PROPERTY.set(v, 1f);
v.setAlpha(1f);
}
});
diff --git a/quickstep/src/com/android/quickstep/util/WorkspaceUnlockAnim.java b/quickstep/src/com/android/quickstep/util/WorkspaceUnlockAnim.java
index b01447e..aa3f0d7 100644
--- a/quickstep/src/com/android/quickstep/util/WorkspaceUnlockAnim.java
+++ b/quickstep/src/com/android/quickstep/util/WorkspaceUnlockAnim.java
@@ -21,6 +21,7 @@
/**
* Animation to animate in a workspace during the unlock transition.
*/
+// TODO(b/219444608): use SCALE_PROPERTY_FACTORY once the scale is reset to 1.0 after unlocking.
public class WorkspaceUnlockAnim {
/** Scale for the workspace icons at the beginning of the animation. */
private static final float START_SCALE = 0.9f;
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index bee1c1a..307c51f 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -30,9 +30,11 @@
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.util.MultiValueUpdateListener;
+import java.util.function.Consumer;
+
/**
* Create an instance via
- * {@link #getFloatingTaskView(StatefulActivity, View, Bitmap, Drawable, RectF)} to
+ * {@link #getFloatingTaskView(StatefulActivity, View, Bitmap, Drawable, RectF, Consumer)} to
* which will have the thumbnail from the provided existing TaskView overlaying the taskview itself.
*
* Can then animate the taskview using
@@ -46,6 +48,8 @@
private SplitPlaceholderView mSplitPlaceholderView;
private RectF mStartingPosition;
+ @Nullable
+ private Consumer<RectF> mAdditionalOffsetter;
private final StatefulActivity mActivity;
private final boolean mIsRtl;
private final Rect mOutline = new Rect();
@@ -77,8 +81,9 @@
}
private void init(StatefulActivity launcher, View originalView, @Nullable Bitmap thumbnail,
- Drawable icon, RectF positionOut) {
+ Drawable icon, RectF positionOut, Consumer<RectF> additionalOffsetter) {
mStartingPosition = positionOut;
+ mAdditionalOffsetter = additionalOffsetter;
updateInitialPositionForView(originalView);
final InsettableFrameLayout.LayoutParams lp =
(InsettableFrameLayout.LayoutParams) getLayoutParams();
@@ -102,15 +107,21 @@
/**
* Configures and returns a an instance of {@link FloatingTaskView} initially matching the
* appearance of {@code originalView}.
+ *
+ * @param additionalOffsetter optional, to set additional offsets to the FloatingTaskView
+ * to account for translations. If {@code null} then the
+ * translation values from originalView will be used
*/
public static FloatingTaskView getFloatingTaskView(StatefulActivity launcher,
- View originalView, @Nullable Bitmap thumbnail, Drawable icon, RectF positionOut) {
+ View originalView, @Nullable Bitmap thumbnail, Drawable icon, RectF positionOut,
+ @Nullable Consumer<RectF> additionalOffsetter) {
final BaseDragLayer dragLayer = launcher.getDragLayer();
ViewGroup parent = (ViewGroup) dragLayer.getParent();
final FloatingTaskView floatingView = (FloatingTaskView) launcher.getLayoutInflater()
.inflate(R.layout.floating_split_select_view, parent, false);
- floatingView.init(launcher, originalView, thumbnail, icon, positionOut);
+ floatingView.init(launcher, originalView, thumbnail, icon, positionOut,
+ additionalOffsetter);
parent.addView(floatingView);
return floatingView;
}
@@ -120,7 +131,12 @@
Utilities.getBoundsForViewInDragLayer(mActivity.getDragLayer(), originalView, viewBounds,
true /* ignoreTransform */, null /* recycle */,
mStartingPosition);
- mStartingPosition.offset(originalView.getTranslationX(), originalView.getTranslationY());
+ if (mAdditionalOffsetter != null) {
+ mAdditionalOffsetter.accept(mStartingPosition);
+ } else {
+ mStartingPosition.offset(originalView.getTranslationX(),
+ originalView.getTranslationY());
+ }
final InsettableFrameLayout.LayoutParams lp = new InsettableFrameLayout.LayoutParams(
Math.round(mStartingPosition.width()),
Math.round(mStartingPosition.height()));
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 3450b7c..a042bff 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -992,13 +992,17 @@
*/
public void launchSideTaskInLiveTileModeForRestartedApp(int taskId) {
int runningTaskViewId = getTaskViewIdFromTaskId(taskId);
- if (mRunningTaskViewId != -1 && mRunningTaskViewId == runningTaskViewId) {
- TransformParams params = mRemoteTargetHandles[0].getTransformParams();
- RemoteAnimationTargets targets = params.getTargetSet();
- if (targets != null && targets.findTask(taskId) != null) {
- launchSideTaskInLiveTileMode(taskId, targets.apps, targets.wallpapers,
- targets.nonApps);
- }
+ if (mRunningTaskViewId == -1 ||
+ mRunningTaskViewId != runningTaskViewId ||
+ mRemoteTargetHandles == null) {
+ return;
+ }
+
+ TransformParams params = mRemoteTargetHandles[0].getTransformParams();
+ RemoteAnimationTargets targets = params.getTargetSet();
+ if (targets != null && targets.findTask(taskId) != null) {
+ launchSideTaskInLiveTileMode(taskId, targets.apps, targets.wallpapers,
+ targets.nonApps);
}
}
@@ -2723,8 +2727,13 @@
if (mSplitHiddenTaskView != null) {
mSplitHiddenTaskView.setVisibility(INVISIBLE);
mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
- mSplitHiddenTaskView, mSplitHiddenTaskView.getThumbnail().getThumbnail(),
- mSplitHiddenTaskView.getIconView().getDrawable(), startingTaskRect);
+ mSplitHiddenTaskView.getThumbnail(),
+ mSplitHiddenTaskView.getThumbnail().getThumbnail(),
+ mSplitHiddenTaskView.getIconView().getDrawable(), startingTaskRect,
+ floatingTaskViewStartingPosition -> floatingTaskViewStartingPosition.offset(
+ mSplitHiddenTaskView.getTranslationX(),
+ mSplitHiddenTaskView.getTranslationY()
+ ));
mFirstFloatingTaskView.setAlpha(1);
mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
mTempRect, true /*fadeWithThumbnail*/);
@@ -2732,7 +2741,7 @@
mSplitSelectSource.view.setVisibility(INVISIBLE);
mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
mSplitSelectSource.view, null,
- mSplitSelectSource.drawable, startingTaskRect);
+ mSplitSelectSource.drawable, startingTaskRect, null /*additionalOffsetter*/);
mFirstFloatingTaskView.setAlpha(1);
mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
mTempRect, true /*fadeWithThumbnail*/);
@@ -4023,8 +4032,12 @@
false /*fadeWithThumbnail*/);
mSecondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
- taskView, taskView.getThumbnail().getThumbnail(),
- taskView.getIconView().getDrawable(), secondTaskStartingBounds);
+ taskView.getThumbnail(), taskView.getThumbnail().getThumbnail(),
+ taskView.getIconView().getDrawable(), secondTaskStartingBounds,
+ floatingTaskViewStartingPosition -> floatingTaskViewStartingPosition.offset(
+ taskView.getTranslationX(),
+ taskView.getTranslationY()
+ ));
mSecondFloatingTaskView.setAlpha(1);
mSecondFloatingTaskView.addAnimation(pendingAnimation, secondTaskStartingBounds,
secondTaskEndingBounds, true /*fadeWithThumbnail*/);
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index cba4833..4529217 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -165,7 +165,7 @@
assertTrue("Fallback Launcher not visible", mDevice.wait(Until.hasObject(By.pkg(
mOtherLauncherActivity.packageName)), WAIT_TIME_MS));
- mLauncher.getBackground().switchToOverview();
+ mLauncher.getLaunchedAppState().switchToOverview();
}
// b/143488140
@@ -174,7 +174,7 @@
public void goToOverviewFromApp() {
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
- mLauncher.getBackground().switchToOverview();
+ mLauncher.getLaunchedAppState().switchToOverview();
}
protected void executeOnRecents(Consumer<RecentsActivity> f) {
@@ -200,7 +200,7 @@
private BaseOverview pressHomeAndGoToOverview() {
mDevice.pressHome();
- return mLauncher.getBackground().switchToOverview();
+ return mLauncher.getLaunchedAppState().switchToOverview();
}
// b/143488140
@@ -213,7 +213,7 @@
Wait.atMost("Expected three apps in the task list",
() -> mLauncher.getRecentTasks().size() >= 3, DEFAULT_ACTIVITY_TIMEOUT, mLauncher);
- BaseOverview overview = mLauncher.getBackground().switchToOverview();
+ BaseOverview overview = mLauncher.getLaunchedAppState().switchToOverview();
executeOnRecents(recents -> {
assertTrue("Don't have at least 3 tasks", getTaskCount(recents) >= 3);
});
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
index 75d057e..5351963 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -78,7 +78,7 @@
closeLauncherActivity();
// The test action.
- mLauncher.getBackground().switchToOverview();
+ mLauncher.getLaunchedAppState().switchToOverview();
}
closeLauncherActivity();
mLauncher.pressHome();
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index e3198a8..396cb1b 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -32,8 +32,8 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.tapl.AllApps;
-import com.android.launcher3.tapl.Background;
+import com.android.launcher3.tapl.HomeAllApps;
+import com.android.launcher3.tapl.LaunchedAppState;
import com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel;
import com.android.launcher3.tapl.Overview;
import com.android.launcher3.tapl.OverviewActions;
@@ -84,7 +84,7 @@
executeOnLauncher(launcher -> assertTrue(
"Launcher activity is the top activity; expecting another activity to be the top "
+ "one",
- isInBackground(launcher)));
+ isInLaunchedApp(launcher)));
}
@Test
@@ -136,7 +136,7 @@
executeOnLauncher(launcher -> assertTrue(
"Launcher activity is the top activity; expecting another activity to be the top "
+ "one",
- isInBackground(launcher)));
+ isInLaunchedApp(launcher)));
// Test dismissing a task.
overview = mLauncher.pressHome().switchToOverview();
@@ -210,21 +210,22 @@
@PortraitLandscape
public void testBackground() throws Exception {
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
- final Background background = getAndAssertBackground();
+ final LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
- assertNotNull("Background.switchToOverview() returned null", background.switchToOverview());
+ assertNotNull("Background.switchToOverview() returned null",
+ launchedAppState.switchToOverview());
assertTrue("Launcher internal state didn't switch to Overview",
isInState(() -> LauncherState.OVERVIEW));
}
- private Background getAndAssertBackground() {
- final Background background = mLauncher.getBackground();
- assertNotNull("Launcher.getBackground() returned null", background);
+ private LaunchedAppState getAndAssertLaunchedApp() {
+ final LaunchedAppState launchedAppState = mLauncher.getLaunchedAppState();
+ assertNotNull("Launcher.getLaunchedApp() returned null", launchedAppState);
executeOnLauncher(launcher -> assertTrue(
"Launcher activity is the top activity; expecting another activity to be the top "
+ "one",
- isInBackground(launcher)));
- return background;
+ isInLaunchedApp(launcher)));
+ return launchedAppState;
}
@Test
@@ -253,13 +254,13 @@
startTestActivity(3);
startTestActivity(4);
- Background background = getAndAssertBackground();
- background.quickSwitchToPreviousApp();
+ LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
+ launchedAppState.quickSwitchToPreviousApp();
assertTrue("The first app we should have quick switched to is not running",
isTestActivityRunning(3));
- background = getAndAssertBackground();
- background.quickSwitchToPreviousApp();
+ launchedAppState = getAndAssertLaunchedApp();
+ launchedAppState.quickSwitchToPreviousApp();
if (mLauncher.getNavigationModel() == NavigationModel.THREE_BUTTON) {
// 3-button mode toggles between 2 apps, rather than going back further.
assertTrue("Second quick switch should have returned to the first app.",
@@ -268,13 +269,13 @@
assertTrue("The second app we should have quick switched to is not running",
isTestActivityRunning(2));
}
- background = getAndAssertBackground();
- background.quickSwitchToPreviousAppSwipeLeft();
+ launchedAppState = getAndAssertLaunchedApp();
+ launchedAppState.quickSwitchToPreviousAppSwipeLeft();
assertTrue("The 2nd app we should have quick switched to is not running",
isTestActivityRunning(3));
- background = getAndAssertBackground();
- background.switchToOverview();
+ launchedAppState = getAndAssertLaunchedApp();
+ launchedAppState.switchToOverview();
}
private boolean isTestActivityRunning(int activityNumber) {
@@ -291,7 +292,7 @@
mLauncher.pressHome().quickSwitchToPreviousApp();
assertTrue("The most recent task is not running after quick switching from home",
isTestActivityRunning(2));
- getAndAssertBackground();
+ getAndAssertLaunchedApp();
}
// TODO(b/204830798): test with all navigation modes(add @NavigationModeSwitch annotation)
@@ -306,7 +307,7 @@
mLauncher.getWorkspace();
waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
- AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
allApps.freeze();
try {
allApps.getAppIcon(APP_NAME).dragToWorkspace(false, false);
diff --git a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
index 0f5a1c8..661beda 100644
--- a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
+++ b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
@@ -51,7 +51,7 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.tapl.Background;
+import com.android.launcher3.tapl.LaunchedAppState;
import com.android.launcher3.testcomponent.ListViewService;
import com.android.launcher3.testcomponent.ListViewService.SimpleViewsFactory;
import com.android.launcher3.testcomponent.TestCommandReceiver;
@@ -119,13 +119,13 @@
try {
// Go to overview once so that all views are initialized and cached
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
- mLauncher.getBackground().switchToOverview().dismissAllTasks();
+ mLauncher.getLaunchedAppState().switchToOverview().dismissAllTasks();
// Track view creations
mInitTracker.startTracking();
startTestActivity(2);
- mLauncher.getBackground().switchToOverview();
+ mLauncher.getLaunchedAppState().switchToOverview();
assertEquals("Views inflated during swipe up", 0, mInitTracker.viewInitCount);
} finally {
@@ -205,18 +205,18 @@
// Go to overview once so that all views are initialized and cached
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
- mLauncher.getBackground().switchToOverview().dismissAllTasks();
+ mLauncher.getLaunchedAppState().switchToOverview().dismissAllTasks();
// Track view creations
mInitTracker.startTracking();
startTestActivity(2);
- Background background = mLauncher.getBackground();
+ LaunchedAppState launchedAppState = mLauncher.getLaunchedAppState();
// Update widget
updateBeforeSwipeUp.accept(widgetId);
- background.switchToOverview();
+ launchedAppState.switchToOverview();
assertEquals("Views inflated during swipe up", 0, mInitTracker.viewInitCount);
// Widget is updated when going home
diff --git a/res/values-v31/styles.xml b/res/values-v31/styles.xml
index 0d2fce0..e42d0a3 100644
--- a/res/values-v31/styles.xml
+++ b/res/values-v31/styles.xml
@@ -87,6 +87,7 @@
<style name="HomeSettings.CollapsedToolbarTitle"
parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
<item name="android:fontFamily">google-sans</item>
+ <item name="android:textSize">20sp</item>
</style>
<style name="HomeSettings.ExpandedToolbarTitle" parent="HomeSettings.CollapsedToolbarTitle">
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index ec96c6d..42f7053 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -34,6 +34,7 @@
import androidx.annotation.IntDef;
+import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.util.SystemUiController;
@@ -44,11 +45,13 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.util.ArrayList;
+import java.util.List;
/**
* Launcher BaseActivity
*/
-public abstract class BaseActivity extends Activity implements ActivityContext {
+public abstract class BaseActivity extends Activity implements ActivityContext,
+ DeviceProfileListenable {
private static final String TAG = "BaseActivity";
@@ -142,6 +145,11 @@
return mDeviceProfile;
}
+ @Override
+ public List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners() {
+ return mDPChangeListeners;
+ }
+
/**
* Returns {@link StatsLogManager} for user event logging.
*/
@@ -261,20 +269,6 @@
protected void onActivityFlagsChanged(int changeBits) { }
- public void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
- mDPChangeListeners.add(listener);
- }
-
- public void removeOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
- mDPChangeListeners.remove(listener);
- }
-
- protected void dispatchDeviceProfileChanged() {
- for (int i = mDPChangeListeners.size() - 1; i >= 0; i--) {
- mDPChangeListeners.get(i).onDeviceProfileChanged(mDeviceProfile);
- }
- }
-
public void addMultiWindowModeChangedListener(MultiWindowModeChangedListener listener) {
mMultiWindowModeChangedListeners.add(listener);
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index c456a4d..62703ad 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -44,6 +44,7 @@
import com.android.launcher3.util.WindowBounds;
import java.io.PrintWriter;
+import java.util.List;
@SuppressLint("NewApi")
public class DeviceProfile {
@@ -1223,6 +1224,35 @@
void onDeviceProfileChanged(DeviceProfile dp);
}
+ /** Allows registering listeners for {@link DeviceProfile} changes. */
+ public interface DeviceProfileListenable {
+
+ /** The current device profile. */
+ DeviceProfile getDeviceProfile();
+
+ /** Registered {@link OnDeviceProfileChangeListener} instances. */
+ List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners();
+
+ /** Notifies listeners of a {@link DeviceProfile} change. */
+ default void dispatchDeviceProfileChanged() {
+ DeviceProfile deviceProfile = getDeviceProfile();
+ List<OnDeviceProfileChangeListener> listeners = getOnDeviceProfileChangeListeners();
+ for (int i = listeners.size() - 1; i >= 0; i--) {
+ listeners.get(i).onDeviceProfileChanged(deviceProfile);
+ }
+ }
+
+ /** Register listener for {@link DeviceProfile} changes. */
+ default void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
+ getOnDeviceProfileChangeListeners().add(listener);
+ }
+
+ /** Unregister listener for {@link DeviceProfile} changes. */
+ default void removeOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
+ getOnDeviceProfileChangeListeners().remove(listener);
+ }
+ }
+
public static class Builder {
private Context mContext;
private InvariantDeviceProfile mInv;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index ebc0c75..fcd147f 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -351,7 +351,7 @@
// We only want to get the SharedPreferences once since it does an FS stat each time we get
// it from the context.
private SharedPreferences mSharedPrefs;
- private OnboardingPrefs mOnboardingPrefs;
+ private OnboardingPrefs<? extends Launcher> mOnboardingPrefs;
// Activity result which needs to be processed after workspace has loaded.
private ActivityResultInfo mPendingActivityResult;
@@ -557,11 +557,12 @@
return new LauncherOverlayManager() { };
}
- protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) {
+ protected OnboardingPrefs<? extends Launcher> createOnboardingPrefs(
+ SharedPreferences sharedPrefs) {
return new OnboardingPrefs<>(this, sharedPrefs);
}
- public OnboardingPrefs getOnboardingPrefs() {
+ public OnboardingPrefs<? extends Launcher> getOnboardingPrefs() {
return mOnboardingPrefs;
}
@@ -588,7 +589,7 @@
}
@Override
- protected void dispatchDeviceProfileChanged() {
+ public void dispatchDeviceProfileChanged() {
super.dispatchDeviceProfileChanged();
mOverlayManager.onDeviceProvideChanged();
}
@@ -1782,6 +1783,11 @@
return mWorkspaceLoading;
}
+ @Override
+ public boolean isBindingItems() {
+ return mWorkspaceLoading;
+ }
+
private void setWorkspaceLoading(boolean value) {
mWorkspaceLoading = value;
}
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index b56c012..4300392 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -27,6 +27,8 @@
import android.view.View;
import android.view.ViewGroup.LayoutParams;
+import com.android.launcher3.util.MultiScalePropertyFactory;
+
public class LauncherAnimUtils {
/**
* Durations for various state animations. These are not defined in resources to allow
@@ -64,6 +66,25 @@
}
};
+ /**
+ * Property to set the scale of workspace and hotseat. The value is based on a combination
+ * of all the ones set, to have a smooth experience even in the case of overlapping scaling
+ * animation.
+ */
+ public static final MultiScalePropertyFactory<View> SCALE_PROPERTY_FACTORY =
+ new MultiScalePropertyFactory<View>("scale_property") {
+ @Override
+ protected void apply(View view, float scale) {
+ view.setScaleX(scale);
+ view.setScaleY(scale);
+ }
+ };
+
+ public static final int SCALE_INDEX_UNFOLD_ANIMATION = 1;
+ public static final int SCALE_INDEX_UNLOCK_ANIMATION = 2;
+ public static final int SCALE_INDEX_WORKSPACE_STATE = 3;
+ public static final int SCALE_INDEX_REVEAL_ANIM = 4;
+
/** Increase the duration if we prevented the fling, as we are going against a high velocity. */
public static int blockedFlingDurationFactor(float velocity) {
return (int) Utilities.boundToRange(Math.abs(velocity) / 2, 2f, 6f);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index cbc21eb..9bc3d15 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -671,14 +671,15 @@
/**
* Returns the full drawable for info without any flattening or pre-processing.
*
- * @param outObj this is set to the internal data associated with {@param info},
+ * @param shouldThemeIcon If true, will theme icons when applicable
+ * @param outObj this is set to the internal data associated with {@code info},
* eg {@link LauncherActivityInfo} or {@link ShortcutInfo}.
*/
@TargetApi(Build.VERSION_CODES.TIRAMISU)
public static Drawable getFullDrawable(Context context, ItemInfo info, int width, int height,
- Object[] outObj) {
+ boolean shouldThemeIcon, Object[] outObj) {
Drawable icon = loadFullDrawableWithoutTheme(context, info, width, height, outObj);
- if (ATLEAST_T && icon instanceof AdaptiveIconDrawable) {
+ if (ATLEAST_T && icon instanceof AdaptiveIconDrawable && shouldThemeIcon) {
AdaptiveIconDrawable aid = (AdaptiveIconDrawable) icon.mutate();
Drawable mono = aid.getMonochrome();
if (mono != null && Themes.isThemedIconEnabled(context)) {
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 1b9647a..98e785f 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -18,7 +18,8 @@
import static androidx.dynamicanimation.animation.DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE;
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WORKSPACE_STATE;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY_FACTORY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
@@ -42,6 +43,7 @@
import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM;
import android.animation.ValueAnimator;
+import android.util.FloatProperty;
import android.view.View;
import android.view.animation.Interpolator;
@@ -62,6 +64,9 @@
*/
public class WorkspaceStateTransitionAnimation {
+ private static final FloatProperty<View> WORKSPACE_STATE_SCALE_PROPERTY =
+ SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WORKSPACE_STATE);
+
private final Launcher mLauncher;
private final Workspace mWorkspace;
@@ -117,7 +122,8 @@
((PendingAnimation) propertySetter).add(getSpringScaleAnimator(mLauncher,
mWorkspace, mNewScale));
} else {
- propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
+ propertySetter.setFloat(mWorkspace, WORKSPACE_STATE_SCALE_PROPERTY, mNewScale,
+ scaleInterpolator);
}
mWorkspace.setPivotToScaleWithSelf(hotseat);
@@ -128,7 +134,7 @@
} else {
Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE,
scaleInterpolator);
- propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale,
+ propertySetter.setFloat(hotseat, WORKSPACE_STATE_SCALE_PROPERTY, hotseatScale,
hotseatScaleInterpolator);
}
@@ -205,9 +211,9 @@
.setDampingRatio(damping)
.setMinimumVisibleChange(MIN_VISIBLE_CHANGE_SCALE)
.setEndValue(scale)
- .setStartValue(SCALE_PROPERTY.get(v))
+ .setStartValue(WORKSPACE_STATE_SCALE_PROPERTY.get(v))
.setStartVelocity(velocityPxPerS)
- .build(v, SCALE_PROPERTY);
+ .build(v, WORKSPACE_STATE_SCALE_PROPERTY);
}
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index fb87f88..114f813 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -62,7 +62,6 @@
public ActivityAllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mActivityContext.addOnDeviceProfileChangeListener(this);
}
public SearchUiManager getSearchUiManager() {
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index a66ae78..59e21c0 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -48,6 +48,7 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget.DragObject;
@@ -75,9 +76,10 @@
*
* @param <T> Type of context inflating all apps.
*/
-public abstract class BaseAllAppsContainerView<T extends Context & ActivityContext> extends
- SpringRelativeLayout implements DragSource, Insettable, OnDeviceProfileChangeListener,
- OnActivePageChangedListener, ScrimView.ScrimDrawingController {
+public abstract class BaseAllAppsContainerView<T extends Context & ActivityContext
+ & DeviceProfileListenable> extends SpringRelativeLayout implements DragSource, Insettable,
+ OnDeviceProfileChangeListener, OnActivePageChangedListener,
+ ScrimView.ScrimDrawingController {
private static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
@@ -148,6 +150,7 @@
mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
mAllAppsStore.addUpdateListener(this::onAppsUpdated);
+ mActivityContext.addOnDeviceProfileChangeListener(this);
}
/** Creates the adapter provider for the main section. */
@@ -580,7 +583,10 @@
void setupHeader() {
mHeader.setVisibility(View.VISIBLE);
- mHeader.setup(mAH, mAH.get(AdapterHolder.WORK).mRecyclerView == null);
+ mHeader.setup(
+ mAH.get(AdapterHolder.MAIN).mRecyclerView,
+ mAH.get(AdapterHolder.WORK).mRecyclerView,
+ mAH.get(AdapterHolder.WORK).mRecyclerView == null);
int padding = mHeader.getMaxTranslation();
for (int i = 0; i < mAH.size(); i++) {
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 059d4b8..ed8761e 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -41,7 +41,6 @@
import com.android.systemui.plugins.PluginListener;
import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
public class FloatingHeaderView extends LinearLayout implements
@@ -226,8 +225,7 @@
return super.getFocusedChild();
}
- <T extends Context & ActivityContext> void setup(
- List<BaseAllAppsContainerView<T>.AdapterHolder> mAH, boolean tabsHidden) {
+ void setup(AllAppsRecyclerView mainRV, AllAppsRecyclerView workRV, boolean tabsHidden) {
for (FloatingHeaderRow row : mAllRows) {
row.setup(this, mAllRows, tabsHidden);
}
@@ -235,10 +233,8 @@
mTabsHidden = tabsHidden;
mTabLayout.setVisibility(tabsHidden ? View.GONE : View.VISIBLE);
- mMainRV = setupRV(mMainRV,
- mAH.get(BaseAllAppsContainerView.AdapterHolder.MAIN).mRecyclerView);
- mWorkRV = setupRV(mWorkRV,
- mAH.get(BaseAllAppsContainerView.AdapterHolder.WORK).mRecyclerView);
+ mMainRV = setupRV(mMainRV, mainRV);
+ mWorkRV = setupRV(mWorkRV, workRV);
mParent = (ViewGroup) mMainRV.getParent();
setMainActive(mMainRVActive || mWorkRV == null);
reset(false);
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 4588a04..8bfd774 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -216,7 +216,8 @@
Object[] outObj = new Object[1];
int w = mWidth;
int h = mHeight;
- Drawable dr = Utilities.getFullDrawable(mActivity, info, w, h, outObj);
+ Drawable dr = Utilities.getFullDrawable(mActivity, info, w, h,
+ true /* shouldThemeIcon */, outObj);
if (dr instanceof AdaptiveIconDrawable) {
int blurMargin = (int) mActivity.getResources()
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 198397a..05d6fc6 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -508,6 +508,7 @@
@Override
protected void closeComplete() {
super.closeComplete();
+ mActivityContext.getDragController().removeDragListener(this);
PopupContainerWithArrow openPopup = getOpen(mActivityContext);
if (openPopup == null || openPopup.mOriginalIcon != mOriginalIcon) {
mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible());
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 4f40567..2bf3b14 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -75,13 +75,10 @@
"home-to-overview-swipe-height";
public static final String REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT =
"background-to-overview-swipe-height";
- public static final String REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT =
- "all-apps-to-overview-swipe-height";
public static final String REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT =
"home-to-all-apps-swipe-height";
public static final String REQUEST_ICON_HEIGHT =
"icon-height";
- public static final String REQUEST_HOTSEAT_TOP = "hotseat-top";
public static final String REQUEST_IS_LAUNCHER_INITIALIZED = "is-launcher-initialized";
public static final String REQUEST_FREEZE_APP_LIST = "freeze-app-list";
public static final String REQUEST_UNFREEZE_APP_LIST = "unfreeze-app-list";
diff --git a/src/com/android/launcher3/util/MultiScalePropertyFactory.java b/src/com/android/launcher3/util/MultiScalePropertyFactory.java
new file mode 100644
index 0000000..f27d0f0
--- /dev/null
+++ b/src/com/android/launcher3/util/MultiScalePropertyFactory.java
@@ -0,0 +1,109 @@
+/*
+ * 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.launcher3.util;
+
+import android.util.ArrayMap;
+import android.util.FloatProperty;
+
+import com.android.launcher3.Utilities;
+
+/**
+ * Allows to combine multiple values set by several sources.
+ *
+ * The various sources are meant to use [set], providing different `setterIndex` params. When it is
+ * not set, 0 is used. This is meant to cover the case multiple animations are going on at the same
+ * time.
+ *
+ * This class behaves similarly to [MultiValueAlpha], but is meant to be more abstract and reusable.
+ * It sets the multiplication of all values, bounded to the max and the min values.
+ *
+ * @param <T> Type where to apply the property.
+ */
+public abstract class MultiScalePropertyFactory<T> {
+
+ private final String mName;
+ private final ArrayMap<Integer, MultiScaleProperty> mProperties =
+ new ArrayMap<Integer, MultiScaleProperty>();
+
+ // This is an optimization for cases when set is called repeatedly with the same setterIndex.
+ private float mMinOfOthers = 0;
+ private float mMaxOfOthers = 0;
+ private float mMultiplicationOfOthers = 0;
+ private Integer mLastIndexSet = -1;
+ private float mLastAggregatedValue = 1.0f;
+
+ public MultiScalePropertyFactory(String name) {
+ mName = name;
+ }
+
+ /** Returns the [MultiFloatProperty] associated with [inx], creating it if not present. */
+ public MultiScaleProperty get(Integer index) {
+ return mProperties.computeIfAbsent(index,
+ (k) -> new MultiScaleProperty(index, mName + "_" + index));
+ }
+
+
+ /**
+ * Each [setValue] will be aggregated with the other properties values created by the
+ * corresponding factory.
+ */
+ class MultiScaleProperty extends FloatProperty<T> {
+ private final int mInx;
+ private float mValue = 1.0f;
+
+ MultiScaleProperty(int inx, String name) {
+ super(name);
+ mInx = inx;
+ }
+
+ @Override
+ public void setValue(T obj, float newValue) {
+ if (mLastIndexSet != mInx) {
+ mMinOfOthers = Float.MAX_VALUE;
+ mMaxOfOthers = Float.MIN_VALUE;
+ mMultiplicationOfOthers = 1.0f;
+ mProperties.forEach((key, property) -> {
+ if (key != mInx) {
+ mMinOfOthers = Math.min(mMinOfOthers, property.mValue);
+ mMaxOfOthers = Math.max(mMaxOfOthers, property.mValue);
+ mMultiplicationOfOthers *= property.mValue;
+ }
+ });
+ mLastIndexSet = mInx;
+ }
+ float minValue = Math.min(mMinOfOthers, newValue);
+ float maxValue = Math.max(mMaxOfOthers, newValue);
+ float multValue = mMultiplicationOfOthers * newValue;
+ mLastAggregatedValue = Utilities.boundToRange(multValue, minValue, maxValue);
+ mValue = newValue;
+ apply(obj, mLastAggregatedValue);
+ }
+
+ @Override
+ public Float get(T t) {
+ return mLastAggregatedValue;
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(mValue);
+ }
+ }
+
+ /** Applies value to object after setValue method is called. */
+ protected abstract void apply(T obj, float value);
+}
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index 5ba0d30..39d7cfe 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -20,7 +20,7 @@
import androidx.annotation.StringDef;
-import com.android.launcher3.Launcher;
+import com.android.launcher3.views.ActivityContext;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -29,8 +29,10 @@
/**
* Stores and retrieves onboarding-related data via SharedPreferences.
+ *
+ * @param <T> Context which owns these preferences.
*/
-public class OnboardingPrefs<T extends Launcher> {
+public class OnboardingPrefs<T extends ActivityContext> {
public static final String HOME_BOUNCE_SEEN = "launcher.apps_view_shown";
public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count";
@@ -39,13 +41,15 @@
public static final String SEARCH_EDU_SEEN = "launcher.search_edu_seen";
public static final String SEARCH_SNACKBAR_COUNT = "launcher.keyboard_snackbar_count";
public static final String TASKBAR_EDU_SEEN = "launcher.taskbar_edu_seen";
+ public static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count";
// When adding a new key, add it here as well, to be able to reset it from Developer Options.
public static final Map<String, String[]> ALL_PREF_KEYS = Map.of(
"All Apps Bounce", new String[] { HOME_BOUNCE_SEEN, HOME_BOUNCE_COUNT },
"Hybrid Hotseat Education", new String[] { HOTSEAT_DISCOVERY_TIP_COUNT,
HOTSEAT_LONGPRESS_TIP_SEEN },
"Search Education", new String[] { SEARCH_EDU_SEEN, SEARCH_SNACKBAR_COUNT },
- "Taskbar Education", new String[] { TASKBAR_EDU_SEEN }
+ "Taskbar Education", new String[] { TASKBAR_EDU_SEEN },
+ "All Apps Visited Count", new String[] {ALL_APPS_VISITED_COUNT}
);
/**
@@ -67,7 +71,8 @@
@StringDef(value = {
HOME_BOUNCE_COUNT,
HOTSEAT_DISCOVERY_TIP_COUNT,
- SEARCH_SNACKBAR_COUNT
+ SEARCH_SNACKBAR_COUNT,
+ ALL_APPS_VISITED_COUNT
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventCountKey {
@@ -80,6 +85,7 @@
maxCounts.put(HOME_BOUNCE_COUNT, 3);
maxCounts.put(HOTSEAT_DISCOVERY_TIP_COUNT, 5);
maxCounts.put(SEARCH_SNACKBAR_COUNT, 3);
+ maxCounts.put(ALL_APPS_VISITED_COUNT, 20);
MAX_COUNTS = Collections.unmodifiableMap(maxCounts);
}
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index a318363..3c90eea 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -34,6 +34,7 @@
import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.ViewCache;
/**
@@ -138,6 +139,16 @@
*/
default void applyOverwritesToLogItem(LauncherAtom.ItemInfo.Builder itemInfoBuilder) { }
+ /** Onboarding preferences for any onboarding data within this context. */
+ default OnboardingPrefs<?> getOnboardingPrefs() {
+ return null;
+ }
+
+ /** Returns {@code true} if items are currently being bound within this context. */
+ default boolean isBindingItems() {
+ return false;
+ }
+
/**
* Returns the ActivityContext associated with the given Context, or throws an exception if
* the Context is not associated with any ActivityContext.
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 106bb92..0f69530 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -247,11 +247,13 @@
* @param originalView The View that the FloatingIconView will replace.
* @param info ItemInfo of the originalView
* @param pos The position of the view.
+ * @param btvIcon The drawable of the BubbleTextView. May be null if original view is not a BTV
+ * @param outIconLoadResult We store the icon results into this object.
*/
@WorkerThread
@SuppressWarnings("WrongThread")
private static void getIconResult(Launcher l, View originalView, ItemInfo info, RectF pos,
- Drawable btvIcon, IconLoadResult iconLoadResult) {
+ @Nullable Drawable btvIcon, IconLoadResult outIconLoadResult) {
Drawable drawable;
boolean supportsAdaptiveIcons = !info.isDisabled(); // Use original icon for disabled icons.
@@ -271,7 +273,9 @@
int width = (int) pos.width();
int height = (int) pos.height();
if (supportsAdaptiveIcons) {
- drawable = getFullDrawable(l, info, width, height, sTmpObjArray);
+ boolean shouldThemeIcon = btvIcon instanceof FastBitmapDrawable
+ && ((FastBitmapDrawable) btvIcon).isThemed();
+ drawable = getFullDrawable(l, info, width, height, shouldThemeIcon, sTmpObjArray);
if (drawable instanceof AdaptiveIconDrawable) {
badge = getBadge(l, info, sTmpObjArray[0]);
} else {
@@ -284,24 +288,25 @@
// Similar to DragView, we simply use the BubbleTextView icon here.
drawable = btvIcon;
} else {
- drawable = getFullDrawable(l, info, width, height, sTmpObjArray);
+ drawable = getFullDrawable(l, info, width, height, true /* shouldThemeIcon */,
+ sTmpObjArray);
}
}
}
drawable = drawable == null ? null : drawable.getConstantState().newDrawable();
int iconOffset = getOffsetForIconBounds(l, drawable, pos);
- synchronized (iconLoadResult) {
- iconLoadResult.btvDrawable = btvIcon == null || drawable == btvIcon
+ synchronized (outIconLoadResult) {
+ outIconLoadResult.btvDrawable = btvIcon == null || drawable == btvIcon
? null : btvIcon.getConstantState().newDrawable();
- iconLoadResult.drawable = drawable;
- iconLoadResult.badge = badge;
- iconLoadResult.iconOffset = iconOffset;
- if (iconLoadResult.onIconLoaded != null) {
- l.getMainExecutor().execute(iconLoadResult.onIconLoaded);
- iconLoadResult.onIconLoaded = null;
+ outIconLoadResult.drawable = drawable;
+ outIconLoadResult.badge = badge;
+ outIconLoadResult.iconOffset = iconOffset;
+ if (outIconLoadResult.onIconLoaded != null) {
+ l.getMainExecutor().execute(outIconLoadResult.onIconLoaded);
+ outIconLoadResult.onIconLoaded = null;
}
- iconLoadResult.isIconLoaded = true;
+ outIconLoadResult.isIconLoaded = true;
}
}
@@ -528,8 +533,7 @@
btvIcon = null;
}
- IconLoadResult result = new IconLoadResult(info,
- btvIcon == null ? false : btvIcon.isThemed());
+ IconLoadResult result = new IconLoadResult(info, btvIcon != null && btvIcon.isThemed());
result.btvDrawable = btvIcon;
final long fetchIconId = sFetchIconId++;
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 95bce31..867e488 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -180,18 +180,6 @@
*/
public static ArrayList<OptionItem> getOptions(Launcher launcher) {
ArrayList<OptionItem> options = new ArrayList<>();
- options.add(new OptionItem(launcher,
- R.string.settings_button_text,
- R.drawable.ic_setting,
- LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS,
- OptionsPopupView::startSettings));
- if (!WidgetsModel.GO_DISABLE_WIDGETS) {
- options.add(new OptionItem(launcher,
- R.string.widget_button_text,
- R.drawable.ic_widget,
- LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS,
- OptionsPopupView::onWidgetsClicked));
- }
int resString = Utilities.existsStyleWallpapers(launcher) ?
R.string.styles_wallpaper_button_text : R.string.wallpaper_button_text;
int resDrawable = Utilities.existsStyleWallpapers(launcher) ?
@@ -201,6 +189,18 @@
resDrawable,
IGNORE,
OptionsPopupView::startWallpaperPicker));
+ if (!WidgetsModel.GO_DISABLE_WIDGETS) {
+ options.add(new OptionItem(launcher,
+ R.string.widget_button_text,
+ R.drawable.ic_widget,
+ LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS,
+ OptionsPopupView::onWidgetsClicked));
+ }
+ options.add(new OptionItem(launcher,
+ R.string.settings_button_text,
+ R.drawable.ic_setting,
+ LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS,
+ OptionsPopupView::startSettings));
return options;
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 5afbee2..79a4673 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -509,7 +509,7 @@
"Launcher still active", launcher -> launcher == null, DEFAULT_UI_TIMEOUT);
}
- protected boolean isInBackground(Launcher launcher) {
+ protected boolean isInLaunchedApp(Launcher launcher) {
return launcher == null || !launcher.hasBeenResumed();
}
@@ -549,7 +549,7 @@
ordinal == TestProtocol.NORMAL_STATE_ORDINAL);
break;
}
- case ALL_APPS: {
+ case HOME_ALL_APPS: {
assertTrue(
"Launcher is not resumed in state: " + expectedContainerType,
isResumed);
@@ -564,7 +564,7 @@
ordinal == TestProtocol.OVERVIEW_STATE_ORDINAL);
break;
}
- case BACKGROUND: {
+ case LAUNCHED_APP: {
assertTrue("Launcher is resumed in state: " + expectedContainerType,
!isResumed);
assertTrue(TestProtocol.stateOrdinalToString(ordinal),
@@ -577,10 +577,10 @@
}
} else {
assertTrue(
- "Container type is not BACKGROUND or FALLBACK_OVERVIEW: "
+ "Container type is not LAUNCHED_APP or FALLBACK_OVERVIEW: "
+ expectedContainerType,
- expectedContainerType == ContainerType.BACKGROUND ||
- expectedContainerType == ContainerType.FALLBACK_OVERVIEW);
+ expectedContainerType == ContainerType.LAUNCHED_APP
+ || expectedContainerType == ContainerType.FALLBACK_OVERVIEW);
}
}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 2035da1..da8bf6e 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -38,6 +38,10 @@
import com.android.launcher3.tapl.AppIconMenuItem;
import com.android.launcher3.tapl.Folder;
import com.android.launcher3.tapl.FolderIcon;
+import com.android.launcher3.tapl.HomeAllApps;
+import com.android.launcher3.tapl.HomeAppIcon;
+import com.android.launcher3.tapl.HomeAppIconMenu;
+import com.android.launcher3.tapl.HomeAppIconMenuItem;
import com.android.launcher3.tapl.Widgets;
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.util.TestUtil;
@@ -215,7 +219,7 @@
assertTrue("Launcher internal state is not Home", isInState(() -> LauncherState.NORMAL));
// Test starting a workspace app.
- final AppIcon app = workspace.getWorkspaceAppIcon("Chrome");
+ final HomeAppIcon app = workspace.getWorkspaceAppIcon("Chrome");
assertNotNull("No Chrome app in workspace", app);
}
@@ -228,7 +232,7 @@
"Launcher activity is the top activity; expecting another activity to be the "
+ "top "
+ "one",
- test.isInBackground(launcher)));
+ test.isInLaunchedApp(launcher)));
} finally {
allApps.unfreeze();
}
@@ -237,7 +241,7 @@
@Test
@PortraitLandscape
public void testAppIconLaunchFromAllAppsFromHome() throws Exception {
- final AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
assertTrue("Launcher internal state is not All Apps",
isInState(() -> LauncherState.ALL_APPS));
@@ -286,9 +290,7 @@
@Test
@PortraitLandscape
public void testLaunchMenuItem() throws Exception {
- final AllApps allApps = mLauncher.
- getWorkspace().
- switchToAllApps();
+ final AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
allApps.freeze();
try {
final AppIconMenu menu = allApps.
@@ -313,8 +315,7 @@
// 1. Open all apps and wait for load complete.
// 2. Drag icon to homescreen.
// 3. Verify that the icon works on homescreen.
- final AllApps allApps = mLauncher.getWorkspace().
- switchToAllApps();
+ final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
allApps.freeze();
try {
allApps.getAppIcon(APP_NAME).dragToWorkspace(false, false);
@@ -325,7 +326,7 @@
executeOnLauncher(launcher -> assertTrue(
"Launcher activity is the top activity; expecting another activity to be the top "
+ "one",
- isInBackground(launcher)));
+ isInLaunchedApp(launcher)));
}
@Test
@@ -334,18 +335,18 @@
// 1. Open all apps and wait for load complete.
// 2. Find the app and long press it to show shortcuts.
// 3. Press icon center until shortcuts appear
- final AllApps allApps = mLauncher
+ final HomeAllApps allApps = mLauncher
.getWorkspace()
.switchToAllApps();
allApps.freeze();
try {
- final AppIconMenu menu = allApps
+ final HomeAppIconMenu menu = allApps
.getAppIcon(APP_NAME)
.openDeepShortcutMenu();
- final AppIconMenuItem menuItem0 = menu.getMenuItem(0);
- final AppIconMenuItem menuItem2 = menu.getMenuItem(2);
+ final HomeAppIconMenuItem menuItem0 = menu.getMenuItem(0);
+ final HomeAppIconMenuItem menuItem2 = menu.getMenuItem(2);
- final AppIconMenuItem menuItem;
+ final HomeAppIconMenuItem menuItem;
final String expectedShortcutName = "Shortcut 3";
if (menuItem0.getText().equals(expectedShortcutName)) {
@@ -364,27 +365,27 @@
}
}
- private AppIcon createShortcutIfNotExist(String name) {
- AppIcon appIcon = mLauncher.getWorkspace().tryGetWorkspaceAppIcon(name);
- if (appIcon == null) {
- AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ private HomeAppIcon createShortcutIfNotExist(String name) {
+ HomeAppIcon homeAppIcon = mLauncher.getWorkspace().tryGetWorkspaceAppIcon(name);
+ if (homeAppIcon == null) {
+ HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
allApps.freeze();
try {
allApps.getAppIcon(name).dragToWorkspace(false, false);
} finally {
allApps.unfreeze();
}
- appIcon = mLauncher.getWorkspace().getWorkspaceAppIcon(name);
+ homeAppIcon = mLauncher.getWorkspace().getWorkspaceAppIcon(name);
}
- return appIcon;
+ return homeAppIcon;
}
@Ignore("b/205014516")
@Test
@PortraitLandscape
public void testDragToFolder() throws Exception {
- final AppIcon playStoreIcon = createShortcutIfNotExist("Play Store");
- final AppIcon gmailIcon = createShortcutIfNotExist("Gmail");
+ final HomeAppIcon playStoreIcon = createShortcutIfNotExist("Play Store");
+ final HomeAppIcon gmailIcon = createShortcutIfNotExist("Gmail");
FolderIcon folderIcon = gmailIcon.dragToIcon(playStoreIcon);
@@ -398,7 +399,7 @@
assertNull("Play Store should be moved to a folder.",
workspace.tryGetWorkspaceAppIcon("Play Store"));
- final AppIcon youTubeIcon = createShortcutIfNotExist("YouTube");
+ final HomeAppIcon youTubeIcon = createShortcutIfNotExist("YouTube");
folderIcon = youTubeIcon.dragToIcon(folderIcon);
folder = folderIcon.open();
@@ -415,7 +416,7 @@
mLauncher.getWorkspace();
waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
- AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
allApps.freeze();
try {
allApps.getAppIcon(APP_NAME).dragToWorkspace(false, false);
@@ -432,16 +433,16 @@
@PortraitLandscape
public void testDeleteFromWorkspace() throws Exception {
// test delete both built-in apps and user-installed app from workspace
- for (String appName : new String[]{"Gmail", "Play Store", APP_NAME}) {
- final AppIcon appIcon = createShortcutIfNotExist(appName);
- Workspace workspace = mLauncher.getWorkspace().deleteAppIcon(appIcon);
+ for (String appName : new String[] {"Gmail", "Play Store", APP_NAME}) {
+ final HomeAppIcon homeAppIcon = createShortcutIfNotExist(appName);
+ Workspace workspace = mLauncher.getWorkspace().deleteAppIcon(homeAppIcon);
assertNull(appName + " app was found after being deleted from workspace",
workspace.tryGetWorkspaceAppIcon(appName));
}
}
private void verifyAppUninstalledFromAllApps(Workspace workspace, String appName) {
- final AllApps allApps = workspace.switchToAllApps();
+ final HomeAllApps allApps = workspace.switchToAllApps();
allApps.freeze();
try {
assertNull(appName + " app was found on all apps after being uninstalled",
@@ -469,7 +470,7 @@
TestUtil.installDummyApp();
try {
Workspace workspace = mLauncher.getWorkspace();
- final AllApps allApps = workspace.switchToAllApps();
+ final HomeAllApps allApps = workspace.switchToAllApps();
allApps.freeze();
try {
workspace = allApps.getAppIcon(DUMMY_APP_NAME).uninstall();
@@ -496,7 +497,7 @@
};
for (Point target : targets) {
- final AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
allApps.freeze();
try {
allApps.getAppIcon(APP_NAME).dragToWorkspace(target.x, target.y);
@@ -508,7 +509,7 @@
}
// test to move a shortcut to other cell.
- final AppIcon launcherTestAppIcon = createShortcutIfNotExist(APP_NAME);
+ final HomeAppIcon launcherTestAppIcon = createShortcutIfNotExist(APP_NAME);
for (Point target : targets) {
launcherTestAppIcon.dragToWorkspace(target.x, target.y);
}
diff --git a/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt b/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt
new file mode 100644
index 0000000..c4a8db6
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt
@@ -0,0 +1,92 @@
+package com.android.launcher3.util
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Unit tests for [MultiScalePropertyFactory] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MultiScalePropertyTest {
+
+ private val received = mutableListOf<Float>()
+
+ private val factory =
+ object : MultiScalePropertyFactory<Int?>("Test") {
+ override fun apply(obj: Int?, value: Float) {
+ received.add(value)
+ }
+ }
+
+ private val p1 = factory.get(1)
+ private val p2 = factory.get(2)
+ private val p3 = factory.get(3)
+
+ @Test
+ fun set_multipleSame_bothAppliedd() {
+ p1.set(null, 0.5f)
+ p1.set(null, 0.5f)
+
+ assertThat(received).containsExactly(0.5f, 0.5f)
+ }
+
+ @Test
+ fun set_differentIndexes_oneValuesNotCounted() {
+ val v1 = 0.5f
+ val v2 = 1.0f
+ p1.set(null, v1)
+ p2.set(null, v2)
+
+ assertThat(received).containsExactly(v1, v1)
+ }
+
+ @Test
+ fun set_onlyOneSetToOne_oneApplied() {
+ p1.set(null, 1.0f)
+
+ assertThat(received).containsExactly(1.0f)
+ }
+
+ @Test
+ fun set_onlyOneLessThanOne_applied() {
+ p1.set(null, 0.5f)
+
+ assertThat(received).containsExactly(0.5f)
+ }
+
+ @Test
+ fun set_differentIndexes_boundToMin() {
+ val v1 = 0.5f
+ val v2 = 0.6f
+ p1.set(null, v1)
+ p2.set(null, v2)
+
+ assertThat(received).containsExactly(v1, v1)
+ }
+
+ @Test
+ fun set_allHigherThanOne_boundToMax() {
+ val v1 = 3.0f
+ val v2 = 2.0f
+ val v3 = 1.0f
+ p1.set(null, v1)
+ p2.set(null, v2)
+ p3.set(null, v3)
+
+ assertThat(received).containsExactly(v1, v1, v1)
+ }
+
+ @Test
+ fun set_differentIndexes_firstModified_aggregationApplied() {
+ val v1 = 0.5f
+ val v2 = 0.6f
+ val v3 = 4f
+ p1.set(null, v1)
+ p2.set(null, v2)
+ p3.set(null, v3)
+
+ assertThat(received).containsExactly(v1, v1, v1 * v2 * v3)
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 800322b..3658f41 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -36,7 +36,7 @@
/**
* Operations on AllApps opened from Home. Also a parent for All Apps opened from Overview.
*/
-public class AllApps extends LauncherInstrumentation.VisibleContainer {
+public abstract class AllApps extends LauncherInstrumentation.VisibleContainer {
private static final int MAX_SCROLL_ATTEMPTS = 40;
private final int mHeight;
@@ -55,11 +55,6 @@
.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
- @Override
- protected LauncherInstrumentation.ContainerType getContainerType() {
- return LauncherInstrumentation.ContainerType.ALL_APPS;
- }
-
private boolean hasClickableIcon(UiObject2 allAppsContainer, UiObject2 appListRecycler,
BySelector appIconSelector, int displayBottom) {
final UiObject2 icon;
@@ -157,7 +152,7 @@
final UiObject2 appIcon = mLauncher.waitForObjectInContainer(appListRecycler,
appIconSelector);
- return new AllAppsAppIcon(mLauncher, appIcon);
+ return createAppIcon(appIcon);
} else {
return null;
}
@@ -178,6 +173,8 @@
return appIcon;
}
+ protected abstract AppIcon createAppIcon(UiObject2 icon);
+
private void scrollBackToBeginning() {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to scroll back in all apps")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsAppIcon.java b/tests/tapl/com/android/launcher3/tapl/AllAppsAppIcon.java
index 03d387e..8adce29 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsAppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsAppIcon.java
@@ -23,7 +23,7 @@
/**
* App icon in all apps.
*/
-final class AllAppsAppIcon extends AppIcon {
+final class AllAppsAppIcon extends HomeAppIcon {
private static final Pattern LONG_CLICK_EVENT = Pattern.compile("onAllAppsItemLongClick");
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
deleted file mode 100644
index 835790d..0000000
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.tapl;
-
-import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
-
-import android.graphics.Point;
-
-import androidx.annotation.NonNull;
-import androidx.test.uiautomator.UiObject2;
-
-import com.android.launcher3.testing.TestProtocol;
-
-/**
- * Operations on AllApps opened from Overview.
- */
-public final class AllAppsFromOverview extends AllApps {
-
- AllAppsFromOverview(LauncherInstrumentation launcher) {
- super(launcher);
- verifyActiveContainer();
- }
-
- /**
- * Swipes down to switch back to Overview whence we came from.
- *
- * @return the overview panel.
- */
- @NonNull
- public Overview switchBackToOverview() {
- try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
- LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
- "want to switch back from all apps to overview")) {
- final UiObject2 allAppsContainer = verifyActiveContainer();
- // Swipe from the search box to the bottom.
- final UiObject2 qsb = mLauncher.waitForObjectInContainer(
- allAppsContainer, "search_container_all_apps");
- final Point start = qsb.getVisibleCenter();
- final int swipeHeight = mLauncher.getTestInfo(
- TestProtocol.REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT).
- getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
-
- final int endY = start.y + swipeHeight;
- LauncherInstrumentation.log("AllAppsFromOverview.switchBackToOverview before swipe");
- mLauncher.swipeToState(start.x, start.y, start.x, endY, 60, OVERVIEW_STATE_ORDINAL,
- LauncherInstrumentation.GestureScope.INSIDE);
-
- try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("swiped down")) {
- return new Overview(mLauncher);
- }
- }
- }
-}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index 50611d7..bef242c 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -16,36 +16,33 @@
package com.android.launcher3.tapl;
-import android.graphics.Point;
-import android.graphics.Rect;
import android.widget.TextView;
-import androidx.annotation.NonNull;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.UiObject2;
import com.android.launcher3.testing.TestProtocol;
-import java.util.function.Supplier;
import java.util.regex.Pattern;
/**
- * App icon, whether in all apps or in workspace/
+ * App icon, whether in all apps, workspace or the taskbar.
*/
-public abstract class AppIcon extends Launchable implements FolderDragTarget {
-
- private final String mAppName;
+public abstract class AppIcon extends Launchable {
AppIcon(LauncherInstrumentation launcher, UiObject2 icon) {
super(launcher, icon);
- mAppName = icon.getText();
}
static BySelector getAppIconSelector(String appName, LauncherInstrumentation launcher) {
return By.clazz(TextView.class).text(appName).pkg(launcher.getLauncherPackageName());
}
+ static BySelector getAnyAppIconSelector() {
+ return By.clazz(TextView.class);
+ }
+
protected abstract Pattern getLongClickEvent();
/**
@@ -53,7 +50,7 @@
*/
public AppIconMenu openMenu() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
- return new AppIconMenu(mLauncher, mLauncher.clickAndGet(
+ return createMenu(mLauncher.clickAndGet(
mObject, "popup_container", getLongClickEvent()));
}
}
@@ -63,33 +60,12 @@
*/
public AppIconMenu openDeepShortcutMenu() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
- return new AppIconMenu(mLauncher, mLauncher.clickAndGet(
+ return createMenu(mLauncher.clickAndGet(
mObject, "deep_shortcuts_container", getLongClickEvent()));
}
}
- /**
- * Drag the AppIcon to the given position of other icon. The drag must result in a folder.
- *
- * @param target the destination icon.
- */
- @NonNull
- public FolderIcon dragToIcon(FolderDragTarget target) {
- try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
- LauncherInstrumentation.Closable c = mLauncher.addContextLayer("want to drag icon")) {
- final Rect dropBounds = target.getDropLocationBounds();
- Workspace.dragIconToWorkspace(
- mLauncher, this,
- () -> {
- final Rect bounds = target.getDropLocationBounds();
- return new Point(bounds.centerX(), bounds.centerY());
- },
- getLongPressIndicator());
- FolderIcon result = target.getTargetFolder(dropBounds);
- mLauncher.assertTrue("Can't find the target folder.", result != null);
- return result;
- }
- }
+ protected abstract AppIconMenu createMenu(UiObject2 menu);
@Override
protected void addExpectedEventsForLongClick() {
@@ -110,63 +86,4 @@
protected String launchableType() {
return "app icon";
}
-
- @Override
- public Rect getDropLocationBounds() {
- return mLauncher.getVisibleBounds(mObject);
- }
-
- @Override
- public FolderIcon getTargetFolder(Rect bounds) {
- for (FolderIcon folderIcon : mLauncher.getWorkspace().getFolderIcons()) {
- final Rect folderIconBounds = folderIcon.getDropLocationBounds();
- if (bounds.contains(folderIconBounds.centerX(), folderIconBounds.centerY())) {
- return folderIcon;
- }
- }
- return null;
- }
-
- /**
- * Uninstall the appIcon by dragging it to the 'uninstall' drop point of the drop_target_bar.
- *
- * @return validated workspace after the existing appIcon being uninstalled.
- */
- public Workspace uninstall() {
- try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
- LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
- "uninstalling app icon")) {
- return Workspace.uninstallAppIcon(
- mLauncher, this,
- this::addExpectedEventsForLongClick
- );
- }
- }
-
- /**
- * Drag an object to the given cell in workspace. The target cell must be empty.
- *
- * @param cellX zero based column number, starting from the left of the screen.
- * @param cellY zero based row number, starting from the top of the screen.
- */
- public AppIcon dragToWorkspace(int cellX, int cellY) {
- try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
- LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
- String.format("want to drag the icon to cell(%d, %d)", cellX, cellY))
- ) {
- final Supplier<Point> dest = () -> Workspace.getCellCenter(mLauncher, cellX, cellY);
- Workspace.dragIconToWorkspace(mLauncher, this, dest, true, getLongPressIndicator(),
- () -> addExpectedEventsForLongClick(), null);
- try (LauncherInstrumentation.Closable ignore = mLauncher.addContextLayer("dragged")) {
- WorkspaceAppIcon appIcon =
- (WorkspaceAppIcon) mLauncher.getWorkspace().getWorkspaceAppIcon(mAppName);
- mLauncher.assertTrue(
- String.format(
- "The %s icon should be in the cell (%d, %d).", mAppName, cellX,
- cellY),
- appIcon.isInCell(cellX, cellY));
- return appIcon;
- }
- }
- }
-}
\ No newline at end of file
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIconMenu.java b/tests/tapl/com/android/launcher3/tapl/AppIconMenu.java
index 7f28151..82d9630 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIconMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIconMenu.java
@@ -25,9 +25,9 @@
/**
* Context menu of an app icon.
*/
-public class AppIconMenu {
- private final LauncherInstrumentation mLauncher;
- private final UiObject2 mDeepShortcutsContainer;
+public abstract class AppIconMenu {
+ protected final LauncherInstrumentation mLauncher;
+ protected final UiObject2 mDeepShortcutsContainer;
AppIconMenu(LauncherInstrumentation launcher,
UiObject2 deepShortcutsContainer) {
@@ -42,6 +42,17 @@
final List<UiObject2> menuItems = mLauncher.getObjectsInContainer(mDeepShortcutsContainer,
"bubble_text");
assertTrue(menuItems.size() > itemNumber);
- return new AppIconMenuItem(mLauncher, menuItems.get(itemNumber));
+ return createMenuItem(menuItems.get(itemNumber));
}
+
+ /**
+ * Returns a menu item with the given text. Fails if it doesn't exist.
+ */
+ public AppIconMenuItem getMenuItem(String shortcutText) {
+ final UiObject2 menuItem = mLauncher.waitForObjectInContainer(mDeepShortcutsContainer,
+ AppIcon.getAppIconSelector(shortcutText, mLauncher));
+ return createMenuItem(menuItem);
+ }
+
+ protected abstract AppIconMenuItem createMenuItem(UiObject2 menuItem);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
index ac0db08..a6a1531 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
@@ -23,7 +23,7 @@
/**
* Menu item in an app icon menu.
*/
-public class AppIconMenuItem extends Launchable {
+public abstract class AppIconMenuItem extends Launchable {
AppIconMenuItem(LauncherInstrumentation launcher, UiObject2 shortcut) {
super(launcher, shortcut);
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 4333b27..589e13c 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -37,7 +37,7 @@
* Indicates the base state with a UI other than Overview running as foreground. It can also
* indicate Launcher as long as Launcher is not in Overview state.
*/
-public class Background extends LauncherInstrumentation.VisibleContainer {
+public abstract class Background extends LauncherInstrumentation.VisibleContainer {
private static final int ZERO_BUTTON_SWIPE_UP_GESTURE_DURATION = 500;
private static final Pattern SQUARE_BUTTON_EVENT = Pattern.compile("onOverviewToggle");
@@ -45,11 +45,6 @@
super(launcher);
}
- @Override
- protected LauncherInstrumentation.ContainerType getContainerType() {
- return LauncherInstrumentation.ContainerType.BACKGROUND;
- }
-
/**
* Swipes up or presses the square button to switch to Overview.
* Returns the base overview, which can be either in Launcher or the fallback recents.
@@ -212,17 +207,17 @@
}
@NonNull
- public Background quickSwitchToPreviousApp() {
+ public LaunchedAppState quickSwitchToPreviousApp() {
boolean toRight = true;
quickSwitch(toRight);
- return new Background(mLauncher);
+ return new LaunchedAppState(mLauncher);
}
@NonNull
- public Background quickSwitchToPreviousAppSwipeLeft() {
+ public LaunchedAppState quickSwitchToPreviousAppSwipeLeft() {
boolean toRight = false;
quickSwitch(toRight);
- return new Background(mLauncher);
+ return new LaunchedAppState(mLauncher);
}
@NonNull
diff --git a/tests/tapl/com/android/launcher3/tapl/Folder.java b/tests/tapl/com/android/launcher3/tapl/Folder.java
index f046b6e..26f0a8b 100644
--- a/tests/tapl/com/android/launcher3/tapl/Folder.java
+++ b/tests/tapl/com/android/launcher3/tapl/Folder.java
@@ -40,7 +40,7 @@
* Find an app icon with given name or raise assertion error.
*/
@NonNull
- public AppIcon getAppIcon(String appName) {
+ public HomeAppIcon getAppIcon(String appName) {
try (LauncherInstrumentation.Closable ignored = mLauncher.addContextLayer(
"Want to get app icon in folder")) {
return new WorkspaceAppIcon(mLauncher,
diff --git a/tests/tapl/com/android/launcher3/tapl/FolderDragTarget.java b/tests/tapl/com/android/launcher3/tapl/FolderDragTarget.java
index d797418..2c60668 100644
--- a/tests/tapl/com/android/launcher3/tapl/FolderDragTarget.java
+++ b/tests/tapl/com/android/launcher3/tapl/FolderDragTarget.java
@@ -19,7 +19,10 @@
import android.graphics.Rect;
public interface FolderDragTarget {
+
+ /** This method requires public access, however should not be called in tests. */
Rect getDropLocationBounds();
+ /** This method requires public access, however should not be called in tests. */
FolderIcon getTargetFolder(Rect bounds);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/FolderIcon.java b/tests/tapl/com/android/launcher3/tapl/FolderIcon.java
index 2e79d70..9b4717f 100644
--- a/tests/tapl/com/android/launcher3/tapl/FolderIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/FolderIcon.java
@@ -52,11 +52,13 @@
return new Folder(mLauncher);
}
+ /** This method requires public access, however should not be called in tests. */
@Override
public Rect getDropLocationBounds() {
return mLauncher.getVisibleBounds(mObject.getParent());
}
+ /** This method requires public access, however should not be called in tests. */
@Override
public FolderIcon getTargetFolder(Rect bounds) {
return this;
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
new file mode 100644
index 0000000..2e00d59
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
@@ -0,0 +1,42 @@
+/*
+ * 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.launcher3.tapl;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.UiObject2;
+
+public class HomeAllApps extends AllApps {
+
+ HomeAllApps(LauncherInstrumentation launcher) {
+ super(launcher);
+ }
+
+ @Override
+ protected LauncherInstrumentation.ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.HOME_ALL_APPS;
+ }
+
+ @NonNull
+ @Override
+ public HomeAppIcon getAppIcon(String appName) {
+ return (AllAppsAppIcon) super.getAppIcon(appName);
+ }
+
+ @Override
+ protected HomeAppIcon createAppIcon(UiObject2 icon) {
+ return new AllAppsAppIcon(mLauncher, icon);
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java b/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java
new file mode 100644
index 0000000..4b36dc0
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java
@@ -0,0 +1,139 @@
+/*
+ * 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.launcher3.tapl;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.UiObject2;
+
+import java.util.function.Supplier;
+
+/**
+ * App icon on the workspace or all apps.
+ */
+public abstract class HomeAppIcon extends AppIcon implements FolderDragTarget, WorkspaceDragSource {
+
+ private final String mAppName;
+
+ HomeAppIcon(LauncherInstrumentation launcher, UiObject2 icon) {
+ super(launcher, icon);
+ mAppName = icon.getText();
+ }
+
+ /**
+ * Drag the AppIcon to the given position of other icon. The drag must result in a folder.
+ *
+ * @param target the destination icon.
+ */
+ @NonNull
+ public FolderIcon dragToIcon(FolderDragTarget target) {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer("want to drag icon")) {
+ final Rect dropBounds = target.getDropLocationBounds();
+ Workspace.dragIconToWorkspace(
+ mLauncher, this,
+ () -> {
+ final Rect bounds = target.getDropLocationBounds();
+ return new Point(bounds.centerX(), bounds.centerY());
+ },
+ getLongPressIndicator());
+ FolderIcon result = target.getTargetFolder(dropBounds);
+ mLauncher.assertTrue("Can't find the target folder.", result != null);
+ return result;
+ }
+ }
+
+ /** This method requires public access, however should not be called in tests. */
+ @Override
+ public Rect getDropLocationBounds() {
+ return mLauncher.getVisibleBounds(mObject);
+ }
+
+ /** This method requires public access, however should not be called in tests. */
+ @Override
+ public FolderIcon getTargetFolder(Rect bounds) {
+ for (FolderIcon folderIcon : mLauncher.getWorkspace().getFolderIcons()) {
+ final Rect folderIconBounds = folderIcon.getDropLocationBounds();
+ if (bounds.contains(folderIconBounds.centerX(), folderIconBounds.centerY())) {
+ return folderIcon;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public HomeAppIconMenu openDeepShortcutMenu() {
+ return (HomeAppIconMenu) super.openDeepShortcutMenu();
+ }
+
+ @Override
+ protected HomeAppIconMenu createMenu(UiObject2 menu) {
+ return new HomeAppIconMenu(mLauncher, menu);
+ }
+
+ /**
+ * Uninstall the appIcon by dragging it to the 'uninstall' drop point of the drop_target_bar.
+ *
+ * @return validated workspace after the existing appIcon being uninstalled.
+ */
+ public Workspace uninstall() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "uninstalling app icon")) {
+ return Workspace.uninstallAppIcon(
+ mLauncher, this,
+ this::addExpectedEventsForLongClick
+ );
+ }
+ }
+
+ /**
+ * Drag an object to the given cell in workspace. The target cell must be empty.
+ *
+ * @param cellX zero based column number, starting from the left of the screen.
+ * @param cellY zero based row number, starting from the top of the screen.
+ */
+ public HomeAppIcon dragToWorkspace(int cellX, int cellY) {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ String.format("want to drag the icon to cell(%d, %d)", cellX, cellY))
+ ) {
+ final Supplier<Point> dest = () -> Workspace.getCellCenter(mLauncher, cellX, cellY);
+ Workspace.dragIconToWorkspace(mLauncher, this, dest, true, getLongPressIndicator(),
+ () -> addExpectedEventsForLongClick(), null);
+ try (LauncherInstrumentation.Closable ignore = mLauncher.addContextLayer("dragged")) {
+ WorkspaceAppIcon appIcon =
+ (WorkspaceAppIcon) mLauncher.getWorkspace().getWorkspaceAppIcon(mAppName);
+ mLauncher.assertTrue(
+ String.format(
+ "The %s icon should be in the cell (%d, %d).", mAppName, cellX,
+ cellY),
+ appIcon.isInCell(cellX, cellY));
+ return appIcon;
+ }
+ }
+ }
+
+
+ /** This method requires public access, however should not be called in tests. */
+ @Override
+ public Launchable getLaunchable() {
+ return this;
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAppIconMenu.java b/tests/tapl/com/android/launcher3/tapl/HomeAppIconMenu.java
new file mode 100644
index 0000000..71fb6c0
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAppIconMenu.java
@@ -0,0 +1,39 @@
+/*
+ * 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.launcher3.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * Context menu of a home screen app icon.
+ */
+public final class HomeAppIconMenu extends AppIconMenu {
+
+ HomeAppIconMenu(LauncherInstrumentation launcher,
+ UiObject2 deepShortcutsContainer) {
+ super(launcher, deepShortcutsContainer);
+ }
+
+ @Override
+ public HomeAppIconMenuItem getMenuItem(int itemNumber) {
+ return (HomeAppIconMenuItem) super.getMenuItem(itemNumber);
+ }
+
+ @Override
+ protected HomeAppIconMenuItem createMenuItem(UiObject2 menuItem) {
+ return new HomeAppIconMenuItem(mLauncher, menuItem);
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAppIconMenuItem.java b/tests/tapl/com/android/launcher3/tapl/HomeAppIconMenuItem.java
new file mode 100644
index 0000000..1ff0c10
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAppIconMenuItem.java
@@ -0,0 +1,35 @@
+/*
+ * 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.launcher3.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * Menu item in a home screen app icon menu.
+ */
+public final class HomeAppIconMenuItem extends AppIconMenuItem implements WorkspaceDragSource {
+
+ HomeAppIconMenuItem(LauncherInstrumentation launcher,
+ UiObject2 shortcut) {
+ super(launcher, shortcut);
+ }
+
+ /** This method requires public access, however should not be called in tests. */
+ @Override
+ public Launchable getLaunchable() {
+ return this;
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 7ec5208..02a6b91 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -18,17 +18,25 @@
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
+import static com.android.launcher3.testing.TestProtocol.SPRING_LOADED_STATE_ORDINAL;
+
import android.graphics.Point;
+import android.view.MotionEvent;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
+import com.android.launcher3.testing.TestProtocol;
+
/**
* Ancestor for AppIcon and AppMenuItem.
*/
abstract class Launchable {
+
+ protected static final int DEFAULT_DRAG_STEPS = 10;
+
protected final LauncherInstrumentation mLauncher;
protected final UiObject2 mObject;
@@ -45,7 +53,7 @@
/**
* Clicks the object to launch its app.
*/
- public Background launch(String expectedPackageName) {
+ public LaunchedAppState launch(String expectedPackageName) {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
return launch(By.pkg(expectedPackageName));
}
@@ -55,56 +63,88 @@
protected abstract String launchableType();
- private Background launch(BySelector selector) {
+ private LaunchedAppState launch(BySelector selector) {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to launch an app from " + launchableType())) {
LauncherInstrumentation.log("Launchable.launch before click "
+ mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(mObject));
final String label = mObject.getText();
- mLauncher.executeAndWaitForEvent(
- () -> {
- mLauncher.clickLauncherObject(mObject);
- expectActivityStartEvents();
- },
- event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
- () -> "Launching an app didn't open a new window: " + label,
- "clicking " + launchableType());
+ executeAndWaitForWindowChange(() -> {
+ mLauncher.clickLauncherObject(mObject);
+ expectActivityStartEvents();
+ }, label, "clicking " + launchableType());
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("clicked")) {
- mLauncher.assertTrue(
- "App didn't start: " + label + " (" + selector + ")",
- TestHelpers.wait(Until.hasObject(selector),
- LauncherInstrumentation.WAIT_TIME_MS));
- return new Background(mLauncher);
+ return assertAppLaunched(label, selector);
}
}
}
- /**
- * Drags an object to the center of homescreen.
- *
- * @param startsActivity whether it's expected to start an activity.
- * @param isWidgetShortcut whether we drag a widget shortcut
- */
- public void dragToWorkspace(boolean startsActivity, boolean isWidgetShortcut) {
- try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
- final Point launchableCenter = getObject().getVisibleCenter();
- final Point displaySize = mLauncher.getRealDisplaySize();
- final int width = displaySize.x / 2;
- Workspace.dragIconToWorkspace(
- mLauncher,
- this,
- new Point(
- launchableCenter.x >= width
- ? launchableCenter.x - width / 2
- : launchableCenter.x + width / 2,
- displaySize.y / 2),
- getLongPressIndicator(),
- startsActivity,
- isWidgetShortcut,
- () -> addExpectedEventsForLongClick());
+ protected void executeAndWaitForWindowChange(Runnable command, String label, String action) {
+ mLauncher.executeAndWaitForEvent(
+ command,
+ event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
+ () -> "Launching an app didn't open a new window: " + label,
+ action);
+ }
+
+ protected LaunchedAppState assertAppLaunched(String label, BySelector selector) {
+ mLauncher.assertTrue(
+ "App didn't start: " + label + " (" + selector + ")",
+ TestHelpers.wait(Until.hasObject(selector),
+ LauncherInstrumentation.WAIT_TIME_MS));
+ return new LaunchedAppState(mLauncher);
+ }
+
+ Point startDrag(long downTime, String longPressIndicator,
+ Runnable expectLongClickEvents, boolean runToSpringLoadedState) {
+ final Point iconCenter = getObject().getVisibleCenter();
+ final Point dragStartCenter = new Point(iconCenter.x,
+ iconCenter.y - getStartDragThreshold());
+
+ if (runToSpringLoadedState) {
+ mLauncher.runToState(() -> movePointerForStartDrag(
+ downTime,
+ iconCenter,
+ dragStartCenter,
+ longPressIndicator,
+ expectLongClickEvents),
+ SPRING_LOADED_STATE_ORDINAL, "long-pressing and triggering drag start");
+ } else {
+ movePointerForStartDrag(
+ downTime,
+ iconCenter,
+ dragStartCenter,
+ longPressIndicator,
+ expectLongClickEvents);
}
+
+
+ return dragStartCenter;
+ }
+
+ /**
+ * Drags this Launchable a short distance before starting a full drag.
+ *
+ * This is necessary for shortcuts, which require being dragged beyond a threshold to close
+ * their container and start drag callbacks.
+ */
+ private void movePointerForStartDrag(long downTime, Point iconCenter, Point dragStartCenter,
+ String longPressIndicator, Runnable expectLongClickEvents) {
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
+ iconCenter, LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.log("movePointerForStartDrag: sent down");
+ expectLongClickEvents.run();
+ mLauncher.waitForLauncherObject(longPressIndicator);
+ LauncherInstrumentation.log("movePointerForStartDrag: indicator");
+ mLauncher.movePointer(iconCenter, dragStartCenter, DEFAULT_DRAG_STEPS, false,
+ downTime, true, LauncherInstrumentation.GestureScope.INSIDE);
+ }
+
+ private int getStartDragThreshold() {
+ return mLauncher.getTestInfo(TestProtocol.REQUEST_START_DRAG_THRESHOLD).getInt(
+ TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
protected abstract void addExpectedEventsForLongClick();
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
new file mode 100644
index 0000000..3f1be80
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -0,0 +1,32 @@
+/*
+ * 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.launcher3.tapl;
+
+/**
+ * Background state operations specific to when an app has been launched.
+ */
+public final class LaunchedAppState extends Background {
+
+ LaunchedAppState(LauncherInstrumentation launcher) {
+ super(launcher);
+ }
+
+ @Override
+ protected LauncherInstrumentation.ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.LAUNCHED_APP;
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 7c377d5..f063191 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -91,6 +91,7 @@
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* The main tapl object. The only object that can be explicitly constructed by the using code. It
@@ -122,7 +123,7 @@
// Types for launcher containers that the user is interacting with. "Background" is a
// pseudo-container corresponding to inactive launcher covered by another app.
public enum ContainerType {
- WORKSPACE, ALL_APPS, OVERVIEW, WIDGETS, BACKGROUND, FALLBACK_OVERVIEW
+ WORKSPACE, HOME_ALL_APPS, OVERVIEW, WIDGETS, FALLBACK_OVERVIEW, LAUNCHED_APP
}
public enum NavigationModel {ZERO_BUTTON, THREE_BUTTON}
@@ -135,7 +136,7 @@
}
// Base class for launcher containers.
- static abstract class VisibleContainer {
+ abstract static class VisibleContainer {
protected final LauncherInstrumentation mLauncher;
protected VisibleContainer(LauncherInstrumentation launcher) {
@@ -500,17 +501,20 @@
}
private String getVisiblePackages() {
- final String apps = mDevice.findObjects(getAnyObjectSelector())
- .stream()
- .map(LauncherInstrumentation::getApplicationPackageSafe)
- .distinct()
- .filter(pkg -> pkg != null && !SYSTEMUI_PACKAGE.equals(pkg))
- .collect(Collectors.joining(", "));
+ final String apps = getVisiblePackagesStream().collect(Collectors.joining(", "));
return !apps.isEmpty()
? "active app: " + apps
: "the test doesn't see views from any app, including Launcher";
}
+ private Stream<String> getVisiblePackagesStream() {
+ return mDevice.findObjects(getAnyObjectSelector())
+ .stream()
+ .map(LauncherInstrumentation::getApplicationPackageSafe)
+ .distinct()
+ .filter(pkg -> pkg != null && !SYSTEMUI_PACKAGE.equals(pkg));
+ }
+
private static String getApplicationPackageSafe(UiObject2 object) {
try {
return object.getApplicationPackage();
@@ -526,7 +530,7 @@
if (hasLauncherObject(OVERVIEW_RES_ID)) return "Overview";
if (hasLauncherObject(WORKSPACE_RES_ID)) return "Workspace";
if (hasLauncherObject(APPS_RES_ID)) return "AllApps";
- return "Background (" + getVisiblePackages() + ")";
+ return "LaunchedApp (" + getVisiblePackages() + ")";
}
public void setSystemHealthSupplier(Function<Long, String> supplier) {
@@ -726,7 +730,7 @@
waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
return waitForLauncherObject(WIDGETS_RES_ID);
}
- case ALL_APPS: {
+ case HOME_ALL_APPS: {
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
@@ -736,13 +740,12 @@
waitUntilLauncherObjectGone(APPS_RES_ID);
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
-
return waitForLauncherObject(OVERVIEW_RES_ID);
}
case FALLBACK_OVERVIEW: {
return waitForFallbackLauncherObject(OVERVIEW_RES_ID);
}
- case BACKGROUND: {
+ case LAUNCHED_APP: {
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
waitUntilLauncherObjectGone(APPS_RES_ID);
waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
@@ -823,6 +826,8 @@
}
GestureScope gestureScope = gestureStartFromLauncher
+ // Without the navigation bar layer, the gesture scope on tablets remains inside the
+ // launcher process.
? (isTablet() ? GestureScope.INSIDE : GestureScope.INSIDE_TO_OUTSIDE)
: GestureScope.OUTSIDE_WITH_PILFER;
linearGesture(
@@ -960,14 +965,14 @@
}
/**
- * Gets the Workspace object if the current state is "background home", i.e. some other app is
- * active. Fails if the launcher is not in that state.
+ * Gets the LaunchedApp object if another app is active. Fails if the launcher is not in that
+ * state.
*
- * @return Background object.
+ * @return LaunchedApp object.
*/
@NonNull
- public Background getBackground() {
- return new Background(this);
+ public LaunchedAppState getLaunchedAppState() {
+ return new LaunchedAppState(this);
}
/**
@@ -1004,32 +1009,17 @@
}
/**
- * Gets the All Apps object if the current state is showing the all apps panel opened by swiping
- * from workspace. Fails if the launcher is not in that state. Please don't call this method if
- * App Apps was opened by swiping up from Overview, as it won't fail and will return an
- * incorrect object.
+ * Gets the homescreen All Apps object if the current state is showing the all apps panel opened
+ * by swiping from workspace. Fails if the launcher is not in that state. Please don't call this
+ * method if App Apps was opened by swiping up from Overview, as it won't fail and will return
+ * an incorrect object.
*
- * @return All Aps object.
+ * @return Home All Apps object.
*/
@NonNull
- public AllApps getAllApps() {
+ public HomeAllApps getAllApps() {
try (LauncherInstrumentation.Closable c = addContextLayer("want to get all apps object")) {
- return new AllApps(this);
- }
- }
-
- /**
- * Gets the All Apps object if the current state is showing the all apps panel opened by swiping
- * from overview. Fails if the launcher is not in that state. Please don't call this method if
- * App Apps was opened by swiping up from home, as it won't fail and will return an
- * incorrect object.
- *
- * @return All Aps object.
- */
- @NonNull
- public AllAppsFromOverview getAllAppsFromOverview() {
- try (LauncherInstrumentation.Closable c = addContextLayer("want to get all apps object")) {
- return new AllAppsFromOverview(this);
+ return new HomeAllApps(this);
}
}
@@ -1117,15 +1107,21 @@
}
}
- @NonNull
- UiObject2 waitForObjectInContainer(UiObject2 container, BySelector selector) {
+ @NonNull UiObject2 waitForObjectInContainer(UiObject2 container, BySelector selector) {
+ return waitForObjectsInContainer(container, selector).get(0);
+ }
+
+ @NonNull List<UiObject2> waitForObjectsInContainer(
+ UiObject2 container, BySelector selector) {
try {
- final UiObject2 object = container.wait(
- Until.findObject(selector),
+ final List<UiObject2> objects = container.wait(
+ Until.findObjects(selector),
WAIT_TIME_MS);
- assertNotNull("Can't find a view in Launcher, id: " + selector + " in container: "
- + container.getResourceName(), object);
- return object;
+ assertNotNull("Can't find views in Launcher, id: " + selector + " in container: "
+ + container.getResourceName(), objects);
+ assertTrue("Can't find views in Launcher, id: " + selector + " in container: "
+ + container.getResourceName(), objects.size() > 0);
+ return objects;
} catch (StaleObjectException e) {
fail("The container disappeared from screen");
return null;
diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
index 0d06be3..66a51a5 100644
--- a/tests/tapl/com/android/launcher3/tapl/Overview.java
+++ b/tests/tapl/com/android/launcher3/tapl/Overview.java
@@ -16,12 +16,7 @@
package com.android.launcher3.tapl;
-import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL;
-
-import androidx.annotation.NonNull;
-
import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
-import com.android.launcher3.testing.TestProtocol;
/**
* Overview pane.
@@ -37,38 +32,6 @@
return LauncherInstrumentation.ContainerType.OVERVIEW;
}
- /**
- * Swipes up to All Apps.
- *
- * @return the App Apps object.
- */
- @NonNull
- public AllAppsFromOverview switchToAllApps() {
- try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
- LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
- "want to switch from overview to all apps")) {
- verifyActiveContainer();
-
- // Swipe from an app icon to the top.
- LauncherInstrumentation.log("Overview.switchToAllApps before swipe");
- mLauncher.swipeToState(
- mLauncher.getDevice().getDisplayWidth() / 2,
- mLauncher.getTestInfo(
- TestProtocol.REQUEST_HOTSEAT_TOP).
- getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD),
- mLauncher.getDevice().getDisplayWidth() / 2,
- 0,
- 12,
- ALL_APPS_STATE_ORDINAL,
- LauncherInstrumentation.GestureScope.INSIDE);
-
- try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
- "swiped all way up from overview")) {
- return new AllAppsFromOverview(mLauncher);
- }
- }
- }
-
@Override
public void dismissAllTasks() {
super.dismissAllTasks();
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index a860e7d..c8caa42 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -127,7 +127,7 @@
/**
* Clicks at the task.
*/
- public Background open() {
+ public LaunchedAppState open() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
verifyActiveContainer();
mLauncher.executeAndWaitForEvent(
@@ -137,7 +137,7 @@
+ mTask.getParent().getContentDescription(),
"clicking an overview task");
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
- return new Background(mLauncher);
+ return new LaunchedAppState(mLauncher);
}
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widget.java b/tests/tapl/com/android/launcher3/tapl/Widget.java
index f569ef4..73e9830 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widget.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widget.java
@@ -30,7 +30,7 @@
/**
* Widget in workspace or a widget list.
*/
-public final class Widget extends Launchable {
+public final class Widget extends Launchable implements WorkspaceDragSource {
private static final Pattern LONG_CLICK_EVENT = Pattern.compile("Widgets.onLongClick");
@@ -57,6 +57,12 @@
return "widget";
}
+ /** This method requires public access, however should not be called in tests. */
+ @Override
+ public Launchable getLaunchable() {
+ return this;
+ }
+
/**
* Drags a non-configurable widget from the widgets container to the workspace and returns the
* resize frame that is shown after the widget is added.
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 1947da3..6e10b28 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.NORMAL_STATE_ORDINAL;
-import static com.android.launcher3.testing.TestProtocol.SPRING_LOADED_STATE_ORDINAL;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertTrue;
@@ -79,7 +78,7 @@
* @return the All Apps object.
*/
@NonNull
- public AllApps switchToAllApps() {
+ public HomeAllApps switchToAllApps() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c =
mLauncher.addContextLayer("want to switch from workspace to all apps")) {
@@ -106,7 +105,7 @@
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"swiped to all apps")) {
- return new AllApps(mLauncher);
+ return new HomeAllApps(mLauncher);
}
}
}
@@ -118,7 +117,7 @@
* @return app icon, if found, null otherwise.
*/
@Nullable
- public AppIcon tryGetWorkspaceAppIcon(String appName) {
+ public HomeAppIcon tryGetWorkspaceAppIcon(String appName) {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to get a workspace icon")) {
final UiObject2 workspace = verifyActiveContainer();
@@ -136,7 +135,7 @@
* @return app icon.
*/
@NonNull
- public AppIcon getWorkspaceAppIcon(String appName) {
+ public HomeAppIcon getWorkspaceAppIcon(String appName) {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to get a workspace icon")) {
return new WorkspaceAppIcon(mLauncher,
@@ -179,12 +178,12 @@
* pageDelta: 3, the latest page that can be created is 2) the icon will be dragged onto the
* page that can be created and is closest to the target page.
*
- * @param appIcon - icon to drag.
+ * @param homeAppIcon - icon to drag.
* @param pageDelta - how many pages should the icon be dragged from the current page.
* It can be a negative value. currentPage + pageDelta should be greater
* than or equal to 0.
*/
- public void dragIcon(AppIcon appIcon, int pageDelta) {
+ public void dragIcon(HomeAppIcon homeAppIcon, int pageDelta) {
if (mHotseat.getVisibleBounds().height() > mHotseat.getVisibleBounds().width()) {
throw new UnsupportedOperationException(
"dragIcon does NOT support dragging when the hotseat is on the side.");
@@ -193,18 +192,18 @@
final UiObject2 workspace = verifyActiveContainer();
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"dragging icon to page with delta: " + pageDelta)) {
- dragIcon(workspace, appIcon, pageDelta);
+ dragIcon(workspace, homeAppIcon, pageDelta);
verifyActiveContainer();
}
}
}
- private void dragIcon(UiObject2 workspace, AppIcon appIcon, int pageDelta) {
+ private void dragIcon(UiObject2 workspace, HomeAppIcon homeAppIcon, int pageDelta) {
int pageWidth = mLauncher.getDevice().getDisplayWidth() / pagesPerScreen();
int targetX = (pageWidth / 2) + pageWidth * pageDelta;
dragIconToWorkspace(
mLauncher,
- appIcon,
+ homeAppIcon,
new Point(targetX, mLauncher.getVisibleBounds(workspace).centerY()),
"popup_container",
false,
@@ -219,16 +218,11 @@
}
@NonNull
- public AppIcon getHotseatAppIcon(String appName) {
+ public HomeAppIcon getHotseatAppIcon(String appName) {
return new WorkspaceAppIcon(mLauncher, mLauncher.waitForObjectInContainer(
mHotseat, AppIcon.getAppIconSelector(appName, mLauncher)));
}
- private static int getStartDragThreshold(LauncherInstrumentation launcher) {
- return launcher.getTestInfo(TestProtocol.REQUEST_START_DRAG_THRESHOLD).getInt(
- TestProtocol.TEST_INFO_RESPONSE_FIELD);
- }
-
/*
* Get the center point of the delete/uninstall icon in the drop target bar.
*/
@@ -242,18 +236,18 @@
/**
* Delete the appIcon from the workspace.
*
- * @param appIcon to be deleted.
+ * @param homeAppIcon to be deleted.
* @return validated workspace after the existing appIcon being deleted.
*/
- public Workspace deleteAppIcon(AppIcon appIcon) {
+ public Workspace deleteAppIcon(HomeAppIcon homeAppIcon) {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"removing app icon from workspace")) {
dragIconToWorkspace(
- mLauncher, appIcon,
+ mLauncher, homeAppIcon,
() -> getDropPointFromDropTargetBar(mLauncher, DELETE_TARGET_TEXT_ID),
true, /* decelerating */
- appIcon.getLongPressIndicator(),
+ homeAppIcon.getLongPressIndicator(),
() -> mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT),
null);
@@ -267,21 +261,23 @@
/**
* Uninstall the appIcon by dragging it to the 'uninstall' drop point of the drop_target_bar.
*
+ * @param launcher the root TAPL instrumentation object of {@link LauncherInstrumentation} type.
+ * @param homeAppIcon to be uninstalled.
* @param launcher the root TAPL instrumentation object of {@link
* LauncherInstrumentation} type.
- * @param appIcon to be uninstalled.
+ * @param homeAppIcon to be uninstalled.
* @param expectLongClickEvents the runnable to be executed to verify expected longclick event.
* @return validated workspace after the existing appIcon being uninstalled.
*/
- static Workspace uninstallAppIcon(LauncherInstrumentation launcher, AppIcon appIcon,
+ static Workspace uninstallAppIcon(LauncherInstrumentation launcher, HomeAppIcon homeAppIcon,
Runnable expectLongClickEvents) {
try (LauncherInstrumentation.Closable c = launcher.addContextLayer(
"uninstalling app icon")) {
dragIconToWorkspace(
- launcher, appIcon,
+ launcher, homeAppIcon,
() -> getDropPointFromDropTargetBar(launcher, UNINSTALL_TARGET_TEXT_ID),
true, /* decelerating */
- appIcon.getLongPressIndicator(),
+ homeAppIcon.getLongPressIndicator(),
expectLongClickEvents,
null);
@@ -334,31 +330,6 @@
o -> new FolderIcon(mLauncher, o)).collect(Collectors.toList());
}
- /**
- * Drag an icon up with a short distance that makes workspace go to spring loaded state.
- *
- * @return the position after dragging.
- */
- private static Point dragIconToSpringLoaded(LauncherInstrumentation launcher, long downTime,
- UiObject2 icon,
- String longPressIndicator, Runnable expectLongClickEvents) {
- final Point iconCenter = icon.getVisibleCenter();
- final Point dragStartCenter = new Point(iconCenter.x,
- iconCenter.y - getStartDragThreshold(launcher));
-
- launcher.runToState(() -> {
- launcher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
- iconCenter, LauncherInstrumentation.GestureScope.INSIDE);
- LauncherInstrumentation.log("dragIconToSpringLoaded: sent down");
- expectLongClickEvents.run();
- launcher.waitForLauncherObject(longPressIndicator);
- LauncherInstrumentation.log("dragIconToSpringLoaded: indicator");
- launcher.movePointer(iconCenter, dragStartCenter, DEFAULT_DRAG_STEPS, false,
- downTime, true, LauncherInstrumentation.GestureScope.INSIDE);
- }, SPRING_LOADED_STATE_ORDINAL, "long-pressing and triggering drag start");
- return dragStartCenter;
- }
-
private static void dropDraggedIcon(LauncherInstrumentation launcher, Point dest, long downTime,
@Nullable Runnable expectedEvents) {
launcher.runToState(
@@ -403,8 +374,11 @@
try (LauncherInstrumentation.Closable ignored = launcher.addContextLayer(
"want to drag icon to workspace")) {
final long downTime = SystemClock.uptimeMillis();
- Point dragStart = dragIconToSpringLoaded(launcher, downTime,
- launchable.getObject(), longPressIndicator, expectLongClickEvents);
+ Point dragStart = launchable.startDrag(
+ downTime,
+ longPressIndicator,
+ expectLongClickEvents,
+ /* runToSpringLoadedState= */ true);
Point targetDest = dest.get();
int displayX = launcher.getRealDisplaySize().x;
diff --git a/tests/tapl/com/android/launcher3/tapl/WorkspaceAppIcon.java b/tests/tapl/com/android/launcher3/tapl/WorkspaceAppIcon.java
index 0523a63..114e6a5 100644
--- a/tests/tapl/com/android/launcher3/tapl/WorkspaceAppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/WorkspaceAppIcon.java
@@ -25,7 +25,7 @@
/**
* App icon in workspace.
*/
-final class WorkspaceAppIcon extends AppIcon {
+final class WorkspaceAppIcon extends HomeAppIcon {
WorkspaceAppIcon(LauncherInstrumentation launcher, UiObject2 icon) {
super(launcher, icon);
diff --git a/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java b/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
new file mode 100644
index 0000000..93c2213
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
@@ -0,0 +1,53 @@
+/*
+ * 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.launcher3.tapl;
+
+import android.graphics.Point;
+
+/** Launchable that can serve as a source for dragging and dropping to the workspace. */
+interface WorkspaceDragSource {
+
+ /**
+ * Drags an object to the center of homescreen.
+ *
+ * @param startsActivity whether it's expected to start an activity.
+ * @param isWidgetShortcut whether we drag a widget shortcut
+ */
+ default void dragToWorkspace(boolean startsActivity, boolean isWidgetShortcut) {
+ Launchable launchable = getLaunchable();
+ LauncherInstrumentation launcher = launchable.mLauncher;
+ try (LauncherInstrumentation.Closable e = launcher.eventsCheck()) {
+ final Point launchableCenter = launchable.getObject().getVisibleCenter();
+ final Point displaySize = launcher.getRealDisplaySize();
+ final int width = displaySize.x / 2;
+ Workspace.dragIconToWorkspace(
+ launcher,
+ launchable,
+ new Point(
+ launchableCenter.x >= width
+ ? launchableCenter.x - width / 2
+ : launchableCenter.x + width / 2,
+ displaySize.y / 2),
+ launchable.getLongPressIndicator(),
+ startsActivity,
+ isWidgetShortcut,
+ launchable::addExpectedEventsForLongClick);
+ }
+ }
+
+ /** This method requires public access, however should not be called in tests. */
+ Launchable getLaunchable();
+}