diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java index 90c035fed0..f1e67479f5 100644 --- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java @@ -60,6 +60,7 @@ public class FallbackTaskbarUIController extends TaskbarUIController { @Override protected void onDestroy() { + super.onDestroy(); mRecentsActivity.setTaskbarUIController(null); mRecentsActivity.getStateManager().removeStateListener(mStateListener); } diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 7d234392c4..2622700871 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -99,6 +99,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { @Override protected void onDestroy() { + super.onDestroy(); onLauncherResumedOrPaused(false); mTaskbarLauncherStateController.onDestroy(); diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java index 0ab775694a..ce1e8b6b6e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java @@ -31,6 +31,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_I import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; @@ -86,6 +87,7 @@ public class NavbarButtonsViewController { private static final int FLAG_DISABLE_RECENTS = 1 << 8; private static final int FLAG_DISABLE_BACK = 1 << 9; private static final int FLAG_NOTIFICATION_SHADE_EXPANDED = 1 << 10; + private static final int FLAG_SCREEN_PINNING_ACTIVE = 1 << 10; private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE; @@ -152,7 +154,9 @@ public class NavbarButtonsViewController { mPropertyHolders.add(new StatePropertyHolder( mControllers.taskbarViewController.getTaskbarIconAlpha() .getProperty(ALPHA_INDEX_KEYGUARD), - flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0, MultiValueAlpha.VALUE, 1, 0)); + flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 + && (flags & FLAG_SCREEN_PINNING_ACTIVE) == 0, + MultiValueAlpha.VALUE, 1, 0)); mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController .getKeyguardBgTaskbar(), @@ -286,6 +290,7 @@ public class NavbarButtonsViewController { int shadeExpandedFlags = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_QUICK_SETTINGS_EXPANDED; boolean isNotificationShadeExpanded = (sysUiStateFlags & shadeExpandedFlags) != 0; + boolean isScreenPinningActive = (sysUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0; // TODO(b/202218289) we're getting IME as not visible on lockscreen from system updateStateForFlag(FLAG_IME_VISIBLE, isImeVisible); @@ -295,6 +300,7 @@ public class NavbarButtonsViewController { updateStateForFlag(FLAG_DISABLE_RECENTS, isRecentsDisabled); updateStateForFlag(FLAG_DISABLE_BACK, isBackDisabled); updateStateForFlag(FLAG_NOTIFICATION_SHADE_EXPANDED, isNotificationShadeExpanded); + updateStateForFlag(FLAG_SCREEN_PINNING_ACTIVE, isScreenPinningActive); if (mA11yButton != null) { // Only used in 3 button diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index cb9d4a4374..692352b3fd 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -361,6 +361,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ mControllers.taskbarStashController.updateStateForSysuiFlags(systemUiStateFlags, fromInit); mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags, fromInit); + mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index 56e9429120..3cdcdf7f89 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -29,8 +29,8 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.hardware.display.DisplayManager; import android.net.Uri; +import android.os.Handler; import android.provider.Settings; -import android.util.Log; import android.view.Display; import androidx.annotation.NonNull; @@ -93,7 +93,8 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen Display display = service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY); mContext = service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null); - mNavButtonController = new TaskbarNavButtonController(service); + mNavButtonController = new TaskbarNavButtonController(service, + SystemUiProxy.INSTANCE.get(mContext), new Handler()); mUserSetupCompleteListener = isUserSetupComplete -> recreateTaskbar(); mComponentCallbacks = new ComponentCallbacks() { private Configuration mOldConfig = mContext.getResources().getConfiguration(); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java index ae23eda2a4..d23336505a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java @@ -19,8 +19,10 @@ package com.android.launcher3.taskbar; import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS; import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_KEY; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; import android.os.Bundle; +import android.os.Handler; import androidx.annotation.IntDef; @@ -40,6 +42,13 @@ import java.lang.annotation.RetentionPolicy; */ public class TaskbarNavButtonController { + /** Allow some time in between the long press for back and recents. */ + static final int SCREEN_PIN_LONG_PRESS_THRESHOLD = 200; + static final int SCREEN_PIN_LONG_PRESS_RESET = SCREEN_PIN_LONG_PRESS_THRESHOLD + 100; + + private long mLastScreenPinLongPress; + private boolean mScreenPinned; + @Retention(RetentionPolicy.SOURCE) @IntDef(value = { BUTTON_BACK, @@ -57,10 +66,20 @@ public class TaskbarNavButtonController { static final int BUTTON_IME_SWITCH = BUTTON_RECENTS << 1; static final int BUTTON_A11Y = BUTTON_IME_SWITCH << 1; - private final TouchInteractionService mService; + private static final int SCREEN_UNPIN_COMBO = BUTTON_BACK | BUTTON_RECENTS; + private int mLongPressedButtons = 0; - public TaskbarNavButtonController(TouchInteractionService service) { + private final TouchInteractionService mService; + private final SystemUiProxy mSystemUiProxy; + private final Handler mHandler; + + private final Runnable mResetLongPress = this::resetScreenUnpin; + + public TaskbarNavButtonController(TouchInteractionService service, + SystemUiProxy systemUiProxy, Handler handler) { mService = service; + mSystemUiProxy = systemUiProxy; + mHandler = handler; } public void onButtonClick(@TaskbarButton int buttonType) { @@ -72,13 +91,13 @@ public class TaskbarNavButtonController { navigateHome(); break; case BUTTON_RECENTS: - navigateToOverview();; + navigateToOverview(); break; case BUTTON_IME_SWITCH: showIMESwitcher(); break; case BUTTON_A11Y: - notifyImeClick(false /* longClick */); + notifyA11yClick(false /* longClick */); break; } } @@ -89,46 +108,98 @@ public class TaskbarNavButtonController { startAssistant(); return true; case BUTTON_A11Y: - notifyImeClick(true /* longClick */); + notifyA11yClick(true /* longClick */); return true; case BUTTON_BACK: - case BUTTON_IME_SWITCH: case BUTTON_RECENTS: + mLongPressedButtons |= buttonType; + return determineScreenUnpin(); + case BUTTON_IME_SWITCH: default: return false; } } + /** + * Checks if the user has long pressed back and recents buttons + * "together" (within {@link #SCREEN_PIN_LONG_PRESS_THRESHOLD})ms + * If so, then requests the system to turn off screen pinning. + * + * @return true if the long press is a valid user action in attempting to unpin an app + * Will always return {@code false} when screen pinning is not active. + * NOTE: Returning true does not mean that screen pinning has stopped + */ + private boolean determineScreenUnpin() { + long timeNow = System.currentTimeMillis(); + if (!mScreenPinned) { + return false; + } + + if (mLastScreenPinLongPress == 0) { + // First button long press registered, just mark time and wait for second button press + mLastScreenPinLongPress = System.currentTimeMillis(); + mHandler.postDelayed(mResetLongPress, SCREEN_PIN_LONG_PRESS_RESET); + return true; + } + + if ((timeNow - mLastScreenPinLongPress) > SCREEN_PIN_LONG_PRESS_THRESHOLD) { + // Too long in-between presses, reset the clock + resetScreenUnpin(); + return false; + } + + if ((mLongPressedButtons & SCREEN_UNPIN_COMBO) == SCREEN_UNPIN_COMBO) { + // Hooray! They did it (finally...) + mSystemUiProxy.stopScreenPinning(); + mHandler.removeCallbacks(mResetLongPress); + resetScreenUnpin(); + } + return true; + } + + private void resetScreenUnpin() { + mLongPressedButtons = 0; + mLastScreenPinLongPress = 0; + } + + public void updateSysuiFlags(int sysuiFlags) { + mScreenPinned = (sysuiFlags & SYSUI_STATE_SCREEN_PINNING) != 0; + } + private void navigateHome() { mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_HOME); } private void navigateToOverview() { + if (mScreenPinned) { + return; + } TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle"); mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_TOGGLE); } private void executeBack() { - SystemUiProxy.INSTANCE.getNoCreate().onBackPressed(); + mSystemUiProxy.onBackPressed(); } private void showIMESwitcher() { - SystemUiProxy.INSTANCE.getNoCreate().onImeSwitcherPressed(); + mSystemUiProxy.onImeSwitcherPressed(); } - private void notifyImeClick(boolean longClick) { - SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate(); + private void notifyA11yClick(boolean longClick) { if (longClick) { - systemUiProxy.notifyAccessibilityButtonLongClicked(); + mSystemUiProxy.notifyAccessibilityButtonLongClicked(); } else { - systemUiProxy.notifyAccessibilityButtonClicked(mService.getDisplayId()); + mSystemUiProxy.notifyAccessibilityButtonClicked(mService.getDisplayId()); } } private void startAssistant() { + if (mScreenPinned) { + return; + } Bundle args = new Bundle(); args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS); - SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate(); - systemUiProxy.startAssistant(args); + mSystemUiProxy.startAssistant(args); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index f713dcabcb..f6bc785a14 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -18,6 +18,8 @@ package com.android.launcher3.taskbar; import android.graphics.Rect; import android.view.View; +import androidx.annotation.CallSuper; + import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -33,11 +35,15 @@ public class TaskbarUIController { // Initialized in init. protected TaskbarControllers mControllers; + @CallSuper protected void init(TaskbarControllers taskbarControllers) { mControllers = taskbarControllers; } - protected void onDestroy() { } + @CallSuper + protected void onDestroy() { + mControllers = null; + } protected boolean isTaskbarTouchable() { return true; diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index b21d677106..19897a1bf8 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -66,6 +66,12 @@ public final class RecentsViewStateController extends // In Overview, we may be layering app surfaces behind Launcher, so we need to notify // DepthController to prevent optimizations which might occlude the layers behind mLauncher.getDepthController().setHasContentBehindLauncher(state.overviewUi); + + if (isSplitSelectionState(state)) { + mRecentsView.applySplitPrimaryScrollOffset(); + } else { + mRecentsView.resetSplitPrimaryScrollOffset(); + } } @Override @@ -90,9 +96,10 @@ public final class RecentsViewStateController extends LauncherState currentState = mLauncher.getStateManager().getState(); if (isSplitSelectionState(toState) && !isSplitSelectionState(currentState)) { builder.add(mRecentsView.createSplitSelectInitAnimation().buildAnim()); + } + if (isSplitSelectionState(toState)) { mRecentsView.applySplitPrimaryScrollOffset(); - } else if (!isSplitSelectionState(toState) && isSplitSelectionState(currentState)) { - builder.add(mRecentsView.cancelSplitSelect(true).buildAnim()); + } else { mRecentsView.resetSplitPrimaryScrollOffset(); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java index 106375a765..4f5f27a2c0 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java @@ -30,11 +30,6 @@ public class SplitScreenSelectState extends OverviewState { super(id); } - @Override - public void onBackPressed(Launcher launcher) { - launcher.getStateManager().goToState(OVERVIEW); - } - @Override public int getVisibleElements(Launcher launcher) { return SPLIT_PLACHOLDER_VIEW; diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index a9fef41c3f..6c623bcc75 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -599,11 +599,11 @@ public class SystemUiProxy implements ISystemUiProxy, } } - public void startShortcut(String packageName, String shortcutId, int stage, int position, + public void startShortcut(String packageName, String shortcutId, int position, Bundle options, UserHandle user) { if (mSplitScreen != null) { try { - mSplitScreen.startShortcut(packageName, shortcutId, stage, position, options, + mSplitScreen.startShortcut(packageName, shortcutId, position, options, user); } catch (RemoteException e) { Log.w(TAG, "Failed call startShortcut"); @@ -611,11 +611,11 @@ public class SystemUiProxy implements ISystemUiProxy, } } - public void startIntent(PendingIntent intent, Intent fillInIntent, int stage, int position, + public void startIntent(PendingIntent intent, Intent fillInIntent, int position, Bundle options) { if (mSplitScreen != null) { try { - mSplitScreen.startIntent(intent, fillInIntent, stage, position, options); + mSplitScreen.startIntent(intent, fillInIntent, position, options); } catch (RemoteException e) { Log.w(TAG, "Failed call startIntent"); } diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java index 325ec044fe..a343e0a593 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java @@ -129,9 +129,7 @@ public class FloatingTaskView extends FrameLayout { public void update(RectF position, float progress, float windowRadius) { MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams(); - float dX = mIsRtl - ? position.left - (lp.getMarginStart() - lp.width) - : position.left - lp.getMarginStart(); + float dX = position.left - lp.getMarginStart(); float dY = position.top - lp.topMargin; setTranslationX(dX); @@ -157,16 +155,10 @@ public class FloatingTaskView extends FrameLayout { lp.ignoreInsets = true; // Position the floating view exactly on top of the original lp.topMargin = Math.round(pos.top); - if (mIsRtl) { - lp.setMarginStart(Math.round(mLauncher.getDeviceProfile().widthPx - pos.right)); - } else { - lp.setMarginStart(Math.round(pos.left)); - } + lp.setMarginStart(Math.round(pos.left)); // Set the properties here already to make sure they are available when running the first // animation frame. - int left = mIsRtl - ? mLauncher.getDeviceProfile().widthPx - lp.getMarginStart() - lp.width - : lp.leftMargin; + int left = lp.leftMargin; layout(left, lp.topMargin, left + lp.width, lp.topMargin + lp.height); } diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java index 00f541d4c6..b43626b50e 100644 --- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java +++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java @@ -157,10 +157,20 @@ public class GroupedTaskView extends TaskView { @Nullable @Override public RunnableList launchTaskAnimated() { - getRecentsView().getSplitPlaceholder().launchTasks(this /*groupedTaskView*/, - null /*callback*/, + if (mTask == null || mSecondaryTask == null) { + return null; + } + + RunnableList endCallback = new RunnableList(); + RecentsView recentsView = getRecentsView(); + // Callbacks run from remote animation when recents animation not currently running + recentsView.getSplitPlaceholder().launchTasks(this /*groupedTaskView*/, + success -> endCallback.executeAllAndDestroy(), false /* freezeTaskList */); - return null; + + // Callbacks get run from recentsView for case when recents animation already running + recentsView.addSideTaskLaunchCallback(endCallback); + return endCallback; } @Override diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 3f212c6b80..3020dd905d 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -107,6 +107,7 @@ import android.widget.ListView; import android.widget.OverScroller; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; import androidx.core.graphics.ColorUtils; @@ -181,6 +182,7 @@ import com.android.wm.shell.pip.IPipAnimationListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; /** @@ -822,7 +824,7 @@ public abstract class RecentsView 0) { - targetPage = indexOfChild(getTaskViewAt(0)); + targetPage = indexOfChild(requireTaskViewAt(0)); } } else if (currentTaskId != -1) { currentTaskView = getTaskViewByTaskId(currentTaskId); @@ -1452,7 +1451,7 @@ public abstract class RecentsView= 0; i--) { - removeView(getTaskViewAt(i)); + removeView(requireTaskViewAt(i)); } if (indexOfChild(mClearAllButton) != -1) { removeView(mClearAllButton); @@ -1498,7 +1497,7 @@ public abstract class RecentsView= 0; i--) { - TaskView taskView = getTaskViewAt(i); + TaskView taskView = requireTaskViewAt(i); if (mIgnoreResetTaskId != taskView.getTaskIds()[0]) { taskView.resetViewTransforms(); taskView.setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1); @@ -1539,7 +1538,7 @@ public abstract class RecentsView 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f; // Pick the next focused task from the preferred row. for (int i = 0; i < taskCount; i++) { - TaskView taskView = getTaskViewAt(i); + TaskView taskView = requireTaskViewAt(i); if (taskView == dismissedTaskView) { continue; } @@ -2826,7 +2825,7 @@ public abstract class RecentsView= 0; i--) { - TaskView child = getTaskViewAt(i); + TaskView child = requireTaskViewAt(i); int[] childTaskIds = child.getTaskIds(); if (!mRunningTaskTileHidden || (childTaskIds[0] != runningTaskId && childTaskIds[1] != runningTaskId)) { @@ -3553,6 +3552,14 @@ public abstract class RecentsView view.getVisibility() != GONE && view != mSplitHiddenTaskView); - - int[] newScroll = new int[getChildCount()]; - getPageScrolls(newScroll, false, SIMPLE_SCROLL_LOGIC); - - boolean needsCurveUpdates = false; - for (int i = mSplitHiddenTaskViewIndex; i >= 0; i--) { - View child = getChildAt(i); - if (child == mSplitHiddenTaskView) { - TaskView taskView = (TaskView) child; - - int dir = mOrientationHandler.getSplitTaskViewDismissDirection(stagePosition, - mActivity.getDeviceProfile()); - FloatProperty dismissingTaskViewTranslate; - Rect hiddenBounds = new Rect(taskView.getLeft(), taskView.getTop(), - taskView.getRight(), taskView.getBottom()); - int distanceDelta = 0; - if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE) { - dismissingTaskViewTranslate = taskView - .getSecondaryDissmissTranslationProperty(); - distanceDelta = initialBounds.top - hiddenBounds.top; - taskView.layout(initialBounds.left, hiddenBounds.top, initialBounds.right, - hiddenBounds.bottom); - } else { - dismissingTaskViewTranslate = taskView - .getPrimaryDismissTranslationProperty(); - distanceDelta = initialBounds.left - hiddenBounds.left; - taskView.layout(hiddenBounds.left, initialBounds.top, hiddenBounds.right, - initialBounds.bottom); - if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE) { - distanceDelta *= -1; - } - } - pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, - dismissingTaskViewTranslate, - distanceDelta)); - pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, ALPHA, 1)); - } else { - // If insertion is on last index (furthest from clear all), we directly add the view - // else we translate all views to the right of insertion index further right, - // ignore views to left - if (showAsGrid()) { - // TODO(b/186800707) handle more elegantly for grid - continue; - } - int scrollDiff = newScroll[i] - oldScroll[i]; - if (scrollDiff != 0) { - FloatProperty translationProperty = child instanceof TaskView - ? ((TaskView) child).getPrimaryDismissTranslationProperty() - : mOrientationHandler.getPrimaryViewTranslate(); - - ResourceProvider rp = DynamicResource.provider(mActivity); - SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_END) - .setDampingRatio( - rp.getFloat(R.dimen.dismiss_task_trans_x_damping_ratio)) - .setStiffness(rp.getFloat(R.dimen.dismiss_task_trans_x_stiffness)); - pendingAnim.add(ObjectAnimator.ofFloat(child, translationProperty, scrollDiff) - .setDuration(duration), ACCEL, sp); - needsCurveUpdates = true; - } - } - } - - if (needsCurveUpdates) { - pendingAnim.addOnFrameCallback(this::updateCurveProperties); - } - - pendingAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - // TODO(b/186800707) Figure out how to undo for grid view - // Need to handle cases where dismissed task is - // * Top Row - // * Bottom Row - // * Focused Task - updateGridProperties(); - resetFromSplitSelectionState(); - updateScrollSynchronously(); - } - }); - - return pendingAnim; - } - /** TODO(b/181707736) More gracefully handle exiting split selection state */ private void resetFromSplitSelectionState() { if (!mActivity.getDeviceProfile().overviewShowAsGrid) { @@ -4077,8 +3981,8 @@ public abstract class RecentsView 0) { - final View taskView = getTaskViewAt(0); - getTaskViewAt(count - 1).getHitRect(mTaskViewDeadZoneRect); + final View taskView = requireTaskViewAt(0); + requireTaskViewAt(count - 1).getHitRect(mTaskViewDeadZoneRect); mTaskViewDeadZoneRect.union(taskView.getLeft(), taskView.getTop(), taskView.getRight(), taskView.getBottom()); } @@ -4559,7 +4463,7 @@ public abstract class RecentsView void show(T activity, int labelStringRedId, + Runnable onDismissed) { + show(activity, labelStringRedId, NO_ID, onDismissed, null); + } + + /** Show a snackbar with a label and action. */ + public static void show(T activity, int labelStringResId, + int actionStringResId, Runnable onDismissed, @Nullable Runnable onActionClicked) { closeOpenViews(activity, true, TYPE_SNACKBAR); Snackbar snackbar = new Snackbar(activity, null); // Set some properties here since inflated xml only contains the children. @@ -87,13 +95,30 @@ public class Snackbar extends AbstractFloatingView { params.setMargins(0, 0, 0, marginBottom + insets.bottom); TextView labelView = snackbar.findViewById(R.id.label); - TextView actionView = snackbar.findViewById(R.id.action); String labelText = res.getString(labelStringResId); - String actionText = res.getString(actionStringResId); - int totalContentWidth = (int) (labelView.getPaint().measureText(labelText) - + actionView.getPaint().measureText(actionText)) + labelView.setText(labelText); + + TextView actionView = snackbar.findViewById(R.id.action); + float actionWidth; + if (actionStringResId != NO_ID) { + String actionText = res.getString(actionStringResId); + actionWidth = actionView.getPaint().measureText(actionText) + + actionView.getPaddingRight() + actionView.getPaddingLeft(); + actionView.setText(actionText); + actionView.setOnClickListener(v -> { + if (onActionClicked != null) { + onActionClicked.run(); + } + snackbar.mOnDismissed = null; + snackbar.close(true); + }); + } else { + actionWidth = 0; + actionView.setVisibility(GONE); + } + + int totalContentWidth = (int) (labelView.getPaint().measureText(labelText) + actionWidth) + labelView.getPaddingRight() + labelView.getPaddingLeft() - + actionView.getPaddingRight() + actionView.getPaddingLeft() + padding * 2; if (totalContentWidth > params.width) { // The text doesn't fit in our standard width so update width to accommodate. @@ -113,17 +138,8 @@ public class Snackbar extends AbstractFloatingView { params.width = maxWidth; } } - labelView.setText(labelText); - actionView.setText(actionText); - actionView.setOnClickListener(v -> { - if (onActionClicked != null) { - onActionClicked.run(); - } - snackbar.mOnDismissed = null; - snackbar.close(true); - }); - snackbar.mOnDismissed = onDismissed; + snackbar.mOnDismissed = onDismissed; snackbar.setAlpha(0); snackbar.setScaleX(0.8f); snackbar.setScaleY(0.8f); diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java index 6e7264ac0b..0bac2ca258 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widgets.java +++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java @@ -77,7 +77,8 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { mLauncher.scroll( widgetsContainer, Direction.UP, - new Rect(0, 0, mLauncher.getVisibleBounds(widgetsContainer).width(), 0), + new Rect(0, 0, mLauncher.getRightGestureMarginInContainer(widgetsContainer) + 1, + 0), FLING_STEPS, false); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) { verifyActiveContainer();