Attached the navigation bar to app for launching from Launcher

- Play the nav bar fade-out animation at the same time when the app
  launching animation starts and make the fade-in animation ends at the
  same time when app launching animation ends.
- To make the nav bar fade-in animation looks like it's attached to the
  app, apply crop rect and translation that the app targets apply to the
  nav target.

Bug: 181638132
Test: manual: click app icon on launcher to launch an activity and
observe the navigation bar animation.

Change-Id: If7e610eca5fccbb747a76c87335a600b018195a6
This commit is contained in:
shawnlin
2021-03-19 16:04:14 +08:00
committed by Shawn Lin
parent 12eeecc36b
commit ffb976c404
13 changed files with 137 additions and 29 deletions
@@ -61,6 +61,8 @@ import android.os.Looper;
import android.os.SystemProperties;
import android.util.Pair;
import android.view.View;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -137,6 +139,15 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
private static final long APP_LAUNCH_ALPHA_DOWN_DURATION =
(long) (APP_LAUNCH_ALPHA_DURATION * APP_LAUNCH_DOWN_DUR_SCALE_FACTOR);
public static final int ANIMATION_NAV_FADE_IN_DURATION = 266;
public static final int ANIMATION_NAV_FADE_OUT_DURATION = 133;
public static final long ANIMATION_DELAY_NAV_FADE_IN =
APP_LAUNCH_DURATION - ANIMATION_NAV_FADE_IN_DURATION;
public static final Interpolator NAV_FADE_IN_INTERPOLATOR =
new PathInterpolator(0f, 0f, 0f, 1f);
public static final Interpolator NAV_FADE_OUT_INTERPOLATOR =
new PathInterpolator(0.2f, 0f, 1f, 1f);
private static final long CROP_DURATION = 375;
private static final long RADIUS_DURATION = 375;
@@ -276,10 +287,11 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
*/
protected void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
@NonNull RemoteAnimationTargetCompat[] appTargets,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing) {
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
@NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing) {
TaskViewUtils.composeRecentsLaunchAnimator(anim, v, appTargets, wallpaperTargets,
launcherClosing, mLauncher.getStateManager(), mLauncher.getOverviewPanel(),
mLauncher.getDepthController());
nonAppTargets, launcherClosing, mLauncher.getStateManager(),
mLauncher.getOverviewPanel(), mLauncher.getDepthController());
}
private boolean areAllTargetsTranslucent(@NonNull RemoteAnimationTargetCompat[] targets) {
@@ -305,6 +317,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
private void composeIconLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
@NonNull RemoteAnimationTargetCompat[] appTargets,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
@NonNull RemoteAnimationTargetCompat[] nonAppTargets,
boolean launcherClosing) {
// Set the state animation first so that any state listeners are called
// before our internal listeners.
@@ -313,8 +326,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
final int rotationChange = getRotationChange(appTargets);
// Note: the targetBounds are relative to the launcher
Rect windowTargetBounds = getWindowTargetBounds(appTargets, rotationChange);
anim.play(getOpeningWindowAnimators(v, appTargets, wallpaperTargets, windowTargetBounds,
areAllTargetsTranslucent(appTargets), rotationChange));
anim.play(getOpeningWindowAnimators(v, appTargets, wallpaperTargets, nonAppTargets,
windowTargetBounds, areAllTargetsTranslucent(appTargets), rotationChange));
if (launcherClosing) {
Pair<AnimatorSet, Runnable> launcherContentAnimator =
getLauncherContentAnimator(true /* isAppOpening */,
@@ -515,6 +528,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
private Animator getOpeningWindowAnimators(View v,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets,
Rect windowTargetBounds, boolean appTargetsAreTranslucent, int rotationChange) {
RectF launcherIconBounds = new RectF();
FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v,
@@ -523,10 +537,11 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
Matrix matrix = new Matrix();
RemoteAnimationTargets openingTargets = new RemoteAnimationTargets(appTargets,
wallpaperTargets, MODE_OPENING);
wallpaperTargets, nonAppTargets, MODE_OPENING);
SurfaceTransactionApplier surfaceApplier =
new SurfaceTransactionApplier(floatingView);
openingTargets.addReleaseCheck(surfaceApplier);
RemoteAnimationTargetCompat navBarTarget = openingTargets.getNavBarRemoteAnimationTarget();
int[] dragLayerBounds = new int[2];
mDragLayer.getLocationOnScreen(dragLayerBounds);
@@ -601,6 +616,11 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd, 0,
CROP_DURATION, EXAGGERATED_EASE);
FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
NAV_FADE_OUT_INTERPOLATOR);
FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN,
ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
@Override
public void onUpdate(float percent) {
// Calculate the size of the scaled icon.
@@ -706,6 +726,21 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
params[i] = builder.build();
}
surfaceApplier.scheduleApply(params);
if (navBarTarget != null) {
final SurfaceParams.Builder navBuilder =
new SurfaceParams.Builder(navBarTarget.leash);
if (mNavFadeIn.value > mNavFadeIn.getStartValue()) {
matrix.setScale(scale, scale);
matrix.postTranslate(windowTransX0, windowTransY0);
navBuilder.withMatrix(matrix)
.withWindowCrop(crop)
.withAlpha(mNavFadeIn.value);
} else {
navBuilder.withAlpha(mNavFadeOut.value);
}
surfaceApplier.scheduleApply(navBuilder.build());
}
}
});
@@ -1088,19 +1123,18 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
RemoteAnimationTargetCompat[] nonAppTargets,
LauncherAnimationRunner.AnimationResult result) {
AnimatorSet anim = new AnimatorSet();
boolean launcherClosing =
launcherIsATargetWithMode(appTargets, MODE_CLOSING);
final boolean launchingFromRecents = isLaunchingFromRecents(mV, appTargets);
final boolean launchingFromTaskbar = mLauncher.isViewInTaskbar(mV);
if (launchingFromRecents) {
composeRecentsLaunchAnimator(anim, mV, appTargets, wallpaperTargets,
composeRecentsLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets,
launcherClosing);
} else if (launchingFromTaskbar) {
// TODO
} else {
composeIconLaunchAnimator(anim, mV, appTargets, wallpaperTargets,
composeIconLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets,
launcherClosing);
}
@@ -247,7 +247,8 @@ public class FallbackSwipeHandler extends
if (appearedTaskTarget.activityType == ACTIVITY_TYPE_HOME) {
RemoteAnimationTargets targets = new RemoteAnimationTargets(
new RemoteAnimationTargetCompat[] {appearedTaskTarget},
new RemoteAnimationTargetCompat[0], appearedTaskTarget.mode);
new RemoteAnimationTargetCompat[0], new RemoteAnimationTargetCompat[0],
appearedTaskTarget.mode);
mHomeAlphaParams.setTargetSet(targets);
updateHomeAlpha();
return true;
@@ -192,7 +192,7 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
RemoteAnimationTargetCompat[] nonAppTargets,
AnimationResult result) -> {
AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets,
wallpaperTargets);
wallpaperTargets, nonAppTargets);
anim.addListener(resetStateListener());
result.setAnimation(anim, RecentsActivity.this, onEndCallback::executeAllAndDestroy);
};
@@ -213,12 +213,13 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
*/
private AnimatorSet composeRecentsLaunchAnimator(TaskView taskView,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets) {
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets) {
AnimatorSet target = new AnimatorSet();
boolean activityClosing = taskIsATargetWithMode(appTargets, getTaskId(), MODE_CLOSING);
PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
createRecentsWindowAnimator(taskView, !activityClosing, appTargets,
wallpaperTargets, null /* depthController */, pa);
wallpaperTargets, nonAppTargets, null /* depthController */, pa);
target.play(pa.buildAnim());
// Found a visible recents task that matches the opening app, lets launch the app from there
@@ -33,7 +33,7 @@ public class RecentsAnimationTargets extends RemoteAnimationTargets {
public RecentsAnimationTargets(RemoteAnimationTargetCompat[] apps,
RemoteAnimationTargetCompat[] wallpapers, Rect homeContentInsets,
Rect minimizedHomeBounds) {
super(apps, wallpapers, MODE_CLOSING);
super(apps, wallpapers, new RemoteAnimationTargetCompat[0], MODE_CLOSING);
this.homeContentInsets = homeContentInsets;
this.minimizedHomeBounds = minimizedHomeBounds;
}
@@ -15,6 +15,8 @@
*/
package com.android.quickstep;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.util.ArrayList;
@@ -30,13 +32,15 @@ public class RemoteAnimationTargets {
public final RemoteAnimationTargetCompat[] unfilteredApps;
public final RemoteAnimationTargetCompat[] apps;
public final RemoteAnimationTargetCompat[] wallpapers;
public final RemoteAnimationTargetCompat[] nonApps;
public final int targetMode;
public final boolean hasRecents;
private boolean mReleased = false;
public RemoteAnimationTargets(RemoteAnimationTargetCompat[] apps,
RemoteAnimationTargetCompat[] wallpapers, int targetMode) {
RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
int targetMode) {
ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>();
boolean hasRecents = false;
if (apps != null) {
@@ -55,6 +59,7 @@ public class RemoteAnimationTargets {
this.wallpapers = wallpapers;
this.targetMode = targetMode;
this.hasRecents = hasRecents;
this.nonApps = nonApps;
}
public RemoteAnimationTargetCompat findTask(int taskId) {
@@ -66,6 +71,18 @@ public class RemoteAnimationTargets {
return null;
}
/**
* Gets the navigation bar remote animation target if exists.
*/
public RemoteAnimationTargetCompat getNavBarRemoteAnimationTarget() {
for (RemoteAnimationTargetCompat target : nonApps) {
if (target.windowType == TYPE_NAVIGATION_BAR) {
return target;
}
}
return null;
}
public boolean isAnimatingHome() {
for (RemoteAnimationTargetCompat target : unfilteredApps) {
if (target.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
@@ -98,6 +115,9 @@ public class RemoteAnimationTargets {
for (RemoteAnimationTargetCompat target : wallpapers) {
target.release();
}
for (RemoteAnimationTargetCompat target : nonApps) {
target.release();
}
}
/**
@@ -18,6 +18,11 @@ package com.android.quickstep;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_DELAY_NAV_FADE_IN;
import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_NAV_FADE_IN_DURATION;
import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_NAV_FADE_OUT_DURATION;
import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_IN_INTERPOLATOR;
import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_OUT_INTERPOLATOR;
import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
import static com.android.launcher3.anim.Interpolators.LINEAR;
@@ -58,6 +63,7 @@ import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
@@ -67,6 +73,7 @@ import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
/**
* Utility class for helpful methods related to {@link TaskView} objects and their tasks.
@@ -137,7 +144,8 @@ public final class TaskViewUtils {
public static void createRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets, DepthController depthController,
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets, DepthController depthController,
PendingAnimation out) {
boolean isRunningTask = v.isRunningTask();
TransformParams params = null;
@@ -146,7 +154,7 @@ public final class TaskViewUtils {
params = v.getRecentsView().getLiveTileParams();
tsv = v.getRecentsView().getLiveTileTaskViewSimulator();
}
createRecentsWindowAnimator(v, skipViewChanges, appTargets, wallpaperTargets,
createRecentsWindowAnimator(v, skipViewChanges, appTargets, wallpaperTargets, nonAppTargets,
depthController, out, params, tsv);
}
@@ -156,7 +164,8 @@ public final class TaskViewUtils {
*/
public static void createRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets, DepthController depthController,
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets, DepthController depthController,
PendingAnimation out, @Nullable TransformParams params,
@Nullable TaskViewSimulator tsv) {
boolean isQuickSwitch = v.isEndQuickswitchCuj();
@@ -164,8 +173,9 @@ public final class TaskViewUtils {
boolean inLiveTileMode = LIVE_TILE.get() && v.getRecentsView().getRunningTaskIndex() != -1;
final RemoteAnimationTargets targets =
new RemoteAnimationTargets(appTargets, wallpaperTargets,
new RemoteAnimationTargets(appTargets, wallpaperTargets, nonAppTargets,
inLiveTileMode ? MODE_CLOSING : MODE_OPENING);
final RemoteAnimationTargetCompat navBarTarget = targets.getNavBarRemoteAnimationTarget();
if (params == null) {
SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
@@ -225,6 +235,30 @@ public final class TaskViewUtils {
TaskViewSimulator finalTsv = tsv;
TransformParams finalParams = params;
out.addOnFrameCallback(() -> finalTsv.apply(finalParams));
if (navBarTarget != null) {
final Rect cropRect = new Rect();
out.addOnFrameListener(new MultiValueUpdateListener() {
FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0,
ANIMATION_NAV_FADE_OUT_DURATION, NAV_FADE_OUT_INTERPOLATOR);
FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN,
ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
@Override
public void onUpdate(float percent) {
final SurfaceParams.Builder navBuilder =
new SurfaceParams.Builder(navBarTarget.leash);
if (mNavFadeIn.value > mNavFadeIn.getStartValue()) {
finalTsv.getCurrentCropRect().round(cropRect);
navBuilder.withMatrix(finalTsv.getCurrentMatrix())
.withWindowCrop(cropRect)
.withAlpha(mNavFadeIn.value);
} else {
navBuilder.withAlpha(mNavFadeOut.value);
}
finalParams.applySurfaceParams(navBuilder.build());
}
});
}
topMostSimulator = tsv;
}
@@ -320,7 +354,8 @@ public final class TaskViewUtils {
*/
public static void composeRecentsSplitLaunchAnimator(@NonNull AnimatorSet anim,
@NonNull TaskView v, @NonNull RemoteAnimationTargetCompat[] appTargets,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
@NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
@NonNull StateManager stateManager, @NonNull DepthController depthController,
int targetStage) {
PendingAnimation out = new PendingAnimation(RECENTS_LAUNCH_DURATION);
@@ -336,7 +371,7 @@ public final class TaskViewUtils {
boolean inLiveTileMode =
ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskIndex() != -1;
final RemoteAnimationTargets targets =
new RemoteAnimationTargets(appTargets, wallpaperTargets,
new RemoteAnimationTargets(appTargets, wallpaperTargets, nonAppTargets,
inLiveTileMode ? MODE_CLOSING : MODE_OPENING);
if (params == null) {
@@ -392,7 +427,8 @@ public final class TaskViewUtils {
public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
@NonNull RemoteAnimationTargetCompat[] appTargets,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
@NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
@NonNull StateManager stateManager, @NonNull RecentsView recentsView,
@NonNull DepthController depthController) {
boolean skipLauncherChanges = !launcherClosing;
@@ -400,7 +436,7 @@ public final class TaskViewUtils {
TaskView taskView = findTaskViewToLaunch(recentsView, v, appTargets);
PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets,
depthController, pa);
nonAppTargets, depthController, pa);
Animator childStateAnimation = null;
// Found a visible recents task that matches the opening app, lets launch the app from there
@@ -64,5 +64,12 @@ public abstract class MultiValueUpdateListener implements ValueAnimator.Animator
mAllProperties.add(this);
}
/**
* Gets the start value.
*/
public float getStartValue() {
return mStart;
}
}
}
@@ -34,7 +34,8 @@ public class RemoteFadeOutAnimationListener implements AnimatorUpdateListener {
public RemoteFadeOutAnimationListener(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets) {
mTarget = new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_CLOSING);
mTarget = new RemoteAnimationTargets(appTargets, wallpaperTargets,
new RemoteAnimationTargetCompat[0], MODE_CLOSING);
}
@Override
@@ -130,7 +130,7 @@ public class SplitSelectStateController {
AnimatorSet anim = new AnimatorSet();
BaseQuickstepLauncher activity = BaseActivity.fromContext(mV.getContext());
TaskViewUtils.composeRecentsSplitLaunchAnimator(anim, mV,
appTargets, wallpaperTargets, true, activity.getStateManager(),
appTargets, wallpaperTargets, nonAppTargets, true, activity.getStateManager(),
activity.getDepthController(), mTargetState);
result.setAnimation(anim, activity);
}
@@ -205,7 +205,7 @@ public class TransformParams {
return mTargetSet;
}
public void applySurfaceParams(SurfaceParams[] params) {
public void applySurfaceParams(SurfaceParams... params) {
if (mSyncTransactionApplier != null) {
mSyncTransactionApplier.scheduleApply(params);
} else {
@@ -766,7 +766,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
} else {
TaskViewUtils.composeRecentsLaunchAnimator(
anim, taskView, apps,
mLiveTileParams.getTargetSet().wallpapers, true /* launcherClosing */,
mLiveTileParams.getTargetSet().wallpapers,
mLiveTileParams.getTargetSet().nonApps, true /* launcherClosing */,
mActivity.getStateManager(), this,
getDepthController());
}
@@ -489,7 +489,7 @@ public class TaskView extends FrameLayout implements Reusable {
AnimatorSet anim = new AnimatorSet();
TaskViewUtils.composeRecentsLaunchAnimator(
anim, this, targets.apps,
targets.wallpapers, true /* launcherClosing */,
targets.wallpapers, targets.nonApps, true /* launcherClosing */,
mActivity.getStateManager(), recentsView,
recentsView.getDepthController());
anim.addListener(new AnimatorListenerAdapter() {
@@ -117,11 +117,18 @@ public class PendingAnimation implements PropertySetter {
* Adds a callback to be run on every frame of the animation
*/
public void addOnFrameCallback(Runnable runnable) {
addOnFrameListener(anim -> runnable.run());
}
/**
* Adds a listener to be run on every frame of the animation
*/
public void addOnFrameListener(ValueAnimator.AnimatorUpdateListener listener) {
if (mProgressAnimator == null) {
mProgressAnimator = ValueAnimator.ofFloat(0, 1);
}
mProgressAnimator.addUpdateListener(anim -> runnable.run());
mProgressAnimator.addUpdateListener(listener);
}
/**