Merge "Fix switch access for overview grid" into sc-v2-dev
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 0f92274..25b39ed 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -28,6 +28,7 @@
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
<uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS"/>
<uses-permission android:name="android.permission.REMOVE_TASKS"/>
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>
<uses-permission android:name="android.permission.STATUS_BAR"/>
<uses-permission android:name="android.permission.STOP_APP_SWITCHES"/>
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index 90c035f..f1e6747 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -60,6 +60,7 @@
@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 7d23439..2622700 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -99,6 +99,7 @@
@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 f6e0426..ce1e8b6b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -31,12 +31,14 @@
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;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
+import android.content.pm.ActivityInfo.Config;
import android.content.res.ColorStateList;
import android.graphics.Rect;
import android.graphics.Region;
@@ -85,6 +87,7 @@
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;
@@ -151,7 +154,9 @@
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(),
@@ -285,6 +290,7 @@
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);
@@ -294,6 +300,7 @@
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
@@ -445,6 +452,12 @@
return mFloatingRotationButtonBounds.contains((int) ev.getX(), (int) ev.getY());
}
+ public void onConfigurationChanged(@Config int configChanges) {
+ if (mFloatingRotationButton != null) {
+ mFloatingRotationButton.onConfigurationChanged(configChanges);
+ }
+ }
+
public void onDestroy() {
mPropertyHolders.clear();
mControllers.rotationButtonController.unregisterListeners();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 2e1e5bb..692352b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -30,6 +30,7 @@
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo.Config;
import android.content.pm.LauncherApps;
import android.graphics.Insets;
import android.graphics.PixelFormat;
@@ -205,6 +206,10 @@
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
}
+ public void onConfigurationChanged(@Config int configChanges) {
+ mControllers.onConfigurationChanged(configChanges);
+ }
+
public boolean isThreeButtonNav() {
return mNavMode == Mode.THREE_BUTTONS;
}
@@ -356,6 +361,7 @@
mControllers.taskbarStashController.updateStateForSysuiFlags(systemUiStateFlags, fromInit);
mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags,
fromInit);
+ mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 2d4942d..c43fbf9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.taskbar;
+import android.content.pm.ActivityInfo.Config;
+
import androidx.annotation.NonNull;
import com.android.systemui.shared.rotation.RotationButtonController;
@@ -108,6 +110,10 @@
mPostInitCallbacks.clear();
}
+ public void onConfigurationChanged(@Config int configChanges) {
+ navbarButtonsViewController.onConfigurationChanged(configChanges);
+ }
+
/**
* Cleans up all controllers.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 152b255..f3c8cf3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.taskbar;
-import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
@@ -68,9 +67,6 @@
private int mPrevState;
private int mState;
- private LauncherState mTargetStateOverride = null;
- private LauncherState mTargetStateOverrideForStateTransition = null;
-
private boolean mIsAnimatingToLauncherViaGesture;
private boolean mIsAnimatingToLauncherViaResume;
@@ -79,7 +75,6 @@
@Override
public void onStateTransitionStart(LauncherState toState) {
- mTargetStateOverrideForStateTransition = toState;
updateStateForFlag(FLAG_TRANSITION_STATE_START_STASHED,
toState.isTaskbarStashed());
applyState();
@@ -134,18 +129,6 @@
updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, true);
animatorSet.play(stashController.applyStateWithoutStart(duration));
animatorSet.play(applyState(duration, false));
- animatorSet.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animator) {
- mTargetStateOverride = null;
- animator.removeListener(this);
- }
-
- @Override
- public void onAnimationStart(Animator animator) {
- mTargetStateOverride = toState;
- }
- });
TaskBarRecentsAnimationListener listener = new TaskBarRecentsAnimationListener(callbacks);
callbacks.addListener(listener);
@@ -284,7 +267,6 @@
// Reset hotseat alpha to default
mLauncher.getHotseat().setIconsAlpha(1);
}
- mTargetStateOverrideForStateTransition = null;
}
@Override
@@ -296,8 +278,6 @@
animatorSet.play(mIconAlignmentForLauncherState.animateToValue(
getCurrentIconAlignmentRatioForLauncherState(),
isTransitionStateStashed ? 0 : 1));
- } else {
- mTargetStateOverrideForStateTransition = null;
}
}
@@ -318,20 +298,14 @@
}
private void onIconAlignmentRatioChangedForStateTransition() {
- onIconAlignmentRatioChanged(
- mTargetStateOverrideForStateTransition != null
- ? mTargetStateOverrideForStateTransition
- : mLauncher.getStateManager().getState(),
- this::getCurrentIconAlignmentRatioForLauncherState);
+ onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatioForLauncherState);
}
private void onIconAlignmentRatioChanged() {
- onIconAlignmentRatioChanged(mTargetStateOverride != null ? mTargetStateOverride
- : mLauncher.getStateManager().getState(), this::getCurrentIconAlignmentRatio);
+ onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatio);
}
- private void onIconAlignmentRatioChanged(LauncherState state,
- Supplier<Float> alignmentSupplier) {
+ private void onIconAlignmentRatioChanged(Supplier<Float> alignmentSupplier) {
if (mControllers == null) {
return;
}
@@ -341,7 +315,8 @@
mTaskbarBackgroundAlpha.updateValue(1 - alignment);
- setIconAlpha(state, alignment);
+ // Switch taskbar and hotseat in last frame
+ setTaskbarViewVisible(alignment < 1);
}
private float getCurrentIconAlignmentRatio() {
@@ -352,15 +327,6 @@
return mIconAlignmentForLauncherState.value;
}
- private void setIconAlpha(LauncherState state, float progress) {
- if ((state.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
- // If the hotseat icons are visible, then switch taskbar in last frame
- setTaskbarViewVisible(progress < 1);
- } else {
- mIconAlphaForHome.setValue(1 - progress);
- }
- }
-
private void setTaskbarViewVisible(boolean isVisible) {
mIconAlphaForHome.setValue(isVisible ? 1 : 0);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index a65cc56..3cdcdf7 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.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 @@
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();
@@ -106,6 +107,11 @@
if ((configDiff & configsRequiringRecreate) != 0) {
// Color has changed, recreate taskbar to reload background color & icons.
recreateTaskbar();
+ } else {
+ // Config change might be handled without re-creating the taskbar
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.onConfigurationChanged(configDiff);
+ }
}
mOldConfig = newConfig;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index ae23eda..d233365 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -19,8 +19,10 @@
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 @@
*/
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 @@
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 @@
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 @@
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 f713dca..f6bc785 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -18,6 +18,8 @@
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 @@
// 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/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index d74b6c5..c85b256 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -34,6 +34,7 @@
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.util.FloatProperty;
+import android.util.Pair;
import androidx.annotation.NonNull;
@@ -101,11 +102,13 @@
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
PagedOrientationHandler orientationHandler =
((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
- FloatProperty taskViewsFloat = orientationHandler.getSplitSelectTaskOffset(
- TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
- mLauncher.getDeviceProfile());
- setter.setFloat(mRecentsView, taskViewsFloat,
+ Pair<FloatProperty, FloatProperty> taskViewsFloat =
+ orientationHandler.getSplitSelectTaskOffset(
+ TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
+ mLauncher.getDeviceProfile());
+ setter.setFloat(mRecentsView, taskViewsFloat.first,
toState.getSplitSelectTranslation(mLauncher), LINEAR);
+ setter.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR);
setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index b21d677..19897a1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -66,6 +66,12 @@
// 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 @@
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 106375a..4f5f27a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
@@ -31,11 +31,6 @@
}
@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/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 097850f..c5f4a53 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -36,7 +36,6 @@
import com.android.wm.shell.util.GroupedRecentTaskInfo;
import com.android.wm.shell.util.StagedSplitBounds;
-import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
@@ -220,26 +219,6 @@
return newTasks;
}
- public void dump(String prefix, PrintWriter writer) {
- writer.println(prefix + "RecentTasksList:");
- writer.println(prefix + " mChangeId=" + mChangeId);
- writer.println(prefix + " mResultsUi=[id=" + mResultsUi.mRequestId + ", tasks=");
- for (GroupTask task : mResultsUi) {
- writer.println(prefix + " t1=" + task.task1.key.id
- + " t2=" + (task.hasMultipleTasks() ? task.task2.key.id : "-1"));
- }
- writer.println(prefix + " ]");
- int currentUserId = Process.myUserHandle().getIdentifier();
- ArrayList<GroupedRecentTaskInfo> rawTasks =
- mSysUiProxy.getRecentTasks(Integer.MAX_VALUE, currentUserId);
- writer.println(prefix + " rawTasks=[");
- for (GroupedRecentTaskInfo task : rawTasks) {
- writer.println(prefix + " t1=" + task.mTaskInfo1.taskId
- + " t2=" + (task.mTaskInfo2 != null ? task.mTaskInfo2.taskId : "-1"));
- }
- writer.println(prefix + " ]");
- }
-
private static class TaskLoadResult extends ArrayList<GroupTask> {
final int mRequestId;
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index dd6392c..b502676 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -23,6 +23,7 @@
import android.view.RemoteAnimationTarget;
import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
import com.android.launcher3.Utilities;
@@ -77,7 +78,7 @@
public void notifyAnimationCanceled() {
mCancelled = true;
- onAnimationCanceled(null);
+ onAnimationCanceled(new HashMap<>());
}
// Called only in Q platform
@@ -167,16 +168,17 @@
* Callback from the system when the recents animation is canceled. {@param thumbnailData}
* is passed back for rendering screenshot to replace live tile.
*/
- default void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {}
+ default void onRecentsAnimationCanceled(
+ @NonNull HashMap<Integer, ThumbnailData> thumbnailDatas) {}
/**
* Callback made whenever the recents animation is finished.
*/
- default void onRecentsAnimationFinished(RecentsAnimationController controller) {}
+ default void onRecentsAnimationFinished(@NonNull RecentsAnimationController controller) {}
/**
* Callback made when a task started from the recents is ready for an app transition.
*/
- default void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTarget) {}
+ default void onTasksAppeared(@NonNull RemoteAnimationTargetCompat[] appearedTaskTarget) {}
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 5d77a6e..e539a8c 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -43,7 +43,6 @@
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
-import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
@@ -221,11 +220,6 @@
mThumbnailChangeListeners.remove(listener);
}
- public void dump(String prefix, PrintWriter writer) {
- writer.println(prefix + "RecentsModel:");
- mTaskList.dump(" ", writer);
- }
-
/**
* Listener for receiving various task properties changes
*/
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 2543e6c..6c623bc 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -83,16 +83,14 @@
MAIN_EXECUTOR.execute(() -> clearProxy());
};
- // Save the listeners passed into the proxy since OverviewProxyService may not have been bound
- // yet, and we'll need to set/register these listeners with SysUI when they do. Note that it is
- // up to the caller to clear the listeners to prevent leaks as these can be held indefinitely
- // in case SysUI needs to rebind.
- private IPipAnimationListener mPipAnimationListener;
- private ISplitScreenListener mSplitScreenListener;
- private IStartingWindowListener mStartingWindowListener;
- private ISmartspaceCallback mSmartspaceCallback;
- private IRecentTasksListener mRecentTasksListener;
- private final ArrayList<RemoteTransitionCompat> mRemoteTransitions = new ArrayList<>();
+ // Save the listeners passed into the proxy since when set/register these listeners,
+ // setProxy may not have been called, eg. OverviewProxyService is not connected yet.
+ private IPipAnimationListener mPendingPipAnimationListener;
+ private ISplitScreenListener mPendingSplitScreenListener;
+ private IStartingWindowListener mPendingStartingWindowListener;
+ private ISmartspaceCallback mPendingSmartspaceCallback;
+ private IRecentTasksListener mPendingRecentTasksListener;
+ private final ArrayList<RemoteTransitionCompat> mPendingRemoteTransitions = new ArrayList<>();
// Used to dedupe calls to SystemUI
private int mLastShelfHeight;
@@ -169,23 +167,29 @@
mRecentTasks = recentTasks;
linkToDeath();
// re-attach the listeners once missing due to setProxy has not been initialized yet.
- if (mPipAnimationListener != null && mPip != null) {
- setPinnedStackAnimationListener(mPipAnimationListener);
+ if (mPendingPipAnimationListener != null && mPip != null) {
+ setPinnedStackAnimationListener(mPendingPipAnimationListener);
+ mPendingPipAnimationListener = null;
}
- if (mSplitScreenListener != null && mSplitScreen != null) {
- registerSplitScreenListener(mSplitScreenListener);
+ if (mPendingSplitScreenListener != null && mSplitScreen != null) {
+ registerSplitScreenListener(mPendingSplitScreenListener);
+ mPendingSplitScreenListener = null;
}
- if (mStartingWindowListener != null && mStartingWindow != null) {
- setStartingWindowListener(mStartingWindowListener);
+ if (mPendingStartingWindowListener != null && mStartingWindow != null) {
+ setStartingWindowListener(mPendingStartingWindowListener);
+ mPendingStartingWindowListener = null;
}
- if (mSmartspaceCallback != null && mSmartspaceTransitionController != null) {
- setSmartspaceCallback(mSmartspaceCallback);
+ if (mPendingSmartspaceCallback != null && mSmartspaceTransitionController != null) {
+ setSmartspaceCallback(mPendingSmartspaceCallback);
+ mPendingSmartspaceCallback = null;
}
- for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) {
- registerRemoteTransition(mRemoteTransitions.get(i));
+ for (int i = mPendingRemoteTransitions.size() - 1; i >= 0; --i) {
+ registerRemoteTransition(mPendingRemoteTransitions.get(i));
}
- if (mRecentTasksListener != null && mRecentTasks != null) {
- registerRecentTasksListener(mRecentTasksListener);
+ mPendingRemoteTransitions.clear();
+ if (mPendingRecentTasksListener != null && mRecentTasks != null) {
+ registerRecentTasksListener(mPendingRecentTasksListener);
+ mPendingRecentTasksListener = null;
}
if (mPendingSetNavButtonAlpha != null) {
@@ -509,8 +513,9 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call setPinnedStackAnimationListener", e);
}
+ } else {
+ mPendingPipAnimationListener = listener;
}
- mPipAnimationListener = listener;
}
public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
@@ -548,8 +553,9 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerSplitScreenListener");
}
+ } else {
+ mPendingSplitScreenListener = listener;
}
- mSplitScreenListener = listener;
}
public void unregisterSplitScreenListener(ISplitScreenListener listener) {
@@ -560,7 +566,7 @@
Log.w(TAG, "Failed call unregisterSplitScreenListener");
}
}
- mSplitScreenListener = null;
+ mPendingSplitScreenListener = null;
}
/** Start multiple tasks in split-screen simultaneously. */
@@ -593,11 +599,11 @@
}
}
- 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");
@@ -605,11 +611,11 @@
}
}
- 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");
}
@@ -681,8 +687,9 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerRemoteTransition");
}
+ } else {
+ mPendingRemoteTransitions.add(remoteTransition);
}
- mRemoteTransitions.add(remoteTransition);
}
public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) {
@@ -693,7 +700,7 @@
Log.w(TAG, "Failed call registerRemoteTransition");
}
}
- mRemoteTransitions.remove(remoteTransition);
+ mPendingRemoteTransitions.remove(remoteTransition);
}
//
@@ -710,8 +717,9 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call setStartingWindowListener", e);
}
+ } else {
+ mPendingStartingWindowListener = listener;
}
- mStartingWindowListener = listener;
}
//
@@ -725,8 +733,9 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call setStartingWindowListener", e);
}
+ } else {
+ mPendingSmartspaceCallback = callback;
}
- mSmartspaceCallback = callback;
}
//
@@ -740,8 +749,9 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerRecentTasksListener", e);
}
+ } else {
+ mPendingRecentTasksListener = listener;
}
- mRecentTasksListener = listener;
}
public void unregisterRecentTasksListener(IRecentTasksListener listener) {
@@ -752,7 +762,7 @@
Log.w(TAG, "Failed call unregisterRecentTasksListener");
}
}
- mRecentTasksListener = null;
+ mPendingRecentTasksListener = null;
}
public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) {
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index f6f2cf9..2c7fd71 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -973,7 +973,6 @@
pw.println(" resumed=" + resumed);
pw.println(" mConsumer=" + mConsumer.getName());
ActiveGestureLog.INSTANCE.dump("", pw);
- RecentsModel.INSTANCE.get(this).dump("", pw);
pw.println("ProtoTrace:");
pw.println(" file=" + ProtoTracer.INSTANCE.get(this).getTraceFile());
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index d2373c9..169b208 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -31,6 +31,7 @@
import androidx.annotation.Nullable;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateListener;
@@ -73,6 +74,7 @@
@Override
public void startHome() {
mActivity.startHome();
+ AbstractFloatingView.closeAllOpenViews(mActivity, mActivity.isStarted());
}
/**
diff --git a/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java b/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java
new file mode 100644
index 0000000..861ff96
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.annotation.CallSuper;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator;
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Animation that moves launcher icons and widgets from center to the sides (final position)
+ */
+public abstract class BaseUnfoldMoveFromCenterAnimator implements TransitionProgressListener {
+
+ private final UnfoldMoveFromCenterAnimator mMoveFromCenterAnimation;
+
+ private final Map<ViewGroup, Boolean> mOriginalClipToPadding = new HashMap<>();
+ private final Map<ViewGroup, Boolean> mOriginalClipChildren = new HashMap<>();
+
+ public BaseUnfoldMoveFromCenterAnimator(WindowManager windowManager) {
+ mMoveFromCenterAnimation = new UnfoldMoveFromCenterAnimator(windowManager,
+ new LauncherViewsMoveFromCenterTranslationApplier());
+ }
+
+ @CallSuper
+ @Override
+ public void onTransitionStarted() {
+ mMoveFromCenterAnimation.updateDisplayProperties();
+ onPrepareViewsForAnimation();
+ onTransitionProgress(0f);
+ }
+
+ @CallSuper
+ @Override
+ public void onTransitionProgress(float progress) {
+ mMoveFromCenterAnimation.onTransitionProgress(progress);
+ }
+
+ @CallSuper
+ @Override
+ public void onTransitionFinished() {
+ mMoveFromCenterAnimation.onTransitionFinished();
+ mMoveFromCenterAnimation.clearRegisteredViews();
+
+ mOriginalClipChildren.clear();
+ mOriginalClipToPadding.clear();
+ }
+
+ protected void onPrepareViewsForAnimation() {
+
+ }
+
+ protected void registerViewForAnimation(View view) {
+ mMoveFromCenterAnimation.registerViewForAnimation(view);
+ }
+
+ protected void disableClipping(ViewGroup view) {
+ mOriginalClipToPadding.put(view, view.getClipToPadding());
+ mOriginalClipChildren.put(view, view.getClipChildren());
+ view.setClipToPadding(false);
+ view.setClipChildren(false);
+ }
+
+ protected void restoreClipping(ViewGroup view) {
+ final Boolean originalClipToPadding = mOriginalClipToPadding.get(view);
+ if (originalClipToPadding != null) {
+ view.setClipToPadding(originalClipToPadding);
+ }
+ final Boolean originalClipChildren = mOriginalClipChildren.get(view);
+ if (originalClipChildren != null) {
+ view.setClipChildren(originalClipChildren);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
index b39412b..6b6bd6a 100644
--- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
+++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
@@ -18,14 +18,17 @@
import static com.android.launcher3.Utilities.comp;
import android.annotation.Nullable;
-import android.view.ViewTreeObserver;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import androidx.core.view.OneShotPreDrawListener;
import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.util.HorizontalInsettableView;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener;
+import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
/**
@@ -43,6 +46,7 @@
private HorizontalInsettableView mQsbInsettable;
private final ScopedUnfoldTransitionProgressProvider mProgressProvider;
+ private final NaturalRotationUnfoldProgressProvider mNaturalOrientationProgressProvider;
public LauncherUnfoldAnimationController(
Launcher launcher,
@@ -51,10 +55,19 @@
mLauncher = launcher;
mProgressProvider = new ScopedUnfoldTransitionProgressProvider(
unfoldTransitionProgressProvider);
+ mNaturalOrientationProgressProvider = new NaturalRotationUnfoldProgressProvider(launcher,
+ WindowManagerGlobal.getWindowManagerService(), mProgressProvider);
+ mNaturalOrientationProgressProvider.init();
+ // Animated in all orientations
mProgressProvider.addCallback(new UnfoldMoveFromCenterWorkspaceAnimator(launcher,
windowManager));
- mProgressProvider.addCallback(new QsbAnimationListener());
+
+ // Animated only in natural orientation
+ mNaturalOrientationProgressProvider
+ .addCallback(new QsbAnimationListener());
+ mNaturalOrientationProgressProvider
+ .addCallback(new UnfoldMoveFromCenterHotseatAnimator(launcher, windowManager));
}
/**
@@ -66,17 +79,8 @@
mQsbInsettable = (HorizontalInsettableView) hotseat.getQsb();
}
- final ViewTreeObserver obs = mLauncher.getWorkspace().getViewTreeObserver();
- obs.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- if (obs.isAlive()) {
- mProgressProvider.setReadyToHandleTransition(true);
- obs.removeOnPreDrawListener(this);
- }
- return true;
- }
- });
+ OneShotPreDrawListener.add(mLauncher.getWorkspace(),
+ () -> mProgressProvider.setReadyToHandleTransition(true));
}
/**
@@ -92,6 +96,7 @@
*/
public void onDestroy() {
mProgressProvider.destroy();
+ mNaturalOrientationProgressProvider.destroy();
}
private class QsbAnimationListener implements TransitionProgressListener {
diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java
new file mode 100644
index 0000000..dc97dd6
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.launcher3.Hotseat;
+import com.android.launcher3.Launcher;
+
+/**
+ * Animation that moves hotseat icons from center to the sides (final position)
+ */
+public class UnfoldMoveFromCenterHotseatAnimator extends BaseUnfoldMoveFromCenterAnimator {
+
+ private final Launcher mLauncher;
+
+ public UnfoldMoveFromCenterHotseatAnimator(Launcher launcher, WindowManager windowManager) {
+ super(windowManager);
+ mLauncher = launcher;
+ }
+
+ @Override
+ protected void onPrepareViewsForAnimation() {
+ Hotseat hotseat = mLauncher.getHotseat();
+
+ ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets();
+ disableClipping(hotseat);
+
+ for (int i = 0; i < hotseatIcons.getChildCount(); i++) {
+ View child = hotseatIcons.getChildAt(i);
+ registerViewForAnimation(child);
+ }
+ }
+
+ @Override
+ public void onTransitionFinished() {
+ restoreClipping(mLauncher.getHotseat());
+ super.onTransitionFinished();
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
index 95403b2..3d72398 100644
--- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
@@ -16,44 +16,28 @@
package com.android.quickstep.util;
import android.view.View;
-import android.view.ViewGroup;
import android.view.WindowManager;
import com.android.launcher3.CellLayout;
-import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Workspace;
-import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator;
-import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
-
-import java.util.HashMap;
-import java.util.Map;
/**
* Animation that moves launcher icons and widgets from center to the sides (final position)
*/
-public class UnfoldMoveFromCenterWorkspaceAnimator
- implements UnfoldTransitionProgressProvider.TransitionProgressListener {
+public class UnfoldMoveFromCenterWorkspaceAnimator extends BaseUnfoldMoveFromCenterAnimator {
private final Launcher mLauncher;
- private final UnfoldMoveFromCenterAnimator mMoveFromCenterAnimation;
-
- private final Map<ViewGroup, Boolean> mOriginalClipToPadding = new HashMap<>();
- private final Map<ViewGroup, Boolean> mOriginalClipChildren = new HashMap<>();
public UnfoldMoveFromCenterWorkspaceAnimator(Launcher launcher, WindowManager windowManager) {
+ super(windowManager);
mLauncher = launcher;
- mMoveFromCenterAnimation = new UnfoldMoveFromCenterAnimator(windowManager,
- new LauncherViewsMoveFromCenterTranslationApplier());
}
@Override
- public void onTransitionStarted() {
- mMoveFromCenterAnimation.updateDisplayProperties();
-
+ protected void onPrepareViewsForAnimation() {
Workspace workspace = mLauncher.getWorkspace();
- Hotseat hotseat = mLauncher.getHotseat();
// App icons and widgets
workspace
@@ -65,57 +49,17 @@
for (int i = 0; i < itemsContainer.getChildCount(); i++) {
View child = itemsContainer.getChildAt(i);
- mMoveFromCenterAnimation.registerViewForAnimation(child);
+ registerViewForAnimation(child);
}
});
disableClipping(workspace);
-
- // Hotseat icons
- ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets();
- disableClipping(hotseat);
-
- for (int i = 0; i < hotseatIcons.getChildCount(); i++) {
- View child = hotseatIcons.getChildAt(i);
- mMoveFromCenterAnimation.registerViewForAnimation(child);
- }
-
- onTransitionProgress(0f);
- }
-
- @Override
- public void onTransitionProgress(float progress) {
- mMoveFromCenterAnimation.onTransitionProgress(progress);
}
@Override
public void onTransitionFinished() {
- mMoveFromCenterAnimation.onTransitionFinished();
- mMoveFromCenterAnimation.clearRegisteredViews();
-
restoreClipping(mLauncher.getWorkspace());
mLauncher.getWorkspace().forEachVisiblePage(page -> restoreClipping((CellLayout) page));
- restoreClipping(mLauncher.getHotseat());
-
- mOriginalClipChildren.clear();
- mOriginalClipToPadding.clear();
- }
-
- private void disableClipping(ViewGroup view) {
- mOriginalClipToPadding.put(view, view.getClipToPadding());
- mOriginalClipChildren.put(view, view.getClipChildren());
- view.setClipToPadding(false);
- view.setClipChildren(false);
- }
-
- private void restoreClipping(ViewGroup view) {
- final Boolean originalClipToPadding = mOriginalClipToPadding.get(view);
- if (originalClipToPadding != null) {
- view.setClipToPadding(originalClipToPadding);
- }
- final Boolean originalClipChildren = mOriginalClipChildren.get(view);
- if (originalClipChildren != null) {
- view.setClipChildren(originalClipChildren);
- }
+ super.onTransitionFinished();
}
}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index 325ec04..a343e0a 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -129,9 +129,7 @@
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 @@
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 00f541d..9311261 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -157,10 +157,20 @@
@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
@@ -248,4 +258,10 @@
super.updateSnapshotRadius();
mSnapshotView2.setFullscreenParams(mCurrentFullscreenParams);
}
+
+ @Override
+ protected void setIconAndDimTransitionProgress(float progress, boolean invert) {
+ super.setIconAndDimTransitionProgress(progress, invert);
+ mIconView2.setAlpha(mIconView.getAlpha());
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index d001690..3e06f55 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -32,6 +32,7 @@
import androidx.annotation.Nullable;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.statehandlers.DepthController;
@@ -70,6 +71,7 @@
@Override
public void startHome() {
mActivity.getStateManager().goToState(NORMAL);
+ AbstractFloatingView.closeAllOpenViews(mActivity, mActivity.isStarted());
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index d731d36..2ad586d 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.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 java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Objects;
import java.util.function.Consumer;
/**
@@ -822,7 +824,7 @@
@Override
public void onTaskIconChanged(String pkg, UserHandle user) {
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView tv = getTaskViewAt(i);
+ TaskView tv = requireTaskViewAt(i);
Task task = tv.getTask();
if (task != null && task.key != null && pkg.equals(task.key.getPackageName())
&& task.key.userId == user.getIdentifier()) {
@@ -1124,7 +1126,7 @@
}
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
int[] taskIds = taskView.getTaskIds();
if (taskIds[0] == taskId || taskIds[1] == taskId) {
return taskView;
@@ -1141,9 +1143,6 @@
// Reset the running task when leaving overview since it can still have a reference to
// its thumbnail
mTmpRunningTasks = null;
- if (mSplitSelectStateController.isSplitSelectActive()) {
- cancelSplitSelect(false);
- }
// Remove grouped tasks and recycle once we exit overview
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
@@ -1201,7 +1200,7 @@
if (showAsGrid()) {
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
if (isTaskViewVisible(taskView) && taskView.offerTouchToChildren(ev)) {
// Keep consuming events to pass to delegate
return true;
@@ -1438,7 +1437,7 @@
if (runningTaskId != -1) {
targetPage = indexOfChild(newRunningTaskView);
} else if (getTaskViewCount() > 0) {
- targetPage = indexOfChild(getTaskViewAt(0));
+ targetPage = indexOfChild(requireTaskViewAt(0));
}
} else if (currentTaskId != -1) {
currentTaskView = getTaskViewByTaskId(currentTaskId);
@@ -1472,7 +1471,7 @@
private void removeTasksViewsAndClearAllButton() {
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
- removeView(getTaskViewAt(i));
+ removeView(requireTaskViewAt(i));
}
if (indexOfChild(mClearAllButton) != -1) {
removeView(mClearAllButton);
@@ -1518,7 +1517,7 @@
public void resetTaskVisuals() {
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
if (mIgnoreResetTaskId != taskView.getTaskIds()[0]) {
taskView.resetViewTransforms();
taskView.setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
@@ -1528,6 +1527,16 @@
}
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ // resetTaskVisuals is called at the end of dismiss animation which could update
+ // primary and secondary translation of the live tile cut out. We will need to do so
+ // here accordingly.
+ runActionOnRemoteHandles(remoteTargetHandle -> {
+ TaskViewSimulator simulator = remoteTargetHandle.getTaskViewSimulator();
+ simulator.taskPrimaryTranslation.value = 0;
+ simulator.taskSecondaryTranslation.value = 0;
+ simulator.fullScreenProgress.value = 0;
+ simulator.recentsViewScale.value = 1;
+ });
// Similar to setRunningTaskHidden below, reapply the state before runningTaskView is
// null.
if (!mRunningTaskShowScreenshot) {
@@ -1549,7 +1558,7 @@
mFullscreenProgress = fullscreenProgress;
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
- getTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
+ requireTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
}
mClearAllButton.setFullscreenProgress(fullscreenProgress);
@@ -1676,7 +1685,7 @@
float accumulatedTranslationX = 0;
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
taskView.updateTaskSize();
taskView.getPrimaryNonGridTranslationProperty().set(taskView, accumulatedTranslationX);
taskView.getSecondaryNonGridTranslationProperty().set(taskView, 0f);
@@ -1822,7 +1831,7 @@
// Update the task data for the in/visible children
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
Task task = taskView.getTask();
int index = indexOfChild(taskView);
boolean visible;
@@ -1965,7 +1974,7 @@
}
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
if (taskView.getTaskViewId() == taskViewId) {
return taskView;
}
@@ -2063,7 +2072,7 @@
int runningIndex = getCurrentPage();
AnimatorSet as = new AnimatorSet();
for (int i = 0; i < getTaskViewCount(); i++) {
- View taskView = getTaskViewAt(i);
+ View taskView = requireTaskViewAt(i);
if (runningIndex == i && taskView.getAlpha() != 0) {
continue;
}
@@ -2074,7 +2083,7 @@
private void updateChildTaskOrientations() {
for (int i = 0; i < getTaskViewCount(); i++) {
- getTaskViewAt(i).setOrientationState(mOrientationState);
+ requireTaskViewAt(i).setOrientationState(mOrientationState);
}
TaskMenuView tv = (TaskMenuView) getTopOpenViewWithType(mActivity, TYPE_TASK_MENU);
if (tv != null) {
@@ -2279,7 +2288,7 @@
mTaskIconScaledDown = isScaledDown;
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
- getTaskViewAt(i).setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
+ requireTaskViewAt(i).setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
}
}
}
@@ -2295,7 +2304,7 @@
mTaskIconScaledDown = false;
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
taskView.setIconScaleAnimStartProgress(0f);
taskView.animateIconScaleAndDimIntoView();
}
@@ -2367,7 +2376,7 @@
mTopRowIdSet.clear();
}
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
int taskWidthAndSpacing = taskView.getLayoutParams().width + mPageSpacing;
// Evenly distribute tasks between rows unless rearranging due to task dismissal, in
// which case keep tasks in their respective rows. For the running task, don't join
@@ -2432,7 +2441,7 @@
if (j == focusedTaskIndex) {
continue;
}
- widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
+ widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
}
float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
@@ -2451,7 +2460,7 @@
if (j == focusedTaskIndex) {
continue;
}
- widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
+ widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
}
float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
@@ -2529,7 +2538,7 @@
}
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
taskView.setGridTranslationX(gridTranslations[i] - snappedTaskGridTranslationX
+ snappedTaskNonGridScrollAdjustment);
}
@@ -2570,7 +2579,7 @@
mGridProgress = gridProgress;
for (int i = 0; i < taskCount; i++) {
- getTaskViewAt(i).setGridProgress(gridProgress);
+ requireTaskViewAt(i).setGridProgress(gridProgress);
}
mClearAllButton.setGridProgress(gridProgress);
}
@@ -2733,7 +2742,7 @@
mTopRowIdSet.size() > 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;
}
@@ -2836,7 +2845,7 @@
+ (taskCount - 1) * halfAdditionalDismissTranslationOffset,
END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET, 1);
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
anim.setFloat(taskView, TaskView.GRID_END_TRANSLATION_X, longGridRowWidthDiff,
clampToProgress(LINEAR, dismissTranslationInterpolationEnd, 1));
dismissTranslationInterpolationEnd = Utilities.boundToRange(
@@ -3152,7 +3161,7 @@
// Rebalance tasks in the grid
int highestVisibleTaskIndex = getHighestVisibleTaskIndex();
if (highestVisibleTaskIndex < Integer.MAX_VALUE) {
- TaskView taskView = getTaskViewAt(highestVisibleTaskIndex);
+ TaskView taskView = requireTaskViewAt(highestVisibleTaskIndex);
boolean shouldRebalance;
int screenStart = mOrientationHandler.getPrimaryScroll(
@@ -3250,7 +3259,7 @@
IntArray topArray = new IntArray(mTopRowIdSet.size());
int taskViewCount = getTaskViewCount();
for (int i = 0; i < taskViewCount; i++) {
- int taskViewId = getTaskViewAt(i).getTaskViewId();
+ int taskViewId = requireTaskViewAt(i).getTaskViewId();
if (mTopRowIdSet.contains(taskViewId)) {
topArray.add(taskViewId);
}
@@ -3269,7 +3278,7 @@
IntArray bottomArray = new IntArray(bottomRowIdArraySize);
int taskViewCount = getTaskViewCount();
for (int i = 0; i < taskViewCount; i++) {
- int taskViewId = getTaskViewAt(i).getTaskViewId();
+ int taskViewId = requireTaskViewAt(i).getTaskViewId();
if (!mTopRowIdSet.contains(taskViewId) && taskViewId != mFocusedTaskViewId) {
bottomArray.add(taskViewId);
}
@@ -3339,7 +3348,7 @@
int count = getTaskViewCount();
for (int i = 0; i < count; i++) {
- addDismissedTaskAnimations(getTaskViewAt(i), duration, anim);
+ addDismissedTaskAnimations(requireTaskViewAt(i), duration, anim);
}
mPendingAnimation = anim;
@@ -3462,7 +3471,7 @@
mContentAlpha = alpha;
int runningTaskId = getTaskIdsForRunningTaskView()[0];
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
- TaskView child = getTaskViewAt(i);
+ TaskView child = requireTaskViewAt(i);
int[] childTaskIds = child.getTaskIds();
if (!mRunningTaskTileHidden ||
(childTaskIds[0] != runningTaskId && childTaskIds[1] != runningTaskId)) {
@@ -3563,6 +3572,14 @@
return child instanceof TaskView ? (TaskView) child : null;
}
+ /**
+ * A version of {@link #getTaskViewAt} when the caller is sure about the input index.
+ */
+ @NonNull
+ private TaskView requireTaskViewAt(int index) {
+ return Objects.requireNonNull(getTaskViewAt(index));
+ }
+
public void setOnEmptyMessageUpdatedListener(OnEmptyMessageUpdatedListener listener) {
mOnEmptyMessageUpdatedListener = listener;
}
@@ -3779,7 +3796,7 @@
protected void setTaskViewsResistanceTranslation(float translation) {
mTaskViewsSecondaryTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView task = getTaskViewAt(i);
+ TaskView task = requireTaskViewAt(i);
task.getTaskResistanceTranslationProperty().set(task, translation / getScaleY());
}
runActionOnRemoteHandles(
@@ -3789,14 +3806,14 @@
private void updateTaskViewsSnapshotRadius() {
for (int i = 0; i < getTaskViewCount(); i++) {
- getTaskViewAt(i).updateSnapshotRadius();
+ requireTaskViewAt(i).updateSnapshotRadius();
}
}
protected void setTaskViewsPrimarySplitTranslation(float translation) {
mTaskViewsPrimarySplitTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView task = getTaskViewAt(i);
+ TaskView task = requireTaskViewAt(i);
task.getPrimarySplitTranslationProperty().set(task, translation);
}
}
@@ -3804,7 +3821,7 @@
protected void setTaskViewsSecondarySplitTranslation(float translation) {
mTaskViewsSecondarySplitTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
if (taskView == mSplitHiddenTaskView) {
continue;
}
@@ -3818,7 +3835,7 @@
public void applySplitPrimaryScrollOffset() {
if (isSplitPlaceholderFirstInGrid()) {
for (int i = 0; i < getTaskViewCount(); i++) {
- getTaskViewAt(i).setSplitScrollOffsetPrimary(mSplitPlaceholderSize);
+ requireTaskViewAt(i).setSplitScrollOffsetPrimary(mSplitPlaceholderSize);
}
} else if (isSplitPlaceholderLastInGrid()) {
mClearAllButton.setSplitSelectScrollOffsetPrimary(-mSplitPlaceholderSize);
@@ -3860,7 +3877,7 @@
*/
public void resetSplitPrimaryScrollOffset() {
for (int i = 0; i < getTaskViewCount(); i++) {
- getTaskViewAt(i).setSplitScrollOffsetPrimary(0);
+ requireTaskViewAt(i).setSplitScrollOffsetPrimary(0);
}
mClearAllButton.setSplitSelectScrollOffsetPrimary(0);
}
@@ -3940,109 +3957,6 @@
pendingAnimation.buildAnim().start();
}
- public PendingAnimation cancelSplitSelect(boolean animate) {
- SplitSelectStateController splitController = mSplitSelectStateController;
- @StagePosition int stagePosition = splitController.getActiveSplitStagePosition();
- Rect initialBounds = splitController.getInitialBounds();
- splitController.resetState();
- int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
- PendingAnimation pendingAnim = new PendingAnimation(duration);
- mSplitToast.cancel();
- mSplitUnsupportedToast.cancel();
- if (!animate) {
- resetFromSplitSelectionState();
- return pendingAnim;
- }
-
- addViewInLayout(mSplitHiddenTaskView, mSplitHiddenTaskViewIndex,
- mSplitHiddenTaskView.getLayoutParams());
- mSplitHiddenTaskView.setAlpha(0);
- int[] oldScroll = new int[getChildCount()];
- getPageScrolls(oldScroll, false,
- view -> 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<TaskView> 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) {
@@ -4087,8 +4001,8 @@
mTaskViewDeadZoneRect.setEmpty();
int count = getTaskViewCount();
if (count > 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());
}
@@ -4569,7 +4483,7 @@
final int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
float scrollDiff = taskView.getScrollAdjustment(showAsFullscreen, showAsGrid);
int pageScroll = newPageScrolls[i] + (int) scrollDiff;
if ((mIsRtl && pageScroll < clearAllScroll + clearAllWidth)
@@ -4737,7 +4651,7 @@
int overlayEnabledPage = mOverlayEnabled ? getNextPage() : -1;
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
- getTaskViewAt(i).setOverlayEnabled(i == overlayEnabledPage);
+ requireTaskViewAt(i).setOverlayEnabled(i == overlayEnabledPage);
}
}
@@ -4891,7 +4805,7 @@
mColorTint = tintAmount;
for (int i = 0; i < getTaskViewCount(); i++) {
- getTaskViewAt(i).setColorTint(mColorTint, mTintingColor);
+ requireTaskViewAt(i).setColorTint(mColorTint, mTintingColor);
}
Drawable scrimBg = mActivity.getScrimView().getBackground();
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index d91669a..da92551 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -19,6 +19,7 @@
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+import static com.android.launcher3.Utilities.comp;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
@@ -290,8 +291,17 @@
float cornerRadius) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (mTask != null && getTaskView().isRunningTask() && !getTaskView().showScreenshot()) {
- canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mClearPaint);
- canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius,
+ // TODO(b/189265196): Temporary fix to align the surface with the cutout perfectly.
+ // Round up only when the live tile task is displayed in Overview.
+ float rounding = comp(mFullscreenParams.mFullscreenProgress);
+ float left = x + rounding / 2;
+ float top = y + rounding / 2;
+ float right = width - rounding;
+ float bottom = height - rounding;
+
+ canvas.drawRoundRect(left, top, right, bottom, cornerRadius, cornerRadius,
+ mClearPaint);
+ canvas.drawRoundRect(left, top, right, bottom, cornerRadius, cornerRadius,
mDimmingPaintAfterClearing);
return;
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index e8077cf..8dee4e7 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -599,7 +599,9 @@
if (confirmSecondSplitSelectApp()) {
return;
}
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
+ RecentsView recentsView = getRecentsView();
+ RemoteTargetHandle[] remoteTargetHandles = recentsView.mRemoteTargetHandles;
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask() && remoteTargetHandles != null) {
if (!mIsClickableAsLiveTile) {
return;
}
@@ -612,9 +614,7 @@
}
mIsClickableAsLiveTile = false;
- RecentsView recentsView = getRecentsView();
RemoteAnimationTargets targets;
- RemoteTargetHandle[] remoteTargetHandles = recentsView.mRemoteTargetHandles;
if (remoteTargetHandles.length == 1) {
targets = remoteTargetHandles[0].getTransformParams().getTargetSet();
} else {
@@ -912,7 +912,7 @@
return deviceProfile.overviewShowAsGrid && !isFocusedTask();
}
- private void setIconAndDimTransitionProgress(float progress, boolean invert) {
+ protected void setIconAndDimTransitionProgress(float progress, boolean invert) {
if (invert) {
progress = 1 - progress;
}
@@ -1531,6 +1531,7 @@
private final float mCornerRadius;
private final float mWindowCornerRadius;
+ public float mFullscreenProgress;
public RectF mCurrentDrawnInsets = new RectF();
public float mCurrentDrawnCornerRadius;
/** The current scale we apply to the thumbnail to adjust for new left/right insets. */
@@ -1548,6 +1549,8 @@
*/
public void setProgress(float fullscreenProgress, float parentScale, float taskViewScale,
int previewWidth, DeviceProfile dp, PreviewPositionHelper pph) {
+ mFullscreenProgress = fullscreenProgress;
+
RectF insets = pph.getInsetsToDrawInFullscreen(dp);
float currentInsetsLeft = insets.left * fullscreenProgress;
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
new file mode 100644
index 0000000..ba1a60d
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
@@ -0,0 +1,159 @@
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.SCREEN_PIN_LONG_PRESS_THRESHOLD;
+import static com.android.quickstep.OverviewCommandHelper.TYPE_HOME;
+import static com.android.quickstep.OverviewCommandHelper.TYPE_TOGGLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.quickstep.OverviewCommandHelper;
+import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TouchInteractionService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class TaskbarNavButtonControllerTest {
+
+ private final static int DISPLAY_ID = 2;
+
+ @Mock
+ SystemUiProxy mockSystemUiProxy;
+ @Mock
+ TouchInteractionService mockService;
+ @Mock
+ OverviewCommandHelper mockCommandHelper;
+ @Mock
+ Handler mockHandler;
+
+ private TaskbarNavButtonController mNavButtonController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(mockService.getDisplayId()).thenReturn(DISPLAY_ID);
+ when(mockService.getOverviewCommandHelper()).thenReturn(mockCommandHelper);
+ mNavButtonController = new TaskbarNavButtonController(mockService,
+ mockSystemUiProxy, mockHandler);
+ }
+
+ @Test
+ public void testPressBack() {
+ mNavButtonController.onButtonClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(1)).onBackPressed();
+ }
+
+ @Test
+ public void testPressImeSwitcher() {
+ mNavButtonController.onButtonClick(BUTTON_IME_SWITCH);
+ verify(mockSystemUiProxy, times(1)).onImeSwitcherPressed();
+ }
+
+ @Test
+ public void testPressA11yShortClick() {
+ mNavButtonController.onButtonClick(BUTTON_A11Y);
+ verify(mockSystemUiProxy, times(1))
+ .notifyAccessibilityButtonClicked(DISPLAY_ID);
+ }
+
+ @Test
+ public void testPressA11yLongClick() {
+ mNavButtonController.onButtonLongClick(BUTTON_A11Y);
+ verify(mockSystemUiProxy, times(1)).notifyAccessibilityButtonLongClicked();
+ }
+
+ @Test
+ public void testLongPressHome() {
+ mNavButtonController.onButtonLongClick(BUTTON_HOME);
+ verify(mockSystemUiProxy, times(1)).startAssistant(any());
+ }
+
+ @Test
+ public void testPressHome() {
+ mNavButtonController.onButtonClick(BUTTON_HOME);
+ verify(mockCommandHelper, times(1)).addCommand(TYPE_HOME);
+ }
+
+ @Test
+ public void testPressRecents() {
+ mNavButtonController.onButtonClick(BUTTON_RECENTS);
+ verify(mockCommandHelper, times(1)).addCommand(TYPE_TOGGLE);
+ }
+
+ @Test
+ public void testPressRecentsWithScreenPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonClick(BUTTON_RECENTS);
+ verify(mockCommandHelper, times(0)).addCommand(TYPE_TOGGLE);
+ }
+
+ @Test
+ public void testLongPressBackRecentsNotPinned() {
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(0)).stopScreenPinning();
+ }
+
+ @Test
+ public void testLongPressBackRecentsPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(1)).stopScreenPinning();
+ }
+
+ @Test
+ public void testLongPressBackRecentsTooLongPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ try {
+ Thread.sleep(SCREEN_PIN_LONG_PRESS_THRESHOLD + 5);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(0)).stopScreenPinning();
+ }
+
+ @Test
+ public void testLongPressBackRecentsMultipleAttemptPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ try {
+ Thread.sleep(SCREEN_PIN_LONG_PRESS_THRESHOLD + 5);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(0)).stopScreenPinning();
+
+ // Try again w/in threshold
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(1)).stopScreenPinning();
+ }
+
+ @Test
+ public void testLongPressHomeScreenPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonLongClick(BUTTON_HOME);
+ verify(mockSystemUiProxy, times(0)).startAssistant(any());
+ }
+}
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 78f3f11..c689942 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -321,6 +321,9 @@
<!-- Size of the maximum radius for the enforced rounded rectangles. -->
<dimen name="enforced_rounded_corner_max_radius">16dp</dimen>
+<!-- Base Swipe Detector, speed in dp/s -->
+ <dimen name="base_swift_detector_fling_release_velocity">1dp</dimen>
+
<!-- Overview placeholder to compile in Launcher3 without Quickstep -->
<dimen name="task_thumbnail_icon_size">0dp</dimen>
<dimen name="task_thumbnail_icon_drawable_size">0dp</dimen>
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index d844b87..2ebedf7 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -286,7 +286,11 @@
mExtraAttrs = closestProfile.extraAttrs;
iconSize = displayOption.iconSizes;
- iconBitmapSize = ResourceUtils.pxFromDp(iconSize[INDEX_DEFAULT], metrics);
+ float maxIconSize = iconSize[0];
+ for (int i = 1; i < iconSize.length; i++) {
+ maxIconSize = Math.max(maxIconSize, iconSize[i]);
+ }
+ iconBitmapSize = ResourceUtils.pxFromDp(maxIconSize, metrics);
fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
iconTextSize = displayOption.textSizes;
@@ -555,13 +559,10 @@
}
out.multiply(1.0f / weights);
- // Since the bitmaps are persisted, ensure that the default bitmap size is same as
+ // Since the bitmaps are persisted, ensure that all bitmap sizes are not larger than
// predefined size to avoid cache invalidation
- out.iconSizes[INDEX_DEFAULT] =
- closestPoint.iconSizes[INDEX_DEFAULT];
- for (int i = INDEX_DEFAULT + 1; i < COUNT_SIZES; i++) {
- out.iconSizes[i] = Math.min(out.iconSizes[i],
- out.iconSizes[INDEX_DEFAULT]);
+ for (int i = INDEX_DEFAULT; i < COUNT_SIZES; i++) {
+ out.iconSizes[i] = Math.min(out.iconSizes[i], closestPoint.iconSizes[i]);
}
return out;
diff --git a/src/com/android/launcher3/touch/BaseSwipeDetector.java b/src/com/android/launcher3/touch/BaseSwipeDetector.java
index 1276ece..52c3581 100644
--- a/src/com/android/launcher3/touch/BaseSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BaseSwipeDetector.java
@@ -17,6 +17,7 @@
import static android.view.MotionEvent.INVALID_POINTER_ID;
+import android.content.Context;
import android.graphics.PointF;
import android.util.Log;
import android.view.MotionEvent;
@@ -26,6 +27,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.R;
+
import java.util.LinkedList;
import java.util.Queue;
@@ -44,10 +47,9 @@
private static final boolean DBG = false;
private static final String TAG = "BaseSwipeDetector";
private static final float ANIMATION_DURATION = 1200;
- /** The minimum release velocity in pixels per millisecond that triggers fling.*/
- private static final float RELEASE_VELOCITY_PX_MS = 1.0f;
private static final PointF sTempPoint = new PointF();
+ private final float mReleaseVelocity;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
protected final boolean mIsRtl;
@@ -64,6 +66,7 @@
private boolean mIsSettingState;
protected boolean mIgnoreSlopWhenSettling;
+ protected Context mContext;
private enum ScrollState {
IDLE,
@@ -71,10 +74,14 @@
SETTLING // onDragEnd
}
- protected BaseSwipeDetector(@NonNull ViewConfiguration config, boolean isRtl) {
+ protected BaseSwipeDetector(@NonNull Context context, @NonNull ViewConfiguration config,
+ boolean isRtl) {
mTouchSlop = config.getScaledTouchSlop();
mMaxVelocity = config.getScaledMaximumFlingVelocity();
mIsRtl = isRtl;
+ mContext = context;
+ mReleaseVelocity = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.base_swift_detector_fling_release_velocity);
}
public static long calculateDuration(float velocity, float progressNeeded) {
@@ -120,7 +127,7 @@
}
public boolean isFling(float velocity) {
- return Math.abs(velocity) > RELEASE_VELOCITY_PX_MS;
+ return Math.abs(velocity) > mReleaseVelocity;
}
public boolean onTouchEvent(MotionEvent ev) {
@@ -236,7 +243,7 @@
} else {
mSubtractDisplacement.x = mDisplacement.x > 0 ? mTouchSlop : -mTouchSlop;
mSubtractDisplacement.y = mDisplacement.y > 0 ? mTouchSlop : -mTouchSlop;
- }
+ }
}
protected abstract boolean shouldScrollStart(PointF displacement);
diff --git a/src/com/android/launcher3/touch/BothAxesSwipeDetector.java b/src/com/android/launcher3/touch/BothAxesSwipeDetector.java
index 944391e..6e2f0d8 100644
--- a/src/com/android/launcher3/touch/BothAxesSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BothAxesSwipeDetector.java
@@ -21,7 +21,6 @@
import android.view.ViewConfiguration;
import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Utilities;
@@ -43,13 +42,7 @@
private int mScrollDirections;
public BothAxesSwipeDetector(@NonNull Context context, @NonNull Listener l) {
- this(ViewConfiguration.get(context), l, Utilities.isRtl(context.getResources()));
- }
-
- @VisibleForTesting
- protected BothAxesSwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l,
- boolean isRtl) {
- super(config, isRtl);
+ super(context, ViewConfiguration.get(context), Utilities.isRtl(context.getResources()));
mListener = l;
}
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index e127074..c255225 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -36,6 +36,7 @@
import android.graphics.RectF;
import android.graphics.drawable.ShapeDrawable;
import android.util.FloatProperty;
+import android.util.Pair;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.VelocityTracker;
@@ -462,8 +463,8 @@
}
@Override
- public FloatProperty getSplitSelectTaskOffset(FloatProperty primary, FloatProperty secondary,
- DeviceProfile deviceProfile) {
- return primary;
+ public Pair<FloatProperty, FloatProperty> getSplitSelectTaskOffset(FloatProperty primary,
+ FloatProperty secondary, DeviceProfile deviceProfile) {
+ return new Pair<>(primary, secondary);
}
}
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index d954552..54b30fb 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -24,6 +24,7 @@
import android.graphics.RectF;
import android.graphics.drawable.ShapeDrawable;
import android.util.FloatProperty;
+import android.util.Pair;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -113,8 +114,8 @@
float getSecondaryValue(float x, float y);
boolean isLayoutNaturalToLauncher();
- FloatProperty getSplitSelectTaskOffset(FloatProperty primary, FloatProperty secondary,
- DeviceProfile deviceProfile);
+ Pair<FloatProperty, FloatProperty> getSplitSelectTaskOffset(FloatProperty primary,
+ FloatProperty secondary, DeviceProfile deviceProfile);
int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect);
List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp);
/**
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index fbc335c..e69944a 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -35,6 +35,7 @@
import android.graphics.RectF;
import android.graphics.drawable.ShapeDrawable;
import android.util.FloatProperty;
+import android.util.Pair;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.VelocityTracker;
@@ -571,12 +572,12 @@
}
@Override
- public FloatProperty getSplitSelectTaskOffset(FloatProperty primary, FloatProperty secondary,
- DeviceProfile dp) {
- if (dp.isLandscape) { // or seascape
- return primary;
+ public Pair<FloatProperty, FloatProperty> getSplitSelectTaskOffset(FloatProperty primary,
+ FloatProperty secondary, DeviceProfile deviceProfile) {
+ if (deviceProfile.isLandscape) { // or seascape
+ return new Pair<>(primary, secondary);
} else {
- return secondary;
+ return new Pair<>(secondary, primary);
}
}
}
diff --git a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
index f751b7d..5c599c0 100644
--- a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
+++ b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
@@ -106,13 +106,15 @@
public SingleAxisSwipeDetector(@NonNull Context context, @NonNull Listener l,
@NonNull Direction dir) {
- this(ViewConfiguration.get(context), l, dir, Utilities.isRtl(context.getResources()));
+ super(context, ViewConfiguration.get(context), Utilities.isRtl(context.getResources()));
+ mListener = l;
+ mDir = dir;
}
@VisibleForTesting
- protected SingleAxisSwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l,
- @NonNull Direction dir, boolean isRtl) {
- super(config, isRtl);
+ protected SingleAxisSwipeDetector(@NonNull Context context, @NonNull ViewConfiguration config,
+ @NonNull Listener l, @NonNull Direction dir, boolean isRtl) {
+ super(context, config, isRtl);
mListener = l;
mDir = dir;
}
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 8b7ad46..27cf134 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -460,7 +460,7 @@
if (mIconLoadResult != null && mIconLoadResult.isIconLoaded) {
setVisibility(View.VISIBLE);
}
- if (!mIsOpening) {
+ if (!mIsOpening && mOriginalIcon != null) {
// When closing an app, we want the item on the workspace to be invisible immediately
setIconAndDotVisible(mOriginalIcon, false);
}
diff --git a/src/com/android/launcher3/views/Snackbar.java b/src/com/android/launcher3/views/Snackbar.java
index 49fcd2e..f945819 100644
--- a/src/com/android/launcher3/views/Snackbar.java
+++ b/src/com/android/launcher3/views/Snackbar.java
@@ -28,8 +28,9 @@
import android.view.MotionEvent;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -44,7 +45,7 @@
private static final long HIDE_DURATION_MS = 180;
private static final int TIMEOUT_DURATION_MS = 4000;
- private final BaseDraggingActivity mActivity;
+ private final ActivityContext mActivity;
private Runnable mOnDismissed;
public Snackbar(Context context, AttributeSet attrs) {
@@ -53,12 +54,19 @@
public Snackbar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mActivity = BaseDraggingActivity.fromContext(context);
+ mActivity = ActivityContext.lookupContext(context);
inflate(context, R.layout.snackbar, this);
}
- public static void show(BaseDraggingActivity activity, int labelStringResId,
- int actionStringResId, Runnable onDismissed, Runnable onActionClicked) {
+ /** Show a snackbar with just a label. */
+ public static <T extends Context & ActivityContext> 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 <T extends Context & ActivityContext> 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 @@
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 @@
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/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
index 472e1a1..260f556 100644
--- a/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
+++ b/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
@@ -30,6 +30,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -58,6 +59,7 @@
private TouchEventGenerator mGenerator;
private SingleAxisSwipeDetector mDetector;
private int mTouchSlop;
+ Context mContext;
@Mock
private SingleAxisSwipeDetector.Listener mMockListener;
@@ -69,12 +71,13 @@
public void setup() {
MockitoAnnotations.initMocks(this);
mGenerator = new TouchEventGenerator((ev) -> mDetector.onTouchEvent(ev));
- ViewConfiguration orgConfig = ViewConfiguration
- .get(InstrumentationRegistry.getTargetContext());
+ mContext = InstrumentationRegistry.getTargetContext();
+ ViewConfiguration orgConfig = ViewConfiguration.get(mContext);
doReturn(orgConfig.getScaledMaximumFlingVelocity()).when(mMockConfig)
.getScaledMaximumFlingVelocity();
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, VERTICAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, VERTICAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_BOTH, false);
mTouchSlop = orgConfig.getScaledTouchSlop();
doReturn(mTouchSlop).when(mMockConfig).getScaledTouchSlop();
@@ -84,7 +87,8 @@
@Test
public void testDragStart_verticalPositive() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, VERTICAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, VERTICAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100, 100 - mTouchSlop);
@@ -94,7 +98,8 @@
@Test
public void testDragStart_verticalNegative() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, VERTICAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, VERTICAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false);
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100, 100 + mTouchSlop);
@@ -112,7 +117,8 @@
@Test
public void testDragStart_horizontalPositive() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, HORIZONTAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
mGenerator.put(0, 100, 100);
@@ -123,7 +129,8 @@
@Test
public void testDragStart_horizontalNegative() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, HORIZONTAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false);
mGenerator.put(0, 100, 100);
@@ -134,7 +141,8 @@
@Test
public void testDragStart_horizontalRtlPositive() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, true);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, HORIZONTAL, true);
mDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
mGenerator.put(0, 100, 100);
@@ -145,7 +153,8 @@
@Test
public void testDragStart_horizontalRtlNegative() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, true);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, HORIZONTAL, true);
mDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false);
mGenerator.put(0, 100, 100);
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 6e7264a..0bac2ca 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -77,7 +77,8 @@
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();