Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 0d6c664..596802f 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -24,7 +24,7 @@
<string name="recents_empty_message" msgid="7040467240571714191">"Ez dago azkenaldi honetako ezer"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Aplikazioen erabileraren ezarpenak"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Garbitu guztiak"</string>
- <string name="accessibility_recent_apps" msgid="4058661986695117371">"Azken aplikazioak"</string>
+ <string name="accessibility_recent_apps" msgid="4058661986695117371">"Azkenaldiko aplikazioak"</string>
<string name="task_view_closed" msgid="9170038230110856166">"Itxi da zeregina"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g> (<xliff:g id="REMAINING_TIME">%2$s</xliff:g>)"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 42e6809..00a282a 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -15,8 +15,10 @@
*/
package com.android.launcher3.statehandlers;
+import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import android.os.Debug;
import android.os.SystemProperties;
import android.util.Log;
import android.view.View;
@@ -46,6 +48,7 @@
private boolean mFreeformTasksVisible;
private boolean mInOverviewState;
+ private boolean mBackgroundStateEnabled;
private boolean mGestureInProgress;
@Nullable
@@ -113,7 +116,11 @@
* Whether freeform windows are visible in desktop mode.
*/
public boolean areFreeformTasksVisible() {
- return mFreeformTasksVisible;
+ if (DEBUG) {
+ Log.d(TAG, "areFreeformTasksVisible: freeformVisible=" + mFreeformTasksVisible
+ + " overview=" + mInOverviewState);
+ }
+ return mFreeformTasksVisible && !mInOverviewState;
}
/**
@@ -121,7 +128,8 @@
*/
public void setFreeformTasksVisible(boolean freeformTasksVisible) {
if (DEBUG) {
- Log.d(TAG, "setFreeformTasksVisible: visible=" + freeformTasksVisible);
+ Log.d(TAG, "setFreeformTasksVisible: visible=" + freeformTasksVisible
+ + " currentValue=" + mFreeformTasksVisible);
}
if (!isDesktopModeSupported()) {
return;
@@ -146,11 +154,21 @@
}
/**
- * Sets whether the overview is visible and updates launcher visibility based on that.
+ * Process launcher state change and update launcher view visibility based on desktop state
*/
- public void setOverviewStateEnabled(boolean overviewStateEnabled) {
+ public void onLauncherStateChanged(LauncherState state) {
if (DEBUG) {
- Log.d(TAG, "setOverviewStateEnabled: enabled=" + overviewStateEnabled);
+ Log.d(TAG, "onLauncherStateChanged: newState=" + state);
+ }
+ setBackgroundStateEnabled(state == BACKGROUND_APP);
+ // Desktop visibility tracks overview and background state separately
+ setOverviewStateEnabled(state != BACKGROUND_APP && state.overviewUi);
+ }
+
+ private void setOverviewStateEnabled(boolean overviewStateEnabled) {
+ if (DEBUG) {
+ Log.d(TAG, "setOverviewStateEnabled: enabled=" + overviewStateEnabled
+ + " currentValue=" + mInOverviewState);
}
if (!isDesktopModeSupported()) {
return;
@@ -160,7 +178,7 @@
if (mInOverviewState) {
setLauncherViewsVisibility(View.VISIBLE);
markLauncherResumed();
- } else if (mFreeformTasksVisible && !mGestureInProgress) {
+ } else if (areFreeformTasksVisible() && !mGestureInProgress) {
// Switching out of overview state and gesture finished.
// If freeform tasks are still visible, hide launcher again.
setLauncherViewsVisibility(View.INVISIBLE);
@@ -169,6 +187,27 @@
}
}
+ private void setBackgroundStateEnabled(boolean backgroundStateEnabled) {
+ if (DEBUG) {
+ Log.d(TAG, "setBackgroundStateEnabled: enabled=" + backgroundStateEnabled
+ + " currentValue=" + mBackgroundStateEnabled);
+ }
+ if (!isDesktopModeSupported()) {
+ return;
+ }
+ if (backgroundStateEnabled != mBackgroundStateEnabled) {
+ mBackgroundStateEnabled = backgroundStateEnabled;
+ if (mBackgroundStateEnabled) {
+ setLauncherViewsVisibility(View.VISIBLE);
+ markLauncherResumed();
+ } else if (areFreeformTasksVisible() && !mGestureInProgress) {
+ // Switching out of background state. If freeform tasks are visible, pause launcher.
+ setLauncherViewsVisibility(View.INVISIBLE);
+ markLauncherPaused();
+ }
+ }
+ }
+
/**
* Whether recents gesture is currently in progress.
*/
@@ -183,6 +222,9 @@
if (!isDesktopModeSupported()) {
return;
}
+ if (DEBUG) {
+ Log.d(TAG, "setRecentsGestureStart");
+ }
setRecentsGestureInProgress(true);
}
@@ -194,6 +236,9 @@
if (!isDesktopModeSupported()) {
return;
}
+ if (DEBUG) {
+ Log.d(TAG, "setRecentsGestureEnd: endTarget=" + endTarget);
+ }
setRecentsGestureInProgress(false);
if (endTarget == null) {
@@ -203,9 +248,6 @@
}
private void setRecentsGestureInProgress(boolean gestureInProgress) {
- if (DEBUG) {
- Log.d(TAG, "setGestureInProgress: inProgress=" + gestureInProgress);
- }
if (gestureInProgress != mGestureInProgress) {
mGestureInProgress = gestureInProgress;
}
@@ -222,7 +264,8 @@
private void setLauncherViewsVisibility(int visibility) {
if (DEBUG) {
- Log.d(TAG, "setLauncherViewsVisibility: visibility=" + visibility);
+ Log.d(TAG, "setLauncherViewsVisibility: visibility=" + visibility + " "
+ + Debug.getCaller());
}
View workspaceView = mLauncher.getWorkspace();
if (workspaceView != null) {
@@ -236,7 +279,7 @@
private void markLauncherPaused() {
if (DEBUG) {
- Log.d(TAG, "markLauncherPaused");
+ Log.d(TAG, "markLauncherPaused " + Debug.getCaller());
}
StatefulActivity<LauncherState> activity =
QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
@@ -247,7 +290,7 @@
private void markLauncherResumed() {
if (DEBUG) {
- Log.d(TAG, "markLauncherResumed");
+ Log.d(TAG, "markLauncherResumed " + Debug.getCaller());
}
StatefulActivity<LauncherState> activity =
QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index c4255bf..afefe42 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -107,14 +107,17 @@
mControllers = controllers;
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
Resources resources = mActivity.getResources();
+ final int stashedTaskbarHeight;
if (isPhoneGestureNavMode(mActivity.getDeviceProfile())) {
mTaskbarSize = resources.getDimensionPixelSize(R.dimen.taskbar_size);
mStashedHandleWidth =
resources.getDimensionPixelSize(R.dimen.taskbar_stashed_small_screen);
+ stashedTaskbarHeight = resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
} else {
mTaskbarSize = deviceProfile.taskbarHeight;
mStashedHandleWidth = resources
.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width);
+ stashedTaskbarHeight = mControllers.taskbarStashController.getStashedHeight();
}
int taskbarBottomMargin = deviceProfile.taskbarBottomMargin;
mStashedHandleView.getLayoutParams().height = mTaskbarSize + taskbarBottomMargin;
@@ -123,7 +126,6 @@
isPhoneGestureNavMode(deviceProfile) ? 1 : 0);
mTaskbarStashedHandleHintScale.updateValue(1f);
- final int stashedTaskbarHeight = mControllers.taskbarStashController.getStashedHeight();
mStashedHandleView.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 9f8f82a..d4faf47 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -27,6 +27,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY;
import static com.android.launcher3.Utilities.isRunningInTestHarness;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_PINNING;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NO_RECREATION;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
@@ -843,9 +844,17 @@
return getSetupWindowHeight();
}
- if (DisplayController.isTransientTaskbar(this)) {
- return mDeviceProfile.taskbarHeight
- + (2 * mDeviceProfile.taskbarBottomMargin)
+ boolean shouldTreatAsTransient = DisplayController.isTransientTaskbar(this)
+ || (ENABLE_TASKBAR_PINNING.get() && !isThreeButtonNav());
+
+ // Return transient taskbar window height when pinning feature is enabled, so taskbar view
+ // does not get cut off during pinning animation.
+ if (shouldTreatAsTransient) {
+ DeviceProfile transientTaskbarDp = mDeviceProfile.toBuilder(this)
+ .setIsTransientTaskbar(true).build();
+
+ return transientTaskbarDp.taskbarHeight
+ + (2 * transientTaskbarDp.taskbarBottomMargin)
+ resources.getDimensionPixelSize(R.dimen.transient_taskbar_shadow_blur);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 4ad5c88..6ddf9e9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -21,6 +21,8 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION;
+import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.EXTENDED_CONTAINERS;
+import static com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers.ContainerCase.DEVICE_SEARCH_RESULT_CONTAINER;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -64,6 +66,7 @@
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.graphics.DragPreviewProvider;
+import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -626,7 +629,9 @@
if (tag instanceof ItemInfo) {
ItemInfo item = (ItemInfo) tag;
- if (item.container == CONTAINER_ALL_APPS || item.container == CONTAINER_PREDICTION) {
+ if (item.container == CONTAINER_ALL_APPS
+ || item.container == CONTAINER_PREDICTION
+ || isInSearchResultContainer(item)) {
if (mDisallowGlobalDrag) {
// We're dragging in taskbarAllApps, we don't have folders or shortcuts
return iconView;
@@ -648,6 +653,13 @@
return iconView;
}
+ private static boolean isInSearchResultContainer(ItemInfo item) {
+ ContainerInfo containerInfo = item.getContainerInfo();
+ return containerInfo.getContainerCase() == EXTENDED_CONTAINERS
+ && containerInfo.getExtendedContainers().getContainerCase()
+ == DEVICE_SEARCH_RESULT_CONTAINER;
+ }
+
private void setupReturnDragAnimator(float fromX, float fromY, View originalView,
TaskbarReturnPropertiesListener animListener) {
// Finish any pending return animation before starting a new return
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 88ae349..3bfeee8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -45,6 +45,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
@@ -209,7 +210,10 @@
updateStateForFlag(FLAG_RESUMED, true);
}
applyState();
- boolean disallowLongClick = finalState == LauncherState.OVERVIEW_SPLIT_SELECT;
+ boolean disallowLongClick =
+ FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()
+ ? mLauncher.isSplitSelectionEnabled()
+ : finalState == LauncherState.OVERVIEW_SPLIT_SELECT;
com.android.launcher3.taskbar.Utilities.setOverviewDragState(
mControllers, finalState.disallowTaskbarGlobalDrag(),
disallowLongClick, finalState.allowTaskbarInitialSplitSelection());
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index b405320..858141a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -458,7 +458,7 @@
*/
private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp) {
PendingAnimation setter = new PendingAnimation(100);
- if (TaskbarManager.isPhoneButtonNavMode(mActivity)) {
+ if (TaskbarManager.isPhoneMode(launcherDp)) {
// No animation for icons in small-screen
return setter.createPlaybackController();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
index 5182a32..07d86e4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
@@ -158,10 +158,6 @@
if (mAppsView != null) {
return;
}
- // mControllers and getSharedState should never be null here. Do not handle null-pointer
- // to catch invalid states.
- mControllers.getSharedState().allAppsVisible = true;
-
mOverlayContext = mControllers.taskbarOverlayController.requestWindow();
// Initialize search session for All Apps.
@@ -178,10 +174,7 @@
// Ensures All Apps gets touch events in case it is not the top floating view. Floating
// views above it may not be able to intercept the touch, so All Apps should try to.
mOverlayContext.getDragLayer().addTouchController(mSlideInView);
- mSlideInView.addOnCloseListener(() -> {
- mControllers.getSharedState().allAppsVisible = false;
- cleanUpOverlay();
- });
+ mSlideInView.addOnCloseListener(this::cleanUpOverlay);
TaskbarAllAppsViewController viewController = new TaskbarAllAppsViewController(
mOverlayContext,
mSlideInView,
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index 6d740c0..cf5fd59 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -18,17 +18,22 @@
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_TASKBAR_ALL_APPS;
import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.allapps.AllAppsTransitionListener;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.appprediction.AppsDividerView;
import com.android.launcher3.taskbar.NavbarButtonsViewController;
import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.launcher3.taskbar.TaskbarSharedState;
import com.android.launcher3.taskbar.TaskbarStashController;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
import com.android.launcher3.util.DisplayController;
+import java.util.Optional;
+
/**
* Handles the {@link TaskbarAllAppsContainerView} behavior and synchronizes its transitions with
* taskbar stashing.
@@ -41,6 +46,7 @@
private final TaskbarStashController mTaskbarStashController;
private final NavbarButtonsViewController mNavbarButtonsViewController;
private final TaskbarOverlayController mOverlayController;
+ private final @Nullable TaskbarSharedState mTaskbarSharedState;
private final boolean mShowKeyboard;
TaskbarAllAppsViewController(
@@ -56,6 +62,7 @@
mTaskbarStashController = taskbarControllers.taskbarStashController;
mNavbarButtonsViewController = taskbarControllers.navbarButtonsViewController;
mOverlayController = taskbarControllers.taskbarOverlayController;
+ mTaskbarSharedState = taskbarControllers.getSharedState();
mShowKeyboard = showKeyboard;
mSlideInView.init(new TaskbarAllAppsCallbacks(searchSessionController));
@@ -87,8 +94,10 @@
mTaskbarStashController.applyState();
}
+ Optional.ofNullable(mTaskbarSharedState).ifPresent(s -> s.allAppsVisible = true);
mNavbarButtonsViewController.setSlideInViewVisible(true);
mSlideInView.setOnCloseBeginListener(() -> {
+ Optional.ofNullable(mTaskbarSharedState).ifPresent(s -> s.allAppsVisible = false);
mNavbarButtonsViewController.setSlideInViewVisible(false);
AbstractFloatingView.closeOpenContainer(
mContext, AbstractFloatingView.TYPE_ACTION_POPUP);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 289041a..a71333a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -689,7 +689,7 @@
}
@Override
- protected boolean isSplitSelectionEnabled() {
+ public boolean isSplitSelectionEnabled() {
return mSplitSelectStateController.isSplitSelectActive();
}
@@ -987,6 +987,13 @@
.playPlaceholderDismissAnim(this);
}
+ @Override
+ public void dismissSplitSelection() {
+ super.dismissSplitSelection();
+ mSplitSelectStateController.getSplitAnimationController()
+ .playPlaceholderDismissAnim(this);
+ }
+
public <T extends OverviewActionsView> T getActionsView() {
return (T) mActionsView;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
index 1d55da3..3e7d45e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
@@ -21,9 +21,9 @@
import android.graphics.Rect;
import com.android.launcher3.BaseDraggingActivity;
-import com.android.launcher3.Flags;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.config.FeatureFlags;
import com.android.quickstep.views.RecentsView;
/**
@@ -72,7 +72,7 @@
@Override
public boolean isTaskbarStashed(Launcher launcher) {
- if (Flags.enableGridOnlyOverview()) {
+ if (FeatureFlags.enableGridOnlyOverview()) {
return true;
}
return super.isTaskbarStashed(launcher);
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index e788cc4..4dfa81d 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -2084,18 +2084,9 @@
}
private void finishCurrentTransitionToRecents() {
- if (mRecentsView != null
- && mActivityInterface.getDesktopVisibilityController() != null
- && mActivityInterface.getDesktopVisibilityController().areFreeformTasksVisible()) {
- mRecentsView.switchToScreenshot(() -> {
- mRecentsView.finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
- () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
- });
- } else {
- mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
- if (mRecentsAnimationController != null) {
- mRecentsAnimationController.detachNavigationBarFromApp(true);
- }
+ mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
+ if (mRecentsAnimationController != null) {
+ mRecentsAnimationController.detachNavigationBarFromApp(true);
}
}
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 25389c5..8925bd6 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -50,10 +50,10 @@
import androidx.annotation.UiThread;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.BaseState;
@@ -242,7 +242,7 @@
public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect,
PagedOrientationHandler orientedState) {
if (dp.isTablet) {
- if (Flags.enableGridOnlyOverview()) {
+ if (FeatureFlags.enableGridOnlyOverview()) {
calculateGridTaskSize(context, dp, outRect, orientedState);
} else {
calculateFocusTaskSize(context, dp, outRect);
@@ -339,7 +339,7 @@
PagedOrientationHandler orientedState) {
Resources res = context.getResources();
Rect potentialTaskRect = new Rect();
- if (Flags.enableGridOnlyOverview()) {
+ if (FeatureFlags.enableGridOnlyOverview()) {
calculateGridSize(dp, potentialTaskRect);
} else {
calculateFocusTaskSize(context, dp, potentialTaskRect);
@@ -371,7 +371,7 @@
public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect,
PagedOrientationHandler orientedState) {
calculateTaskSize(context, dp, outRect, orientedState);
- boolean isGridOnlyOverview = dp.isTablet && Flags.enableGridOnlyOverview();
+ boolean isGridOnlyOverview = dp.isTablet && FeatureFlags.enableGridOnlyOverview();
int claimedSpaceBelow = isGridOnlyOverview
? dp.overviewActionsTopMarginPx + dp.overviewActionsHeight + dp.stashedTaskbarHeight
: (dp.heightPx - outRect.bottom - dp.getInsets().bottom);
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index 23def14..f898e2f 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -126,4 +126,14 @@
}
return name.toString();
}
+
+ /**
+ * Returns an input consumer of the given class type, or null if none is found.
+ */
+ default <T extends InputConsumer> T getInputConsumerOfClass(Class<T> c) {
+ if (getClass().equals(c)) {
+ return c.cast(this);
+ }
+ return null;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 3d332c2..5d26ec0 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -115,7 +115,8 @@
/* extras= */ 0,
/* gestureEvent= */ ON_START_RECENTS_ANIMATION);
notifyAnimationCanceled();
- animationController.finish(false /* toHome */, false /* sendUserLeaveHint */);
+ animationController.finish(false /* toHome */, false /* sendUserLeaveHint */,
+ null /* finishCb */);
return;
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 8972dc8..341e18c 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -21,6 +21,7 @@
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FINISH_RECENTS_ANIMATION;
import android.content.Context;
+import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.IRecentsAnimationController;
@@ -32,6 +33,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
+import com.android.internal.os.IResultReceiver;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.RunnableList;
import com.android.quickstep.util.ActiveGestureErrorDetector;
@@ -172,12 +174,19 @@
mFinishTargetIsLauncher = toRecents;
mOnFinishedListener.accept(this);
Runnable finishCb = () -> {
- mController.finish(toRecents, sendUserLeaveHint);
+ mController.finish(toRecents, sendUserLeaveHint, new IResultReceiver.Stub() {
+ @Override
+ public void send(int i, Bundle bundle) throws RemoteException {
+ ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation-callback");
+ MAIN_EXECUTOR.execute(() -> {
+ mPendingFinishCallbacks.executeAllAndDestroy();
+ });
+ }
+ });
InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
InteractionJankMonitorWrapper.end(
InteractionJankMonitorWrapper.CUJ_APP_SWIPE_TO_RECENTS);
- MAIN_EXECUTOR.execute(mPendingFinishCallbacks::executeAllAndDestroy);
};
if (forceFinish) {
finishCb.run();
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 1448a52..3fdc7ba 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -66,6 +66,7 @@
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.SettingsCache;
import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
+import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.NavBarPosition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
@@ -239,6 +240,7 @@
public void onDisplayInfoChanged(Context context, Info info, int flags) {
if ((flags & (CHANGE_ROTATION | CHANGE_NAVIGATION_MODE)) != 0) {
mMode = info.navigationMode;
+ ActiveGestureLog.INSTANCE.setIsFullyGesturalNavMode(isFullyGesturalNavMode());
mNavBarPosition = new NavBarPosition(mMode, info);
if (mMode == NO_BUTTON) {
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index e358a8e..073dea0 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -17,7 +17,7 @@
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
-import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.launcher3.config.FeatureFlags.enableGridOnlyOverview;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
@@ -78,6 +78,8 @@
private final TaskThumbnailCache mThumbnailCache;
private final ComponentCallbacks mCallbacks;
+ private final TaskStackChangeListeners mTaskStackChangeListeners;
+
private RecentsModel(Context context) {
this(context, new IconProvider(context));
}
@@ -89,13 +91,14 @@
SystemUiProxy.INSTANCE.get(context)),
new TaskIconCache(context, RECENTS_MODEL_EXECUTOR, iconProvider),
new TaskThumbnailCache(context, RECENTS_MODEL_EXECUTOR),
- iconProvider);
+ iconProvider,
+ TaskStackChangeListeners.getInstance());
}
@VisibleForTesting
RecentsModel(Context context, RecentTasksList taskList, TaskIconCache iconCache,
- TaskThumbnailCache thumbnailCache,
- IconProvider iconProvider) {
+ TaskThumbnailCache thumbnailCache, IconProvider iconProvider,
+ TaskStackChangeListeners taskStackChangeListeners) {
mContext = context;
mTaskList = taskList;
mIconCache = iconCache;
@@ -117,7 +120,8 @@
mCallbacks = null;
}
- TaskStackChangeListeners.getInstance().registerTaskStackListener(this);
+ mTaskStackChangeListeners = taskStackChangeListeners;
+ mTaskStackChangeListeners.registerTaskStackListener(this);
iconProvider.registerIconChangeListener(this, MAIN_EXECUTOR.getHandler());
}
@@ -358,6 +362,8 @@
if (mCallbacks != null) {
mContext.unregisterComponentCallbacks(mCallbacks);
}
+ mIconCache.removeTaskVisualsChangeListener();
+ mTaskStackChangeListeners.unregisterTaskStackListener(this);
}
/**
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index f5a7ecc..4b47209 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -42,7 +42,6 @@
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
import com.android.quickstep.util.ActiveGestureLog;
-import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -119,7 +118,8 @@
}
}
// But force-finish it anyways
- finishRunningRecentsAnimation(false /* toHome */, true /* forceFinish */);
+ finishRunningRecentsAnimation(false /* toHome */, true /* forceFinish */,
+ null /* forceFinishCb */);
if (mCallbacks != null) {
// If mCallbacks still != null, that means we are getting this startRecentsAnimation()
@@ -261,12 +261,6 @@
// to let the transition controller collect Home activity.
CachedTaskInfo cti = gestureState.getRunningTask();
boolean homeIsOnTop = cti != null && cti.isHomeTask();
- if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
- if (cti != null && cti.isFreeformTask()) {
- // No transient launch when desktop task is on top
- homeIsOnTop = true;
- }
- }
if (activityInterface.allowAllAppsFromOverview()) {
homeIsOnTop = true;
}
@@ -325,19 +319,20 @@
* Finishes the running recents animation.
*/
public void finishRunningRecentsAnimation(boolean toHome) {
- finishRunningRecentsAnimation(toHome, false /* forceFinish */);
+ finishRunningRecentsAnimation(toHome, false /* forceFinish */, null /* forceFinishCb */);
}
/**
* Finishes the running recents animation.
* @param forceFinish will synchronously finish the controller
*/
- public void finishRunningRecentsAnimation(boolean toHome, boolean forceFinish) {
+ public void finishRunningRecentsAnimation(boolean toHome, boolean forceFinish,
+ Runnable forceFinishCb) {
if (mController != null) {
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "finishRunningRecentsAnimation", toHome);
if (forceFinish) {
- mController.finishController(toHome, null, false /* sendUserLeaveHint */,
+ mController.finishController(toHome, forceFinishCb, false /* sendUserLeaveHint */,
true /* forceFinish */);
} else {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), toHome
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 7d03d77..bd3ccb7 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -34,8 +34,8 @@
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
-import com.android.launcher3.Flags;
import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut;
@@ -80,7 +80,7 @@
boolean isInLandscape = orientedState.getTouchRotation() != ROTATION_0;
boolean isTablet = activity.getDeviceProfile().isTablet;
- boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
+ boolean isGridOnlyOverview = isTablet && FeatureFlags.enableGridOnlyOverview();
// Add overview actions to the menu when in in-place rotate landscape mode, or in
// grid-only overview.
if ((!canLauncherRotate && isInLandscape) || isGridOnlyOverview) {
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
index e5fca4b..2ca9f99 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
@@ -15,7 +15,7 @@
*/
package com.android.quickstep;
-import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.launcher3.config.FeatureFlags.enableGridOnlyOverview;
import android.content.Context;
import android.content.res.Resources;
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java
index 63771f0..5557639 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java
@@ -48,6 +48,14 @@
*/
protected abstract String getDelegatorName();
+ @Override
+ public <T extends InputConsumer> T getInputConsumerOfClass(Class<T> c) {
+ if (getClass().equals(c)) {
+ return c.cast(this);
+ }
+ return mDelegate.getInputConsumerOfClass(c);
+ }
+
protected void setActive(MotionEvent ev) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(getDelegatorName())
.append(" became active"));
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index addcfb8..fc3f3ab 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -52,9 +52,15 @@
if (isInArea(motionEvent.getRawX())) {
Runnable longPressRunnable = mNavHandleLongPressHandler.getLongPressRunnable();
if (longPressRunnable != null) {
- setActive(motionEvent);
-
- MAIN_EXECUTOR.post(longPressRunnable);
+ OtherActivityInputConsumer oaic = getInputConsumerOfClass(
+ OtherActivityInputConsumer.class);
+ if (oaic != null) {
+ oaic.setForceFinishRecentsTransitionCallback(longPressRunnable);
+ setActive(motionEvent);
+ } else {
+ setActive(motionEvent);
+ MAIN_EXECUTOR.post(longPressRunnable);
+ }
}
}
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 7e61167..28c00eb 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -125,6 +125,9 @@
// Might be displacement in X or Y, depending on the direction we are swiping from the nav bar.
private float mStartDisplacement;
+ // The callback called upon finishing the recents transition if it was force-canceled
+ private Runnable mForceFinishRecentsTransitionCallback;
+
public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState,
boolean isDeferredDownTarget, Consumer<OtherActivityInputConsumer> onCompleteCallback,
@@ -444,7 +447,7 @@
// animateToProgress so we have to manually finish here. In the case of
// ACTION_CANCEL, someone else may be doing something so finish synchronously.
mTaskAnimationManager.finishRunningRecentsAnimation(false /* toHome */,
- isCanceled /* forceFinish */);
+ isCanceled /* forceFinish */, mForceFinishRecentsTransitionCallback);
} else {
// The animation hasn't started yet, so insert a replacement handler into the
// callbacks which immediately finishes the animation after it starts.
@@ -513,6 +516,14 @@
}
/**
+ * Sets a callback to be called when the recents transition is force-canceled by another input
+ * consumer being made active.
+ */
+ public void setForceFinishRecentsTransitionCallback(Runnable r) {
+ mForceFinishRecentsTransitionCallback = r;
+ }
+
+ /**
* A listener which just finishes the animation immediately after starting. Replaces
* AbsSwipeUpHandler if the gesture itself finishes before the animation even starts.
*/
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
index 3388642..7d3a860 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
@@ -21,7 +21,9 @@
import android.media.session.MediaSessionManager;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.View;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.Utilities;
@@ -52,6 +54,7 @@
private final boolean mStartingInActivityBounds;
private boolean mTargetHandledTouch;
private boolean mHasSetTouchModeForFirstDPadEvent;
+ private boolean mIsWaitingForAttachToWindow;
public OverviewInputConsumer(GestureState gestureState, T activity,
@Nullable InputMonitorCompat inputMonitor, boolean startingInActivityBounds) {
@@ -118,21 +121,47 @@
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (!mHasSetTouchModeForFirstDPadEvent) {
- // When Overview is launched via meta+tab or swipe up from an app, the touch
- // mode somehow is not changed to false by the Android framework. The subsequent
- // key events (e.g. DPAD_LEFT, DPAD_RIGHT) can only be dispatched to focused
- // views, while focus can only be requested in
- // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To
- // note, here we launch overview with live tile.
- mHasSetTouchModeForFirstDPadEvent = true;
- mActivity.getRootView().getViewRootImpl().touchModeChanged(false);
+ if (mHasSetTouchModeForFirstDPadEvent) {
+ break;
}
+ View viewRoot = mActivity.getRootView();
+ if (viewRoot.isAttachedToWindow()) {
+ setTouchModeChanged(viewRoot);
+ break;
+ }
+ if (mIsWaitingForAttachToWindow) {
+ break;
+ }
+ mIsWaitingForAttachToWindow = true;
+ viewRoot.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View view) {
+ view.removeOnAttachStateChangeListener(this);
+ mIsWaitingForAttachToWindow = false;
+ setTouchModeChanged(viewRoot);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View view) {
+ // Do nothing
+ }
+ });
break;
default:
break;
}
mActivity.dispatchKeyEvent(ev);
}
+
+ private void setTouchModeChanged(@NonNull View viewRoot) {
+ // When Overview is launched via meta+tab or swipe up from an app, the touch
+ // mode somehow is not changed to false by the Android framework. The
+ // subsequent key events (e.g. DPAD_LEFT, DPAD_RIGHT) can only be dispatched
+ // to focused views, while focus can only be requested in
+ // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To
+ // note, here we launch overview with live tile.
+ mHasSetTouchModeForFirstDPadEvent = true;
+ viewRoot.getViewRootImpl().touchModeChanged(false);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
index 20fa921..ee72144 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
@@ -74,6 +74,11 @@
@NonNull PrintWriter writer,
@NonNull ActiveGestureLog.EventLog eventLog) {
writer.println(prefix + "Error messages for gesture ID: " + eventLog.logId);
+ if (!eventLog.mIsFullyGesturalNavMode) {
+ writer.println(prefix
+ + "\tSkipping gesture error detection because gesture navigation not enabled");
+ return;
+ }
boolean errorDetected = false;
// Use a Set since the order is inherently checked in the loop.
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
index 7103e63..ca686ec 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
@@ -35,6 +35,8 @@
public static final ActiveGestureLog INSTANCE = new ActiveGestureLog();
+ private boolean mIsFullyGesturalNavMode;
+
/**
* NOTE: This value should be kept same as
* ActivityTaskManagerService#INTENT_EXTRA_LOG_TRACE_ID in platform
@@ -127,7 +129,7 @@
@Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
EventLog lastEventLog = logs[(nextIndex + logs.length - 1) % logs.length];
if (lastEventLog == null || mCurrentLogId != lastEventLog.logId) {
- EventLog eventLog = new EventLog(mCurrentLogId);
+ EventLog eventLog = new EventLog(mCurrentLogId, mIsFullyGesturalNavMode);
EventEntry eventEntry = new EventEntry();
eventEntry.update(type, event, extras, compoundString, gestureEvent);
@@ -214,6 +216,10 @@
return mCurrentLogId++;
}
+ public void setIsFullyGesturalNavMode(boolean isFullyGesturalNavMode) {
+ mIsFullyGesturalNavMode = isFullyGesturalNavMode;
+ }
+
/** Returns the current log ID. This should be used when a log trace is being reused. */
public int getLogId() {
return mCurrentLogId;
@@ -277,9 +283,11 @@
protected final List<EventEntry> eventEntries = new ArrayList<>();
protected final int logId;
+ protected final boolean mIsFullyGesturalNavMode;
- private EventLog(int logId) {
+ private EventLog(int logId, boolean isFullyGesturalNavMode) {
this.logId = logId;
+ mIsFullyGesturalNavMode = isFullyGesturalNavMode;
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index f67d7dc..45c63b2 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -118,7 +118,7 @@
private final Handler mHandler;
private final RecentsModel mRecentTasksModel;
@Nullable
- private final Runnable mActivityBackCallback;
+ private Runnable mActivityBackCallback;
private final SplitAnimationController mSplitAnimationController;
private final AppPairsController mAppPairsController;
private final SplitSelectDataHolder mSplitSelectDataHolder;
@@ -185,6 +185,7 @@
public void onDestroy() {
mContext = null;
+ mActivityBackCallback = null;
}
/**
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index fba847f..cfb4d0d 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -16,7 +16,7 @@
package com.android.quickstep.views;
-import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.launcher3.config.FeatureFlags.enableGridOnlyOverview;
import android.content.Context;
import android.util.AttributeSet;
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index dc6b5a2..9ff990e 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -18,7 +18,6 @@
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import android.content.Context;
@@ -41,7 +40,6 @@
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.desktop.DesktopRecentsTransitionController;
@@ -338,16 +336,18 @@
@Override
public RunnableList launchTaskAnimated() {
RunnableList endCallback = new RunnableList();
- endCallback.add(() -> Launcher.getLauncher(mActivity).getStateManager().goToState(NORMAL));
+ RecentsView recentsView = getRecentsView();
DesktopRecentsTransitionController recentsController =
- getRecentsView().getDesktopRecentsController();
+ recentsView.getDesktopRecentsController();
if (recentsController != null) {
recentsController.launchDesktopFromRecents(this, success -> {
endCallback.executeAllAndDestroy();
});
}
+ // Callbacks get run from recentsView for case when recents animation already running
+ recentsView.addSideTaskLaunchCallback(endCallback);
return endCallback;
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 1867fe9..fb9e640 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -137,16 +137,16 @@
@Override
public void onStateTransitionStart(LauncherState toState) {
setOverviewStateEnabled(toState.overviewUi);
- if (toState.overviewUi) {
- // If overview is enabled, we want to update at the start
- updateOverviewStateForDesktop(true);
- }
+
setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
setOverviewFullscreenEnabled(toState.getOverviewFullscreenProgress() == 1);
if (toState == OVERVIEW_MODAL_TASK) {
setOverviewSelectEnabled(true);
}
setFreezeViewVisibility(true);
+ if (mActivity.getDesktopVisibilityController() != null) {
+ mActivity.getDesktopVisibilityController().onLauncherStateChanged(toState);
+ }
}
@Override
@@ -167,11 +167,6 @@
runActionOnRemoteHandles(remoteTargetHandle ->
remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true));
}
-
- if (!finalState.overviewUi) {
- // If overview is disabled, we want to update at the end
- updateOverviewStateForDesktop(false);
- }
}
@Override
@@ -183,9 +178,6 @@
& CLEAR_ALL_BUTTON) != 0;
setDisallowScrollToClearAll(!hasClearAllButton);
}
- if (mActivity.getDesktopVisibilityController() != null) {
- mActivity.getDesktopVisibilityController().setOverviewStateEnabled(enabled);
- }
}
@Override
@@ -282,11 +274,4 @@
null /* transition */);
}
}
-
- private void updateOverviewStateForDesktop(boolean enabled) {
- DesktopVisibilityController controller = mActivity.getDesktopVisibilityController();
- if (controller != null) {
- controller.setOverviewStateEnabled(enabled);
- }
- }
}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 7f1d619..9141c99 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -29,9 +29,9 @@
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Flags;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiValueAlpha;
@@ -289,7 +289,7 @@
return 0;
}
- if (mDp.isTablet && Flags.enableGridOnlyOverview()) {
+ if (mDp.isTablet && FeatureFlags.enableGridOnlyOverview()) {
return mDp.stashedTaskbarHeight;
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 2aba4d0..4136a89 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -42,7 +42,7 @@
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
-import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.launcher3.config.FeatureFlags.enableGridOnlyOverview;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_ACTIONS_SPLIT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index df907e7..5298eea 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -77,7 +77,6 @@
import com.android.app.animation.Interpolators;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Flags;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -115,8 +114,6 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
-import kotlin.Unit;
-
import java.lang.annotation.Retention;
import java.util.Arrays;
import java.util.Collections;
@@ -125,6 +122,8 @@
import java.util.function.Consumer;
import java.util.stream.Stream;
+import kotlin.Unit;
+
/**
* A task in the Recents view.
*/
@@ -1146,7 +1145,7 @@
} else if (dp.isTablet) {
int alignedOptionIndex = 0;
if (getRecentsView().isOnGridBottomRow(menuContainer.getTaskView()) && dp.isLandscape) {
- if (Flags.enableGridOnlyOverview()) {
+ if (FeatureFlags.enableGridOnlyOverview()) {
// With no focused task, there is less available space below the tasks, so align
// the arrow to the third option in the menu.
alignedOptionIndex = 2;
diff --git a/quickstep/tests/src/com/android/quickstep/RecentsModelTest.java b/quickstep/tests/src/com/android/quickstep/RecentsModelTest.java
index 08e0898..c552d83 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentsModelTest.java
+++ b/quickstep/tests/src/com/android/quickstep/RecentsModelTest.java
@@ -42,6 +42,7 @@
import com.android.launcher3.icons.IconProvider;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import org.junit.After;
import org.junit.Before;
@@ -93,7 +94,7 @@
when(mThumbnailCache.isPreloadingEnabled()).thenReturn(true);
mRecentsModel = new RecentsModel(mContext, mTasksList, mock(TaskIconCache.class),
- mThumbnailCache, mock(IconProvider.class));
+ mThumbnailCache, mock(IconProvider.class), mock(TaskStackChangeListeners.class));
mResource = mock(Resources.class);
when(mResource.getInteger((R.integer.recentsThumbnailCacheSize))).thenReturn(3);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 3039261..e8f0447 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -82,8 +82,7 @@
@After
public void tearDown() {
- executeOnLauncher(launcher -> {
- if (launcher == null) return;
+ executeOnLauncherInTearDown(launcher -> {
RecentsView recentsView = launcher.getOverviewPanel();
recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(false);
});
@@ -213,6 +212,7 @@
@Test
+ @ScreenRecord // b/303329286
public void testOverviewActionsMenu_iconAppChipMenu() throws Exception {
try (AutoCloseable c = TestUtil.overrideFlag(ENABLE_OVERVIEW_ICON_MENU, true)) {
startTestAppsWithCheck();
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 37bd4f1..57163ff 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -250,6 +250,10 @@
<!-- Folder name format when folder has 4 or more items shown in preview-->
<string name="folder_name_format_overflow">Folder: <xliff:g id="name" example="Games">%1$s</xliff:g>, <xliff:g id="size" example="2">%2$d</xliff:g> or more items</string>
+ <!-- App pair accessibility -->
+ <!-- App pair name -->
+ <string name="app_pair_name_format">App pair: <xliff:g id="app1" example="Chrome">%1$s</xliff:g> and <xliff:g id="app2" example="YouTube">%2$s</xliff:g></string>
+
<!-- Strings for the customization mode -->
<!-- Text for wallpaper change button [CHAR LIMIT=30]-->
<string name="styles_wallpaper_button_text">Wallpaper & style</string>
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 7b0d71b..189db21 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -3,6 +3,7 @@
import static com.android.launcher3.CellLayout.SPRING_LOADED_PROGRESS;
import static com.android.launcher3.LauncherAnimUtils.LAYOUT_HEIGHT;
import static com.android.launcher3.LauncherAnimUtils.LAYOUT_WIDTH;
+import static com.android.launcher3.LauncherPrefs.RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_RESIZE_COMPLETED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_RESIZE_STARTED;
import static com.android.launcher3.views.BaseDragLayer.LAYOUT_X;
@@ -55,8 +56,6 @@
private static final float RESIZE_THRESHOLD = 0.66f;
private static final int RESIZE_TRANSITION_DURATION_MS = 150;
- private static final String KEY_RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN =
- "launcher.reconfigurable_widget_education_tip_seen";
private static final Rect sTmpRect = new Rect();
private static final Rect sTmpRect2 = new Rect();
@@ -276,9 +275,8 @@
if (!hasSeenReconfigurableWidgetEducationTip()) {
post(() -> {
if (showReconfigurableWidgetEducationTip() != null) {
- mLauncher.getSharedPrefs().edit()
- .putBoolean(KEY_RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN,
- true).apply();
+ LauncherPrefs.get(getContext()).put(
+ RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN, true);
}
});
}
@@ -872,8 +870,7 @@
}
private boolean hasSeenReconfigurableWidgetEducationTip() {
- return mLauncher.getSharedPrefs()
- .getBoolean(KEY_RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN, false)
+ return LauncherPrefs.get(getContext()).get(RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN)
|| Utilities.isRunningInTestHarness();
}
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index c96e22d..9a2193f 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -1772,7 +1772,7 @@
/** Gets the space that the overview actions will take, including bottom margin. */
public int getOverviewActionsClaimedSpace() {
- int overviewActionsSpace = isTablet && Flags.enableGridOnlyOverview()
+ int overviewActionsSpace = isTablet && FeatureFlags.enableGridOnlyOverview()
? 0
: (overviewActionsTopMarginPx + overviewActionsHeight);
return overviewActionsSpace + getOverviewActionsClaimedSpaceBelow();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 7a16e1f..919ad21 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -28,6 +28,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.BuildConfig.APPLICATION_ID;
+import static com.android.launcher3.BuildConfig.QSB_ON_FIRST_SCREEN;
import static com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY;
import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WIDGET_TRANSITION;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
@@ -44,7 +45,7 @@
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
-import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
@@ -236,7 +237,6 @@
import com.android.launcher3.widget.picker.WidgetsFullSheet;
import com.android.systemui.plugins.LauncherOverlayPlugin;
import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.plugins.shared.LauncherExterns;
import com.android.systemui.plugins.shared.LauncherOverlayManager;
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
@@ -258,7 +258,7 @@
* Default launcher application.
*/
public class Launcher extends StatefulActivity<LauncherState>
- implements LauncherExterns, Callbacks, InvariantDeviceProfile.OnIDPChangeListener,
+ implements Callbacks, InvariantDeviceProfile.OnIDPChangeListener,
PluginListener<LauncherOverlayPlugin> {
public static final String TAG = "Launcher";
@@ -426,6 +426,8 @@
private BaseSearchConfig mBaseSearchConfig;
private StartupLatencyLogger mStartupLatencyLogger;
private CellPosMapper mCellPosMapper = CellPosMapper.DEFAULT;
+ private boolean mIsFirstPagePinnedItemEnabled = QSB_ON_FIRST_SCREEN
+ && !ENABLE_SMARTSPACE_REMOVAL.get();
private final CannedAnimationCoordinator mAnimationCoordinator =
new CannedAnimationCoordinator(this);
@@ -693,7 +695,7 @@
@Override
public void onPluginConnected(LauncherOverlayPlugin overlayManager, Context context) {
- switchOverlay(() -> overlayManager.createOverlayManager(this, this));
+ switchOverlay(() -> overlayManager.createOverlayManager(this));
}
@Override
@@ -1318,7 +1320,9 @@
// Until the workspace is bound, ensure that we keep the wallpaper offset locked to the
// default state, otherwise we will update to the wrong offsets in RTL
mWorkspace.lockWallpaperToDefaultPage();
- mWorkspace.bindAndInitFirstWorkspaceScreen();
+ if (!ENABLE_SMARTSPACE_REMOVAL.get()) {
+ mWorkspace.bindAndInitFirstWorkspaceScreen();
+ }
mDragController.addDragListener(mWorkspace);
// Get the search/delete/uninstall bar
@@ -2159,15 +2163,22 @@
}
@Override
+ public void setIsFirstPagePinnedItemEnabled(boolean isFirstPagePinnedItemEnabled) {
+ mIsFirstPagePinnedItemEnabled = isFirstPagePinnedItemEnabled;
+ mWorkspace.bindAndInitFirstWorkspaceScreen();
+ }
+
+ @Override
public void bindScreens(IntArray orderedScreenIds) {
mWorkspace.mPageIndicator.setAreScreensBinding(true);
int firstScreenPosition = 0;
if ((FeatureFlags.QSB_ON_FIRST_SCREEN
+ && mIsFirstPagePinnedItemEnabled
&& !shouldShowFirstPageWidget())
&& orderedScreenIds.indexOf(FIRST_SCREEN_ID) != firstScreenPosition) {
orderedScreenIds.removeValue(FIRST_SCREEN_ID);
orderedScreenIds.add(firstScreenPosition, FIRST_SCREEN_ID);
- } else if ((!FeatureFlags.QSB_ON_FIRST_SCREEN
+ } else if (((!FeatureFlags.QSB_ON_FIRST_SCREEN && !mIsFirstPagePinnedItemEnabled)
|| shouldShowFirstPageWidget())
&& orderedScreenIds.isEmpty()) {
// If there are no screens, we need to have an empty screen
@@ -2218,6 +2229,7 @@
for (int i = 0; i < count; i++) {
int screenId = orderedScreenIds.get(i);
if (FeatureFlags.QSB_ON_FIRST_SCREEN
+ && mIsFirstPagePinnedItemEnabled
&& !shouldShowFirstPageWidget()
&& screenId == FIRST_SCREEN_ID) {
// No need to bind the first screen, as its always bound.
@@ -2958,7 +2970,7 @@
for (int j = 0; j < layout.getChildCount(); j++) {
Object tag = layout.getChildAt(j).getTag();
if (tag != null) {
- writer.println(prefix + " " + tag.toString());
+ writer.println(prefix + " " + tag);
}
}
}
@@ -2968,7 +2980,7 @@
for (int j = 0; j < layout.getChildCount(); j++) {
Object tag = layout.getChildAt(j).getTag();
if (tag != null) {
- writer.println(prefix + " " + tag.toString());
+ writer.println(prefix + " " + tag);
}
}
}
@@ -3098,11 +3110,16 @@
}
/** To be overridden by subclasses */
- protected boolean isSplitSelectionEnabled() {
+ public boolean isSplitSelectionEnabled() {
// Overridden
return false;
}
+ /** Call to dismiss the intermediary split selection state. */
+ public void dismissSplitSelection() {
+ // Overridden; move this into ActivityContext if necessary for Taskbar
+ }
+
@Override
public void returnToHomescreen() {
super.returnToHomescreen();
@@ -3234,7 +3251,6 @@
/**
* Call this after onCreate to set or clear overlay.
*/
- @Override
public void setLauncherOverlay(LauncherOverlay overlay) {
mWorkspace.setLauncherOverlay(overlay);
}
@@ -3342,16 +3358,10 @@
return mModelWriter;
}
- @Override
public SharedPreferences getSharedPrefs() {
return mSharedPrefs;
}
- @Override
- public SharedPreferences getDevicePrefs() {
- return LauncherPrefs.getDevicePrefs(this);
- }
-
public int getOrientation() {
return mOldConfig.orientation;
}
@@ -3406,6 +3416,10 @@
// Overridden
}
+ public boolean getIsFirstPagePinnedItemEnabled() {
+ return mIsFirstPagePinnedItemEnabled;
+ }
+
/**
* Returns the animation coordinator for playing one-off animations
*/
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 9db8c82..ab41a31 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -21,6 +21,8 @@
import static com.android.launcher3.LauncherPrefs.ICON_STATE;
import static com.android.launcher3.LauncherPrefs.THEMED_ICONS;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
+import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
@@ -123,6 +125,23 @@
.addUserEventListener(mModel::onUserEvent);
mOnTerminateCallback.add(userChangeListener::close);
+ if (ENABLE_SMARTSPACE_REMOVAL.get()) {
+ OnSharedPreferenceChangeListener firstPagePinnedItemListener =
+ new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(
+ SharedPreferences sharedPreferences, String key) {
+ if (SMARTSPACE_ON_HOME_SCREEN.equals(key)) {
+ mModel.forceReload();
+ }
+ }
+ };
+ LauncherPrefs.getPrefs(mContext).registerOnSharedPreferenceChangeListener(
+ firstPagePinnedItemListener);
+ mOnTerminateCallback.add(() -> LauncherPrefs.getPrefs(mContext)
+ .unregisterOnSharedPreferenceChangeListener(firstPagePinnedItemListener));
+ }
+
LockedUserState.get(context).runOnUserUnlocked(() -> {
CustomWidgetManager cwm = CustomWidgetManager.INSTANCE.get(mContext);
cwm.setWidgetRefreshCallback(mModel::refreshAndBindWidgetsAndShortcuts);
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 4db2fca..f2df230 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -24,7 +24,6 @@
import com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN
import com.android.launcher3.LauncherFiles.DEVICE_PREFERENCES_KEY
import com.android.launcher3.LauncherFiles.SHARED_PREFERENCES_KEY
-import com.android.launcher3.allapps.WorkProfileManager
import com.android.launcher3.model.DeviceGridState
import com.android.launcher3.pm.InstallSessionHelper
import com.android.launcher3.provider.RestoreDbTask
@@ -312,7 +311,7 @@
val THEMED_ICONS =
backedUpItem(Themes.KEY_THEMED_ICONS, false, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
@JvmField val PROMISE_ICON_IDS = backedUpItem(InstallSessionHelper.PROMISE_ICON_IDS, "")
- @JvmField val WORK_EDU_STEP = backedUpItem(WorkProfileManager.KEY_WORK_EDU_STEP, 0)
+ @JvmField val WORK_EDU_STEP = backedUpItem("showed_work_profile_edu", 0)
@JvmField
val WORKSPACE_SIZE =
backedUpItem(
@@ -380,6 +379,16 @@
encryptionType = EncryptionType.DEVICE_PROTECTED
)
+ // Preferences for widget configurations
+ @JvmField
+ val RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN =
+ backedUpItem("launcher.reconfigurable_widget_education_tip_seen", false)
+ @JvmField
+ val WIDGETS_EDUCATION_DIALOG_SEEN =
+ backedUpItem("launcher.widgets_education_dialog_seen", false)
+ @JvmField
+ val WIDGETS_EDUCATION_TIP_SEEN = backedUpItem("launcher.widgets_education_tip_seen", false)
+
@VisibleForTesting
@JvmStatic
fun <T> backedUpItem(
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index c20d602..eeb5fe0 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -28,6 +28,7 @@
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
@@ -596,18 +597,19 @@
* Initializes and binds the first page
*/
public void bindAndInitFirstWorkspaceScreen() {
- if (!FeatureFlags.QSB_ON_FIRST_SCREEN
+ if ((!FeatureFlags.QSB_ON_FIRST_SCREEN
+ || !mLauncher.getIsFirstPagePinnedItemEnabled())
|| shouldShowFirstPageWidget()) {
+ mFirstPagePinnedItem = null;
return;
}
// Add the first page
CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, getChildCount());
- // Always add a first page pinned widget on the first screen.
if (mFirstPagePinnedItem == null) {
// In transposed layout, we add the first page pinned widget in the Grid.
// As workspace does not touch the edges, we do not need a full
- // width first page pinned widget.
+ // width first page pinned item.
mFirstPagePinnedItem = LayoutInflater.from(getContext())
.inflate(R.layout.search_container_workspace, firstPage, false);
}
@@ -627,7 +629,7 @@
// transition animations competing with us changing the scroll when we add pages
disableLayoutTransitions();
- // Recycle the first page pinned widget
+ // Recycle the first page pinned item
if (mFirstPagePinnedItem != null) {
((ViewGroup) mFirstPagePinnedItem.getParent()).removeView(mFirstPagePinnedItem);
}
@@ -638,12 +640,14 @@
mScreenOrder.clear();
mWorkspaceScreens.clear();
+ // Ensure that the first page is always present
+ if (!ENABLE_SMARTSPACE_REMOVAL.get()) {
+ bindAndInitFirstWorkspaceScreen();
+ }
+
// Remove any deferred refresh callbacks
mLauncher.mHandler.removeCallbacksAndMessages(DeferredWidgetRefresh.class);
- // Ensure that the first page is always present
- bindAndInitFirstWorkspaceScreen();
-
// Re-enable the layout transitions
enableLayoutTransitions();
}
@@ -802,6 +806,13 @@
// and we store them as extra empty screens.
for (int i = 0; i < finalScreens.size(); i++) {
int screenId = finalScreens.keyAt(i);
+
+ // We don't want to remove the first screen even if it's empty because that's where
+ // first page pinned item would go if it gets turned back on.
+ if (ENABLE_SMARTSPACE_REMOVAL.get() && screenId == FIRST_SCREEN_ID) {
+ continue;
+ }
+
CellLayout screen = finalScreens.get(screenId);
mWorkspaceScreens.remove(screenId);
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index 05ed9ba..ac0e5a4 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -62,8 +62,6 @@
public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActivePageChangedListener {
private static final String TAG = "WorkProfileManager";
- public static final String KEY_WORK_EDU_STEP = "showed_work_profile_edu";
-
public static final int STATE_ENABLED = 1;
public static final int STATE_DISABLED = 2;
public static final int STATE_TRANSITION = 3;
diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java
index 1dc4ad2..8121245 100644
--- a/src/com/android/launcher3/apppairs/AppPairIcon.java
+++ b/src/com/android/launcher3/apppairs/AppPairIcon.java
@@ -17,7 +17,9 @@
package com.android.launcher3.apppairs;
import android.content.Context;
+import android.graphics.Canvas;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -26,6 +28,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.model.data.FolderInfo;
@@ -37,11 +40,41 @@
/**
* A {@link android.widget.FrameLayout} used to represent an app pair icon on the workspace.
+ * <br>
+ * The app pair icon is two parallel background rectangles with rounded corners. Icons of the two
+ * member apps are set into these rectangles.
*/
public class AppPairIcon extends FrameLayout implements DraggableView {
+ /**
+ * Design specs -- the below ratios are in relation to the size of a standard app icon.
+ */
+ private static final float OUTER_PADDING_SCALE = 1 / 30f;
+ private static final float INNER_PADDING_SCALE = 1 / 24f;
+ private static final float MEMBER_ICON_SCALE = 11 / 30f;
+ private static final float CENTER_CHANNEL_SCALE = 1 / 30f;
+ private static final float BIG_RADIUS_SCALE = 1 / 5f;
+ private static final float SMALL_RADIUS_SCALE = 1 / 15f;
+
+ // App pair icons are slightly smaller than regular icons, so we pad the icon by this much on
+ // each side.
+ float mOuterPadding;
+ // Inside of the icon, the two member apps are padded by this much.
+ float mInnerPadding;
+ // The two member apps have icons that are this big (in diameter).
+ float mMemberIconSize;
+ // The size of the center channel.
+ float mCenterChannelSize;
+ // The large outer radius of the background rectangles.
+ float mBigRadius;
+ // The small inner radius of the background rectangles.
+ float mSmallRadius;
+ // The app pairs icon appears differently in portrait and landscape.
+ boolean mIsLandscape;
private ActivityContext mActivity;
+ // A view that holds the app pair's title.
private BubbleTextView mAppPairName;
+ // The underlying ItemInfo that stores info about the app pair members, etc.
private FolderInfo mInfo;
public AppPairIcon(Context context, AttributeSet attrs) {
@@ -53,11 +86,11 @@
}
/**
- * Builds an AppPairIcon to be added to the Launcher
+ * Builds an AppPairIcon to be added to the Launcher.
*/
public static AppPairIcon inflateIcon(int resId, ActivityContext activity,
@Nullable ViewGroup group, FolderInfo appPairInfo) {
-
+ DeviceProfile grid = activity.getDeviceProfile();
LayoutInflater inflater = (group != null)
? LayoutInflater.from(group.getContext())
: activity.getLayoutInflater();
@@ -67,26 +100,114 @@
Collections.sort(appPairInfo.contents, Comparator.comparingInt(a -> a.rank));
icon.setClipToPadding(false);
- icon.mAppPairName = icon.findViewById(R.id.app_pair_icon_name);
-
- // TODO (jeremysim b/274189428): Replace this placeholder icon
- WorkspaceItemInfo placeholder = new WorkspaceItemInfo();
- placeholder.newIcon(icon.getContext());
- icon.mAppPairName.applyFromWorkspaceItem(placeholder);
-
- icon.mAppPairName.setText(appPairInfo.title);
-
icon.setTag(appPairInfo);
icon.setOnClickListener(activity.getItemOnClickListener());
icon.mInfo = appPairInfo;
icon.mActivity = activity;
+ // Set up app pair title
+ icon.mAppPairName = icon.findViewById(R.id.app_pair_icon_name);
+ icon.mAppPairName.setCompoundDrawablePadding(0);
+ FrameLayout.LayoutParams lp =
+ (FrameLayout.LayoutParams) icon.mAppPairName.getLayoutParams();
+ lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx;
+ icon.mAppPairName.setText(appPairInfo.title);
+
+ // Set up accessibility
+ icon.setContentDescription(icon.getAccessibilityTitle(
+ appPairInfo.contents.get(0).title, appPairInfo.contents.get(1).title));
icon.setAccessibilityDelegate(activity.getAccessibilityDelegate());
return icon;
}
@Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+
+ // Calculate device-specific measurements
+ DeviceProfile grid = mActivity.getDeviceProfile();
+ int defaultIconSize = grid.iconSizePx;
+ mOuterPadding = OUTER_PADDING_SCALE * defaultIconSize;
+ mInnerPadding = INNER_PADDING_SCALE * defaultIconSize;
+ mMemberIconSize = MEMBER_ICON_SCALE * defaultIconSize;
+ mCenterChannelSize = CENTER_CHANNEL_SCALE * defaultIconSize;
+ mBigRadius = BIG_RADIUS_SCALE * defaultIconSize;
+ mSmallRadius = SMALL_RADIUS_SCALE * defaultIconSize;
+ mIsLandscape = grid.isLandscape;
+
+ // Calculate drawable area position
+ float leftBound = (canvas.getWidth() / 2f) - (defaultIconSize / 2f);
+ float topBound = getPaddingTop();
+
+ // Prepare to draw app pair icon background
+ Drawable background = new AppPairIconBackground(getContext(), this);
+ background.setBounds(0, 0, defaultIconSize, defaultIconSize);
+
+ // Draw background
+ canvas.save();
+ canvas.translate(leftBound, topBound);
+ background.draw(canvas);
+ canvas.restore();
+
+ // Prepare to draw icons
+ WorkspaceItemInfo app1 = mInfo.contents.get(0);
+ WorkspaceItemInfo app2 = mInfo.contents.get(1);
+ Drawable app1Icon = app1.newIcon(getContext());
+ Drawable app2Icon = app2.newIcon(getContext());
+ app1Icon.setBounds(0, 0, defaultIconSize, defaultIconSize);
+ app2Icon.setBounds(0, 0, defaultIconSize, defaultIconSize);
+
+ // Draw first icon
+ canvas.save();
+ canvas.translate(leftBound, topBound);
+ // The app icons are placed differently depending on device orientation.
+ if (mIsLandscape) {
+ canvas.translate(
+ (defaultIconSize / 2f) - (mCenterChannelSize / 2f) - mInnerPadding
+ - mMemberIconSize,
+ (defaultIconSize / 2f) - (mMemberIconSize / 2f)
+ );
+ } else {
+ canvas.translate(
+ (defaultIconSize / 2f) - (mMemberIconSize / 2f),
+ (defaultIconSize / 2f) - (mCenterChannelSize / 2f) - mInnerPadding
+ - mMemberIconSize
+ );
+
+ }
+ canvas.scale(MEMBER_ICON_SCALE, MEMBER_ICON_SCALE);
+ app1Icon.draw(canvas);
+ canvas.restore();
+
+ // Draw second icon
+ canvas.save();
+ canvas.translate(leftBound, topBound);
+ // The app icons are placed differently depending on device orientation.
+ if (mIsLandscape) {
+ canvas.translate(
+ (defaultIconSize / 2f) + (mCenterChannelSize / 2f) + mInnerPadding,
+ (defaultIconSize / 2f) - (mMemberIconSize / 2f)
+ );
+ } else {
+ canvas.translate(
+ (defaultIconSize / 2f) - (mMemberIconSize / 2f),
+ (defaultIconSize / 2f) + (mCenterChannelSize / 2f) + mInnerPadding
+ );
+ }
+ canvas.scale(MEMBER_ICON_SCALE, MEMBER_ICON_SCALE);
+ app2Icon.draw(canvas);
+ canvas.restore();
+ }
+
+ /**
+ * Returns a formatted accessibility title for app pairs.
+ */
+ public String getAccessibilityTitle(CharSequence app1, CharSequence app2) {
+ return getContext().getString(R.string.app_pair_name_format, app1, app2);
+ }
+
+ @Override
public int getViewType() {
return DRAGGABLE_ICON;
}
diff --git a/src/com/android/launcher3/apppairs/AppPairIconBackground.java b/src/com/android/launcher3/apppairs/AppPairIconBackground.java
new file mode 100644
index 0000000..735c82f
--- /dev/null
+++ b/src/com/android/launcher3/apppairs/AppPairIconBackground.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2023 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.apppairs;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+
+import com.android.launcher3.R;
+
+/**
+ * A Drawable for the background behind the twin app icons (looks like two rectangles).
+ */
+class AppPairIconBackground extends Drawable {
+ // The icon that we will draw this background on.
+ private final AppPairIcon icon;
+ private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ /**
+ * Null values to use with
+ * {@link Canvas#drawDoubleRoundRect(RectF, float[], RectF, float[], Paint)}, since there
+ * doesn't seem to be any other API for drawing rectangles with 4 different corner radii.
+ */
+ private static final RectF EMPTY_RECT = new RectF();
+ private static final float[] ARRAY_OF_ZEROES = new float[8];
+
+ AppPairIconBackground(Context context, AppPairIcon appPairIcon) {
+ icon = appPairIcon;
+ // Set up background paint color
+ TypedArray ta = context.getTheme().obtainStyledAttributes(R.styleable.FolderIconPreview);
+ mBackgroundPaint.setStyle(Paint.Style.FILL);
+ mBackgroundPaint.setColor(
+ ta.getColor(R.styleable.FolderIconPreview_folderPreviewColor, 0));
+ ta.recycle();
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (icon.mIsLandscape) {
+ drawLeftRightSplit(canvas);
+ } else {
+ drawTopBottomSplit(canvas);
+ }
+ }
+
+ /**
+ * When device is in landscape, we draw the rectangles with a left-right split.
+ */
+ private void drawLeftRightSplit(Canvas canvas) {
+ // Get the bounds where we will draw the background image
+ int width = getBounds().width();
+ int height = getBounds().height();
+
+ // The left half of the background image, excluding center channel
+ RectF leftSide = new RectF(
+ icon.mOuterPadding,
+ icon.mOuterPadding,
+ (width / 2f) - (icon.mCenterChannelSize / 2f),
+ height - icon.mOuterPadding
+ );
+ // The right half of the background image, excluding center channel
+ RectF rightSide = new RectF(
+ (width / 2f) + (icon.mCenterChannelSize / 2f),
+ icon.mOuterPadding,
+ width - icon.mOuterPadding,
+ height - icon.mOuterPadding
+ );
+
+ drawCustomRoundedRect(canvas, leftSide, new float[]{
+ icon.mBigRadius, icon.mBigRadius,
+ icon.mSmallRadius, icon.mSmallRadius,
+ icon.mSmallRadius, icon.mSmallRadius,
+ icon.mBigRadius, icon.mBigRadius});
+ drawCustomRoundedRect(canvas, rightSide, new float[]{
+ icon.mSmallRadius, icon.mSmallRadius,
+ icon.mBigRadius, icon.mBigRadius,
+ icon.mBigRadius, icon.mBigRadius,
+ icon.mSmallRadius, icon.mSmallRadius});
+ }
+
+ /**
+ * When device is in portrait, we draw the rectangles with a top-bottom split.
+ */
+ private void drawTopBottomSplit(Canvas canvas) {
+ // Get the bounds where we will draw the background image
+ int width = getBounds().width();
+ int height = getBounds().height();
+
+ // The top half of the background image, excluding center channel
+ RectF topSide = new RectF(
+ icon.mOuterPadding,
+ icon.mOuterPadding,
+ width - icon.mOuterPadding,
+ (height / 2f) - (icon.mCenterChannelSize / 2f)
+ );
+ // The bottom half of the background image, excluding center channel
+ RectF bottomSide = new RectF(
+ icon.mOuterPadding,
+ (height / 2f) + (icon.mCenterChannelSize / 2f),
+ width - icon.mOuterPadding,
+ height - icon.mOuterPadding
+ );
+
+ drawCustomRoundedRect(canvas, topSide, new float[]{
+ icon.mBigRadius, icon.mBigRadius,
+ icon.mBigRadius, icon.mBigRadius,
+ icon.mSmallRadius, icon.mSmallRadius,
+ icon.mSmallRadius, icon.mSmallRadius});
+ drawCustomRoundedRect(canvas, bottomSide, new float[]{
+ icon.mSmallRadius, icon.mSmallRadius,
+ icon.mSmallRadius, icon.mSmallRadius,
+ icon.mBigRadius, icon.mBigRadius,
+ icon.mBigRadius, icon.mBigRadius});
+ }
+
+ /**
+ * Draws a rectangle with custom rounded corners.
+ * @param c The Canvas to draw on.
+ * @param rect The bounds of the rectangle.
+ * @param radii An array of 8 radii for the corners: top left x, top left y, top right x, top
+ * right y, bottom right x, and so on.
+ */
+ private void drawCustomRoundedRect(Canvas c, RectF rect, float[] radii) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ // Canvas.drawDoubleRoundRect is supported from Q onward
+ c.drawDoubleRoundRect(rect, radii, EMPTY_RECT, ARRAY_OF_ZEROES, mBackgroundPaint);
+ } else {
+ // Fallback rectangle with uniform rounded corners
+ c.drawRoundRect(rect, icon.mBigRadius, icon.mBigRadius, mBackgroundPaint);
+ }
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.OPAQUE;
+ }
+
+ @Override
+ public void setAlpha(int i) {
+ // Required by Drawable but not used.
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ // Required by Drawable but not used.
+ }
+}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 08a2f64..c70e786 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -167,6 +167,10 @@
return SMARTSPACE_AS_A_WIDGET.get() && WIDGET_ON_FIRST_SCREEN;
}
+ public static final BooleanFlag ENABLE_SMARTSPACE_REMOVAL = getDebugFlag(290799975,
+ "ENABLE_SMARTSPACE_REMOVAL", DISABLED, "Enable SmartSpace removal for "
+ + "home screen");
+
// TODO(Block 10): Clean up flags
public static final BooleanFlag ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION = getDebugFlag(270614790,
"ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION", DISABLED,
@@ -308,6 +312,16 @@
+ "waiting for SystemUI and then merging the SystemUI progress whenever we "
+ "start receiving the events");
+ // TODO(Block 23): Clean up flags
+ // Aconfig migration complete for ENABLE_GRID_ONLY_OVERVIEW.
+ @VisibleForTesting
+ public static final BooleanFlag ENABLE_GRID_ONLY_OVERVIEW = getDebugFlag(270397206,
+ "ENABLE_GRID_ONLY_OVERVIEW", TEAMFOOD,
+ "Enable a grid-only overview without a focused task.");
+ public static boolean enableGridOnlyOverview() {
+ return ENABLE_GRID_ONLY_OVERVIEW.get() || Flags.enableGridOnlyOverview();
+ }
+
// Aconfig migration complete for ENABLE_OVERVIEW_ICON_MENU.
@VisibleForTesting
public static final BooleanFlag ENABLE_OVERVIEW_ICON_MENU = getDebugFlag(257950105,
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 7ce5c20..3330448 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -527,7 +527,7 @@
}
// Add first page QSB
- if (FeatureFlags.QSB_ON_FIRST_SCREEN
+ if (FeatureFlags.QSB_ON_FIRST_SCREEN && dataModel.isFirstPagePinnedItemEnabled
&& !shouldShowFirstPageWidget()) {
CellLayout firstScreen = mWorkspaceScreens.get(FIRST_SCREEN_ID);
View qsb = mHomeElementInflater.inflate(R.layout.qsb_preview, firstScreen, false);
diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java
index bb7248f..1791539 100644
--- a/src/com/android/launcher3/icons/ShortcutCachingLogic.java
+++ b/src/com/android/launcher3/icons/ShortcutCachingLogic.java
@@ -107,7 +107,7 @@
try {
return context.getSystemService(LauncherApps.class)
.getShortcutIconDrawable(shortcutInfo, density);
- } catch (SecurityException | IllegalStateException e) {
+ } catch (SecurityException | IllegalStateException | NullPointerException e) {
Log.e(TAG, "Failed to get shortcut icon", e);
return null;
}
diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
index 7421205..9b2344d 100644
--- a/src/com/android/launcher3/model/BaseLauncherBinder.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -16,6 +16,7 @@
package com.android.launcher3.model;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.model.ItemInstallQueue.FLAG_LOADER_RUNNING;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -293,6 +294,10 @@
executeCallbacksTask(c -> {
c.clearPendingBinds();
c.startBinding();
+ if (ENABLE_SMARTSPACE_REMOVAL.get()) {
+ c.setIsFirstPagePinnedItemEnabled(
+ mBgDataModel.isFirstPagePinnedItemEnabled);
+ }
}, mUiExecutor);
// Bind workspace screens
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 0ffedc8..54ecc00 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -17,6 +17,8 @@
import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY;
+import static com.android.launcher3.BuildConfig.QSB_ON_FIRST_SCREEN;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
import static com.android.launcher3.shortcuts.ShortcutRequest.PINNED;
@@ -130,6 +132,8 @@
* Load id for which the callbacks were successfully bound
*/
public int lastLoadId = -1;
+ public boolean isFirstPagePinnedItemEnabled = QSB_ON_FIRST_SCREEN
+ && !ENABLE_SMARTSPACE_REMOVAL.get();
/**
* Clears all the data
@@ -489,6 +493,7 @@
default void bindItems(List<ItemInfo> shortcuts, boolean forceAnimateIcons) { }
default void bindScreens(IntArray orderedScreenIds) { }
+ default void setIsFirstPagePinnedItemEnabled(boolean isFirstPagePinnedItemEnabled) { }
default void finishBindingItems(IntSet pagesBoundFirst) { }
default void preAddApps() { }
default void bindAppsAdded(IntArray newScreens,
diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
index eed4ee6..efd5574 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
@@ -18,7 +18,9 @@
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.LauncherSettings.Favorites.TMP_TABLE;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
+import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN;
import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
@@ -38,6 +40,7 @@
import androidx.annotation.NonNull;
import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
@@ -330,6 +333,8 @@
final Point trg = new Point(trgX, trgY);
final Point next = new Point(0, screenId == 0
&& (FeatureFlags.QSB_ON_FIRST_SCREEN
+ && (!ENABLE_SMARTSPACE_REMOVAL.get() || LauncherPrefs.getPrefs(destReader.mContext)
+ .getBoolean(SMARTSPACE_ON_HOME_SCREEN, true))
&& !shouldShowFirstPageWidget())
? 1 /* smartspace */ : 0);
List<DbEntry> existedEntries = destReader.mWorkspaceEntriesByScreenId.get(screenId);
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 9c4cd46..4370043 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -471,7 +471,7 @@
// cause the item loading to get skipped
ShortcutKey.fromItemInfo(info);
}
- if (checkItemPlacement(info)) {
+ if (checkItemPlacement(info, dataModel.isFirstPagePinnedItemEnabled)) {
dataModel.addItem(mContext, info, false, logger);
} else {
markDeleted("Item position overlap");
@@ -481,7 +481,7 @@
/**
* check & update map of what's occupied; used to discard overlapping/invalid items
*/
- protected boolean checkItemPlacement(ItemInfo item) {
+ protected boolean checkItemPlacement(ItemInfo item, boolean isFirstPagePinnedItemEnabled) {
int containerIndex = item.screenId;
if (item.container == Favorites.CONTAINER_HOTSEAT) {
final GridOccupancy hotseatOccupancy =
@@ -530,7 +530,7 @@
if (!mOccupied.containsKey(item.screenId)) {
GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1);
if (item.screenId == Workspace.FIRST_SCREEN_ID && (FeatureFlags.QSB_ON_FIRST_SCREEN
- && !shouldShowFirstPageWidget())) {
+ && !shouldShowFirstPageWidget() && isFirstPagePinnedItemEnabled)) {
// Mark the first X columns (X is width of the search container) in the first row as
// occupied (if the feature is enabled) in order to account for the search
// container.
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 15666cf..6ab8fc5 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
@@ -119,6 +120,7 @@
*/
public class LoaderTask implements Runnable {
private static final String TAG = "LoaderTask";
+ public static final String SMARTSPACE_ON_HOME_SCREEN = "pref_smartspace_home_screen";
private static final boolean DEBUG = true;
@@ -368,6 +370,9 @@
mModelDelegate.markActive();
logASplit("workspaceDelegateItems");
}
+ mBgDataModel.isFirstPagePinnedItemEnabled = FeatureFlags.QSB_ON_FIRST_SCREEN
+ && (!ENABLE_SMARTSPACE_REMOVAL.get() || LauncherPrefs.getPrefs(
+ mApp.getContext()).getBoolean(SMARTSPACE_ON_HOME_SCREEN, true));
}
private void loadWorkspaceImpl(
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index e52e878..a75f326 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -16,7 +16,7 @@
package com.android.launcher3.testing;
import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
-import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.launcher3.config.FeatureFlags.enableGridOnlyOverview;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 122b1e0..a09e5a4 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -30,6 +30,7 @@
import com.android.launcher3.CellLayout;
import com.android.launcher3.DropTarget;
import com.android.launcher3.Launcher;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.folder.Folder;
@@ -136,6 +137,9 @@
if (launcher.isWorkspaceLocked()) return false;
// Return early if an item is already being dragged (e.g. when long-pressing two shortcuts)
if (launcher.getDragController().isDragging()) return false;
+ // Return early if user is in the middle of selecting split-screen apps
+ if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get() &&
+ launcher.isSplitSelectionEnabled()) return false;
return true;
}
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 96ae4a3..1232069 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -40,6 +40,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.Workspace;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.testing.TestLogging;
@@ -205,6 +206,10 @@
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
mLauncher.getStatsLogManager().logger().log(LAUNCHER_WORKSPACE_LONGPRESS);
mLauncher.showDefaultOptions(mTouchDownPoint.x, mTouchDownPoint.y);
+ if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get() &&
+ mLauncher.isSplitSelectionEnabled()) {
+ mLauncher.dismissSplitSelection();
+ }
} else {
cancelLongPress();
}
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 04f2ffa..0d55f15 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -146,6 +146,15 @@
}
/**
+ * @return {@code true} if user has selected the first split app and is in the process of
+ * selecting the second
+ */
+ default boolean isSplitSelectionEnabled() {
+ // Overridden
+ return false;
+ }
+
+ /**
* The root view to support drag-and-drop and popup support.
*/
BaseDragLayer getDragLayer();
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 742d2dc..fc9c774 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -16,6 +16,7 @@
package com.android.launcher3.widget;
import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_TIP_SEEN;
import android.content.Context;
import android.graphics.Canvas;
@@ -40,6 +41,7 @@
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragOptions;
@@ -63,8 +65,6 @@
/** The default number of cells that can fit horizontally in a widget sheet. */
public static final int DEFAULT_MAX_HORIZONTAL_SPANS = 4;
- protected static final String KEY_WIDGETS_EDUCATION_TIP_SEEN =
- "launcher.widgets_education_tip_seen";
protected final Rect mInsets = new Rect();
/* Touch handling related member variables. */
@@ -330,15 +330,14 @@
/* arrowXCoord= */coords[0] + view.getWidth() / 2,
/* yCoord= */coords[1]);
if (arrowTipView != null) {
- mActivityContext.getSharedPrefs().edit()
- .putBoolean(KEY_WIDGETS_EDUCATION_TIP_SEEN, true).apply();
+ LauncherPrefs.get(getContext()).put(WIDGETS_EDUCATION_TIP_SEEN, true);
}
return arrowTipView;
}
/** Returns {@code true} if tip has previously been shown on any of {@link BaseWidgetSheet}. */
protected boolean hasSeenEducationTip() {
- return mActivityContext.getSharedPrefs().getBoolean(KEY_WIDGETS_EDUCATION_TIP_SEEN, false)
+ return LauncherPrefs.get(getContext()).get(WIDGETS_EDUCATION_TIP_SEEN)
|| Utilities.isRunningInTestHarness();
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 37ec65c..78116ae 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -18,6 +18,7 @@
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_DIALOG_SEEN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
@@ -56,6 +57,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
@@ -98,8 +100,6 @@
// resolution or landscape on phone. This ratio defines the max percentage of content area that
// the table can display.
private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.75f;
- private static final String KEY_WIDGETS_EDUCATION_DIALOG_SEEN =
- "launcher.widgets_education_dialog_seen";
private final UserManagerState mUserManagerState = new UserManagerState();
private final UserHandle mCurrentUser = Process.myUserHandle();
@@ -853,15 +853,13 @@
/** Shows education dialog for widgets. */
private WidgetsEduView showEducationDialog() {
- mActivityContext.getSharedPrefs().edit()
- .putBoolean(KEY_WIDGETS_EDUCATION_DIALOG_SEEN, true).apply();
+ LauncherPrefs.get(getContext()).put(WIDGETS_EDUCATION_DIALOG_SEEN, true);
return WidgetsEduView.showEducationDialog(mActivityContext);
}
/** Returns {@code true} if education dialog has previously been shown. */
protected boolean hasSeenEducationDialog() {
- return mActivityContext.getSharedPrefs()
- .getBoolean(KEY_WIDGETS_EDUCATION_DIALOG_SEEN, false)
+ return LauncherPrefs.get(getContext()).get(WIDGETS_EDUCATION_DIALOG_SEEN)
|| Utilities.isRunningInTestHarness();
}
diff --git a/src_plugins/com/android/systemui/plugins/LauncherOverlayPlugin.java b/src_plugins/com/android/systemui/plugins/LauncherOverlayPlugin.java
index 9e22355..32f0216 100644
--- a/src_plugins/com/android/systemui/plugins/LauncherOverlayPlugin.java
+++ b/src_plugins/com/android/systemui/plugins/LauncherOverlayPlugin.java
@@ -18,7 +18,6 @@
import android.app.Activity;
import com.android.systemui.plugins.annotations.ProvidesInterface;
-import com.android.systemui.plugins.shared.LauncherExterns;
import com.android.systemui.plugins.shared.LauncherOverlayManager;
/**
@@ -29,6 +28,6 @@
String ACTION = "com.android.systemui.action.PLUGIN_LAUNCHER_OVERLAY";
int VERSION = 1;
- LauncherOverlayManager createOverlayManager(Activity activity, LauncherExterns externs);
+ LauncherOverlayManager createOverlayManager(Activity activity);
}
diff --git a/src_plugins/com/android/systemui/plugins/shared/LauncherExterns.java b/src_plugins/com/android/systemui/plugins/shared/LauncherExterns.java
deleted file mode 100644
index 173b454..0000000
--- a/src_plugins/com/android/systemui/plugins/shared/LauncherExterns.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2016 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.systemui.plugins.shared;
-
-import android.content.SharedPreferences;
-
-import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
-
-/**
- * This interface defines the set of methods that the Launcher activity exposes. Methods
- * here should be safe to call from classes outside of com.android.launcher3.*
- */
-public interface LauncherExterns {
-
- /**
- * Returns the shared main preference
- */
- SharedPreferences getSharedPrefs();
-
- /**
- * Returns the device specific preference
- */
- SharedPreferences getDevicePrefs();
-
- /**
- * Sets the overlay on the target activity
- */
- void setLauncherOverlay(LauncherOverlay overlay);
-}
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java
index 712806c..5b87a05 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java
@@ -45,7 +45,7 @@
/**
* Test runs in Out of process (Oop) and In process (Ipc)
- * Test the behaviour of uninstalling and removing apps both from AllApps and from the Workspace.
+ * Test the behaviour of uninstalling and removing apps both from AllApps, Workspace and Hotseat.
*/
public class TaplUninstallRemove extends AbstractLauncherUiTest {
@@ -164,4 +164,19 @@
TestUtil.uninstallDummyApp();
}
}
+
+ /**
+ * Drag icon from the Hotseat to the delete drop target
+ */
+ @Test
+ @PortraitLandscape
+ public void testAddDeleteShortcutOnHotseat() {
+ mLauncher.getWorkspace()
+ .deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))
+ .switchToAllApps()
+ .getAppIcon(APP_NAME)
+ .dragToHotseat(0);
+ mLauncher.getWorkspace().deleteAppIcon(
+ mLauncher.getWorkspace().getHotseatAppIcon(APP_NAME));
+ }
}
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
index 544ed6b..389ec5c 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -175,7 +175,7 @@
// Item outside screen bounds are not placed
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(4, 4, 1, 1, CONTAINER_DESKTOP, 1)));
+ newItemInfo(4, 4, 1, 1, CONTAINER_DESKTOP, 1), true));
}
@Test
@@ -186,22 +186,22 @@
// Overlapping mItems are not placed
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1)));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1), true));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1)));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1), true));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2)));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2), true));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2)));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2), true));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(1, 1, 1, 1, CONTAINER_DESKTOP, 1)));
+ newItemInfo(1, 1, 1, 1, CONTAINER_DESKTOP, 1), true));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(2, 2, 2, 2, CONTAINER_DESKTOP, 1)));
+ newItemInfo(2, 2, 2, 2, CONTAINER_DESKTOP, 1), true));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(3, 2, 1, 2, CONTAINER_DESKTOP, 1)));
+ newItemInfo(3, 2, 1, 2, CONTAINER_DESKTOP, 1), true));
}
@Test
@@ -212,12 +212,12 @@
// Hotseat mItems are only placed based on screenId
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 1)));
+ newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 1), true));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 2)));
+ newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 2), true));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 3)));
+ newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 3), true));
}
private ItemInfo newItemInfo(int cellX, int cellY, int spanX, int spanY,
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index e837b8b..fe51509 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -183,8 +183,8 @@
if (TestHelpers.isInLauncherProcess()) {
Utilities.enableRunningInTestHarnessForTests();
mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand(
- TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString()).
- getString("result"));
+ TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString())
+ .getString("result"));
mLauncher.setOnSettledStateAction(
containerType -> executeOnLauncher(
launcher ->
@@ -207,7 +207,7 @@
final SimpleBroadcastReceiver broadcastReceiver =
new SimpleBroadcastReceiver(i -> count.countDown());
broadcastReceiver.registerPkgActions(mTargetContext, pkg,
- Intent.ACTION_PACKAGE_RESTARTED, Intent.ACTION_PACKAGE_DATA_CLEARED);
+ Intent.ACTION_PACKAGE_RESTARTED, Intent.ACTION_PACKAGE_DATA_CLEARED);
mDevice.executeShellCommand("pm clear " + pkg);
assertTrue(pkg + " didn't restart", count.await(10, TimeUnit.SECONDS));
@@ -344,6 +344,15 @@
});
}
+ // Execute an action on Launcher, but forgive it when launcher is null.
+ // Launcher can be null if teardown is happening after a failed setup step where launcher
+ // activity failed to be created.
+ protected void executeOnLauncherInTearDown(Consumer<Launcher> f) {
+ executeOnLauncher(launcher -> {
+ if (launcher != null) f.accept(launcher);
+ });
+ }
+
// Cannot be used in TaplTests between a Tapl call injecting a gesture and a tapl call
// expecting the results of that gesture because the wait can hide flakeness.
protected void waitForState(String message, Supplier<LauncherState> state) {
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index f37b676..799ef5b 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -82,16 +82,4 @@
// Check that pressHome works when the menu is shown.
mLauncher.goHome();
}
-
- @Test
- @PortraitLandscape
- public void testAddDeleteShortcutOnHotseat() {
- mLauncher.getWorkspace()
- .deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))
- .switchToAllApps()
- .getAppIcon(APP_NAME)
- .dragToHotseat(0);
- mLauncher.getWorkspace().deleteAppIcon(
- mLauncher.getWorkspace().getHotseatAppIcon(APP_NAME));
- }
}
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index ac710fd..485ef94 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.ui;
+import static com.android.launcher3.LauncherPrefs.WORK_EDU_STEP;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
@@ -29,6 +30,7 @@
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
+import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
import com.android.launcher3.allapps.AllAppsPagedView;
@@ -89,8 +91,8 @@
@After
public void removeWorkProfile() throws Exception {
- executeOnLauncher(launcher -> {
- if (launcher == null || launcher.getAppsView() == null) {
+ executeOnLauncherInTearDown(launcher -> {
+ if (launcher.getAppsView() == null) {
return;
}
launcher.getAppsView().getAppsStore().disableDeferUpdates(DEFER_UPDATES_TEST);
@@ -174,7 +176,7 @@
assumeTrue(mWorkProfileSetupSuccessful);
waitForWorkTabSetup();
executeOnLauncher(l -> {
- l.getSharedPrefs().edit().putInt(WorkProfileManager.KEY_WORK_EDU_STEP, 0).commit();
+ LauncherPrefs.get(l).putSync(WORK_EDU_STEP.to(0));
((AllAppsPagedView) l.getAppsView().getContentView()).setCurrentPage(WORK_PAGE);
l.getAppsView().getWorkManager().reset();
});
diff --git a/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java
index 62a8179..00e00fa 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java
@@ -83,7 +83,7 @@
@After
public void tearDown() throws Exception {
- executeOnLauncher(launcher -> launcher.enableHotseatEdu(true));
+ executeOnLauncherInTearDown(launcher -> launcher.enableHotseatEdu(true));
if (mLauncherLayout != null) {
mLauncherLayout.close();
}
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
index 4b65439..51b7b18 100644
--- a/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
@@ -62,18 +62,6 @@
+ "NexusOverviewActionsView:id/overview_actions_view|FrameLayout:id"
+ "/select_mode_buttons|ImageButton:id/close",
DRAG_LAYER
- + "NexusOverviewActionsView:id/overview_actions_view|LinearLayout:id"
- + "/action_buttons|Button:id/action_screenshot",
- DRAG_LAYER
- + "NexusOverviewActionsView:id/overview_actions_view|LinearLayout:id"
- + "/action_buttons|Button:id/action_select",
- DRAG_LAYER
- + "NexusOverviewActionsView:id/overview_actions_view|LinearLayout:id"
- + "/action_buttons|Button:id/action_split",
- DRAG_LAYER
- + "NexusOverviewActionsView:id/overview_actions_view|LinearLayout:id"
- + "/action_buttons|Space:id/action_split_space",
- DRAG_LAYER
+ "PopupContainerWithArrow:id/popup_container|LinearLayout:id"
+ "/deep_shortcuts_container|DeepShortcutView:id/deep_shortcut_material"
+ "|DeepShortcutTextView:id/bubble_text",
@@ -116,23 +104,14 @@
RECENTS_DRAG_LAYER + "FallbackRecentsView:id/overview_panel",
DRAG_LAYER
+ "NexusOverviewActionsView:id/overview_actions_view"
- + "|LinearLayout:id/action_buttons|Button:id/action_screenshot",
+ + "|LinearLayout:id/action_buttons",
RECENTS_DRAG_LAYER
+ "NexusOverviewActionsView:id/overview_actions_view"
- + "|LinearLayout:id/action_buttons|Button:id/action_screenshot",
+ + "|LinearLayout:id/action_buttons",
+ DRAG_LAYER + "IconView",
DRAG_LAYER
- + "NexusOverviewActionsView:id/overview_actions_view"
- + "|LinearLayout:id/action_buttons|Button:id/action_select",
- RECENTS_DRAG_LAYER
- + "NexusOverviewActionsView:id/overview_actions_view"
- + "|LinearLayout:id/action_buttons|Button:id/action_select",
- DRAG_LAYER
- + "NexusOverviewActionsView:id/overview_actions_view"
- + "|LinearLayout:id/action_buttons|Button:id/action_split",
- RECENTS_DRAG_LAYER
- + "NexusOverviewActionsView:id/overview_actions_view"
- + "|LinearLayout:id/action_buttons|Button:id/action_split",
- DRAG_LAYER + "IconView"
+ + "OptionsPopupView:id/popup_container|DeepShortcutView:id/system_shortcut"
+ + "|BubbleTextView:id/bubble_text"
));
// Minimal increase or decrease of view's alpha between frames that triggers the error.
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java
index 0d4eaf1..e333074 100644
--- a/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java
@@ -38,7 +38,8 @@
private static final IgnoreNode IGNORED_NODES_ROOT = buildIgnoreNodesTree(List.of(
CONTENT + "LauncherRootView:id/launcher|FloatingIconView",
- DRAG_LAYER + "LauncherRecentsView:id/overview_panel|TaskView|TextView",
+ DRAG_LAYER + "LauncherRecentsView:id/overview_panel|TaskView",
+ DRAG_LAYER + "LauncherRecentsView:id/overview_panel|ClearAllButton:id/clear_all",
DRAG_LAYER
+ "LauncherAllAppsContainerView:id/apps_view|AllAppsRecyclerView:id"
+ "/apps_list_view|BubbleTextView:id/icon",
@@ -54,6 +55,8 @@
+ "|ScrollView:id/widget_preview_scroll_view|WidgetCell:id/widget_cell"
+ "|WidgetCellPreview:id/widget_preview_container|ImageView:id/widget_badge",
RECENTS_DRAG_LAYER + "FallbackRecentsView:id/overview_panel|TaskView",
+ RECENTS_DRAG_LAYER
+ + "FallbackRecentsView:id/overview_panel|ClearAllButton:id/clear_all",
DRAG_LAYER + "SearchContainerView:id/apps_view",
DRAG_LAYER + "LauncherDragView",
DRAG_LAYER + "FloatingTaskView|FloatingTaskThumbnailView:id/thumbnail",
@@ -64,7 +67,8 @@
+ "WidgetsTwoPaneSheet|SpringRelativeLayout:id/container|LinearLayout:id"
+ "/linear_layout_container|FrameLayout:id/recycler_view_container"
+ "|FrameLayout:id/widgets_two_pane_sheet_recyclerview|WidgetsRecyclerView:id"
- + "/primary_widgets_list_view|WidgetsListHeader:id/widgets_list_header"
+ + "/primary_widgets_list_view|WidgetsListHeader:id/widgets_list_header",
+ DRAG_LAYER + "NexusOverviewActionsView:id/overview_actions_view"
));
// Per-AnalysisNode data that's specific to this detector.
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index fc589bd..2a2a83f 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -28,7 +28,6 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemClock;
-import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -302,10 +301,6 @@
final UiObject2 workspace = verifyActiveContainer();
List<UiObject2> workspaceIcons =
mLauncher.waitForObjectsInContainer(workspace, AppIcon.getAnyAppIconSelector());
- Log.d("b/288944469", "List size = " + workspaceIcons.size());
- for (int i = 0; i < workspaceIcons.size(); i++) {
- Log.d("b/288944469", "index = " + i + " tesxt = " + workspaceIcons.get(i).getText());
- }
return workspaceIcons.stream()
.collect(
Collectors.toMap(