summaryrefslogtreecommitdiffstats
path: root/quickstep/recents_ui_overrides/src/com/android
diff options
context:
space:
mode:
authorWinson Chung <winsonc@google.com>2019-05-30 13:15:54 -0700
committerWinson Chung <winsonc@google.com>2019-05-30 13:18:41 -0700
commit0ef6fe00b0e2a7ef59db149b5031a0fbcdde86b2 (patch)
tree8c22093ed56fde2969f13c73aee87aea99de05f0 /quickstep/recents_ui_overrides/src/com/android
parent8be337b8a761709ea2679dd3776ff23f884987ff (diff)
parenta1898247cae3e259dc8cad37207ddaf56fdc1a82 (diff)
downloadpackages_apps_Trebuchet-0ef6fe00b0e2a7ef59db149b5031a0fbcdde86b2.tar.gz
packages_apps_Trebuchet-0ef6fe00b0e2a7ef59db149b5031a0fbcdde86b2.tar.bz2
packages_apps_Trebuchet-0ef6fe00b0e2a7ef59db149b5031a0fbcdde86b2.zip
Merging ub-launcher3-qt-dev, build 5619253
Test: Manual Bug:112282235 P3 Starting an app from Launcher very rarely takes > 10 sec Bug:121279417 P2 Why LauncherInstrumentation.WAIT_TIME_MS == 60000? Bug:123892607 P1 Test broken: WellbeingTests.testPauseAppFromAllApps Bug:123900446 P1 App to home animation should zoom into the app icon Bug:125844074 P2 Final UX and animations for Launcher DWB integration Bug:131360075 P1 [Gesture Nav] Polish/finish landscape Bug:131698989 P2 Add task callback for locked state change Bug:131741395 P2 Allow windows to scale/move past overview positioning Bug:131768436 P1 Bad placement of search bar Bug:131854153 P1 Lots of Cuttlefish (and not only) tests are broken Bug:131867841 P1 Changing display size does not update the grid Bug:132460627 P1 Unable to swipe to all apps screen on devices Bug:132687470 P1 Swiping home from forced landscape app creates cutoff task thumbnail Bug:132756514 P1 Sometimes (when quick switching?) user gets stuck in full-screen recents view Bug:132900132 P1 Apparently, tests start running while provisioning is still in progress Bug:132917885 P1 Reduce swipe-up gesture region height in landscape Bug:132975416 P1 Flake in NexusPredictionAppTracker.getAppPredictionContextExtras Bug:132993129 P1 If predictions disabled, app predictions loading bar appears briefly on device restart Bug:133113732 P1 [B1/C1][QT][CTS_Verifier_9.0_r1]Device Owner Tests-LockTask UI-Enable Overview button failure Bug:133167096 P1 It is way too easy to dismiss apps from the lock screen Bug:133651528 P1 [QT]"Pixel Launcher isn't responding" dialog pop up ,after DUT restored. Bug:133765434 P1 [Flaky test] Launching task didn't open a new window Bug:133765491 P1 App docked in split screen flickers with emptiness observed while rotating the device Bug:133783088 P1 Footer showing up on all overview task snapshots even with no items showing. Bug:133867119 P2 Lab-only flake: want to switch from workspace to all apps; Swipe failed to receive an event for the swipe end Bug:64712476 P3 Import translations for dev branches Change-Id: Ib4bcefdbb4027992e75e2742d72f199e13467875
Diffstat (limited to 'quickstep/recents_ui_overrides/src/com/android')
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java2
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java25
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java11
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java6
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java7
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java54
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/LockScreenRecentsActivity.java31
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java76
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java122
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java9
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java208
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java9
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java59
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java154
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java53
15 files changed, 663 insertions, 163 deletions
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java
index af67e1bbb..8f1282ded 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java
@@ -56,7 +56,7 @@ public class PredictionAppTracker extends AppLaunchTracker {
private static final int MSG_LAUNCH = 2;
private static final int MSG_PREDICT = 3;
- private final Context mContext;
+ protected final Context mContext;
private final Handler mMessageHandler;
// Accessed only on worker thread
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java
index 55f4c98e9..4a486f8e5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -28,7 +28,6 @@ import android.os.Build;
import android.util.AttributeSet;
import android.util.IntProperty;
import android.util.Log;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.LinearLayout;
@@ -115,8 +114,6 @@ public class PredictionRowView extends LinearLayout implements
private final AnimatedFloat mOverviewScrollFactor =
new AnimatedFloat(this::updateTranslationAndAlpha);
- private View mLoadingProgress;
-
private boolean mPredictionsEnabled = false;
public PredictionRowView(@NonNull Context context) {
@@ -165,7 +162,6 @@ public class PredictionRowView extends LinearLayout implements
public void setup(FloatingHeaderView parent, FloatingHeaderRow[] rows, boolean tabsHidden) {
mParent = parent;
- setPredictionsEnabled(mPredictionUiStateManager.arePredictionsEnabled());
}
private void setPredictionsEnabled(boolean predictionsEnabled) {
@@ -205,7 +201,7 @@ public class PredictionRowView extends LinearLayout implements
@Override
public boolean hasVisibleContent() {
- return mPredictionUiStateManager.arePredictionsEnabled();
+ return mPredictionsEnabled;
}
/**
@@ -241,9 +237,6 @@ public class PredictionRowView extends LinearLayout implements
}
private void applyPredictionApps() {
- if (mLoadingProgress != null) {
- removeView(mLoadingProgress);
- }
if (!mPredictionsEnabled) {
mParent.onHeightUpdated();
return;
@@ -290,15 +283,8 @@ public class PredictionRowView extends LinearLayout implements
}
if (predictionCount == 0) {
- if (mLoadingProgress == null) {
- mLoadingProgress = LayoutInflater.from(getContext())
- .inflate(R.layout.prediction_load_progress, this, false);
- }
- addView(mLoadingProgress);
- } else {
- mLoadingProgress = null;
+ setPredictionsEnabled(false);
}
-
mParent.onHeightUpdated();
}
@@ -342,11 +328,8 @@ public class PredictionRowView extends LinearLayout implements
public void setTextAlpha(int alpha) {
mIconCurrentTextAlpha = alpha;
int iconColor = setColorAlphaBound(mIconTextColor, mIconCurrentTextAlpha);
-
- if (mLoadingProgress == null) {
- for (int i = 0; i < getChildCount(); i++) {
- ((BubbleTextView) getChildAt(i)).setTextColor(iconColor);
- }
+ for (int i = 0; i < getChildCount(); i++) {
+ ((BubbleTextView) getChildAt(i)).setTextColor(iconColor);
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java
index 6dad9afe5..64cb4b465 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java
@@ -24,7 +24,6 @@ import android.app.prediction.AppPredictor;
import android.app.prediction.AppTarget;
import android.content.ComponentName;
import android.content.Context;
-import android.os.Handler;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import com.android.launcher3.AppInfo;
@@ -63,7 +62,6 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf
OnIDPChangeListener, OnUpdateListener {
public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state";
- private static final long INITIAL_CALLBACK_WAIT_TIMEOUT_MS = 5000;
// TODO (b/129421797): Update the client constants
public enum Client {
@@ -110,13 +108,8 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf
for (int i = 0; i < mPredictionServicePredictions.length; i++) {
mPredictionServicePredictions[i] = Collections.emptyList();
}
-
mGettingValidPredictionResults = Utilities.getDevicePrefs(context)
.getBoolean(LAST_PREDICTION_ENABLED_STATE, true);
- if (mGettingValidPredictionResults) {
- new Handler().postDelayed(
- this::updatePredictionStateAfterCallback, INITIAL_CALLBACK_WAIT_TIMEOUT_MS);
- }
// Call this last
mCurrentState = parseLastState();
@@ -293,10 +286,6 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf
dispatchOnChange(false);
}
- public boolean arePredictionsEnabled() {
- return mCurrentState.isEnabled;
- }
-
private boolean canApplyPredictions(PredictionState newState) {
if (mAppsView == null) {
// If there is no apps view, no need to schedule.
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
index 7a6cd2d55..e3e339add 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
@@ -22,6 +22,7 @@ import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
import static com.android.launcher3.LauncherStateManager.ANIM_ALL;
import static com.android.launcher3.LauncherStateManager.ATOMIC_OVERVIEW_PEEK_COMPONENT;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -34,8 +35,10 @@ import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.quickstep.OverviewInteractionState;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.system.QuickStepContract;
/**
* Touch controller which handles swipe and hold to go to Overview
@@ -99,7 +102,8 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
* having it as part of the existing animation to the target state.
*/
private boolean handlingOverviewAnim() {
- return mStartState == NORMAL;
+ int stateFlags = OverviewInteractionState.INSTANCE.get(mLauncher).getSystemUiStateFlags();
+ return mStartState == NORMAL && (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0;
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index e1dd124a9..18b8af4fa 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -30,6 +30,7 @@ import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import android.view.MotionEvent;
@@ -44,10 +45,12 @@ import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.quickstep.OverviewInteractionState;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.system.QuickStepContract;
/**
* Handles quick switching to a recent task from the home screen.
@@ -80,6 +83,10 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll
@Override
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+ int stateFlags = OverviewInteractionState.INSTANCE.get(mLauncher).getSystemUiStateFlags();
+ if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) {
+ return NORMAL;
+ }
return isDragTowardPositive ? QUICK_SWITCH : NORMAL;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index 4b2e487da..5af09f7fd 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -30,6 +30,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -56,6 +57,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.util.LayoutUtils;
+import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -68,6 +70,8 @@ import java.util.function.Consumer;
*/
public final class LauncherActivityControllerHelper implements ActivityControlHelper<Launcher> {
+ private Runnable mAdjustInterpolatorsRunnable;
+
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
LayoutUtils.calculateLauncherTaskSize(context, dp, outRect);
@@ -148,8 +152,21 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
@NonNull
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
+ // Return an empty APC here since we have an non-user controlled animation to home.
long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
- return activity.getStateManager().createAnimationToNewWorkspace(NORMAL, accuracy);
+ AnimatorSet as = new AnimatorSet();
+ as.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ activity.getStateManager().goToState(NORMAL, false);
+ }
+ });
+ return AnimatorPlaybackController.wrap(as, accuracy);
+ }
+
+ @Override
+ public void playAtomicAnimation(float velocity) {
+ new StaggeredWorkspaceAnim(activity, workspaceView, velocity).start();
}
};
}
@@ -194,6 +211,13 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
}
@Override
+ public void adjustActivityControllerInterpolators() {
+ if (mAdjustInterpolatorsRunnable != null) {
+ mAdjustInterpolatorsRunnable.run();
+ }
+ }
+
+ @Override
public void onTransitionCancelled() {
activity.getStateManager().goToState(startState, false /* animate */);
}
@@ -275,6 +299,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
playScaleDownAnim(anim, activity, fromState, endState);
anim.setDuration(transitionLength * 2);
+ anim.setInterpolator(LINEAR);
AnimatorPlaybackController controller =
AnimatorPlaybackController.wrap(anim, transitionLength * 2);
activity.getStateManager().setCurrentUserControlledAnimation(controller);
@@ -291,7 +316,6 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
Animator shiftAnim = new SpringObjectAnimator<>(activity.getAllAppsController(),
"allAppsSpringFromACH", activity.getAllAppsController().getShiftRange(),
SPRING_DAMPING_RATIO, SPRING_STIFFNESS, progressValues);
- shiftAnim.setInterpolator(LINEAR);
return shiftAnim;
}
@@ -310,19 +334,37 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
= fromState.getOverviewScaleAndTranslation(launcher);
LauncherState.ScaleAndTranslation endScaleAndTranslation
= endState.getOverviewScaleAndTranslation(launcher);
+ float fromTranslationY = fromScaleAndTranslation.translationY;
+ float endTranslationY = endScaleAndTranslation.translationY;
float fromFullscreenProgress = fromState.getOverviewFullscreenProgress();
float endFullscreenProgress = endState.getOverviewFullscreenProgress();
Animator scale = ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY,
fromScaleAndTranslation.scale, endScaleAndTranslation.scale);
Animator translateY = ObjectAnimator.ofFloat(recentsView, TRANSLATION_Y,
- fromScaleAndTranslation.translationY, endScaleAndTranslation.translationY);
+ fromTranslationY, endTranslationY);
Animator applyFullscreenProgress = ObjectAnimator.ofFloat(recentsView,
RecentsView.FULLSCREEN_PROGRESS, fromFullscreenProgress, endFullscreenProgress);
- scale.setInterpolator(LINEAR);
- translateY.setInterpolator(LINEAR);
- applyFullscreenProgress.setInterpolator(LINEAR);
anim.playTogether(scale, translateY, applyFullscreenProgress);
+
+ mAdjustInterpolatorsRunnable = () -> {
+ // Adjust the translateY interpolator to account for the running task's top inset.
+ // When progress <= 1, this is handled by each task view as they set their fullscreen
+ // progress. However, once we go to progress > 1, fullscreen progress stays at 0, so
+ // recents as a whole needs to translate further to keep up with the app window.
+ TaskView runningTaskView = recentsView.getRunningTaskView();
+ if (runningTaskView == null) {
+ runningTaskView = recentsView.getTaskViewAt(recentsView.getCurrentPage());
+ }
+ TimeInterpolator oldInterpolator = translateY.getInterpolator();
+ Rect fallbackInsets = launcher.getDeviceProfile().getInsets();
+ float extraTranslationY = runningTaskView.getThumbnail().getInsets(fallbackInsets).top;
+ float normalizedTranslationY = extraTranslationY / (fromTranslationY - endTranslationY);
+ translateY.setInterpolator(t -> {
+ float newT = oldInterpolator.getInterpolation(t);
+ return newT <= 1f ? newT : newT + normalizedTranslationY * (newT - 1);
+ });
+ };
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LockScreenRecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LockScreenRecentsActivity.java
new file mode 100644
index 000000000..65f323c7d
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LockScreenRecentsActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Empty activity to start a recents transition
+ */
+public class LockScreenRecentsActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ finish();
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 0c997dd59..7563c3f55 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -22,8 +22,11 @@ import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INP
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
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_SCREEN_PINNING;
import android.annotation.TargetApi;
import android.app.ActivityManager;
@@ -79,6 +82,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.InputMonitorCompat;
+import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import java.io.FileDescriptor;
@@ -197,6 +201,8 @@ public class TouchInteractionService extends Service implements
public void onSystemUiStateChanged(int stateFlags) {
mSystemUiStateFlags = stateFlags;
+ mOverviewInteractionState.setSystemUiStateFlags(stateFlags);
+ mOverviewComponentObserver.onSystemUiStateChanged(stateFlags);
}
/** Deprecated methods **/
@@ -331,16 +337,8 @@ public class TouchInteractionService extends Service implements
defaultDisplay.getRealSize(realSize);
mSwipeTouchRegion.set(0, 0, realSize.x, realSize.y);
if (mMode == Mode.NO_BUTTON) {
- switch (defaultDisplay.getRotation()) {
- case Surface.ROTATION_90:
- case Surface.ROTATION_270:
- mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - getNavbarSize(
- ResourceUtils.NAVBAR_LANDSCAPE_BOTTOM_SIZE);
- break;
- default:
- mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - getNavbarSize(
- ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE);
- }
+ mSwipeTouchRegion.top = mSwipeTouchRegion.bottom -
+ getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
} else {
switch (defaultDisplay.getRotation()) {
case Surface.ROTATION_90:
@@ -353,7 +351,7 @@ public class TouchInteractionService extends Service implements
break;
default:
mSwipeTouchRegion.top = mSwipeTouchRegion.bottom
- - getNavbarSize(ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE);
+ - getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
}
}
}
@@ -472,22 +470,19 @@ public class TouchInteractionService extends Service implements
private boolean validSystemUiFlags() {
return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
- && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0;
- }
-
- private boolean topTaskLocked() {
- return ActivityManagerWrapper.getInstance().isLockToAppActive();
+ && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0
+ && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
+ || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0);
}
private InputConsumer newConsumer(boolean useSharedState, MotionEvent event) {
- boolean topTaskLocked = topTaskLocked();
- boolean isInValidSystemUiState = validSystemUiFlags() && !topTaskLocked;
+ boolean isInValidSystemUiState = validSystemUiFlags();
if (!mIsUserUnlocked) {
if (isInValidSystemUiState) {
// This handles apps launched in direct boot mode (e.g. dialer) as well as apps
// launched while device is locked even after exiting direct boot mode (e.g. camera).
- return new DeviceLockedInputConsumer(this);
+ return createDeviceLockedInputConsumer(mAM.getRunningTask(0));
} else {
return InputConsumer.NO_OP;
}
@@ -498,13 +493,15 @@ public class TouchInteractionService extends Service implements
if (mMode == Mode.NO_BUTTON) {
final ActivityControlHelper activityControl =
mOverviewComponentObserver.getActivityControlHelper();
- if (mAssistantAvailable && !topTaskLocked
- && AssistantTouchConsumer.withinTouchRegion(this, event)) {
+ if (mAssistantAvailable
+ && !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
+ && AssistantTouchConsumer.withinTouchRegion(this, event)
+ && !ActivityManagerWrapper.getInstance().isLockToAppActive()) {
base = new AssistantTouchConsumer(this, mISystemUiProxy, activityControl, base,
mInputMonitorCompat);
}
- if (ActivityManagerWrapper.getInstance().isScreenPinningActive()) {
+ if ((mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0) {
// Note: we only allow accessibility to wrap this, and it replaces the previous
// base input consumer (which should be NO_OP anyway since topTaskLocked == true).
base = new ScreenPinnedInputConsumer(this, mISystemUiProxy, activityControl);
@@ -520,16 +517,15 @@ public class TouchInteractionService extends Service implements
}
private InputConsumer newBaseConsumer(boolean useSharedState, MotionEvent event) {
- if (mKM.isDeviceLocked()) {
- // This handles apps launched in direct boot mode (e.g. dialer) as well as apps launched
- // while device is locked even after exiting direct boot mode (e.g. camera).
- return new DeviceLockedInputConsumer(this);
- }
-
final RunningTaskInfo runningTaskInfo = mAM.getRunningTask(0);
if (!useSharedState) {
mSwipeSharedState.clearAllState();
}
+ if (mKM.isDeviceLocked()) {
+ // This handles apps launched in direct boot mode (e.g. dialer) as well as apps launched
+ // while device is locked even after exiting direct boot mode (e.g. camera).
+ return createDeviceLockedInputConsumer(runningTaskInfo);
+ }
final ActivityControlHelper activityControl =
mOverviewComponentObserver.getActivityControlHelper();
@@ -567,6 +563,15 @@ public class TouchInteractionService extends Service implements
mSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion);
}
+ private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) {
+ if (mMode == Mode.NO_BUTTON && taskInfo != null) {
+ return new DeviceLockedInputConsumer(this, mSwipeSharedState, mInputMonitorCompat,
+ mSwipeTouchRegion, taskInfo.taskId);
+ } else {
+ return InputConsumer.NO_OP;
+ }
+ }
+
/**
* To be called by the consumer when it's no longer active.
*/
@@ -593,17 +598,14 @@ public class TouchInteractionService extends Service implements
// Dump everything
pw.println("TouchState:");
pw.println(" navMode=" + mMode);
- pw.println(" validSystemUiFlags=" + validSystemUiFlags()
- + " flags=" + mSystemUiStateFlags);
- pw.println(" topTaskLocked=" + topTaskLocked());
+ pw.println(" validSystemUiFlags=" + validSystemUiFlags());
+ pw.println(" systemUiFlags=" + mSystemUiStateFlags);
+ pw.println(" systemUiFlagsDesc="
+ + QuickStepContract.getSystemUiStateString(mSystemUiStateFlags));
pw.println(" isDeviceLocked=" + mKM.isDeviceLocked());
- pw.println(" screenPinned=" +
- ActivityManagerWrapper.getInstance().isScreenPinningActive());
pw.println(" assistantAvailable=" + mAssistantAvailable);
- pw.println(" a11yClickable="
- + ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0));
- pw.println(" a11yLongClickable="
- + ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0));
+ pw.println(" assistantDisabled="
+ + QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags));
pw.println(" resumed="
+ mOverviewComponentObserver.getActivityControlHelper().isResumed());
pw.println(" useSharedState=" + mConsumer.useSharedSwipeState());
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 2ff5c0c6a..0d0478ae0 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -39,6 +39,7 @@ import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget
import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.NEW_TASK;
import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.RECENTS;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -105,6 +106,7 @@ import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.LatencyTrackerCompat;
+import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.WindowCallbacksCompat;
@@ -170,7 +172,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
public enum GestureEndTarget {
- HOME(1, STATE_SCALED_CONTROLLER_HOME, true, false, ContainerType.WORKSPACE, false),
+ HOME(1, STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT, true, false,
+ ContainerType.WORKSPACE, false),
RECENTS(1, STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT
| STATE_SCREENSHOT_VIEW_SHOWN, true, false, ContainerType.TASKSWITCHER, true),
@@ -216,6 +219,12 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
private static final long SHELF_ANIM_DURATION = 120;
public static final long RECENTS_ATTACH_DURATION = 300;
+ // Start resisting when swiping past this factor of mTransitionDragLength.
+ private static final float DRAG_LENGTH_FACTOR_START_PULLBACK = 1.4f;
+ // This is how far down we can scale down, where 0f is full screen and 1f is recents.
+ private static final float DRAG_LENGTH_FACTOR_MAX_PULLBACK = 1.8f;
+ private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;
+
/**
* Used as the page index for logging when we return to the last task at the end of the gesture.
*/
@@ -230,7 +239,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
private RunningWindowAnim mRunningWindowAnim;
private boolean mIsShelfPeeking;
private DeviceProfile mDp;
+ // The distance needed to drag to reach the task size in recents.
private int mTransitionDragLength;
+ // How much further we can drag past recents, as a factor of mTransitionDragLength.
+ private float mDragLengthFactor = 1;
// Shift in the range of [0, 1].
// 0 => preview snapShot is completely visible, and hotseat is completely translated down
@@ -331,9 +343,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
| STATE_SCALED_CONTROLLER_RECENTS,
this::finishCurrentTransitionToRecents);
- mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_COMPLETED
- | STATE_SCALED_CONTROLLER_HOME | STATE_APP_CONTROLLER_RECEIVED
- | STATE_LAUNCHER_DRAWN,
+ mStateCallback.addCallback(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED
+ | STATE_SCALED_CONTROLLER_HOME,
this::finishCurrentTransitionToHome);
mStateCallback.addCallback(STATE_SCALED_CONTROLLER_HOME | STATE_CURRENT_TASK_FINISHED,
this::reset);
@@ -375,6 +386,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
mTransitionDragLength = mActivityControlHelper.getSwipeUpDestinationAndLength(
dp, mContext, tempRect);
mClipAnimationHelper.updateTargetRect(tempRect);
+ if (mMode == Mode.NO_BUTTON) {
+ // We can drag all the way to the top of the screen.
+ mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
+ }
}
private long getFadeInDuration() {
@@ -546,11 +561,18 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
public void updateDisplacement(float displacement) {
// We are moving in the negative x/y direction
displacement = -displacement;
- if (displacement > mTransitionDragLength && mTransitionDragLength > 0) {
- mCurrentShift.updateValue(1);
+ if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) {
+ mCurrentShift.updateValue(mDragLengthFactor);
} else {
float translation = Math.max(displacement, 0);
float shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
+ if (shift > DRAG_LENGTH_FACTOR_START_PULLBACK) {
+ float pullbackProgress = Utilities.getProgress(shift,
+ DRAG_LENGTH_FACTOR_START_PULLBACK, mDragLengthFactor);
+ pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
+ shift = DRAG_LENGTH_FACTOR_START_PULLBACK + pullbackProgress
+ * (DRAG_LENGTH_FACTOR_MAX_PULLBACK - DRAG_LENGTH_FACTOR_START_PULLBACK);
+ }
mCurrentShift.updateValue(shift);
}
}
@@ -638,6 +660,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) {
mLauncherTransitionController = anim;
+ mLauncherTransitionController.dispatchSetInterpolator(t -> t * mDragLengthFactor);
+ mAnimationFactory.adjustActivityControllerInterpolators();
mLauncherTransitionController.dispatchOnStart();
updateLauncherTransitionProgress();
}
@@ -690,7 +714,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
if (mGestureEndTarget == HOME) {
return;
}
- float progress = mCurrentShift.value;
+ // Normalize the progress to 0 to 1, as the animation controller will clamp it to that
+ // anyway. The controller mimics the drag length factor by applying it to its interpolators.
+ float progress = mCurrentShift.value / mDragLengthFactor;
mLauncherTransitionController.setPlayFraction(
progress <= mShiftAtGestureStart || mShiftAtGestureStart >= 1
? 0 : (progress - mShiftAtGestureStart) / (1 - mShiftAtGestureStart));
@@ -835,16 +861,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
}
}
- @UiThread
- private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity,
+ private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity, boolean isFling,
boolean isCancel) {
- PointF velocityPxPerMs = new PointF(velocity.x / 1000, velocity.y / 1000);
- long duration = MAX_SWIPE_DURATION;
- float currentShift = mCurrentShift.value;
final GestureEndTarget endTarget;
- float endShift;
- final float startShift;
- Interpolator interpolator = DEACCEL;
final boolean goingToNewTask;
if (mRecentsView != null) {
if (!mRecentsAnimationWrapper.hasTargets()) {
@@ -859,7 +878,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
} else {
goingToNewTask = false;
}
- final boolean reachedOverviewThreshold = currentShift >= MIN_PROGRESS_FOR_OVERVIEW;
+ final boolean reachedOverviewThreshold = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW;
if (!isFling) {
if (isCancel) {
endTarget = LAST_TASK;
@@ -869,7 +888,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
} else if (goingToNewTask) {
endTarget = NEW_TASK;
} else {
- endTarget = currentShift < MIN_PROGRESS_FOR_OVERVIEW ? LAST_TASK : HOME;
+ endTarget = !reachedOverviewThreshold ? LAST_TASK : HOME;
}
} else {
endTarget = reachedOverviewThreshold && mGestureStarted
@@ -878,12 +897,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
? NEW_TASK
: LAST_TASK;
}
- endShift = endTarget.endShift;
- long expectedDuration = Math.abs(Math.round((endShift - currentShift)
- * MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER));
- duration = Math.min(MAX_SWIPE_DURATION, expectedDuration);
- startShift = currentShift;
- interpolator = endTarget == RECENTS ? OVERSHOOT_1_2 : DEACCEL;
} else {
if (mMode == Mode.NO_BUTTON && endVelocity < 0 && !mIsShelfPeeking) {
// If swiping at a diagonal, base end target on the faster velocity.
@@ -896,9 +909,36 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
} else {
endTarget = goingToNewTask ? NEW_TASK : LAST_TASK;
}
- endShift = endTarget.endShift;
+ }
+
+ int stateFlags = OverviewInteractionState.INSTANCE.get(mActivity).getSystemUiStateFlags();
+ if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0
+ && (endTarget == RECENTS || endTarget == LAST_TASK)) {
+ return LAST_TASK;
+ }
+ return endTarget;
+ }
+
+ @UiThread
+ private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity,
+ boolean isCancel) {
+ PointF velocityPxPerMs = new PointF(velocity.x / 1000, velocity.y / 1000);
+ long duration = MAX_SWIPE_DURATION;
+ float currentShift = mCurrentShift.value;
+ final GestureEndTarget endTarget = calculateEndTarget(velocity, endVelocity,
+ isFling, isCancel);
+ float endShift = endTarget.endShift;
+ final float startShift;
+ Interpolator interpolator = DEACCEL;
+ if (!isFling) {
+ long expectedDuration = Math.abs(Math.round((endShift - currentShift)
+ * MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER));
+ duration = Math.min(MAX_SWIPE_DURATION, expectedDuration);
+ startShift = currentShift;
+ interpolator = endTarget == RECENTS ? OVERSHOOT_1_2 : DEACCEL;
+ } else {
startShift = Utilities.boundToRange(currentShift - velocityPxPerMs.y
- * SINGLE_FRAME_MS / mTransitionDragLength, 0, 1);
+ * SINGLE_FRAME_MS / mTransitionDragLength, 0, mDragLengthFactor);
float minFlingVelocity = mContext.getResources()
.getDimension(R.dimen.quickstep_fling_min_velocity);
if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) {
@@ -936,8 +976,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
} else if (endTarget == RECENTS) {
mLiveTileOverlay.startIconAnimation();
if (mRecentsView != null) {
- duration = Utilities.boundToRange(mRecentsView.getScroller().getDuration(),
- duration, MAX_SWIPE_DURATION);
+ if (mRecentsView.getScroller().getDuration() > MAX_SWIPE_DURATION) {
+ mRecentsView.snapToPage(mRecentsView.getNextPage(), (int) MAX_SWIPE_DURATION);
+ }
+ duration = Math.max(duration, mRecentsView.getScroller().getDuration());
}
if (mMode == Mode.NO_BUTTON) {
setShelfState(ShelfAnimState.OVERVIEW, interpolator, duration);
@@ -1015,6 +1057,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
setStateOnUiThread(target.endState);
}
});
+ homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
windowAnim.start(velocityPxPerMs);
mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
mLauncherTransitionController = null;
@@ -1055,6 +1098,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
mLauncherTransitionController.getAnimationPlayer().end();
} else {
mLauncherTransitionController.dispatchSetInterpolator(adjustedInterpolator);
+ mAnimationFactory.adjustActivityControllerInterpolators();
mLauncherTransitionController.getAnimationPlayer().setDuration(duration);
if (QUICKSTEP_SPRINGS.get()) {
@@ -1091,12 +1135,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
// FolderIconView can be seen morphing into the icon shape.
final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
anim.addOnUpdateListener((currentRect, progress) -> {
- float interpolatedProgress = Interpolators.ACCEL_1_5.getInterpolation(progress);
-
homeAnim.setPlayFraction(progress);
- float windowAlpha = Utilities.mapToRange(interpolatedProgress, 0,
- windowAlphaThreshold, 1f, 0f, Interpolators.LINEAR);
+ float windowAlpha = Math.max(0, Utilities.mapToRange(progress, 0,
+ windowAlphaThreshold, 1f, 0f, Interpolators.LINEAR));
mTransformParams.setProgress(progress)
.setCurrentRectAndTargetAlpha(currentRect, windowAlpha);
mClipAnimationHelper.applyTransform(targetSet, mTransformParams,
@@ -1251,8 +1293,15 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
if (mTaskSnapshot == null) {
mTaskSnapshot = controller.screenshotTask(mRunningTaskId);
}
- TaskView taskView = mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot);
- if (taskView != null) {
+ final TaskView taskView;
+ if (mGestureEndTarget == HOME) {
+ // Capture the screenshot before finishing the transition to home to ensure it's
+ // taken in the correct orientation, but no need to update the thumbnail.
+ taskView = null;
+ } else {
+ taskView = mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot);
+ }
+ if (taskView != null && !mCanceled) {
// Defer finishing the animation until the next launcher frame with the
// new thumbnail
finishTransitionPosted = new WindowCallbacksCompat(taskView) {
@@ -1262,6 +1311,13 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
@Override
public void onPostDraw(Canvas canvas) {
+ // If we were cancelled after this was attached, do not update
+ // the state.
+ if (mCanceled) {
+ detach();
+ return;
+ }
+
if (mDeferFrameCount > 0) {
mDeferFrameCount--;
// Workaround, detach and reattach to invalidate the root node for
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java
index 09d323ee6..182072957 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.view.WindowInsets;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.R;
@@ -71,7 +70,7 @@ public class RecentsRootView extends BaseDragLayer<RecentsActivity> {
// Update device profile before notifying the children.
mActivity.getDeviceProfile().updateInsets(insets);
setInsets(insets);
- return true; // I'll take it from here
+ return false; // Let children get the full insets
}
@Override
@@ -89,10 +88,4 @@ public class RecentsRootView extends BaseDragLayer<RecentsActivity> {
mActivity.getDeviceProfile().updateInsets(mInsets);
super.setInsets(mInsets);
}
-
- @Override
- public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
- updateTouchExcludeRegion(insets);
- return super.dispatchApplyWindowInsets(insets);
- }
} \ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index d01b5ec19..db2af59ac 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -15,26 +15,102 @@
*/
package com.android.quickstep.inputconsumers;
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_POINTER_DOWN;
+import static android.view.MotionEvent.ACTION_UP;
+
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
+import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
+import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Point;
import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.quickstep.LockScreenRecentsActivity;
+import com.android.quickstep.MultiStateCallback;
+import com.android.quickstep.SwipeSharedState;
+import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.RecentsAnimationListenerSet;
+import com.android.quickstep.util.SwipeAnimationTargetSet;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.BackgroundExecutor;
+import com.android.systemui.shared.system.InputMonitorCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
/**
* A dummy input consumer used when the device is still locked, e.g. from secure camera.
*/
-public class DeviceLockedInputConsumer implements InputConsumer {
+public class DeviceLockedInputConsumer implements InputConsumer,
+ SwipeAnimationTargetSet.SwipeAnimationListener {
+
+ private static final float SCALE_DOWN = 0.75f;
+
+ private static final String[] STATE_NAMES = DEBUG_STATES ? new String[2] : null;
+ private static int getFlagForIndex(int index, String name) {
+ if (DEBUG_STATES) {
+ STATE_NAMES[index] = name;
+ }
+ return 1 << index;
+ }
+
+ private static final int STATE_TARGET_RECEIVED =
+ getFlagForIndex(0, "STATE_TARGET_RECEIVED");
+ private static final int STATE_HANDLER_INVALIDATED =
+ getFlagForIndex(1, "STATE_HANDLER_INVALIDATED");
private final Context mContext;
private final float mTouchSlopSquared;
+ private final SwipeSharedState mSwipeSharedState;
+ private final InputMonitorCompat mInputMonitorCompat;
+
private final PointF mTouchDown = new PointF();
+ private final ClipAnimationHelper mClipAnimationHelper;
+ private final ClipAnimationHelper.TransformParams mTransformParams;
+ private final Point mDisplaySize;
+ private final MultiStateCallback mStateCallback;
+ private final RectF mSwipeTouchRegion;
+ public final int mRunningTaskId;
+
+ private VelocityTracker mVelocityTracker;
+ private float mProgress;
- public DeviceLockedInputConsumer(Context context) {
+ private boolean mThresholdCrossed = false;
+
+ private SwipeAnimationTargetSet mTargetSet;
+
+ public DeviceLockedInputConsumer(Context context, SwipeSharedState swipeSharedState,
+ InputMonitorCompat inputMonitorCompat, RectF swipeTouchRegion, int runningTaskId) {
mContext = context;
mTouchSlopSquared = squaredTouchSlop(context);
+ mSwipeSharedState = swipeSharedState;
+ mClipAnimationHelper = new ClipAnimationHelper(context);
+ mTransformParams = new ClipAnimationHelper.TransformParams();
+ mInputMonitorCompat = inputMonitorCompat;
+ mSwipeTouchRegion = swipeTouchRegion;
+ mRunningTaskId = runningTaskId;
+
+ // Do not use DeviceProfile as the user data might be locked
+ mDisplaySize = new Point();
+ context.getSystemService(WindowManager.class).getDefaultDisplay().getRealSize(mDisplaySize);
+
+ // Init states
+ mStateCallback = new MultiStateCallback(STATE_NAMES);
+ mStateCallback.addCallback(STATE_TARGET_RECEIVED | STATE_HANDLER_INVALIDATED,
+ this::endRemoteAnimation);
+
+ mVelocityTracker = VelocityTracker.obtain();
}
@Override
@@ -44,17 +120,137 @@ public class DeviceLockedInputConsumer implements InputConsumer {
@Override
public void onMotionEvent(MotionEvent ev) {
+ if (mVelocityTracker == null) {
+ return;
+ }
+ mVelocityTracker.addMovement(ev);
+
float x = ev.getX();
float y = ev.getY();
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mTouchDown.set(x, y);
- } else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
- if (squaredHypot(x - mTouchDown.x, y - mTouchDown.y) > mTouchSlopSquared) {
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mTouchDown.set(x, y);
+ break;
+ case ACTION_POINTER_DOWN: {
+ if (!mThresholdCrossed) {
+ // Cancel interaction in case of multi-touch interaction
+ int ptrIdx = ev.getActionIndex();
+ if (!mSwipeTouchRegion.contains(ev.getX(ptrIdx), ev.getY(ptrIdx))) {
+ int action = ev.getAction();
+ ev.setAction(ACTION_CANCEL);
+ finishTouchTracking(ev);
+ ev.setAction(action);
+ }
+ }
+ break;
+ }
+ case MotionEvent.ACTION_MOVE: {
+ if (!mThresholdCrossed) {
+ if (squaredHypot(x - mTouchDown.x, y - mTouchDown.y) > mTouchSlopSquared) {
+ startRecentsTransition();
+ }
+ } else {
+ float dy = Math.max(mTouchDown.y - y, 0);
+ mProgress = dy / mDisplaySize.y;
+ mTransformParams.setProgress(mProgress);
+ if (mTargetSet != null) {
+ mClipAnimationHelper.applyTransform(mTargetSet, mTransformParams);
+ }
+ }
+ break;
+ }
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ finishTouchTracking(ev);
+ break;
+ }
+ }
+
+ /**
+ * Called when the gesture has ended. Does not correlate to the completion of the interaction as
+ * the animation can still be running.
+ */
+ private void finishTouchTracking(MotionEvent ev) {
+ mStateCallback.setState(STATE_HANDLER_INVALIDATED);
+ if (mThresholdCrossed && ev.getAction() == ACTION_UP) {
+ mVelocityTracker.computeCurrentVelocity(1000,
+ ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity());
+
+ float velocityY = mVelocityTracker.getYVelocity();
+ float flingThreshold = mContext.getResources()
+ .getDimension(R.dimen.quickstep_fling_threshold_velocity);
+
+ boolean dismissTask;
+ if (Math.abs(velocityY) > flingThreshold) {
+ // Is fling
+ dismissTask = velocityY < 0;
+ } else {
+ dismissTask = mProgress >= (1 - MIN_PROGRESS_FOR_OVERVIEW);
+ }
+ if (dismissTask) {
// For now, just start the home intent so user is prompted to unlock the device.
mContext.startActivity(new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
}
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+
+ private void startRecentsTransition() {
+ mThresholdCrossed = true;
+ RecentsAnimationListenerSet newListenerSet =
+ mSwipeSharedState.newRecentsAnimationListenerSet();
+ newListenerSet.addListener(this);
+ Intent intent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .setComponent(new ComponentName(mContext, LockScreenRecentsActivity.class))
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
+ mInputMonitorCompat.pilferPointers();
+ BackgroundExecutor.get().submit(
+ () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
+ intent, null, newListenerSet, null, null));
+ }
+
+ @Override
+ public void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet) {
+ mTargetSet = targetSet;
+
+ Rect displaySize = new Rect(0, 0, mDisplaySize.x, mDisplaySize.y);
+ RemoteAnimationTargetCompat targetCompat = targetSet.findTask(mRunningTaskId);
+ if (targetCompat != null) {
+ mClipAnimationHelper.updateSource(displaySize, targetCompat);
+ }
+
+ Utilities.scaleRectAboutCenter(displaySize, SCALE_DOWN);
+ displaySize.offsetTo(displaySize.left, 0);
+ mClipAnimationHelper.updateTargetRect(displaySize);
+ mClipAnimationHelper.applyTransform(mTargetSet, mTransformParams);
+
+ mStateCallback.setState(STATE_TARGET_RECEIVED);
+ }
+
+ @Override
+ public void onRecentsAnimationCanceled() {
+ mTargetSet = null;
+ }
+
+ private void endRemoteAnimation() {
+ if (mTargetSet != null) {
+ mTargetSet.finishController(
+ false /* toRecents */, null /* callback */, false /* sendUserLeaveHint */);
+ }
+ }
+
+ @Override
+ public void onConsumerAboutToBeSwitched() {
+ mStateCallback.setState(STATE_HANDLER_INVALIDATED);
+ }
+
+ @Override
+ public boolean allowInterceptByParent() {
+ return !mThresholdCrossed;
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java
index 805cf3328..0ae469c70 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -23,7 +23,6 @@ import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MOD
import android.annotation.TargetApi;
import android.content.Context;
-import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.Rect;
@@ -160,14 +159,16 @@ public class ClipAnimationHelper {
public RectF applyTransform(RemoteAnimationTargetSet targetSet, TransformParams params,
boolean launcherOnTop) {
+ float progress = params.progress;
if (params.currentRect == null) {
RectF currentRect;
mTmpRectF.set(mTargetRect);
Utilities.scaleRectFAboutCenter(mTmpRectF, params.offsetScale);
- float progress = params.progress;
currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTmpRectF);
currentRect.offset(params.offsetX, 0);
+ // Don't clip past progress > 1.
+ progress = Math.min(1, progress);
final RectF sourceWindowClipInsets = params.forLiveTile
? mSourceWindowClipInsetsForLiveTile : mSourceWindowClipInsets;
mClipRectF.left = sourceWindowClipInsets.left * progress;
@@ -189,7 +190,7 @@ public class ClipAnimationHelper {
float alpha = 1f;
int layer = RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers);
float cornerRadius = 0f;
- float scale = params.currentRect.width() / crop.width();
+ float scale = Math.max(params.currentRect.width(), mTargetRect.width()) / crop.width();
if (app.mode == targetSet.targetMode) {
if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
mTmpMatrix.setRectToRect(mSourceRect, params.currentRect, ScaleToFit.FILL);
@@ -198,7 +199,7 @@ public class ClipAnimationHelper {
if (mSupportsRoundedCornersOnWindows) {
float windowCornerRadius = mUseRoundedCornersOnWindows
? mWindowCornerRadius : 0;
- cornerRadius = Utilities.mapRange(params.progress, windowCornerRadius,
+ cornerRadius = Utilities.mapRange(progress, windowCornerRadius,
mTaskCornerRadius);
mCurrentCornerRadius = cornerRadius;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
index 3f4ad58ab..77dc6f32e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -16,26 +16,22 @@
package com.android.quickstep.util;
import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.RectF;
-import android.util.FloatProperty;
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.FlingSpringAnim;
import java.util.ArrayList;
import java.util.List;
-import static com.android.launcher3.anim.Interpolators.DEACCEL;
/**
* Applies spring forces to animate from a starting rect to a target rect,
@@ -43,14 +39,6 @@ import static com.android.launcher3.anim.Interpolators.DEACCEL;
*/
public class RectFSpringAnim {
- /**
- * Although the rect position animation takes an indefinite amount of time since it depends on
- * the initial velocity and applied forces, scaling from the starting rect to the target rect
- * can be done in parallel at a fixed duration. Update callbacks are sent based on the progress
- * of this animation, while the end callback is sent after all animations finish.
- */
- private static final long RECT_SCALE_DURATION = 250;
-
private static final FloatPropertyCompat<RectFSpringAnim> RECT_CENTER_X =
new FloatPropertyCompat<RectFSpringAnim>("rectCenterXSpring") {
@Override
@@ -79,17 +67,17 @@ public class RectFSpringAnim {
}
};
- private static final FloatProperty<RectFSpringAnim> RECT_SCALE_PROGRESS =
- new FloatProperty<RectFSpringAnim>("rectScaleProgress") {
+ private static final FloatPropertyCompat<RectFSpringAnim> RECT_SCALE_PROGRESS =
+ new FloatPropertyCompat<RectFSpringAnim>("rectScaleProgress") {
@Override
- public Float get(RectFSpringAnim anim) {
- return anim.mCurrentScaleProgress;
+ public float getValue(RectFSpringAnim object) {
+ return object.mCurrentScaleProgress;
}
@Override
- public void setValue(RectFSpringAnim anim, float currentScaleProgress) {
- anim.mCurrentScaleProgress = currentScaleProgress;
- anim.onUpdate();
+ public void setValue(RectFSpringAnim object, float value) {
+ object.mCurrentScaleProgress = value;
+ object.onUpdate();
}
};
@@ -106,7 +94,7 @@ public class RectFSpringAnim {
private float mCurrentScaleProgress;
private FlingSpringAnim mRectXAnim;
private FlingSpringAnim mRectYAnim;
- private ValueAnimator mRectScaleAnim;
+ private SpringAnimation mRectScaleAnim;
private boolean mAnimsStarted;
private boolean mRectXAnimEnded;
private boolean mRectYAnimEnded;
@@ -177,17 +165,18 @@ public class RectFSpringAnim {
mRectYAnim = new FlingSpringAnim(this, RECT_Y, startY, endY, startVelocityY,
mMinVisChange, minYValue, maxYValue, springVelocityFactor, onYEndListener);
- mRectScaleAnim = ObjectAnimator.ofPropertyValuesHolder(this,
- PropertyValuesHolder.ofFloat(RECT_SCALE_PROGRESS, 1))
- .setDuration(RECT_SCALE_DURATION);
- mRectScaleAnim.setInterpolator(DEACCEL);
- mRectScaleAnim.addListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationSuccess(Animator animator) {
- mRectScaleAnimEnded = true;
- maybeOnEnd();
- }
- });
+ float minVisibleChange = 1f / mStartRect.height();
+ mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS)
+ .setSpring(new SpringForce(1f)
+ .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+ .setStiffness(SpringForce.STIFFNESS_LOW))
+ .setStartVelocity(velocityPxPerMs.y * minVisibleChange)
+ .setMaxValue(1f)
+ .setMinimumVisibleChange(minVisibleChange)
+ .addEndListener((animation, canceled, value, velocity) -> {
+ mRectScaleAnimEnded = true;
+ maybeOnEnd();
+ });
mRectXAnim.start();
mRectYAnim.start();
@@ -202,7 +191,9 @@ public class RectFSpringAnim {
if (mAnimsStarted) {
mRectXAnim.end();
mRectYAnim.end();
- mRectScaleAnim.end();
+ if (mRectScaleAnim.canSkipToEnd()) {
+ mRectScaleAnim.skipToEnd();
+ }
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
new file mode 100644
index 000000000..93b6e4ba5
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2019 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.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.Nullable;
+import androidx.dynamicanimation.animation.SpringForce;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils.ViewProgressProperty;
+import com.android.launcher3.R;
+import com.android.launcher3.ShortcutAndWidgetContainer;
+import com.android.launcher3.anim.SpringObjectAnimator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
+/**
+ * Creates an animation where all the workspace items are moved into their final location,
+ * staggered row by row from the bottom up.
+ * This is used in conjunction with the swipe up to home animation.
+ */
+public class StaggeredWorkspaceAnim {
+
+ private static final int APP_CLOSE_ROW_START_DELAY_MS = 16;
+ private static final int ALPHA_DURATION_MS = 200;
+
+ private static final float MAX_VELOCITY_PX_PER_S = 22f;
+
+ private static final float DAMPING_RATIO =
+ (SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY + SpringForce.DAMPING_RATIO_LOW_BOUNCY) / 2f;
+ private static final float STIFFNESS = SpringForce.STIFFNESS_LOW;
+
+ private final float mVelocity;
+ private final float mSpringTransY;
+ private final View mViewToIgnore;
+
+ private final List<ValueAnimator> mAnimators = new ArrayList<>();
+
+ /**
+ * @param floatingViewOriginalView The FloatingIconView's original view.
+ */
+ public StaggeredWorkspaceAnim(Launcher launcher, @Nullable View floatingViewOriginalView,
+ float velocity) {
+ mVelocity = velocity;
+ // We ignore this view since it's visibility and position is controlled by
+ // the FloatingIconView.
+ mViewToIgnore = floatingViewOriginalView;
+
+ // Scale the translationY based on the initial velocity to better sync the workspace items
+ // with the floating view.
+ float transFactor = 0.1f + 0.9f * Math.abs(velocity) / MAX_VELOCITY_PX_PER_S;
+ mSpringTransY = transFactor * launcher.getResources()
+ .getDimensionPixelSize(R.dimen.swipe_up_max_workspace_trans_y);;
+
+ DeviceProfile grid = launcher.getDeviceProfile();
+ ShortcutAndWidgetContainer currentPage = ((CellLayout) launcher.getWorkspace()
+ .getChildAt(launcher.getWorkspace().getCurrentPage()))
+ .getShortcutsAndWidgets();
+
+ // Hotseat and QSB takes up two additional rows.
+ int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2);
+
+ // Set up springs on workspace items.
+ for (int i = currentPage.getChildCount() - 1; i >= 0; i--) {
+ View child = currentPage.getChildAt(i);
+ CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
+ addStaggeredAnimationForView(child, lp.cellY + lp.cellVSpan, totalRows);
+ }
+
+ // Set up springs for the hotseat and qsb.
+ if (grid.isVerticalBarLayout()) {
+ ViewGroup hotseat = (ViewGroup) launcher.getHotseat().getChildAt(0);
+ for (int i = hotseat.getChildCount() - 1; i >= 0; i--) {
+ View child = hotseat.getChildAt(i);
+ CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
+ addStaggeredAnimationForView(child, lp.cellY + 1, totalRows);
+ }
+ } else {
+ View hotseat = launcher.getHotseat().getChildAt(0);
+ addStaggeredAnimationForView(hotseat, grid.inv.numRows + 1, totalRows);
+
+ View qsb = launcher.findViewById(R.id.search_container_all_apps);
+ addStaggeredAnimationForView(qsb, grid.inv.numRows + 2, totalRows);
+ }
+ }
+
+ /**
+ * Starts the animation.
+ */
+ public void start() {
+ for (Animator a : mAnimators) {
+ if (a instanceof SpringObjectAnimator) {
+ ((SpringObjectAnimator) a).startSpring(1f, mVelocity, null);
+ } else {
+ a.start();
+ }
+ }
+ }
+
+ /**
+ * Adds an alpha/trans animator for {@param v}, with a start delay based on the view's row.
+ *
+ * @param v A view on the workspace.
+ * @param row The bottom-most row that contains the view.
+ * @param totalRows Total number of rows.
+ */
+ private void addStaggeredAnimationForView(View v, int row, int totalRows) {
+ if (v == mViewToIgnore) {
+ return;
+ }
+
+ // Invert the rows, because we stagger starting from the bottom of the screen.
+ int invertedRow = totalRows - row;
+ // Add 1 to the inverted row so that the bottom most row has a start delay.
+ long startDelay = (long) ((invertedRow + 1) * APP_CLOSE_ROW_START_DELAY_MS);
+
+ v.setTranslationY(mSpringTransY);
+ SpringObjectAnimator springTransY = new SpringObjectAnimator<>(
+ new ViewProgressProperty(v, View.TRANSLATION_Y), "staggeredSpringTransY", 1f,
+ DAMPING_RATIO, STIFFNESS, mSpringTransY, 0);
+ springTransY.setStartDelay(startDelay);
+ mAnimators.add(springTransY);
+
+ v.setAlpha(0);
+ ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 0f, 1f);
+ alpha.setInterpolator(LINEAR);
+ alpha.setDuration(ALPHA_DURATION_MS);
+ alpha.setStartDelay(startDelay);
+ mAnimators.add(alpha);
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 053b7389c..f8d454f34 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -52,6 +52,7 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.logging.UserEventDispatcher;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -145,11 +146,13 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
};
private final TaskOutlineProvider mOutlineProvider;
+ private final FooterOutlineProvider mFooterOutlineProvider;
private Task mTask;
private TaskThumbnailView mSnapshotView;
private TaskMenuView mMenuView;
private IconView mIconView;
+ private View mTaskFooterContainer;
private DigitalWellBeingToast mDigitalWellBeingToast;
private float mCurveScale;
private float mFullscreenProgress;
@@ -180,6 +183,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
super(context, attrs, defStyleAttr);
mActivity = BaseDraggingActivity.fromContext(context);
setOnClickListener((view) -> {
+ if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
+ android.util.Log.d(TestProtocol.NO_START_TASK_TAG, "TaskView onClick");
+ }
if (getTask() == null) {
return;
}
@@ -203,6 +209,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources());
mCurrentFullscreenParams = new FullscreenDrawParams(mCornerRadius);
mOutlineProvider = new TaskOutlineProvider(getResources(), mCurrentFullscreenParams);
+ mFooterOutlineProvider = new FooterOutlineProvider(mCurrentFullscreenParams);
setOutlineProvider(mOutlineProvider);
}
@@ -212,6 +219,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
mSnapshotView = findViewById(R.id.snapshot);
mIconView = findViewById(R.id.icon);
mDigitalWellBeingToast = findViewById(R.id.digital_well_being_toast);
+ mTaskFooterContainer = findViewById(R.id.task_footer_container);
+ mTaskFooterContainer.setOutlineProvider(mFooterOutlineProvider);
+ mTaskFooterContainer.setClipToOutline(true);
}
public TaskMenuView getMenuView() {
@@ -279,6 +289,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
public void launchTask(boolean animate, boolean freezeTaskList, Consumer<Boolean> resultCallback,
Handler resultCallbackHandler) {
+ if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
+ android.util.Log.d(TestProtocol.NO_START_TASK_TAG, "launchTask");
+ }
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (isRunningTask()) {
getRecentsView().finishRecentsAnimation(false /* toRecents */,
@@ -293,6 +306,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private void launchTaskInternal(boolean animate, boolean freezeTaskList,
Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
+ if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
+ android.util.Log.d(TestProtocol.NO_START_TASK_TAG, "launchTaskInternal");
+ }
if (mTask != null) {
final ActivityOptions opts;
if (animate) {
@@ -410,6 +426,15 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
.getInterpolation(progress);
mIconView.setScaleX(scale);
mIconView.setScaleY(scale);
+
+ int footerVerticalOffset = (int) (mTaskFooterContainer.getHeight() * (1.0f - scale));
+ mTaskFooterContainer.setTranslationY(
+ mCurrentFullscreenParams.mCurrentDrawnInsets.bottom +
+ mCurrentFullscreenParams.mCurrentDrawnInsets.top +
+ footerVerticalOffset);
+ mFooterOutlineProvider.setFullscreenDrawParams(
+ mCurrentFullscreenParams, footerVerticalOffset);
+ mTaskFooterContainer.invalidateOutline();
}
public void setIconScaleAnimStartProgress(float startProgress) {
@@ -550,6 +575,29 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
}
}
+ private static final class FooterOutlineProvider extends ViewOutlineProvider {
+
+ private FullscreenDrawParams mFullscreenDrawParams;
+ private int mVerticalOffset;
+ private final Rect mOutlineRect = new Rect();
+
+ FooterOutlineProvider(FullscreenDrawParams params) {
+ mFullscreenDrawParams = params;
+ }
+
+ void setFullscreenDrawParams(FullscreenDrawParams params, int verticalOffset) {
+ mFullscreenDrawParams = params;
+ mVerticalOffset = verticalOffset;
+ }
+
+ @Override
+ public void getOutline(View view, Outline outline) {
+ mOutlineRect.set(0, 0, view.getWidth(), view.getHeight());
+ mOutlineRect.offset(0, -mVerticalOffset);
+ outline.setRoundRect(mOutlineRect, mFullscreenDrawParams.mCurrentDrawnCornerRadius);
+ }
+ }
+
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
@@ -633,12 +681,12 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
* @param progress: 0 = show icon and no insets; 1 = don't show icon and show full insets.
*/
public void setFullscreenProgress(float progress) {
+ progress = Utilities.boundToRange(progress, 0, 1);
if (progress == mFullscreenProgress) {
return;
}
mFullscreenProgress = progress;
boolean isFullscreen = mFullscreenProgress > 0;
- setIconScaleAndDim(progress, true /* invert */);
mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
setClipChildren(!isFullscreen);
setClipToPadding(!isFullscreen);
@@ -662,6 +710,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
/ (getWidth() + currentInsetsLeft + currentInsetsRight));
}
+ // Some of the items in here are dependent on the current fullscreen params
+ setIconScaleAndDim(progress, true /* invert */);
+
thumbnail.setFullscreenParams(mCurrentFullscreenParams);
mOutlineProvider.setFullscreenParams(mCurrentFullscreenParams);
invalidateOutline();