Merge "Merging from ub-launcher3-master @ build 6304996" into rvc-dev am: c83758f223

Change-Id: I9a2c0cb3ca78a62f90ffe13076b63785f255a882
This commit is contained in:
Zak Cohen
2020-03-18 18:13:08 +00:00
committed by Automerger Merge Worker
59 changed files with 1904 additions and 796 deletions
@@ -20,15 +20,14 @@ import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherStateManager.ANIM_ALL_COMPONENTS;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_TRANSLATE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator;
@@ -47,9 +46,9 @@ import androidx.annotation.Nullable;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.views.RecentsView;
@@ -210,17 +209,20 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
.setValues(values)
.build(mLauncher);
case INDEX_PAUSE_TO_OVERVIEW_ANIM: {
AnimatorSetBuilder builder = new AnimatorSetBuilder();
builder.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
builder.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3);
StateAnimationConfig config = new StateAnimationConfig();
config.duration = ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
config.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
config.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3);
if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
builder.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
builder.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
}
LauncherStateManager stateManager = mLauncher.getStateManager();
return stateManager.createAtomicAnimation(
stateManager.getCurrentStableState(), OVERVIEW, builder,
ANIM_ALL_COMPONENTS, ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW);
stateManager.getCurrentStableState(), OVERVIEW, config);
}
default:
@@ -20,7 +20,6 @@ import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.os.Build;
import android.util.FloatProperty;
@@ -29,10 +28,10 @@ import androidx.annotation.NonNull;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.quickstep.views.ClearAllButton;
import com.android.quickstep.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
@@ -61,25 +60,22 @@ public final class RecentsViewStateController extends
}
@Override
void setStateWithAnimationInternal(@NonNull final LauncherState toState,
@NonNull AnimatorSetBuilder builder, @NonNull AnimationConfig config) {
super.setStateWithAnimationInternal(toState, builder, config);
void setStateWithAnimationInternal(@NonNull LauncherState toState,
@NonNull StateAnimationConfig config, @NonNull PendingAnimation builder) {
super.setStateWithAnimationInternal(toState, config, builder);
ValueAnimator updateAnim = ValueAnimator.ofFloat(0, 1).setDuration(config.duration);
if (toState.overviewUi) {
// While animating into recents, update the visible task data as needed
updateAnim.addUpdateListener(valueAnimator -> mRecentsView.loadVisibleTaskData());
builder.addOnFrameCallback(mRecentsView::loadVisibleTaskData);
mRecentsView.updateEmptyMessage();
} else {
updateAnim.addListener(
builder.getAnim().addListener(
AnimationSuccessListener.forRunnable(mRecentsView::resetTaskVisuals));
}
builder.play(updateAnim);
PropertySetter propertySetter = config.getPropertySetter(builder);
setAlphas(propertySetter, toState.getVisibleElements(mLauncher));
float fullscreenProgress = toState.getOverviewFullscreenProgress();
propertySetter.setFloat(mRecentsView, FULLSCREEN_PROGRESS, fullscreenProgress, LINEAR);
setAlphas(builder, toState.getVisibleElements(mLauncher));
builder.setFloat(mRecentsView, FULLSCREEN_PROGRESS,
toState.getOverviewFullscreenProgress(), LINEAR);
}
private void setAlphas(PropertySetter propertySetter, int visibleElements) {
@@ -14,17 +14,18 @@
* limitations under the License.
*/
package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCRIM_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.states.StateAnimationConfig;
public class OverviewPeekState extends OverviewState {
public OverviewPeekState(int id) {
@@ -41,11 +42,11 @@ public class OverviewPeekState extends OverviewState {
@Override
public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
AnimatorSetBuilder builder) {
StateAnimationConfig config) {
if (this == OVERVIEW_PEEK && fromState == NORMAL) {
builder.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
builder.setInterpolator(ANIM_OVERVIEW_SCRIM_FADE, FAST_OUT_SLOW_IN);
config.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
config.setInterpolator(ANIM_OVERVIEW_SCRIM_FADE, FAST_OUT_SLOW_IN);
}
}
}
@@ -18,13 +18,6 @@ package com.android.launcher3.uioverrides.states;
import static android.view.View.VISIBLE;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
@@ -32,6 +25,13 @@ import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
@@ -48,8 +48,8 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Workspace;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.SysUINavigationMode;
@@ -225,14 +225,14 @@ public class OverviewState extends LauncherState {
@Override
public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
AnimatorSetBuilder builder) {
StateAnimationConfig config) {
if ((fromState == NORMAL || fromState == HINT_STATE) && this == OVERVIEW) {
if (SysUINavigationMode.getMode(launcher) == NO_BUTTON) {
builder.setInterpolator(ANIM_WORKSPACE_SCALE,
config.setInterpolator(ANIM_WORKSPACE_SCALE,
fromState == NORMAL ? ACCEL : OVERSHOOT_1_2);
builder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL);
config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL);
} else {
builder.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
// Scale up the recents, if it is not coming from the side
RecentsView overview = launcher.getOverviewPanel();
@@ -240,15 +240,15 @@ public class OverviewState extends LauncherState {
SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
}
}
builder.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
builder.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get()
&& removeShelfFromOverview(launcher)
? OVERSHOOT_1_2
: OVERSHOOT_1_7;
builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator);
builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, translationInterpolator);
builder.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator);
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, translationInterpolator);
config.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
}
}
@@ -21,16 +21,16 @@ import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
import static com.android.launcher3.LauncherStateManager.PLAY_ATOMIC_OVERVIEW_PEEK;
import static com.android.launcher3.LauncherStateManager.SKIP_OVERVIEW;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_HEADER_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_HEADER_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
@@ -44,10 +44,10 @@ import android.view.ViewConfiguration;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppTransitionManagerImpl;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationFlags;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.VibratorWrapper;
import com.android.quickstep.SystemUiProxy;
@@ -105,8 +105,12 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
LauncherState fromState = isPaused ? NORMAL : OVERVIEW_PEEK;
LauncherState toState = isPaused ? OVERVIEW_PEEK : NORMAL;
long peekDuration = isPaused ? PEEK_IN_ANIM_DURATION : PEEK_OUT_ANIM_DURATION;
mPeekAnim = mLauncher.getStateManager().createAtomicAnimation(fromState, toState,
new AnimatorSetBuilder(), PLAY_ATOMIC_OVERVIEW_PEEK, peekDuration);
StateAnimationConfig config = new StateAnimationConfig();
config.duration = peekDuration;
config.animFlags = PLAY_ATOMIC_OVERVIEW_PEEK;
mPeekAnim = mLauncher.getStateManager().createAtomicAnimation(
fromState, toState, config);
mPeekAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -130,10 +134,10 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
}
@Override
protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState,
LauncherState toState) {
protected StateAnimationConfig getConfigForStates(
LauncherState fromState, LauncherState toState) {
if (fromState == NORMAL && toState == ALL_APPS) {
AnimatorSetBuilder builder = new AnimatorSetBuilder();
StateAnimationConfig builder = new StateAnimationConfig();
// Fade in prediction icons quickly, then rest of all apps after reaching overview.
float progressToReachOverview = NORMAL.getVerticalProgress(mLauncher)
- OVERVIEW.getVerticalProgress(mLauncher);
@@ -152,7 +156,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
builder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_3);
return builder;
} else if (fromState == ALL_APPS && toState == NORMAL) {
AnimatorSetBuilder builder = new AnimatorSetBuilder();
StateAnimationConfig builder = new StateAnimationConfig();
// Keep all apps/predictions opaque until the very end of the transition.
float progressToReachOverview = OVERVIEW.getVerticalProgress(mLauncher);
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
@@ -165,7 +169,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
1));
return builder;
}
return super.getAnimatorSetBuilderForStates(fromState, toState);
return super.getConfigForStates(fromState, toState);
}
@Override
@@ -211,9 +215,11 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (mCancelled) {
mPeekAnim = mLauncher.getStateManager().createAtomicAnimation(mFromState,
mToState, new AnimatorSetBuilder(), PLAY_ATOMIC_OVERVIEW_PEEK,
PEEK_OUT_ANIM_DURATION);
StateAnimationConfig config = new StateAnimationConfig();
config.animFlags = PLAY_ATOMIC_OVERVIEW_PEEK;
config.duration = PEEK_OUT_ANIM_DURATION;
mPeekAnim = mLauncher.getStateManager().createAtomicAnimation(
mFromState, mToState, config);
mPeekAnim.start();
}
mAtomicAnim = null;
@@ -15,8 +15,7 @@
*/
package com.android.launcher3.uioverrides.touchcontrollers;
import static android.view.View.TRANSLATION_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -26,9 +25,6 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TI
import static com.android.launcher3.touch.AbstractStateChangeTouchController.SUCCESS_TRANSITION_PROGRESS;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
@@ -36,16 +32,16 @@ import android.view.animation.Interpolator;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -132,46 +128,37 @@ public class NavBarToHomeTouchController implements TouchController,
private void initCurrentAnimation() {
long accuracy = (long) (getShiftRange() * 2);
final AnimatorSet anim = new AnimatorSet();
final PendingAnimation builder = new PendingAnimation(accuracy);
if (mStartState == OVERVIEW) {
RecentsView recentsView = mLauncher.getOverviewPanel();
float pullbackDist = mPullbackDistance;
if (!recentsView.isRtl()) {
pullbackDist = -pullbackDist;
}
ObjectAnimator pullback = ObjectAnimator.ofFloat(recentsView, TRANSLATION_X,
pullbackDist);
pullback.setInterpolator(PULLBACK_INTERPOLATOR);
builder.setFloat(recentsView, VIEW_TRANSLATE_X, pullbackDist, PULLBACK_INTERPOLATOR);
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
pullback.addUpdateListener(
valueAnimator -> recentsView.redrawLiveTile(false /* mightNeedToRefill */));
builder.addOnFrameCallback(
() -> recentsView.redrawLiveTile(false /* mightNeedToRefill */));
}
anim.play(pullback);
} else if (mStartState == ALL_APPS) {
AnimatorSetBuilder builder = new AnimatorSetBuilder();
AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
Animator allAppsProgress = ObjectAnimator.ofFloat(allAppsController, ALL_APPS_PROGRESS,
-mPullbackDistance / allAppsController.getShiftRange());
allAppsProgress.setInterpolator(PULLBACK_INTERPOLATOR);
builder.play(allAppsProgress);
builder.setFloat(allAppsController, ALL_APPS_PROGRESS,
-mPullbackDistance / allAppsController.getShiftRange(), PULLBACK_INTERPOLATOR);
// Slightly fade out all apps content to further distinguish from scrolling.
builder.setInterpolator(AnimatorSetBuilder.ANIM_ALL_APPS_FADE, Interpolators
.mapToProgress(PULLBACK_INTERPOLATOR, 0, 0.5f));
AnimationConfig config = new AnimationConfig();
StateAnimationConfig config = new StateAnimationConfig();
config.duration = accuracy;
allAppsController.setAlphas(mEndState.getVisibleElements(mLauncher), config, builder);
anim.play(builder.build());
config.setInterpolator(StateAnimationConfig.ANIM_ALL_APPS_FADE, Interpolators
.mapToProgress(PULLBACK_INTERPOLATOR, 0, 0.5f));
allAppsController.setAlphas(mEndState, config, builder);
}
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher);
if (topView != null) {
Animator hintCloseAnim = topView.createHintCloseAnim(mPullbackDistance);
if (hintCloseAnim != null) {
hintCloseAnim.setInterpolator(PULLBACK_INTERPOLATOR);
anim.play(hintCloseAnim);
}
topView.addHintCloseAnim(mPullbackDistance, PULLBACK_INTERPOLATOR, builder);
}
anim.setDuration(accuracy);
mCurrentAnimation = AnimatorPlaybackController.wrap(anim, accuracy)
mCurrentAnimation = builder.createPlaybackController()
.setOnCancelRunnable(this::clearState);
}
@@ -19,9 +19,9 @@ package com.android.launcher3.uioverrides.touchcontrollers;
import static com.android.launcher3.LauncherState.HINT_STATE;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherStateManager.PLAY_ATOMIC_OVERVIEW_PEEK;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import android.animation.AnimatorSet;
@@ -34,7 +34,7 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.VibratorWrapper;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
@@ -171,11 +171,11 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
// StaggeredWorkspaceAnim doesn't animate overview, so we handle it here.
stateManager.cancelAnimation();
AnimatorSetBuilder builder = new AnimatorSetBuilder();
long duration = OVERVIEW.getTransitionDuration(mLauncher);
StateAnimationConfig config = new StateAnimationConfig();
config.duration = OVERVIEW.getTransitionDuration(mLauncher);
config.animFlags = PLAY_ATOMIC_OVERVIEW_PEEK;
AnimatorSet anim = stateManager.createAtomicAnimation(
stateManager.getState(), NORMAL, builder,
PLAY_ATOMIC_OVERVIEW_PEEK, duration);
stateManager.getState(), NORMAL, config);
anim.addListener(AnimationSuccessListener.forRunnable(
() -> onSwipeInteractionCompleted(NORMAL, Touch.SWIPE)));
anim.start();
@@ -21,18 +21,18 @@ import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.QUICK_SWITCH;
import static com.android.launcher3.LauncherStateManager.ANIM_ALL_COMPONENTS;
import static com.android.launcher3.LauncherStateManager.SKIP_OVERVIEW;
import static com.android.launcher3.anim.AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_5;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
@@ -55,15 +55,13 @@ import android.view.animation.Interpolator;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.AnimationFlags;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.OverviewScrim;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.BaseSwipeDetector;
import com.android.launcher3.touch.BothAxesSwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -192,11 +190,9 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
ShelfAnimState shelfState = isPaused ? PEEK : HIDE;
if (shelfState == PEEK) {
// Some shelf elements (e.g. qsb) were hidden, but we need them visible when peeking.
AnimatorSetBuilder builder = new AnimatorSetBuilder();
AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
allAppsController.setAlphas(NORMAL.getVisibleElements(mLauncher),
new AnimationConfig(), builder);
builder.build().setDuration(0).start();
allAppsController.setAlphas(
NORMAL, new StateAnimationConfig(), NO_ANIM_PROPERTY_SETTER);
if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
// Hotseat was hidden, but we need it visible when peeking.
@@ -209,12 +205,12 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
private void setupAnimators() {
// Animate the non-overview components (e.g. workspace, shelf) out of the way.
AnimatorSetBuilder nonOverviewBuilder = new AnimatorSetBuilder();
StateAnimationConfig nonOverviewBuilder = new StateAnimationConfig();
nonOverviewBuilder.setInterpolator(ANIM_WORKSPACE_FADE, FADE_OUT_INTERPOLATOR);
nonOverviewBuilder.setInterpolator(ANIM_ALL_APPS_FADE, FADE_OUT_INTERPOLATOR);
nonOverviewBuilder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, TRANSLATE_OUT_INTERPOLATOR);
nonOverviewBuilder.setInterpolator(ANIM_VERTICAL_PROGRESS, TRANSLATE_OUT_INTERPOLATOR);
updateNonOverviewAnim(QUICK_SWITCH, nonOverviewBuilder, ANIM_ALL_COMPONENTS);
updateNonOverviewAnim(QUICK_SWITCH, nonOverviewBuilder);
mNonOverviewAnim.dispatchOnStart();
if (mRecentsView.getTaskViewCount() == 0) {
@@ -230,11 +226,12 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
}
/** Create state animation to control non-overview components. */
private void updateNonOverviewAnim(LauncherState toState, AnimatorSetBuilder builder,
@AnimationFlags int animComponents) {
long accuracy = (long) (Math.max(mXRange, mYRange) * 2);
mNonOverviewAnim = mLauncher.getStateManager().createAnimationToNewWorkspace(toState,
builder, accuracy, this::clearState, animComponents | SKIP_OVERVIEW);
private void updateNonOverviewAnim(LauncherState toState, StateAnimationConfig config) {
config.duration = (long) (Math.max(mXRange, mYRange) * 2);
config.animFlags = config.animFlags | SKIP_OVERVIEW;
mNonOverviewAnim = mLauncher.getStateManager()
.createAnimationToNewWorkspace(toState, config)
.setOnCancelRunnable(this::clearState);
}
private void setupOverviewAnimators() {
@@ -419,8 +416,10 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
if (flingUpToNormal && !mIsHomeScreenVisible) {
// We are flinging to home while workspace is invisible, run the same staggered
// animation as from an app.
StateAnimationConfig config = new StateAnimationConfig();
// Update mNonOverviewAnim to do nothing so it doesn't interfere.
updateNonOverviewAnim(targetState, new AnimatorSetBuilder(), 0 /* animComponents */);
config.animFlags = 0;
updateNonOverviewAnim(targetState, config);
nonOverviewAnim = mNonOverviewAnim.getAnimationPlayer();
new StaggeredWorkspaceAnim(mLauncher, velocity.y, false /* animateOverviewScrim */)
@@ -17,18 +17,17 @@ package com.android.launcher3.uioverrides.touchcontrollers;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.QUICK_SWITCH;
import static com.android.launcher3.LauncherStateManager.ANIM_ALL_COMPONENTS;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
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.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -41,7 +40,7 @@ import androidx.annotation.Nullable;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -108,30 +107,30 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll
@Override
protected float initCurrentAnimation(int animComponents) {
AnimatorSetBuilder animatorSetBuilder = new AnimatorSetBuilder();
setupInterpolators(animatorSetBuilder);
long accuracy = (long) (getShiftRange() * 2);
mCurrentAnimation = mLauncher.getStateManager().createAnimationToNewWorkspace(mToState,
animatorSetBuilder, accuracy, this::clearState, ANIM_ALL_COMPONENTS);
mCurrentAnimation.getAnimationPlayer().addUpdateListener(valueAnimator -> {
updateFullscreenProgress((Float) valueAnimator.getAnimatedValue());
});
StateAnimationConfig config = new StateAnimationConfig();
setupInterpolators(config);
config.duration = (long) (getShiftRange() * 2);
mCurrentAnimation = mLauncher.getStateManager()
.createAnimationToNewWorkspace(mToState, config)
.setOnCancelRunnable(this::clearState);
mCurrentAnimation.getAnimationPlayer().addUpdateListener(valueAnimator ->
updateFullscreenProgress((Float) valueAnimator.getAnimatedValue()));
return 1 / getShiftRange();
}
private void setupInterpolators(AnimatorSetBuilder animatorSetBuilder) {
animatorSetBuilder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_2);
animatorSetBuilder.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_2);
private void setupInterpolators(StateAnimationConfig stateAnimationConfig) {
stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_2);
stateAnimationConfig.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_2);
if (SysUINavigationMode.getMode(mLauncher) == Mode.NO_BUTTON) {
// Overview lives to the left of workspace, so translate down later than over
animatorSetBuilder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL_2);
animatorSetBuilder.setInterpolator(ANIM_VERTICAL_PROGRESS, ACCEL_2);
animatorSetBuilder.setInterpolator(ANIM_OVERVIEW_SCALE, ACCEL_2);
animatorSetBuilder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, ACCEL_2);
animatorSetBuilder.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL_2);
stateAnimationConfig.setInterpolator(ANIM_VERTICAL_PROGRESS, ACCEL_2);
stateAnimationConfig.setInterpolator(ANIM_OVERVIEW_SCALE, ACCEL_2);
stateAnimationConfig.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, ACCEL_2);
stateAnimationConfig.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
} else {
animatorSetBuilder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, LINEAR);
animatorSetBuilder.setInterpolator(ANIM_VERTICAL_PROGRESS, LINEAR);
stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_TRANSLATE, LINEAR);
stateAnimationConfig.setInterpolator(ANIM_VERTICAL_PROGRESS, LINEAR);
}
}
@@ -214,7 +214,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
if (mCurrentAnimation != null) {
mCurrentAnimation.setOnCancelRunnable(null);
}
mCurrentAnimation = AnimatorPlaybackController.wrap(mPendingAnimation, maxDuration)
mCurrentAnimation = mPendingAnimation.createPlaybackController()
.setOnCancelRunnable(this::clearState);
onUserControlledAnimationCreated(mCurrentAnimation);
mCurrentAnimation.getTarget().addListener(this);
@@ -48,7 +48,7 @@ import com.android.systemui.shared.system.TransactionCompat;
*
* @param <T> activity that contains the overview
*/
final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> implements
final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> extends
RemoteAnimationProvider {
private static final long RECENTS_LAUNCH_DURATION = 250;
@@ -213,7 +213,7 @@ public final class FallbackActivityInterface implements
@Override
public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTargetCompat target) {
// TODO: Remove this once b/77875376 is fixed
return target.sourceContainerBounds;
return target.screenSpaceBounds;
}
@Override
@@ -33,6 +33,7 @@ import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -187,7 +188,15 @@ public class OverviewCommandHelper {
// Otherwise, start overview.
mListener = mActivityInterface.createActivityInitListener(this::onActivityReady);
mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(),
this::createWindowAnimation, mContext, MAIN_EXECUTOR.getHandler(),
new RemoteAnimationProvider() {
@Override
public AnimatorSet createWindowAnimation(
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets) {
return RecentsActivityCommand.this.createWindowAnimation(appTargets,
wallpaperTargets);
}
}, mContext, MAIN_EXECUTOR.getHandler(),
mAnimationProvider.getRecentsLaunchDuration());
}
@@ -50,6 +50,7 @@ import com.android.systemui.shared.system.WindowManagerWrapper;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
@@ -119,7 +120,7 @@ public class AppWindowAnimationHelper {
private void updateSourceStack(RemoteAnimationTargetCompat target) {
mSourceInsets.set(target.contentInsets);
mSourceStackBounds.set(target.sourceContainerBounds);
mSourceStackBounds.set(target.screenSpaceBounds);
// TODO: Should sourceContainerBounds already have this offset?
mSourceStackBounds.offsetTo(target.position.x, target.position.y);
@@ -199,9 +200,17 @@ public class AppWindowAnimationHelper {
for (int i = 0; i < params.mTargetSet.unfilteredApps.length; i++) {
RemoteAnimationTargetCompat app = params.mTargetSet.unfilteredApps[i];
SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
mTmpMatrix.setTranslate(app.position.x, app.position.y);
if (app.localBounds != null) {
mTmpMatrix.setTranslate(0, 0);
if (app.activityType == ACTIVITY_TYPE_HOME && app.mode == MODE_CLOSING) {
mTmpMatrix.setTranslate(app.localBounds.left, app.localBounds.top);
}
} else {
mTmpMatrix.setTranslate(app.position.x, app.position.y);
}
Rect crop = mTmpRect;
crop.set(app.sourceContainerBounds);
crop.set(app.screenSpaceBounds);
crop.offsetTo(0, 0);
float alpha;
float cornerRadius = 0f;
@@ -211,7 +220,11 @@ public class AppWindowAnimationHelper {
alpha = mTaskAlphaCallback.getAlpha(app, params.mTargetAlpha);
if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
mTmpMatrix.setRectToRect(mSourceRect, mCurrentRect, ScaleToFit.FILL);
mTmpMatrix.postTranslate(app.position.x, app.position.y);
if (app.localBounds != null) {
mTmpMatrix.postTranslate(app.localBounds.left, app.localBounds.top);
} else {
mTmpMatrix.postTranslate(app.position.x, app.position.y);
}
mCurrentClipRectF.roundOut(crop);
if (mSupportsRoundedCornersOnWindows) {
if (params.mCornerRadius > -1) {
@@ -18,9 +18,10 @@ package com.android.quickstep.util;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherStateManager.ANIM_ALL_COMPONENTS;
import static com.android.launcher3.LauncherStateManager.SKIP_OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -33,14 +34,13 @@ import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Workspace;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.graphics.OverviewScrim;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.DynamicResource;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.plugins.ResourceProvider;
@@ -143,11 +143,11 @@ public class StaggeredWorkspaceAnim {
* Setup workspace with 0 duration to prepare for our staggered animation.
*/
private void prepareToAnimate(Launcher launcher) {
AnimatorSetBuilder builder = new AnimatorSetBuilder();
StateAnimationConfig config = new StateAnimationConfig();
config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW;
config.duration = 0;
// setRecentsAttachedToAppWindow() will animate recents out.
launcher.getStateManager().createAtomicAnimation(
BACKGROUND_APP, NORMAL, builder, ANIM_ALL_COMPONENTS | SKIP_OVERVIEW, 0);
builder.build().start();
launcher.getStateManager().createAtomicAnimation(BACKGROUND_APP, NORMAL, config).start();
// Stop scrolling so that it doesn't interfere with the translation offscreen.
launcher.<RecentsView>getOverviewPanel().getScroller().forceFinished(true);
@@ -197,16 +197,12 @@ public class StaggeredWorkspaceAnim {
}
private void addScrimAnimationForState(Launcher launcher, LauncherState state, long duration) {
AnimatorSetBuilder scrimAnimBuilder = new AnimatorSetBuilder();
AnimationConfig scrimAnimConfig = new AnimationConfig();
scrimAnimConfig.duration = duration;
PropertySetter scrimPropertySetter = scrimAnimConfig.getPropertySetter(scrimAnimBuilder);
launcher.getWorkspace().getStateTransitionAnimation().setScrim(scrimPropertySetter, state);
mAnimators.play(scrimAnimBuilder.build());
Animator fadeOverviewScrim = ObjectAnimator.ofFloat(
launcher.getDragLayer().getOverviewScrim(), OverviewScrim.SCRIM_PROGRESS,
state.getOverviewScrimAlpha(launcher));
fadeOverviewScrim.setDuration(duration);
mAnimators.play(fadeOverviewScrim);
PendingAnimation builder = new PendingAnimation(duration, mAnimators);
launcher.getWorkspace().getStateTransitionAnimation().setScrim(builder, state);
builder.setFloat(
launcher.getDragLayer().getOverviewScrim(),
OverviewScrim.SCRIM_PROGRESS,
state.getOverviewScrimAlpha(launcher),
ACCEL_DEACCEL);
}
}
@@ -1195,7 +1195,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
if (mPendingAnimation != null) {
mPendingAnimation.finish(false, Touch.SWIPE);
}
PendingAnimation anim = new PendingAnimation();
PendingAnimation anim = new PendingAnimation(duration);
int count = getPageCount();
if (count == 0) {
@@ -1311,7 +1311,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
if (FeatureFlags.IS_STUDIO_BUILD && mPendingAnimation != null) {
throw new IllegalStateException("Another pending animation is still running");
}
PendingAnimation anim = new PendingAnimation();
PendingAnimation anim = new PendingAnimation(duration);
int count = getTaskViewCount();
for (int i = 0; i < count; i++) {
@@ -1345,8 +1345,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
}
private void runDismissAnimation(PendingAnimation pendingAnim) {
AnimatorPlaybackController controller =
AnimatorPlaybackController.wrap(pendingAnim, DISMISS_TASK_DURATION);
AnimatorPlaybackController controller = pendingAnim.createPlaybackController();
controller.dispatchOnStart();
controller.setEndAction(() -> pendingAnim.finish(true, Touch.SWIPE));
controller.getAnimationPlayer().setInterpolator(FAST_OUT_SLOW_IN);
@@ -1671,7 +1670,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
int count = getTaskViewCount();
if (count == 0) {
return new PendingAnimation();
return new PendingAnimation(duration);
}
int targetSysUiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
@@ -1710,10 +1709,9 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
anim.play(backgroundBlur);
}
anim.play(progressAnim);
anim.setDuration(duration)
.setInterpolator(interpolator);
anim.setDuration(duration).setInterpolator(interpolator);
mPendingAnimation = new PendingAnimation();
mPendingAnimation = new PendingAnimation(duration);
mPendingAnimation.add(anim);
mPendingAnimation.addEndListener((endState) -> {
if (endState.isSuccess) {
@@ -285,8 +285,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
public AnimatorPlaybackController createLaunchAnimationForRunningTask() {
final PendingAnimation pendingAnimation = getRecentsView().createTaskLaunchAnimation(
this, RECENTS_LAUNCH_DURATION, TOUCH_RESPONSE_INTERPOLATOR);
AnimatorPlaybackController currentAnimation =
AnimatorPlaybackController.wrap(pendingAnimation, RECENTS_LAUNCH_DURATION);
AnimatorPlaybackController currentAnimation = pendingAnimation.createPlaybackController();
currentAnimation.setEndAction(() -> {
pendingAnimation.finish(true, Touch.SWIPE);
launchTask(false);
@@ -52,10 +52,12 @@ import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.util.RemoteFadeOutAnimationListener;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.util.stream.Stream;
@@ -262,17 +264,21 @@ public abstract class BaseQuickstepLauncher extends Launcher
public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) {
QuickstepAppTransitionManagerImpl appTransitionManager =
(QuickstepAppTransitionManagerImpl) getAppTransitionManager();
appTransitionManager.setRemoteAnimationProvider((appTargets, wallpaperTargets) -> {
appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() {
@Override
public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets) {
// On the first call clear the reference.
signal.cancel();
// On the first call clear the reference.
signal.cancel();
ValueAnimator fadeAnimation = ValueAnimator.ofFloat(1, 0);
fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(appTargets,
wallpaperTargets));
AnimatorSet anim = new AnimatorSet();
anim.play(fadeAnimation);
return anim;
ValueAnimator fadeAnimation = ValueAnimator.ofFloat(1, 0);
fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(appTargets,
wallpaperTargets));
AnimatorSet anim = new AnimatorSet();
anim.play(fadeAnimation);
return anim;
}
}, signal);
}
@@ -34,7 +34,8 @@ import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@TargetApi(Build.VERSION_CODES.P)
public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {
public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat,
WrappedAnimationRunnerImpl {
private final Handler mHandler;
private final boolean mStartAtFrontOfQueue;
@@ -49,6 +50,10 @@ public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCo
mStartAtFrontOfQueue = startAtFrontOfQueue;
}
public Handler getHandler() {
return mHandler;
}
// Called only in R+ platform
@BinderThread
public void onAnimationStart(RemoteAnimationTargetCompat[] appTargets,
@@ -15,6 +15,7 @@
*/
package com.android.launcher3;
import android.animation.AnimatorSet;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
@@ -25,6 +26,7 @@ import android.os.Handler;
import com.android.launcher3.util.ActivityTracker;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.util.function.BiPredicate;
@@ -51,17 +53,21 @@ public class LauncherInitListener extends ActivityInitListener<Launcher> {
// Set a one-time animation provider. After the first call, this will get cleared.
// TODO: Probably also check the intended target id.
CancellationSignal cancellationSignal = new CancellationSignal();
appTransitionManager.setRemoteAnimationProvider((appTargets, wallpaperTargets) -> {
appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() {
@Override
public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets) {
// On the first call clear the reference.
cancellationSignal.cancel();
RemoteAnimationProvider provider = mRemoteAnimationProvider;
mRemoteAnimationProvider = null;
// On the first call clear the reference.
cancellationSignal.cancel();
RemoteAnimationProvider provider = mRemoteAnimationProvider;
mRemoteAnimationProvider = null;
if (provider != null && launcher.getStateManager().getState().overviewUi) {
return provider.createWindowAnimation(appTargets, wallpaperTargets);
if (provider != null && launcher.getStateManager().getState().overviewUi) {
return provider.createWindowAnimation(appTargets, wallpaperTargets);
}
return null;
}
return null;
}, cancellationSignal);
}
launcher.deferOverlayCallbacksUntilNextResumeOrStop();
@@ -49,6 +49,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
@@ -86,8 +87,6 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.WindowManagerWrapper;
import java.lang.ref.WeakReference;
/**
* {@link LauncherAppTransitionManager} with Quickstep-specific app transitions for launching from
* home and/or all-apps. Not used for 3p launchers.
@@ -299,8 +298,12 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
if (mLauncher.isInMultiWindowMode()) {
for (RemoteAnimationTargetCompat target : appTargets) {
if (target.mode == MODE_OPENING) {
bounds.set(target.sourceContainerBounds);
bounds.offsetTo(target.position.x, target.position.y);
bounds.set(target.screenSpaceBounds);
if (target.localBounds != null) {
bounds.set(target.localBounds);
} else {
bounds.offsetTo(target.position.x, target.position.y);
}
return bounds;
}
}
@@ -460,6 +463,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
RectF targetBounds = new RectF(windowTargetBounds);
RectF currentBounds = new RectF();
RectF temp = new RectF();
Point tmpPos = new Point();
AnimatorSet animatorSet = new AnimatorSet();
ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
@@ -547,6 +551,13 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
for (int i = appTargets.length - 1; i >= 0; i--) {
RemoteAnimationTargetCompat target = appTargets[i];
SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash);
tmpPos.set(target.position.x, target.position.y);
if (target.localBounds != null) {
final Rect localBounds = target.localBounds;
tmpPos.set(target.localBounds.left, target.localBounds.top);
}
if (target.mode == MODE_OPENING) {
matrix.setScale(scale, scale);
matrix.postTranslate(transX0, transY0);
@@ -563,9 +574,9 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
.withAlpha(1f - mIconAlpha.value)
.withCornerRadius(mWindowRadius.value);
} else {
matrix.setTranslate(target.position.x, target.position.y);
matrix.setTranslate(tmpPos.x, tmpPos.y);
builder.withMatrix(matrix)
.withWindowCrop(target.sourceContainerBounds)
.withWindowCrop(target.screenSpaceBounds)
.withAlpha(1f);
}
builder.withLayer(RemoteAnimationProvider.getLayer(target, MODE_OPENING));
@@ -662,7 +673,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
RemoteAnimationTargetCompat target = appTargets[i];
params[i] = new SurfaceParams.Builder(target.leash)
.withAlpha(1f)
.withWindowCrop(target.sourceContainerBounds)
.withWindowCrop(target.screenSpaceBounds)
.withLayer(RemoteAnimationProvider.getLayer(target, MODE_OPENING))
.withCornerRadius(cornerRadius)
.build();
@@ -681,6 +692,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
SyncRtSurfaceTransactionApplierCompat surfaceApplier =
new SyncRtSurfaceTransactionApplierCompat(mDragLayer);
Matrix matrix = new Matrix();
Point tmpPos = new Point();
ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
int duration = CLOSING_TRANSITION_DURATION_MS;
float windowCornerRadius = mDeviceProfile.isMultiWindowMode
@@ -697,22 +709,28 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
for (int i = appTargets.length - 1; i >= 0; i--) {
RemoteAnimationTargetCompat target = appTargets[i];
SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash);
tmpPos.set(target.position.x, target.position.y);
if (target.localBounds != null) {
tmpPos.set(target.localBounds.left, target.localBounds.top);
}
if (target.mode == MODE_CLOSING) {
matrix.setScale(mScale.value, mScale.value,
target.sourceContainerBounds.centerX(),
target.sourceContainerBounds.centerY());
target.screenSpaceBounds.centerX(),
target.screenSpaceBounds.centerY());
matrix.postTranslate(0, mDy.value);
matrix.postTranslate(target.position.x, target.position.y);
matrix.postTranslate(tmpPos.x, tmpPos.y);
builder.withMatrix(matrix)
.withAlpha(mAlpha.value)
.withCornerRadius(windowCornerRadius);
} else {
matrix.setTranslate(target.position.x, target.position.y);
matrix.setTranslate(tmpPos.x, tmpPos.y);
builder.withMatrix(matrix)
.withAlpha(1f);
}
params[i] = builder
.withWindowCrop(target.sourceContainerBounds)
.withWindowCrop(target.screenSpaceBounds)
.withLayer(RemoteAnimationProvider.getLayer(target, MODE_CLOSING))
.build();
}
@@ -784,52 +802,6 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
== PackageManager.PERMISSION_GRANTED;
}
/**
* Used with WrappedLauncherAnimationRunner as an interface for the runner to call back to the
* implementation.
*/
protected interface WrappedAnimationRunnerImpl {
Handler getHandler();
void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
LauncherAnimationRunner.AnimationResult result);
}
/**
* This class is needed to wrap any animation runner that is a part of the
* RemoteAnimationDefinition:
* - Launcher creates a new instance of the LauncherAppTransitionManagerImpl whenever it is
* created, which in turn registers a new definition
* - When the definition is registered, window manager retains a strong binder reference to the
* runner passed in
* - If the Launcher activity is recreated, the new definition registered will replace the old
* reference in the system's activity record, but until the system server is GC'd, the binder
* reference will still exist, which references the runner in the Launcher process, which
* references the (old) Launcher activity through this class
*
* Instead we make the runner provided to the definition static only holding a weak reference to
* the runner implementation. When this animation manager is destroyed, we remove the Launcher
* reference to the runner, leaving only the weak ref from the runner.
*/
protected static class WrappedLauncherAnimationRunner<R extends WrappedAnimationRunnerImpl>
extends LauncherAnimationRunner {
private WeakReference<R> mImpl;
public WrappedLauncherAnimationRunner(R animationRunnerImpl, boolean startAtFrontOfQueue) {
super(animationRunnerImpl.getHandler(), startAtFrontOfQueue);
mImpl = new WeakReference<>(animationRunnerImpl);
}
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) {
R animationRunnerImpl = mImpl.get();
if (animationRunnerImpl != null) {
animationRunnerImpl.onCreateAnimation(appTargets, wallpaperTargets, result);
}
}
}
/**
* Remote animation runner for animation from the app to Launcher, including recents.
*/
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3;
import android.os.Handler;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
/**
* Used with WrappedLauncherAnimationRunner as an interface for the runner to call back to the
* implementation.
*/
public interface WrappedAnimationRunnerImpl {
Handler getHandler();
void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
LauncherAnimationRunner.AnimationResult result);
}
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.lang.ref.WeakReference;
/**
* This class is needed to wrap any animation runner that is a part of the
* RemoteAnimationDefinition:
* - Launcher creates a new instance of the LauncherAppTransitionManagerImpl whenever it is
* created, which in turn registers a new definition
* - When the definition is registered, window manager retains a strong binder reference to the
* runner passed in
* - If the Launcher activity is recreated, the new definition registered will replace the old
* reference in the system's activity record, but until the system server is GC'd, the binder
* reference will still exist, which references the runner in the Launcher process, which
* references the (old) Launcher activity through this class
*
* Instead we make the runner provided to the definition static only holding a weak reference to
* the runner implementation. When this animation manager is destroyed, we remove the Launcher
* reference to the runner, leaving only the weak ref from the runner.
*/
public class WrappedLauncherAnimationRunner<R extends WrappedAnimationRunnerImpl>
extends LauncherAnimationRunner {
private WeakReference<R> mImpl;
public WrappedLauncherAnimationRunner(R animationRunnerImpl, boolean startAtFrontOfQueue) {
super(animationRunnerImpl.getHandler(), startAtFrontOfQueue);
mImpl = new WeakReference<>(animationRunnerImpl);
}
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) {
R animationRunnerImpl = mImpl.get();
if (animationRunnerImpl != null) {
animationRunnerImpl.onCreateAnimation(appTargets, wallpaperTargets, result);
}
}
}
@@ -16,19 +16,23 @@
package com.android.launcher3.uioverrides;
import android.animation.ValueAnimator;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.AnimatedFloat.VALUE;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.UiThreadHelper;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SystemUiProxy;
public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler {
private final BaseQuickstepLauncher mLauncher;
private final AnimatedFloat mBackAlpha = new AnimatedFloat(this::updateBackAlpha);
public BackButtonAlphaHandler(BaseQuickstepLauncher launcher) {
mLauncher = launcher;
@@ -38,8 +42,8 @@ public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler
public void setState(LauncherState state) { }
@Override
public void setStateWithAnimation(LauncherState toState,
AnimatorSetBuilder builder, LauncherStateManager.AnimationConfig config) {
public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
PendingAnimation animation) {
if (config.onlyPlayAtomicComponent()) {
return;
}
@@ -51,17 +55,12 @@ public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler
return;
}
float fromAlpha = SystemUiProxy.INSTANCE.get(mLauncher).getLastBackButtonAlpha();
float toAlpha = toState.hideBackButton ? 0 : 1;
if (Float.compare(fromAlpha, toAlpha) != 0) {
ValueAnimator anim = ValueAnimator.ofFloat(fromAlpha, toAlpha);
anim.setDuration(config.duration);
anim.addUpdateListener(valueAnimator -> {
final float alpha = (float) valueAnimator.getAnimatedValue();
UiThreadHelper.setBackButtonAlphaAsync(mLauncher,
BaseQuickstepLauncher.SET_BACK_BUTTON_ALPHA, alpha, false /* animate */);
});
builder.play(anim);
}
mBackAlpha.value = SystemUiProxy.INSTANCE.get(mLauncher).getLastBackButtonAlpha();
animation.setFloat(mBackAlpha, VALUE, toState.hideBackButton ? 0 : 1, LINEAR);
}
private void updateBackAlpha() {
UiThreadHelper.setBackButtonAlphaAsync(mLauncher,
BaseQuickstepLauncher.SET_BACK_BUTTON_ALPHA, mBackAlpha.value, false /* animate */);
}
}
@@ -26,8 +26,8 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SurfaceControlCompat;
import com.android.systemui.shared.system.TransactionCompat;
@@ -133,16 +133,15 @@ public class BackgroundBlurController implements LauncherStateManager.StateHandl
}
@Override
public void setStateWithAnimation(LauncherState toState, AnimatorSetBuilder builder,
LauncherStateManager.AnimationConfig config) {
public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
PendingAnimation animation) {
if (mSurface == null || config.onlyPlayAtomicComponent()) {
return;
}
int toBackgroundBlurRadius = toState.getBackgroundBlurRadius(mLauncher);
if (mBackgroundBlurRadius != toBackgroundBlurRadius) {
PropertySetter propertySetter = config.getPropertySetter(builder);
propertySetter.setInt(this, BACKGROUND_BLUR, toBackgroundBlurRadius, LINEAR);
animation.setInt(this, BACKGROUND_BLUR, toBackgroundBlurRadius, LINEAR);
}
}
@@ -20,17 +20,17 @@ import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherStateManager.PLAY_ATOMIC_OVERVIEW_PEEK;
import static com.android.launcher3.LauncherStateManager.PLAY_ATOMIC_OVERVIEW_SCALE;
import static com.android.launcher3.LauncherStateManager.SKIP_OVERVIEW;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCRIM_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import android.util.FloatProperty;
import android.view.View;
@@ -41,11 +41,10 @@ import androidx.annotation.NonNull;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.graphics.OverviewScrim;
import com.android.launcher3.states.StateAnimationConfig;
/**
* State handler for recents view. Manages UI changes and animations for recents view based off the
@@ -86,8 +85,8 @@ public abstract class BaseRecentsViewStateController<T extends View>
}
@Override
public final void setStateWithAnimation(@NonNull final LauncherState toState,
@NonNull AnimatorSetBuilder builder, @NonNull AnimationConfig config) {
public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
PendingAnimation builder) {
if (!config.hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_PEEK | PLAY_ATOMIC_OVERVIEW_SCALE)) {
// The entire recents animation is played atomically.
return;
@@ -95,25 +94,24 @@ public abstract class BaseRecentsViewStateController<T extends View>
if (config.hasAnimationFlag(SKIP_OVERVIEW)) {
return;
}
setStateWithAnimationInternal(toState, builder, config);
setStateWithAnimationInternal(toState, config, builder);
}
/**
* Core logic for animating the recents view UI.
*
* @param toState state to animate to
* @param builder animator set builder
* @param config current animation config
* @param setter animator set builder
*/
void setStateWithAnimationInternal(@NonNull final LauncherState toState,
@NonNull AnimatorSetBuilder builder, @NonNull AnimationConfig config) {
PropertySetter setter = config.getPropertySetter(builder);
@NonNull StateAnimationConfig config, @NonNull PendingAnimation setter) {
ScaleAndTranslation scaleAndTranslation = toState.getOverviewScaleAndTranslation(mLauncher);
Interpolator scaleInterpolator = builder.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR);
Interpolator scaleInterpolator = config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR);
setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndTranslation.scale, scaleInterpolator);
Interpolator translateXInterpolator = builder.getInterpolator(
Interpolator translateXInterpolator = config.getInterpolator(
ANIM_OVERVIEW_TRANSLATE_X, LINEAR);
Interpolator translateYInterpolator = builder.getInterpolator(
Interpolator translateYInterpolator = config.getInterpolator(
ANIM_OVERVIEW_TRANSLATE_Y, LINEAR);
float translationX = scaleAndTranslation.translationX;
if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
@@ -123,14 +121,14 @@ public abstract class BaseRecentsViewStateController<T extends View>
setter.setFloat(mRecentsView, VIEW_TRANSLATE_Y, scaleAndTranslation.translationY,
translateYInterpolator);
setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
builder.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
setter.setFloat(scrim, SCRIM_PROGRESS, toState.getOverviewScrimAlpha(mLauncher),
builder.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
config.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
if (mActionsView != null) {
setter.setFloat(mActionsView, VIEW_TRANSLATE_X, translationX, translateXInterpolator);
setter.setFloat(mActionsView, VIEW_ALPHA, toState.overviewUi ? 1 : 0,
builder.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
}
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.uioverrides;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.content.Context;
import android.os.Bundle;
import android.util.Size;
import android.view.View;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.graphics.LauncherPreviewRenderer;
import com.android.systemui.shared.system.SurfaceViewRequestReceiver;
/** Render preview using surface view. */
public class PreviewSurfaceRenderer {
/** Handle a received surface view request. */
public static void render(Context context, Bundle bundle) {
final String gridName = bundle.getString("name");
bundle.remove("name");
final InvariantDeviceProfile idp = new InvariantDeviceProfile(context, gridName);
MAIN_EXECUTOR.execute(() -> {
View view = new LauncherPreviewRenderer(context, idp).getRenderedView();
new SurfaceViewRequestReceiver().onReceive(context, bundle, view,
new Size(view.getMeasuredWidth(), view.getMeasuredHeight()));
});
}
}
@@ -9,7 +9,7 @@ import android.view.MotionEvent;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationFlags;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -19,13 +19,13 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import android.animation.TimeInterpolator;
@@ -37,11 +37,10 @@ import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationFlags;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.uioverrides.states.OverviewState;
@@ -148,16 +147,16 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
return isTouchOverHotseat(mLauncher, ev) ? ContainerType.HOTSEAT : ContainerType.WORKSPACE;
}
private AnimatorSetBuilder getNormalToOverviewAnimation() {
private StateAnimationConfig getNormalToOverviewAnimation() {
mAllAppsInterpolatorWrapper.baseInterpolator = LINEAR;
AnimatorSetBuilder builder = new AnimatorSetBuilder();
StateAnimationConfig builder = new StateAnimationConfig();
builder.setInterpolator(ANIM_VERTICAL_PROGRESS, mAllAppsInterpolatorWrapper);
return builder;
}
public static AnimatorSetBuilder getOverviewToAllAppsAnimation() {
AnimatorSetBuilder builder = new AnimatorSetBuilder();
private static StateAnimationConfig getOverviewToAllAppsAnimation() {
StateAnimationConfig builder = new StateAnimationConfig();
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL,
0, ALL_APPS_CONTENT_FADE_THRESHOLD));
builder.setInterpolator(ANIM_OVERVIEW_FADE, Interpolators.clampToProgress(DEACCEL,
@@ -165,8 +164,8 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
return builder;
}
private AnimatorSetBuilder getAllAppsToOverviewAnimation() {
AnimatorSetBuilder builder = new AnimatorSetBuilder();
private StateAnimationConfig getAllAppsToOverviewAnimation() {
StateAnimationConfig builder = new StateAnimationConfig();
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL,
1 - ALL_APPS_CONTENT_FADE_THRESHOLD, 1));
builder.setInterpolator(ANIM_OVERVIEW_FADE, Interpolators.clampToProgress(ACCEL,
@@ -174,41 +173,42 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
return builder;
}
private AnimatorSetBuilder getNormalToAllAppsAnimation() {
AnimatorSetBuilder builder = new AnimatorSetBuilder();
private StateAnimationConfig getNormalToAllAppsAnimation() {
StateAnimationConfig builder = new StateAnimationConfig();
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL,
0, ALL_APPS_CONTENT_FADE_THRESHOLD));
return builder;
}
private AnimatorSetBuilder getAllAppsToNormalAnimation() {
AnimatorSetBuilder builder = new AnimatorSetBuilder();
private StateAnimationConfig getAllAppsToNormalAnimation() {
StateAnimationConfig builder = new StateAnimationConfig();
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL,
1 - ALL_APPS_CONTENT_FADE_THRESHOLD, 1));
return builder;
}
@Override
protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState,
LauncherState toState) {
AnimatorSetBuilder builder = new AnimatorSetBuilder();
protected StateAnimationConfig getConfigForStates(
LauncherState fromState, LauncherState toState) {
final StateAnimationConfig config;
if (fromState == NORMAL && toState == OVERVIEW) {
builder = getNormalToOverviewAnimation();
config = getNormalToOverviewAnimation();
} else if (fromState == OVERVIEW && toState == ALL_APPS) {
builder = getOverviewToAllAppsAnimation();
config = getOverviewToAllAppsAnimation();
} else if (fromState == ALL_APPS && toState == OVERVIEW) {
builder = getAllAppsToOverviewAnimation();
config = getAllAppsToOverviewAnimation();
} else if (fromState == NORMAL && toState == ALL_APPS) {
builder = getNormalToAllAppsAnimation();
config = getNormalToAllAppsAnimation();
} else if (fromState == ALL_APPS && toState == NORMAL) {
builder = getAllAppsToNormalAnimation();
config = getAllAppsToNormalAnimation();
} else {
config = new StateAnimationConfig();
}
return builder;
return config;
}
@Override
protected float initCurrentAnimation(@AnimationFlags int animComponents) {
animComponents = updateAnimComponentsOnReinit(animComponents);
protected float initCurrentAnimation(@AnimationFlags int animFlags) {
float range = getShiftRange();
long maxAccuracy = (long) (2 * range);
@@ -217,8 +217,10 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
float totalShift = endVerticalShift - startVerticalShift;
final AnimatorSetBuilder builder = totalShift == 0 ? new AnimatorSetBuilder()
: getAnimatorSetBuilderForStates(mFromState, mToState);
final StateAnimationConfig config = totalShift == 0 ? new StateAnimationConfig()
: getConfigForStates(mFromState, mToState);
config.animFlags = updateAnimComponentsOnReinit(animFlags);
config.duration = maxAccuracy;
cancelPendingAnim();
@@ -232,15 +234,15 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
cancelPendingAnim();
clearState();
};
mCurrentAnimation = AnimatorPlaybackController.wrap(mPendingAnimation, maxAccuracy)
mCurrentAnimation = mPendingAnimation.createPlaybackController()
.setOnCancelRunnable(onCancelRunnable);
mLauncher.getStateManager().setCurrentUserControlledAnimation(mCurrentAnimation);
totalShift = LayoutUtils.getShelfTrackingDistance(mLauncher,
mLauncher.getDeviceProfile());
} else {
mCurrentAnimation = mLauncher.getStateManager()
.createAnimationToNewWorkspace(mToState, builder, maxAccuracy, this::clearState,
animComponents);
.createAnimationToNewWorkspace(mToState, config)
.setOnCancelRunnable(this::clearState);
}
if (totalShift == 0) {
@@ -21,21 +21,22 @@ import android.content.Context;
import android.os.Handler;
import com.android.launcher3.LauncherAnimationRunner;
import com.android.launcher3.WrappedLauncherAnimationRunner;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.TransactionCompat;
@FunctionalInterface
public interface RemoteAnimationProvider {
public abstract class RemoteAnimationProvider {
LauncherAnimationRunner mAnimationRunner;
static final int Z_BOOST_BASE = 800570000;
AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
public abstract AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets);
default ActivityOptions toActivityOptions(Handler handler, long duration, Context context) {
LauncherAnimationRunner runner = new LauncherAnimationRunner(handler,
ActivityOptions toActivityOptions(Handler handler, long duration, Context context) {
mAnimationRunner = new LauncherAnimationRunner(handler,
false /* startAtFrontOfQueue */) {
@Override
@@ -44,8 +45,11 @@ public interface RemoteAnimationProvider {
result.setAnimation(createWindowAnimation(appTargets, wallpaperTargets), context);
}
};
final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner(
mAnimationRunner, false /* startAtFrontOfQueue */);
return ActivityOptionsCompat.makeRemoteAnimation(
new RemoteAnimationAdapterCompat(runner, duration, 0));
new RemoteAnimationAdapterCompat(wrapper, duration, 0));
}
/**
@@ -63,7 +67,7 @@ public interface RemoteAnimationProvider {
}
}
static int getLayer(RemoteAnimationTargetCompat target, int boostModeTarget) {
public static int getLayer(RemoteAnimationTargetCompat target, int boostModeTarget) {
return target.mode == boostModeTarget
? Z_BOOST_BASE + target.prefixOrderIndex
: target.prefixOrderIndex;
@@ -72,7 +76,7 @@ public interface RemoteAnimationProvider {
/**
* @return the target with the lowest opaque layer for a certain app animation, or null.
*/
static RemoteAnimationTargetCompat findLowestOpaqueLayerTarget(
public static RemoteAnimationTargetCompat findLowestOpaqueLayerTarget(
RemoteAnimationTargetCompat[] appTargets, int mode) {
int lowestLayer = Integer.MAX_VALUE;
int lowestLayerIndex = -1;
+1 -1
View File
@@ -208,7 +208,7 @@
<string name="notification_dots_service_title">Show notification dots</string>
<!-- Label for the setting that allows the automatic placement of launcher shortcuts for applications and games installed on the device [CHAR LIMIT=40] -->
<string name="auto_add_shortcuts_label">Add icon to Home screen</string>
<string name="auto_add_shortcuts_label">Add app icons to Home screen</string>
<!-- Text description of the setting that allows the automatic placement of launcher shortcuts for applications and games installed on the device [CHAR LIMIT=NONE] -->
<string name="auto_add_shortcuts_description">For new apps</string>
@@ -0,0 +1,155 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.model;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
import static com.android.launcher3.LauncherSettings.Favorites.TMP_CONTENT_URI;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import static com.android.launcher3.util.LauncherModelHelper.APP_ICON;
import static com.android.launcher3.util.LauncherModelHelper.DESKTOP;
import static com.android.launcher3.util.LauncherModelHelper.HOTSEAT;
import static com.android.launcher3.util.LauncherModelHelper.SHORTCUT;
import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Point;
import android.os.Process;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import java.util.HashSet;
/** Unit tests for {@link GridSizeMigrationTaskV2} */
@RunWith(LauncherRoboTestRunner.class)
public class GridSizeMigrationTaskV2Test {
private LauncherModelHelper mModelHelper;
private Context mContext;
private SQLiteDatabase mDb;
private HashSet<String> mValidPackages;
private InvariantDeviceProfile mIdp;
@Before
public void setUp() {
mModelHelper = new LauncherModelHelper();
mContext = RuntimeEnvironment.application;
mDb = mModelHelper.provider.getDb();
mValidPackages = new HashSet<>();
mValidPackages.add(TEST_PACKAGE);
mIdp = InvariantDeviceProfile.INSTANCE.get(mContext);
long userSerial = UserCache.INSTANCE.get(mContext).getSerialNumberForUser(
Process.myUserHandle());
dropTable(mDb, LauncherSettings.Favorites.TMP_TABLE);
LauncherSettings.Favorites.addTableToDb(mDb, userSerial, false,
LauncherSettings.Favorites.TMP_TABLE);
}
@Test
public void testMigration() {
final String testPackage1 = "com.android.launcher3.validpackage1";
final String testPackage2 = "com.android.launcher3.validpackage2";
final String testPackage3 = "com.android.launcher3.validpackage3";
final String testPackage4 = "com.android.launcher3.validpackage4";
final String testPackage5 = "com.android.launcher3.validpackage5";
final String testPackage7 = "com.android.launcher3.validpackage7";
mValidPackages.add(testPackage1);
mValidPackages.add(testPackage2);
mValidPackages.add(testPackage3);
mValidPackages.add(testPackage4);
mValidPackages.add(testPackage5);
mValidPackages.add(testPackage7);
int[] srcHotseatItems = {
mModelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI),
mModelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI),
-1,
mModelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI),
mModelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI),
};
mModelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage5, 5, TMP_CONTENT_URI);
int[] destHotseatItems = {
-1,
mModelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2),
-1,
};
mModelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage7);
mIdp.numHotseatIcons = 3;
mIdp.numColumns = 3;
mIdp.numRows = 3;
GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages, 5);
GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages, 3);
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
destReader, 3, new Point(mIdp.numColumns, mIdp.numRows));
task.migrate();
Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
new String[]{LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.INTENT},
"container=" + CONTAINER_HOTSEAT, null, null, null);
assertEquals(c.getCount(), 3);
int screenIndex = c.getColumnIndex(LauncherSettings.Favorites.SCREEN);
int intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT);
c.moveToNext();
assertEquals(c.getInt(screenIndex), 1);
assertTrue(c.getString(intentIndex).contains(testPackage2));
c.moveToNext();
assertEquals(c.getInt(screenIndex), 0);
assertTrue(c.getString(intentIndex).contains(testPackage1));
c.moveToNext();
assertEquals(c.getInt(screenIndex), 2);
assertTrue(c.getString(intentIndex).contains(testPackage3));
c.close();
c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
new String[]{LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
LauncherSettings.Favorites.INTENT},
"container=" + CONTAINER_DESKTOP, null, null, null);
assertEquals(c.getCount(), 2);
intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT);
int cellXIndex = c.getColumnIndex(LauncherSettings.Favorites.CELLX);
int cellYIndex = c.getColumnIndex(LauncherSettings.Favorites.CELLY);
c.moveToNext();
assertTrue(c.getString(intentIndex).contains(testPackage7));
c.moveToNext();
assertTrue(c.getString(intentIndex).contains(testPackage5));
assertEquals(c.getInt(cellXIndex), 0);
assertEquals(c.getInt(cellYIndex), 2);
}
}
@@ -230,7 +230,21 @@ public class LauncherModelHelper {
}
public int addItem(int type, int screen, int container, int x, int y) {
return addItem(type, screen, container, x, y, mDefaultProfileId);
return addItem(type, screen, container, x, y, mDefaultProfileId, TEST_PACKAGE);
}
public int addItem(int type, int screen, int container, int x, int y, long profileId) {
return addItem(type, screen, container, x, y, profileId, TEST_PACKAGE);
}
public int addItem(int type, int screen, int container, int x, int y, String packageName) {
return addItem(type, screen, container, x, y, mDefaultProfileId, packageName);
}
public int addItem(int type, int screen, int container, int x, int y, String packageName,
int id, Uri contentUri) {
addItem(type, screen, container, x, y, mDefaultProfileId, packageName, id, contentUri);
return id;
}
/**
@@ -238,11 +252,19 @@ public class LauncherModelHelper {
* @param type {@link #APP_ICON} or {@link #SHORTCUT} or >= 2 for
* folder (where the type represents the number of items in the folder).
*/
public int addItem(int type, int screen, int container, int x, int y, long profileId) {
public int addItem(int type, int screen, int container, int x, int y, long profileId,
String packageName) {
Context context = RuntimeEnvironment.application;
int id = LauncherSettings.Settings.call(context.getContentResolver(),
LauncherSettings.Settings.METHOD_NEW_ITEM_ID)
.getInt(LauncherSettings.Settings.EXTRA_VALUE);
addItem(type, screen, container, x, y, profileId, packageName, id, CONTENT_URI);
return id;
}
public void addItem(int type, int screen, int container, int x, int y, long profileId,
String packageName, int id, Uri contentUri) {
Context context = RuntimeEnvironment.application;
ContentValues values = new ContentValues();
values.put(LauncherSettings.Favorites._ID, id);
@@ -257,7 +279,7 @@ public class LauncherModelHelper {
if (type == APP_ICON || type == SHORTCUT) {
values.put(LauncherSettings.Favorites.ITEM_TYPE, type);
values.put(LauncherSettings.Favorites.INTENT,
new Intent(Intent.ACTION_MAIN).setPackage(TEST_PACKAGE).toUri(0));
new Intent(Intent.ACTION_MAIN).setPackage(packageName).toUri(0));
} else {
values.put(LauncherSettings.Favorites.ITEM_TYPE,
LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
@@ -267,8 +289,7 @@ public class LauncherModelHelper {
}
}
context.getContentResolver().insert(CONTENT_URI, values);
return id;
context.getContentResolver().insert(contentUri, values);
}
public int[][][] createGrid(int[][][] typeArray) {
@@ -22,7 +22,6 @@ import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CH
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import android.animation.Animator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
@@ -30,11 +29,12 @@ import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Interpolator;
import android.widget.LinearLayout;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TouchController;
@@ -134,9 +134,8 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
* Creates a user-controlled animation to hint that the view will be closed if completed.
* @param distanceToMove The max distance that elements should move from their starting point.
*/
public @Nullable Animator createHintCloseAnim(float distanceToMove) {
return null;
}
public void addHintCloseAnim(
float distanceToMove, Interpolator interpolator, PendingAnimation target) { }
public abstract void logActionCommand(int command);
@@ -17,6 +17,7 @@
package com.android.launcher3;
import static com.android.launcher3.config.FeatureFlags.MULTI_DB_GRID_MIRATION_ALGO;
import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -164,8 +165,11 @@ public class LauncherProvider extends ContentProvider {
return false;
}
mOpenHelper.close();
DatabaseHelper oldHelper = mOpenHelper;
mOpenHelper = new DatabaseHelper(getContext());
copyTable(oldHelper.getReadableDatabase(), Favorites.TABLE_NAME,
mOpenHelper.getWritableDatabase(), Favorites.TMP_TABLE, getContext());
oldHelper.close();
return true;
}
@@ -102,6 +102,11 @@ public class LauncherSettings {
*/
public static final String PREVIEW_TABLE_NAME = "favorites_preview";
/**
* Temporary table used specifically for multi-db grid migrations
*/
public static final String TMP_TABLE = "favorites_tmp";
/**
* The content:// style URL for "favorites" table
*/
@@ -114,6 +119,12 @@ public class LauncherSettings {
public static final Uri PREVIEW_CONTENT_URI = Uri.parse("content://"
+ LauncherProvider.AUTHORITY + "/" + PREVIEW_TABLE_NAME);
/**
* The content:// style URL for "favorites_tmp" table
*/
public static final Uri TMP_CONTENT_URI = Uri.parse("content://"
+ LauncherProvider.AUTHORITY + "/" + TMP_TABLE);
/**
* The content:// style URL for a given row, identified by its id.
*
+13 -13
View File
@@ -20,11 +20,6 @@ import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
import static android.view.View.VISIBLE;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
@@ -32,6 +27,11 @@ import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL;
@@ -46,9 +46,9 @@ import android.view.View;
import android.view.animation.Interpolator;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.states.HintState;
import com.android.launcher3.states.SpringLoadedState;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.states.AllAppsState;
import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -325,13 +325,13 @@ public abstract class LauncherState {
* - Setting some start values (e.g. scale) for views that are hidden but about to be shown.
*/
public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
AnimatorSetBuilder builder) {
StateAnimationConfig config) {
if (this == NORMAL && fromState == OVERVIEW) {
builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
builder.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
builder.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
builder.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
Workspace workspace = launcher.getWorkspace();
// Start from a higher workspace scale, but only if we're invisible so we don't jump.
@@ -363,7 +363,7 @@ public abstract class LauncherState {
}
} else if (this == NORMAL && fromState == OVERVIEW_PEEK) {
// Keep fully visible until the very end (when overview is offscreen) to make invisible.
builder.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1);
config.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1);
}
}
@@ -17,26 +17,23 @@
package com.android.launcher3;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.IntDef;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.anim.PropertySetter.AnimatedPropertySetter;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
/**
@@ -84,28 +81,7 @@ public class LauncherStateManager {
public static final String TAG = "StateManager";
// We separate the state animations into "atomic" and "non-atomic" components. The atomic
// components may be run atomically - that is, all at once, instead of user-controlled. However,
// atomic components are not restricted to this purpose; they can be user-controlled alongside
// non atomic components as well. Note that each gesture model has exactly one atomic component,
// PLAY_ATOMIC_OVERVIEW_SCALE *or* PLAY_ATOMIC_OVERVIEW_PEEK.
@IntDef(flag = true, value = {
PLAY_NON_ATOMIC,
PLAY_ATOMIC_OVERVIEW_SCALE,
PLAY_ATOMIC_OVERVIEW_PEEK,
SKIP_OVERVIEW,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AnimationFlags {}
public static final int PLAY_NON_ATOMIC = 1 << 0;
public static final int PLAY_ATOMIC_OVERVIEW_SCALE = 1 << 1;
public static final int PLAY_ATOMIC_OVERVIEW_PEEK = 1 << 2;
public static final int SKIP_OVERVIEW = 1 << 3;
public static final int ANIM_ALL_COMPONENTS = PLAY_NON_ATOMIC | PLAY_ATOMIC_OVERVIEW_SCALE
| PLAY_ATOMIC_OVERVIEW_PEEK;
private final AnimationConfig mConfig = new AnimationConfig();
private final AnimationState mConfig = new AnimationState();
private final Handler mUiHandler;
private final Launcher mLauncher;
private final ArrayList<StateListener> mListeners = new ArrayList<>();
@@ -140,7 +116,7 @@ public class LauncherStateManager {
writer.println(prefix + "\tmCurrentStableState:" + mCurrentStableState);
writer.println(prefix + "\tmState:" + mState);
writer.println(prefix + "\tmRestState:" + mRestState);
writer.println(prefix + "\tisInTransition:" + (mConfig.mCurrentAnimation != null));
writer.println(prefix + "\tisInTransition:" + (mConfig.currentAnimation != null));
}
public StateHandler[] getStateHandlers() {
@@ -171,7 +147,7 @@ public class LauncherStateManager {
*/
public boolean isInStableState(LauncherState state) {
return mState == state && mCurrentStableState == state
&& (mConfig.mTargetState == null || mConfig.mTargetState == state);
&& (mConfig.targetState == null || mConfig.targetState == state);
}
/**
@@ -218,12 +194,12 @@ public class LauncherStateManager {
}
public void reapplyState(boolean cancelCurrentAnimation) {
boolean wasInAnimation = mConfig.mCurrentAnimation != null;
boolean wasInAnimation = mConfig.currentAnimation != null;
if (cancelCurrentAnimation) {
cancelAllStateElementAnimation();
cancelAnimation();
}
if (mConfig.mCurrentAnimation == null) {
if (mConfig.currentAnimation == null) {
for (StateHandler handler : getStateHandlers()) {
handler.setState(mState);
}
@@ -237,16 +213,16 @@ public class LauncherStateManager {
final Runnable onCompleteRunnable) {
animated &= Utilities.areAnimationsEnabled(mLauncher);
if (mLauncher.isInState(state)) {
if (mConfig.mCurrentAnimation == null) {
if (mConfig.currentAnimation == null) {
// Run any queued runnable
if (onCompleteRunnable != null) {
onCompleteRunnable.run();
}
return;
} else if (!mConfig.userControlled && animated && mConfig.mTargetState == state) {
} else if (!mConfig.userControlled && animated && mConfig.targetState == state) {
// We are running the same animation as requested
if (onCompleteRunnable != null) {
mConfig.mCurrentAnimation.addListener(
mConfig.currentAnimation.addListener(
AnimationSuccessListener.forRunnable(onCompleteRunnable));
}
return;
@@ -276,9 +252,9 @@ public class LauncherStateManager {
if (delay > 0) {
// Create the animation after the delay as some properties can change between preparing
// the animation and running the animation.
int startChangeId = mConfig.mChangeId;
int startChangeId = mConfig.changeId;
mUiHandler.postDelayed(() -> {
if (mConfig.mChangeId == startChangeId) {
if (mConfig.changeId == startChangeId) {
goToStateAnimated(state, fromState, onCompleteRunnable);
}
}, delay);
@@ -294,11 +270,11 @@ public class LauncherStateManager {
mConfig.duration = state == NORMAL
? fromState.getTransitionDuration(mLauncher)
: state.getTransitionDuration(mLauncher);
AnimatorSetBuilder builder = new AnimatorSetBuilder();
prepareForAtomicAnimation(fromState, state, builder);
AnimatorSet animation = createAnimationToNewWorkspaceInternal(
state, builder, onCompleteRunnable);
prepareForAtomicAnimation(fromState, state, mConfig);
AnimatorSet animation = createAnimationToNewWorkspaceInternal(state).getAnim();
if (onCompleteRunnable != null) {
animation.addListener(AnimationSuccessListener.forRunnable(onCompleteRunnable));
}
mUiHandler.post(new StartAnimRunnable(animation));
}
@@ -308,44 +284,22 @@ public class LauncherStateManager {
* - Setting some start values (e.g. scale) for views that are hidden but about to be shown.
*/
public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
AnimatorSetBuilder builder) {
toState.prepareForAtomicAnimation(mLauncher, fromState, builder);
}
public AnimatorSet createAtomicAnimation(LauncherState fromState, LauncherState toState,
AnimatorSetBuilder builder, @AnimationFlags int animFlags, long duration) {
prepareForAtomicAnimation(fromState, toState, builder);
AnimationConfig config = new AnimationConfig();
config.mAnimFlags = animFlags;
config.duration = duration;
for (StateHandler handler : mLauncher.getStateManager().getStateHandlers()) {
handler.setStateWithAnimation(toState, builder, config);
}
return builder.build();
StateAnimationConfig config) {
toState.prepareForAtomicAnimation(mLauncher, fromState, config);
}
/**
* Creates a {@link AnimatorPlaybackController} that can be used for a controlled
* state transition. The UI is force-set to fromState before creating the controller.
* @param fromState the initial state for the transition.
* @param state the final state for the transition.
* @param duration intended duration for normal playback. Use higher duration for better
* accuracy.
* Creates an animation representing atomic transitions between the provided states
*/
public AnimatorPlaybackController createAnimationToNewWorkspace(
LauncherState fromState, LauncherState state, long duration) {
// Since we are creating a state animation to a different state, temporarily prevent state
// change as part of config reset.
LauncherState originalRestState = mRestState;
mRestState = state;
mConfig.reset();
mRestState = originalRestState;
public AnimatorSet createAtomicAnimation(
LauncherState fromState, LauncherState toState, StateAnimationConfig config) {
PendingAnimation builder = new PendingAnimation(config.duration);
prepareForAtomicAnimation(fromState, toState, config);
for (StateHandler handler : getStateHandlers()) {
handler.setState(fromState);
for (StateHandler handler : mLauncher.getStateManager().getStateHandlers()) {
handler.setStateWithAnimation(toState, config, builder);
}
return createAnimationToNewWorkspace(state, duration);
return builder.getAnim();
}
/**
@@ -362,32 +316,27 @@ public class LauncherStateManager {
public AnimatorPlaybackController createAnimationToNewWorkspace(
LauncherState state, long duration, @AnimationFlags int animComponents) {
return createAnimationToNewWorkspace(state, new AnimatorSetBuilder(), duration, null,
animComponents);
StateAnimationConfig config = new StateAnimationConfig();
config.duration = duration;
config.animFlags = animComponents;
return createAnimationToNewWorkspace(state, config);
}
public AnimatorPlaybackController createAnimationToNewWorkspace(LauncherState state,
AnimatorSetBuilder builder, long duration, Runnable onCancelRunnable,
@AnimationFlags int animComponents) {
StateAnimationConfig config) {
mConfig.reset();
mConfig.userControlled = true;
mConfig.mAnimFlags = animComponents;
mConfig.duration = duration;
mConfig.playbackController = AnimatorPlaybackController.wrap(
createAnimationToNewWorkspaceInternal(state, builder, null), duration)
.setOnCancelRunnable(onCancelRunnable);
config.copyTo(mConfig);
mConfig.playbackController = createAnimationToNewWorkspaceInternal(state)
.createPlaybackController();
return mConfig.playbackController;
}
protected AnimatorSet createAnimationToNewWorkspaceInternal(final LauncherState state,
AnimatorSetBuilder builder, final Runnable onCompleteRunnable) {
private PendingAnimation createAnimationToNewWorkspaceInternal(final LauncherState state) {
PendingAnimation builder = new PendingAnimation(mConfig.duration);
for (StateHandler handler : getStateHandlers()) {
handler.setStateWithAnimation(state, builder, mConfig);
handler.setStateWithAnimation(state, mConfig, builder);
}
final AnimatorSet animation = builder.build();
animation.addListener(new AnimationSuccessListener() {
builder.getAnim().addListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
@@ -397,15 +346,11 @@ public class LauncherStateManager {
@Override
public void onAnimationSuccess(Animator animator) {
// Run any queued runnables
if (onCompleteRunnable != null) {
onCompleteRunnable.run();
}
onStateTransitionEnd(state);
}
});
mConfig.setAnimation(animation, state);
return mConfig.mCurrentAnimation;
mConfig.setAnimation(builder.getAnim(), state);
return builder;
}
private void onStateTransitionStart(LauncherState state) {
@@ -452,7 +397,7 @@ public class LauncherStateManager {
}
public void moveToRestState() {
if (mConfig.mCurrentAnimation != null && mConfig.userControlled) {
if (mConfig.currentAnimation != null && mConfig.userControlled) {
// The user is doing something. Lets not mess it up
return;
}
@@ -500,12 +445,12 @@ public class LauncherStateManager {
&& mConfig.playbackController.getTarget() == childAnim) {
clearCurrentAnimation();
break;
} else if (mConfig.mCurrentAnimation == childAnim) {
} else if (mConfig.currentAnimation == childAnim) {
clearCurrentAnimation();
break;
}
}
boolean reapplyNeeded = mConfig.mCurrentAnimation != null;
boolean reapplyNeeded = mConfig.currentAnimation != null;
cancelAnimation();
if (reapplyNeeded) {
reapplyState();
@@ -557,9 +502,9 @@ public class LauncherStateManager {
}
private void clearCurrentAnimation() {
if (mConfig.mCurrentAnimation != null) {
mConfig.mCurrentAnimation.removeListener(mConfig);
mConfig.mCurrentAnimation = null;
if (mConfig.currentAnimation != null) {
mConfig.currentAnimation.removeListener(mConfig);
mConfig.currentAnimation = null;
}
mConfig.playbackController = null;
}
@@ -574,54 +519,42 @@ public class LauncherStateManager {
@Override
public void run() {
if (mConfig.mCurrentAnimation != mAnim) {
if (mConfig.currentAnimation != mAnim) {
return;
}
mAnim.start();
}
}
public static class AnimationConfig extends AnimatorListenerAdapter {
public long duration;
public boolean userControlled;
public AnimatorPlaybackController playbackController;
private @AnimationFlags int mAnimFlags = ANIM_ALL_COMPONENTS;
private PropertySetter mPropertySetter;
private static class AnimationState extends StateAnimationConfig implements AnimatorListener {
private static final StateAnimationConfig DEFAULT = new StateAnimationConfig();
public AnimatorPlaybackController playbackController;
public AnimatorSet currentAnimation;
public LauncherState targetState;
private AnimatorSet mCurrentAnimation;
private LauncherState mTargetState;
// Id to keep track of config changes, to tie an animation with the corresponding request
private int mChangeId = 0;
public int changeId = 0;
/**
* Cancels the current animation and resets config variables.
*/
public void reset() {
duration = 0;
userControlled = false;
mAnimFlags = ANIM_ALL_COMPONENTS;
mPropertySetter = null;
mTargetState = null;
DEFAULT.copyTo(this);
targetState = null;
if (playbackController != null) {
playbackController.getAnimationPlayer().cancel();
playbackController.dispatchOnCancel();
} else if (mCurrentAnimation != null) {
mCurrentAnimation.setDuration(0);
mCurrentAnimation.cancel();
} else if (currentAnimation != null) {
currentAnimation.setDuration(0);
currentAnimation.cancel();
}
mCurrentAnimation = null;
currentAnimation = null;
playbackController = null;
mChangeId ++;
}
public PropertySetter getPropertySetter(AnimatorSetBuilder builder) {
if (mPropertySetter == null) {
mPropertySetter = duration == 0 ? NO_ANIM_PROPERTY_SETTER
: new AnimatedPropertySetter(duration, builder);
}
return mPropertySetter;
changeId++;
}
@Override
@@ -629,51 +562,25 @@ public class LauncherStateManager {
if (playbackController != null && playbackController.getTarget() == animation) {
playbackController = null;
}
if (mCurrentAnimation == animation) {
mCurrentAnimation = null;
if (currentAnimation == animation) {
currentAnimation = null;
}
}
public void setAnimation(AnimatorSet animation, LauncherState targetState) {
mCurrentAnimation = animation;
mTargetState = targetState;
mCurrentAnimation.addListener(this);
currentAnimation = animation;
this.targetState = targetState;
currentAnimation.addListener(this);
}
/**
* @return Whether Overview is scaling as part of this animation. If this is the only
* component (i.e. NON_ATOMIC_COMPONENT isn't included), then this scaling is happening
* atomically, rather than being part of a normal state animation. StateHandlers can use
* this to designate part of their animation that should scale with Overview.
*/
public boolean playAtomicOverviewScaleComponent() {
return hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_SCALE);
}
@Override
public void onAnimationStart(Animator animator) { }
/**
* @return Whether this animation will play atomically at the same time as a different,
* user-controlled state transition. StateHandlers, which contribute to both animations, can
* use this to avoid animating the same properties in both animations, since they'd conflict
* with one another.
*/
public boolean onlyPlayAtomicComponent() {
return getAnimComponents() == PLAY_ATOMIC_OVERVIEW_SCALE
|| getAnimComponents() == PLAY_ATOMIC_OVERVIEW_PEEK;
}
@Override
public void onAnimationCancel(Animator animator) { }
/**
* Returns true if the config and any of the provided component flags
*/
public boolean hasAnimationFlag(@AnimationFlags int a) {
return (mAnimFlags & a) != 0;
}
/**
* @return Only the flags that determine which animation components to play.
*/
public @AnimationFlags int getAnimComponents() {
return mAnimFlags & ANIM_ALL_COMPONENTS;
}
@Override
public void onAnimationRepeat(Animator animator) { }
}
public interface StateHandler {
@@ -686,8 +593,8 @@ public class LauncherStateManager {
/**
* Sets the UI to {@param state} by animating any changes.
*/
void setStateWithAnimation(LauncherState toState,
AnimatorSetBuilder builder, AnimationConfig config);
void setStateWithAnimation(
LauncherState toState, StateAnimationConfig config, PendingAnimation animation);
}
public interface StateListener {
+6 -6
View File
@@ -60,11 +60,10 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;
import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dot.FolderDotInfo;
import com.android.launcher3.dragndrop.DragController;
@@ -83,6 +82,7 @@ import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.pageindicators.WorkspacePageIndicator;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.WorkspaceTouchListener;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -1383,10 +1383,10 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
* Sets the current workspace {@link LauncherState}, then animates the UI
*/
@Override
public void setStateWithAnimation(LauncherState toState,
AnimatorSetBuilder builder, AnimationConfig config) {
public void setStateWithAnimation(
LauncherState toState, StateAnimationConfig config, PendingAnimation animation) {
StateTransitionListener listener = new StateTransitionListener(toState);
mStateTransitionAnimation.setStateWithAnimation(toState, builder, config);
mStateTransitionAnimation.setStateWithAnimation(toState, config, animation);
// Invalidate the pages now, so that we have the visible pages before the
// animation is started
@@ -1399,7 +1399,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
stepAnimator.addUpdateListener(listener);
stepAnimator.setDuration(config.duration);
stepAnimator.addListener(listener);
builder.play(stepAnimator);
animation.add(stepAnimator);
}
public WorkspaceStateTransitionAnimation getStateTransitionAnimation() {
@@ -22,27 +22,27 @@ import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_TRANSLATE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.ZOOM_OUT;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import static com.android.launcher3.graphics.WorkspaceAndHotseatScrim.SCRIM_PROGRESS;
import static com.android.launcher3.graphics.WorkspaceAndHotseatScrim.SYSUI_PROGRESS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
import android.view.View;
import android.view.animation.Interpolator;
import com.android.launcher3.LauncherState.PageAlphaProvider;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.graphics.WorkspaceAndHotseatScrim;
import com.android.launcher3.states.StateAnimationConfig;
/**
* Manages the animations between each of the workspace states.
@@ -60,13 +60,15 @@ public class WorkspaceStateTransitionAnimation {
}
public void setState(LauncherState toState) {
setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER, new AnimatorSetBuilder(),
new AnimationConfig());
setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig());
}
public void setStateWithAnimation(LauncherState toState, AnimatorSetBuilder builder,
AnimationConfig config) {
setWorkspaceProperty(toState, config.getPropertySetter(builder), builder, config);
/**
* @see com.android.launcher3.LauncherStateManager.StateHandler#setStateWithAnimation
*/
public void setStateWithAnimation(
LauncherState toState, StateAnimationConfig config, PendingAnimation animation) {
setWorkspaceProperty(toState, animation, config);
}
public float getFinalScale() {
@@ -77,7 +79,7 @@ public class WorkspaceStateTransitionAnimation {
* Starts a transition animation for the workspace.
*/
private void setWorkspaceProperty(LauncherState state, PropertySetter propertySetter,
AnimatorSetBuilder builder, AnimationConfig config) {
StateAnimationConfig config) {
ScaleAndTranslation scaleAndTranslation = state.getWorkspaceScaleAndTranslation(mLauncher);
ScaleAndTranslation hotseatScaleAndTranslation = state.getHotseatScaleAndTranslation(
mLauncher);
@@ -87,11 +89,11 @@ public class WorkspaceStateTransitionAnimation {
final int childCount = mWorkspace.getChildCount();
for (int i = 0; i < childCount; i++) {
applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, pageAlphaProvider,
propertySetter, builder, config);
propertySetter, config);
}
int elements = state.getVisibleElements(mLauncher);
Interpolator fadeInterpolator = builder.getInterpolator(ANIM_WORKSPACE_FADE,
Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
pageAlphaProvider.interpolator);
boolean playAtomicComponent = config.playAtomicOverviewScaleComponent();
Hotseat hotseat = mWorkspace.getHotseat();
@@ -99,7 +101,7 @@ public class WorkspaceStateTransitionAnimation {
AllAppsContainerView qsbScaleView = mLauncher.getAppsView();
View qsbView = qsbScaleView.getSearchView();
if (playAtomicComponent) {
Interpolator scaleInterpolator = builder.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
Interpolator scaleInterpolator = config.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
if (!hotseat.getRotationMode().isTransposed) {
@@ -107,7 +109,7 @@ public class WorkspaceStateTransitionAnimation {
setPivotToScaleWithWorkspace(qsbScaleView);
}
float hotseatScale = hotseatScaleAndTranslation.scale;
Interpolator hotseatScaleInterpolator = builder.getInterpolator(ANIM_HOTSEAT_SCALE,
Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE,
scaleInterpolator);
propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale,
hotseatScaleInterpolator);
@@ -127,13 +129,13 @@ public class WorkspaceStateTransitionAnimation {
Interpolator translationInterpolator = !playAtomicComponent
? LINEAR
: builder.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
: config.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_X,
scaleAndTranslation.translationX, translationInterpolator);
propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_Y,
scaleAndTranslation.translationY, translationInterpolator);
Interpolator hotseatTranslationInterpolator = builder.getInterpolator(
Interpolator hotseatTranslationInterpolator = config.getInterpolator(
ANIM_HOTSEAT_TRANSLATE, translationInterpolator);
propertySetter.setFloat(hotseat, VIEW_TRANSLATE_Y,
hotseatScaleAndTranslation.translationY, hotseatTranslationInterpolator);
@@ -166,12 +168,12 @@ public class WorkspaceStateTransitionAnimation {
public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
applyChildState(state, cl, childIndex, state.getWorkspacePageAlphaProvider(mLauncher),
NO_ANIM_PROPERTY_SETTER, new AnimatorSetBuilder(), new AnimationConfig());
NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig());
}
private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter,
AnimatorSetBuilder builder, AnimationConfig config) {
StateAnimationConfig config) {
float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex);
int drawableAlpha = Math.round(pageAlpha * (state.hasWorkspacePageBackground ? 255 : 0));
@@ -181,7 +183,7 @@ public class WorkspaceStateTransitionAnimation {
DRAWABLE_ALPHA, drawableAlpha, ZOOM_OUT);
}
if (config.playAtomicOverviewScaleComponent()) {
Interpolator fadeInterpolator = builder.getInterpolator(ANIM_WORKSPACE_FADE,
Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
pageAlphaProvider.interpolator);
propertySetter.setFloat(cl.getShortcutsAndWidgets(), VIEW_ALPHA,
pageAlpha, fadeInterpolator);
@@ -5,13 +5,13 @@ import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
import static com.android.launcher3.LauncherState.APPS_VIEW_ITEM_MASK;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.VERTICAL_SWIPE_INDICATOR;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_HEADER_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_HEADER_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.util.SystemUiController.UI_STATE_ALL_APPS;
import android.animation.Animator;
@@ -24,12 +24,12 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ScrimView;
@@ -112,7 +112,7 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
* @param progress value between 0 and 1, 0 shows all apps and 1 shows workspace
*
* @see #setState(LauncherState)
* @see #setStateWithAnimation(LauncherState, AnimatorSetBuilder, AnimationConfig)
* @see #setStateWithAnimation(LauncherState, StateAnimationConfig, PendingAnimation)
*/
public void setProgress(float progress) {
mProgress = progress;
@@ -143,7 +143,7 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
@Override
public void setState(LauncherState state) {
setProgress(state.getVerticalProgress(mLauncher));
setAlphas(state, null, new AnimatorSetBuilder());
setAlphas(state, new StateAnimationConfig(), NO_ANIM_PROPERTY_SETTER);
onProgressAnimationEnd();
}
@@ -153,7 +153,7 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
*/
@Override
public void setStateWithAnimation(LauncherState toState,
AnimatorSetBuilder builder, AnimationConfig config) {
StateAnimationConfig config, PendingAnimation builder) {
float targetProgress = toState.getVerticalProgress(mLauncher);
if (Float.compare(mProgress, targetProgress) == 0) {
setAlphas(toState, config, builder);
@@ -168,14 +168,14 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
}
Interpolator interpolator = config.userControlled ? LINEAR : toState == OVERVIEW
? builder.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN)
? config.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN)
: FAST_OUT_SLOW_IN;
Animator anim = createSpringAnimation(mProgress, targetProgress);
anim.setDuration(config.duration);
anim.setInterpolator(builder.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator));
anim.setInterpolator(config.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator));
anim.addListener(getProgressAnimatorListener());
builder.play(anim);
builder.add(anim);
setAlphas(toState, config, builder);
}
@@ -184,21 +184,18 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
return ObjectAnimator.ofFloat(this, ALL_APPS_PROGRESS, progressValues);
}
private void setAlphas(LauncherState toState, AnimationConfig config,
AnimatorSetBuilder builder) {
setAlphas(toState.getVisibleElements(mLauncher), config, builder);
}
public void setAlphas(int visibleElements, AnimationConfig config, AnimatorSetBuilder builder) {
PropertySetter setter = config == null ? NO_ANIM_PROPERTY_SETTER
: config.getPropertySetter(builder);
/**
* Updates the property for the provided state
*/
public void setAlphas(LauncherState state, StateAnimationConfig config, PropertySetter setter) {
int visibleElements = state.getVisibleElements(mLauncher);
boolean hasHeaderExtra = (visibleElements & ALL_APPS_HEADER_EXTRA) != 0;
boolean hasAllAppsContent = (visibleElements & ALL_APPS_CONTENT) != 0;
boolean hasAnyVisibleItem = (visibleElements & APPS_VIEW_ITEM_MASK) != 0;
Interpolator allAppsFade = builder.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
Interpolator headerFade = builder.getInterpolator(ANIM_ALL_APPS_HEADER_FADE, allAppsFade);
Interpolator allAppsFade = config.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
Interpolator headerFade = config.getInterpolator(ANIM_ALL_APPS_HEADER_FADE, allAppsFade);
setter.setViewAlpha(mAppsView.getContentView(), hasAllAppsContent ? 1 : 0, allAppsFade);
setter.setViewAlpha(mAppsView.getScrollBar(), hasAllAppsContent ? 1 : 0, allAppsFade);
mAppsView.getFloatingHeaderView().setContentVisibility(hasHeaderExtra, hasAllAppsContent,
@@ -64,13 +64,6 @@ public class AnimatorPlaybackController implements ValueAnimator.AnimatorUpdateL
return new AnimatorPlaybackController(anim, duration, childAnims);
}
public static AnimatorPlaybackController wrap(PendingAnimation anim, long duration) {
/**
* TODO: use {@link AnimatorSet#setCurrentPlayTime(long)} once b/68382377 is fixed.
*/
return new AnimatorPlaybackController(anim.anim, duration, anim.animHolders);
}
private static final FloatProperty<ValueAnimator> CURRENT_PLAY_TIME =
new FloatProperty<ValueAnimator>("current-play-time") {
@Override
@@ -96,8 +89,8 @@ public class AnimatorPlaybackController implements ValueAnimator.AnimatorUpdateL
protected boolean mTargetCancelled = false;
protected Runnable mOnCancelRunnable;
private AnimatorPlaybackController(
AnimatorSet anim, long duration, ArrayList<Holder> childAnims) {
/** package private */
AnimatorPlaybackController(AnimatorSet anim, long duration, ArrayList<Holder> childAnims) {
mAnim = anim;
mDuration = duration;
@@ -1,65 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.anim;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.util.SparseArray;
import android.view.animation.Interpolator;
import java.util.ArrayList;
/**
* Utility class for building animator set
*/
public class AnimatorSetBuilder {
public static final int ANIM_VERTICAL_PROGRESS = 0;
public static final int ANIM_WORKSPACE_SCALE = 1;
public static final int ANIM_WORKSPACE_TRANSLATE = 2;
public static final int ANIM_WORKSPACE_FADE = 3;
public static final int ANIM_HOTSEAT_SCALE = 4;
public static final int ANIM_HOTSEAT_TRANSLATE = 5;
public static final int ANIM_OVERVIEW_SCALE = 6;
public static final int ANIM_OVERVIEW_TRANSLATE_X = 7;
public static final int ANIM_OVERVIEW_TRANSLATE_Y = 8;
public static final int ANIM_OVERVIEW_FADE = 9;
public static final int ANIM_ALL_APPS_FADE = 10;
public static final int ANIM_OVERVIEW_SCRIM_FADE = 11;
public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions
protected final ArrayList<Animator> mAnims = new ArrayList<>();
private final SparseArray<Interpolator> mInterpolators = new SparseArray<>();
public void play(Animator anim) {
mAnims.add(anim);
}
public AnimatorSet build() {
AnimatorSet anim = new AnimatorSet();
anim.playTogether(mAnims);
return anim;
}
public Interpolator getInterpolator(int animId, Interpolator fallback) {
return mInterpolators.get(animId, fallback);
}
public void setInterpolator(int animId, Interpolator interpolator) {
mInterpolators.put(animId, interpolator);
}
}
@@ -19,9 +19,12 @@ import static com.android.launcher3.anim.AnimatorPlaybackController.addAnimation
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.annotation.TargetApi;
import android.os.Build;
import android.animation.ValueAnimator;
import android.util.FloatProperty;
import android.util.IntProperty;
import android.view.View;
import com.android.launcher3.anim.AnimatorPlaybackController.Holder;
@@ -37,14 +40,24 @@ import java.util.function.Consumer;
*
* TODO: Find a better name
*/
@TargetApi(Build.VERSION_CODES.O)
public class PendingAnimation {
public class PendingAnimation implements PropertySetter {
private final ArrayList<Consumer<EndState>> mEndListeners = new ArrayList<>();
/** package private **/
final AnimatorSet anim = new AnimatorSet();
final ArrayList<Holder> animHolders = new ArrayList<>();
private final ArrayList<Holder> mAnimHolders = new ArrayList<>();
private final AnimatorSet mAnim;
private final long mDuration;
private ValueAnimator mProgressAnimator;
public PendingAnimation(long duration) {
this(duration, new AnimatorSet());
}
public PendingAnimation(long duration, AnimatorSet targetSet) {
mDuration = duration;
mAnim = targetSet;
}
/**
* Utility method to sent an interpolator on an animation and add it to the list
@@ -63,8 +76,8 @@ public class PendingAnimation {
}
public void add(Animator a, SpringProperty springProperty) {
anim.play(a);
addAnimationHoldersRecur(a, springProperty, animHolders);
mAnim.play(a);
addAnimationHoldersRecur(a, springProperty, mAnimHolders);
}
public void finish(boolean isSuccess, int logAction) {
@@ -74,6 +87,67 @@ public class PendingAnimation {
mEndListeners.clear();
}
@Override
public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
if (view == null || view.getAlpha() == alpha) {
return;
}
ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
anim.addListener(new AlphaUpdateListener(view));
anim.setDuration(mDuration).setInterpolator(interpolator);
add(anim);
}
@Override
public <T> void setFloat(T target, FloatProperty<T> property, float value,
TimeInterpolator interpolator) {
if (property.get(target) == value) {
return;
}
Animator anim = ObjectAnimator.ofFloat(target, property, value);
anim.setDuration(mDuration).setInterpolator(interpolator);
add(anim);
}
@Override
public <T> void setInt(T target, IntProperty<T> property, int value,
TimeInterpolator interpolator) {
if (property.get(target) == value) {
return;
}
Animator anim = ObjectAnimator.ofInt(target, property, value);
anim.setDuration(mDuration).setInterpolator(interpolator);
add(anim);
}
/**
* Adds a callback to be run on every frame of the animation
*/
public void addOnFrameCallback(Runnable runnable) {
if (mProgressAnimator == null) {
mProgressAnimator = ValueAnimator.ofFloat(0, 1).setDuration(mDuration);
add(mProgressAnimator);
}
mProgressAnimator.addUpdateListener(anim -> runnable.run());
}
public AnimatorSet getAnim() {
return mAnim;
}
/**
* Creates a controller for this animation
*/
public AnimatorPlaybackController createPlaybackController() {
return new AnimatorPlaybackController(mAnim, mDuration, mAnimHolders);
}
/**
* Add a listener of receiving the end state.
* Note that the listeners are called as a result of calling {@link #finish(boolean, int)}
* and not automatically
*/
public void addEndListener(Consumer<EndState> listener) {
mEndListeners.add(listener);
}
@@ -16,8 +16,6 @@
package com.android.launcher3.anim;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.util.FloatProperty;
import android.util.IntProperty;
@@ -26,68 +24,35 @@ import android.view.View;
/**
* Utility class for setting a property with or without animation
*/
public class PropertySetter {
public interface PropertySetter {
public static final PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter();
PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter() { };
public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
/**
* Sets the view alpha using the provided interpolator.
* Unlike {@link #setFloat}, this also updates the visibility of the view as alpha changes
* between zero and non-zero.
*/
default void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
if (view != null) {
view.setAlpha(alpha);
AlphaUpdateListener.updateVisibility(view);
}
}
public <T> void setFloat(T target, FloatProperty<T> property, float value,
/**
* Updates the float property of the target using the provided interpolator
*/
default <T> void setFloat(T target, FloatProperty<T> property, float value,
TimeInterpolator interpolator) {
property.setValue(target, value);
}
public <T> void setInt(T target, IntProperty<T> property, int value,
/**
* Updates the int property of the target using the provided interpolator
*/
default <T> void setInt(T target, IntProperty<T> property, int value,
TimeInterpolator interpolator) {
property.setValue(target, value);
}
public static class AnimatedPropertySetter extends PropertySetter {
private final long mDuration;
private final AnimatorSetBuilder mStateAnimator;
public AnimatedPropertySetter(long duration, AnimatorSetBuilder builder) {
mDuration = duration;
mStateAnimator = builder;
}
@Override
public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
if (view == null || view.getAlpha() == alpha) {
return;
}
ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
anim.addListener(new AlphaUpdateListener(view));
anim.setDuration(mDuration).setInterpolator(interpolator);
mStateAnimator.play(anim);
}
@Override
public <T> void setFloat(T target, FloatProperty<T> property, float value,
TimeInterpolator interpolator) {
if (property.get(target) == value) {
return;
}
Animator anim = ObjectAnimator.ofFloat(target, property, value);
anim.setDuration(mDuration).setInterpolator(interpolator);
mStateAnimator.play(anim);
}
@Override
public <T> void setInt(T target, IntProperty<T> property, int value,
TimeInterpolator interpolator) {
if (property.get(target) == value) {
return;
}
Animator anim = ObjectAnimator.ofInt(target, property, value);
anim.setDuration(mDuration).setInterpolator(interpolator);
mStateAnimator.play(anim);
}
}
}
@@ -100,11 +100,11 @@ public final class FeatureFlags {
"Suggests folder names instead of blank text.");
public static final BooleanFlag APP_SEARCH_IMPROVEMENTS = new DeviceFlag(
"APP_SEARCH_IMPROVEMENTS", false,
"APP_SEARCH_IMPROVEMENTS", true,
"Adds localized title and keyword search and ranking");
public static final BooleanFlag ENABLE_PREDICTION_DISMISS = new DeviceFlag(
"ENABLE_PREDICTION_DISMISS", true, "Allow option to dimiss apps from predicted list");
public static final BooleanFlag ENABLE_PREDICTION_DISMISS = getDebugFlag(
"ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list");
public static final BooleanFlag ENABLE_QUICK_CAPTURE_GESTURE = getDebugFlag(
"ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture");
@@ -117,11 +117,11 @@ public final class FeatureFlags {
"ASSISTANT_GIVES_LAUNCHER_FOCUS", false,
"Allow Launcher to handle nav bar gestures while Assistant is running over it");
public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = new DeviceFlag(
public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = getDebugFlag(
"ENABLE_HYBRID_HOTSEAT", false, "Fill gaps in hotseat with predicted apps");
public static final BooleanFlag HOTSEAT_MIGRATE_NEW_PAGE = new DeviceFlag(
"HOTSEAT_MIGRATE_NEW_PAGE", true,
public static final BooleanFlag HOTSEAT_MIGRATE_NEW_PAGE = getDebugFlag(
"HOTSEAT_MIGRATE_NEW_PAGE", false,
"Migrates hotseat to a new workspace page instead of same page");
public static final BooleanFlag ENABLE_DEEP_SHORTCUT_ICON_CACHE = getDebugFlag(
@@ -131,13 +131,18 @@ public final class FeatureFlags {
"MULTI_DB_GRID_MIRATION_ALGO", false, "Use the multi-db grid migration algorithm");
public static final BooleanFlag ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER = getDebugFlag(
"ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER", true,
"Show launcher preview in grid picker");
"ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER", true, "Show launcher preview in grid picker");
public static final BooleanFlag USE_SURFACE_VIEW_FOR_GRID_PREVIEW = getDebugFlag(
"USE_SURFACE_VIEW_FOR_GRID_PREVIEW", false, "Use surface view for grid preview");
public static final BooleanFlag ENABLE_OVERVIEW_ACTIONS = getDebugFlag(
"ENABLE_OVERVIEW_ACTIONS", true, "Show app actions instead of the shelf in Overview."
+ " As part of this decoupling, also distinguish swipe up from nav bar vs above it.");
public static final BooleanFlag ENABLE_SELECT_MODE = getDebugFlag(
"ENABLE_SELECT_MODE", true, "Show Select Mode button in Overview Actions");
public static final BooleanFlag ENABLE_DATABASE_RESTORE = getDebugFlag(
"ENABLE_DATABASE_RESTORE", true,
"Enable database restore when new restore session is created");
@@ -1,5 +1,6 @@
package com.android.launcher3.graphics;
import static com.android.launcher3.config.FeatureFlags.USE_SURFACE_VIEW_FOR_GRID_PREVIEW;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.content.ContentProvider;
@@ -19,6 +20,7 @@ import android.util.Xml;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.InvariantDeviceProfile.GridOption;
import com.android.launcher3.R;
import com.android.launcher3.uioverrides.PreviewSurfaceRenderer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -62,6 +64,11 @@ public class GridOptionsProvider extends ContentProvider {
private static final String KEY_PREVIEW = "preview";
private static final String MIME_TYPE_PNG = "image/png";
private static final String METHOD_GET_PREVIEW = "get_preview";
private static final String METADATA_KEY_PREVIEW_VERSION = "preview_version";
public static final PipeDataWriter<Future<Bitmap>> BITMAP_WRITER =
new PipeDataWriter<Future<Bitmap>>() {
@Override
@@ -98,6 +105,10 @@ public class GridOptionsProvider extends ContentProvider {
.add(KEY_IS_DEFAULT, idp.numColumns == gridOption.numColumns
&& idp.numRows == gridOption.numRows);
}
Bundle metadata = new Bundle();
metadata.putString(METADATA_KEY_PREVIEW_VERSION,
USE_SURFACE_VIEW_FOR_GRID_PREVIEW.get() ? "V2" : "V1");
cursor.setExtras(metadata);
return cursor;
}
@@ -188,4 +199,14 @@ public class GridOptionsProvider extends ContentProvider {
throw new FileNotFoundException(e.getMessage());
}
}
@Override
public Bundle call(String method, String arg, Bundle extras) {
if (!METHOD_GET_PREVIEW.equals(method)) {
return null;
}
PreviewSurfaceRenderer.render(getContext(), extras);
return null;
}
}
@@ -262,6 +262,13 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
});
}
/** Populate preview and render it. */
public View getRenderedView() {
MainThreadRenderer renderer = new MainThreadRenderer(mContext);
renderer.populate();
return renderer.mRootView;
}
private class MainThreadRenderer extends ContextThemeWrapper
implements ActivityContext, WorkspaceLayoutManager, LayoutInflater.Factory2 {
@@ -388,7 +395,7 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
}
}
private void renderScreenShot(Canvas canvas) {
private void populate() {
if (ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER.get()) {
boolean needsToMigrate = needsToMigrate(mContext, mIdp);
boolean success = false;
@@ -499,7 +506,10 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
measureView(mRootView, mDp.widthPx, mDp.heightPx);
// Additional measure for views which use auto text size API
measureView(mRootView, mDp.widthPx, mDp.heightPx);
}
private void renderScreenShot(Canvas canvas) {
populate();
mRootView.draw(canvas);
dispatchVisibilityAggregated(mRootView, false);
}
@@ -143,7 +143,7 @@ public class UserEventDispatcher implements ResourceBasedOverride {
fillIntentInfo(itemTarget, intent, userHandle);
}
LauncherEvent event = newLauncherEvent(action, targets);
ItemInfo info = (ItemInfo) v.getTag();
ItemInfo info = v == null ? null : (ItemInfo) v.getTag();
if (info != null && Utilities.IS_DEBUG_DEVICE && FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) {
FileLog.d(TAG, "appLaunch: packageName:" + info.getTargetComponent().getPackageName()
+ ",isWorkApp:" + (info.user != null && !Process.myUserHandle().equals(
@@ -936,8 +936,8 @@ public class GridSizeMigrationTask {
boolean dbChanged = false;
if (migrateForPreview) {
copyTable(transaction.getDb(), Favorites.TABLE_NAME, Favorites.PREVIEW_TABLE_NAME,
context);
copyTable(transaction.getDb(), Favorites.TABLE_NAME, transaction.getDb(),
Favorites.PREVIEW_TABLE_NAME, context);
}
GridBackupTable backupTable = new GridBackupTable(context, transaction.getDb(),
@@ -950,10 +950,11 @@ public class GridSizeMigrationTask {
HashSet<String> validPackages = getValidPackages(context);
// Hotseat.
if (srcHotseatCount != idp.numHotseatIcons) {
// Migrate hotseat.
dbChanged = new GridSizeMigrationTask(context, transaction.getDb(), validPackages,
migrateForPreview, srcHotseatCount, idp.numHotseatIcons).migrateHotseat();
if (srcHotseatCount != idp.numHotseatIcons
&& new GridSizeMigrationTask(context, transaction.getDb(), validPackages,
migrateForPreview, srcHotseatCount,
idp.numHotseatIcons).migrateHotseat()) {
dbChanged = true;
}
// Grid size
@@ -16,9 +16,46 @@
package com.android.launcher3.model;
import static com.android.launcher3.Utilities.getPointString;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Point;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Utilities;
import com.android.launcher3.graphics.LauncherPreviewRenderer;
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.widget.WidgetManagerHelper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* This class takes care of shrinking the workspace (by maximum of one row and one column), as a
@@ -26,14 +63,63 @@ import com.android.launcher3.InvariantDeviceProfile;
*/
public class GridSizeMigrationTaskV2 {
private GridSizeMigrationTaskV2(Context context) {
public static final String KEY_MIGRATION_SRC_WORKSPACE_SIZE = "migration_src_workspace_size";
public static final String KEY_MIGRATION_SRC_HOTSEAT_COUNT = "migration_src_hotseat_count";
private static final String TAG = "GridSizeMigrationTaskV2";
private static final boolean DEBUG = true;
private final Context mContext;
private final SQLiteDatabase mDb;
private final DbReader mSrcReader;
private final DbReader mDestReader;
private final List<DbEntry> mHotseatItems;
private final List<DbEntry> mWorkspaceItems;
private final List<DbEntry> mHotseatDiff;
private final List<DbEntry> mWorkspaceDiff;
private final int mDestHotseatSize;
private final int mTrgX, mTrgY;
@VisibleForTesting
protected GridSizeMigrationTaskV2(Context context, SQLiteDatabase db, DbReader srcReader,
DbReader destReader, int destHotseatSize, Point targetSize) {
mContext = context;
mDb = db;
mSrcReader = srcReader;
mDestReader = destReader;
mHotseatItems = destReader.loadHotseatEntries();
mWorkspaceItems = destReader.loadAllWorkspaceEntries();
mHotseatDiff = calcDiff(mSrcReader.loadHotseatEntries(), mHotseatItems);
mWorkspaceDiff = calcDiff(mSrcReader.loadAllWorkspaceEntries(), mWorkspaceItems);
mDestHotseatSize = destHotseatSize;
mTrgX = targetSize.x;
mTrgY = targetSize.y;
}
/**
* Check given a new IDP, if migration is necessary.
*/
public static boolean needsToMigrate(Context context, InvariantDeviceProfile idp) {
SharedPreferences prefs = Utilities.getPrefs(context);
String gridSizeString = getPointString(idp.numColumns, idp.numRows);
return !gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, ""))
|| idp.numHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT,
idp.numHotseatIcons);
}
/** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */
public static boolean migrateGridIfNeeded(Context context) {
// To be implemented.
return true;
if (context instanceof LauncherPreviewRenderer.PreviewContext) {
return true;
}
return migrateGridIfNeeded(context, null);
}
/**
@@ -43,7 +129,608 @@ public class GridSizeMigrationTaskV2 {
* @return false if the migration failed.
*/
public static boolean migrateGridIfNeeded(Context context, InvariantDeviceProfile idp) {
// To be implemented.
boolean migrateForPreview = idp != null;
if (!migrateForPreview) {
idp = LauncherAppState.getIDP(context);
}
if (!needsToMigrate(context, idp)) {
return true;
}
SharedPreferences prefs = Utilities.getPrefs(context);
String gridSizeString = getPointString(idp.numColumns, idp.numRows);
if (gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, ""))
&& idp.numHotseatIcons == prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT,
idp.numHotseatIcons)) {
// Skip if workspace and hotseat sizes have not changed.
return true;
}
HashSet<String> validPackages = getValidPackages(context);
int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons);
if (!LauncherSettings.Settings.call(
context.getContentResolver(),
LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER).getBoolean(
LauncherSettings.Settings.EXTRA_VALUE)) {
return false;
}
long migrationStartTime = System.currentTimeMillis();
try (SQLiteTransaction t = (SQLiteTransaction) LauncherSettings.Settings.call(
context.getContentResolver(),
LauncherSettings.Settings.METHOD_NEW_TRANSACTION).getBinder(
LauncherSettings.Settings.EXTRA_VALUE)) {
DbReader srcReader = new DbReader(t.getDb(), LauncherSettings.Favorites.TMP_TABLE,
context, validPackages, srcHotseatCount);
DbReader destReader = new DbReader(t.getDb(), LauncherSettings.Favorites.TABLE_NAME,
context, validPackages, idp.numHotseatIcons);
Point targetSize = new Point(idp.numColumns, idp.numRows);
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(context, t.getDb(),
srcReader, destReader, idp.numHotseatIcons, targetSize);
task.migrate();
dropTable(t.getDb(), LauncherSettings.Favorites.TMP_TABLE);
t.commit();
return true;
} catch (Exception e) {
Log.e(TAG, "Error during grid migration", e);
return false;
} finally {
Log.v(TAG, "Workspace migration completed in "
+ (System.currentTimeMillis() - migrationStartTime));
// Save current configuration, so that the migration does not run again.
prefs.edit()
.putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
.putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)
.apply();
}
}
@VisibleForTesting
protected boolean migrate() {
if (mHotseatDiff.isEmpty() && mWorkspaceDiff.isEmpty()) {
return false;
}
// Migrate hotseat
HotseatPlacementSolution hotseatSolution = new HotseatPlacementSolution(mDb, mSrcReader,
mContext, mDestHotseatSize, mHotseatItems, mHotseatDiff);
hotseatSolution.find();
// Sort the items by the reading order.
Collections.sort(mWorkspaceDiff);
// Migrate workspace.
for (int screenId = 0; screenId <= mDestReader.mLastScreenId; screenId++) {
if (DEBUG) {
Log.d(TAG, "Migrating " + screenId);
}
List<DbEntry> entries = mDestReader.loadWorkspaceEntries(screenId);
GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader,
mContext, entries, screenId, mTrgX, mTrgY, mWorkspaceDiff);
workspaceSolution.find();
if (mWorkspaceDiff.isEmpty()) {
break;
}
}
int screenId = mDestReader.mLastScreenId + 1;
while (!mWorkspaceDiff.isEmpty()) {
GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader,
mContext, new ArrayList<>(), screenId, mTrgX, mTrgY, mWorkspaceDiff);
workspaceSolution.find();
screenId++;
}
return true;
}
/** Return what's in the src but not in the dest */
private static List<DbEntry> calcDiff(List<DbEntry> src, List<DbEntry> dest) {
Set<String> destSet = dest.parallelStream().map(DbEntry::getIntentStr).collect(
Collectors.toSet());
List<DbEntry> diff = new ArrayList<>();
for (DbEntry entry : src) {
if (!destSet.contains(entry.mIntent)) {
diff.add(entry);
}
}
return diff;
}
private static void insertEntryInDb(SQLiteDatabase db, Context context,
ArrayList<DbEntry> entriesFromSrcDb, DbEntry entry) {
int id = -1;
switch (entry.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: {
for (DbEntry e : entriesFromSrcDb) {
if (TextUtils.equals(e.mIntent, entry.mIntent)) {
id = e.id;
}
}
break;
}
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: {
for (DbEntry e : entriesFromSrcDb) {
if (e.mFolderItems.size() == entry.mFolderItems.size()
&& e.mFolderItems.containsAll(entry.mFolderItems)) {
id = e.id;
}
}
break;
}
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: {
for (DbEntry e : entriesFromSrcDb) {
if (TextUtils.equals(e.mProvider, entry.mProvider)) {
id = e.id;
break;
}
}
break;
}
default:
return;
}
Cursor c = db.query(LauncherSettings.Favorites.TMP_TABLE, null,
LauncherSettings.Favorites._ID + " = '" + id + "'", null, null, null, null);
while (c.moveToNext()) {
ContentValues values = new ContentValues();
DatabaseUtils.cursorRowToContentValues(c, values);
entry.updateContentValues(values);
values.put(LauncherSettings.Favorites._ID,
LauncherSettings.Settings.call(context.getContentResolver(),
LauncherSettings.Settings.METHOD_NEW_ITEM_ID).getInt(
LauncherSettings.Settings.EXTRA_VALUE));
db.insert(LauncherSettings.Favorites.TABLE_NAME, null, values);
}
c.close();
}
private static void removeEntryFromDb(SQLiteDatabase db, IntArray entryId) {
db.delete(LauncherSettings.Favorites.TABLE_NAME, Utilities.createDbSelectionQuery(
LauncherSettings.Favorites._ID, entryId), null);
}
private static HashSet<String> getValidPackages(Context context) {
// Initialize list of valid packages. This contain all the packages which are already on
// the device and packages which are being installed. Any item which doesn't belong to
// this set is removed.
// Since the loader removes such items anyway, removing these items here doesn't cause
// any extra data loss and gives us more free space on the grid for better migration.
HashSet<String> validPackages = new HashSet<>();
for (PackageInfo info : context.getPackageManager()
.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES)) {
validPackages.add(info.packageName);
}
InstallSessionHelper.INSTANCE.get(context)
.getActiveSessions().keySet()
.forEach(packageUserKey -> validPackages.add(packageUserKey.mPackageName));
return validPackages;
}
protected static class GridPlacementSolution {
private final SQLiteDatabase mDb;
private final DbReader mSrcReader;
private final Context mContext;
private final GridOccupancy mOccupied;
private final int mScreenId;
private final int mTrgX;
private final int mTrgY;
private final List<DbEntry> mItemsToPlace;
private int mNextStartX;
private int mNextStartY;
GridPlacementSolution(SQLiteDatabase db, DbReader srcReader, Context context,
List<DbEntry> placedWorkspaceItems, int screenId, int trgX,
int trgY, List<DbEntry> itemsToPlace) {
mDb = db;
mSrcReader = srcReader;
mContext = context;
mOccupied = new GridOccupancy(trgX, trgY);
mScreenId = screenId;
mTrgX = trgX;
mTrgY = trgY;
mNextStartX = 0;
mNextStartY = mTrgY - 1;
for (DbEntry entry : placedWorkspaceItems) {
mOccupied.markCells(entry, true);
}
mItemsToPlace = itemsToPlace;
}
public void find() {
Iterator<DbEntry> iterator = mItemsToPlace.iterator();
while (iterator.hasNext()) {
final DbEntry entry = iterator.next();
if (entry.minSpanX > mTrgX || entry.minSpanY > mTrgY) {
iterator.remove();
continue;
}
if (findPlacement(entry)) {
insertEntryInDb(mDb, mContext, mSrcReader.mWorkspaceEntries, entry);
iterator.remove();
}
}
}
private boolean findPlacement(DbEntry entry) {
for (int y = mNextStartY; y >= 0; y--) {
for (int x = mNextStartX; x < mTrgX; x++) {
boolean fits = mOccupied.isRegionVacant(x, y, entry.spanX, entry.spanY);
boolean minFits = mOccupied.isRegionVacant(x, y, entry.minSpanX,
entry.minSpanY);
if (minFits) {
entry.spanX = entry.minSpanX;
entry.spanY = entry.minSpanY;
}
if (fits || minFits) {
entry.screenId = mScreenId;
entry.cellX = x;
entry.cellY = y;
mOccupied.markCells(entry, true);
mNextStartX = x + entry.spanX;
mNextStartY = y;
return true;
}
}
}
return false;
}
}
protected static class HotseatPlacementSolution {
private final SQLiteDatabase mDb;
private final DbReader mSrcReader;
private final Context mContext;
private final HotseatOccupancy mOccupied;
private final List<DbEntry> mItemsToPlace;
HotseatPlacementSolution(SQLiteDatabase db, DbReader srcReader, Context context,
int hotseatSize, List<DbEntry> placedHotseatItems, List<DbEntry> itemsToPlace) {
mDb = db;
mSrcReader = srcReader;
mContext = context;
mOccupied = new HotseatOccupancy(hotseatSize);
for (DbEntry entry : placedHotseatItems) {
mOccupied.markCells(entry, true);
}
mItemsToPlace = itemsToPlace;
}
public void find() {
for (int i = 0; i < mOccupied.mCells.length; i++) {
if (!mOccupied.mCells[i] && !mItemsToPlace.isEmpty()) {
DbEntry entry = mItemsToPlace.remove(0);
entry.screenId = i;
// These values does not affect the item position, but we should set them
// to something other than -1.
entry.cellX = i;
entry.cellY = 0;
insertEntryInDb(mDb, mContext, mSrcReader.mHotseatEntries, entry);
mOccupied.markCells(entry, true);
}
}
}
private class HotseatOccupancy {
private final boolean[] mCells;
private HotseatOccupancy(int hotseatSize) {
mCells = new boolean[hotseatSize];
}
private void markCells(ItemInfo item, boolean value) {
mCells[item.screenId] = value;
}
}
}
protected static class DbReader {
private final SQLiteDatabase mDb;
private final String mTableName;
private final Context mContext;
private final HashSet<String> mValidPackages;
private final int mHotseatSize;
private int mLastScreenId = -1;
private final ArrayList<DbEntry> mHotseatEntries = new ArrayList<>();
private final ArrayList<DbEntry> mWorkspaceEntries = new ArrayList<>();
DbReader(SQLiteDatabase db, String tableName, Context context,
HashSet<String> validPackages, int hotseatSize) {
mDb = db;
mTableName = tableName;
mContext = context;
mValidPackages = validPackages;
mHotseatSize = hotseatSize;
}
protected ArrayList<DbEntry> loadHotseatEntries() {
Cursor c = queryWorkspace(
new String[]{
LauncherSettings.Favorites._ID, // 0
LauncherSettings.Favorites.ITEM_TYPE, // 1
LauncherSettings.Favorites.INTENT, // 2
LauncherSettings.Favorites.SCREEN}, // 3
LauncherSettings.Favorites.CONTAINER + " = "
+ LauncherSettings.Favorites.CONTAINER_HOTSEAT);
final int indexId = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
final int indexItemType = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
final int indexIntent = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
final int indexScreen = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
IntArray entriesToRemove = new IntArray();
while (c.moveToNext()) {
DbEntry entry = new DbEntry();
entry.id = c.getInt(indexId);
entry.itemType = c.getInt(indexItemType);
entry.screenId = c.getInt(indexScreen);
if (entry.screenId >= mHotseatSize) {
entriesToRemove.add(entry.id);
continue;
}
try {
// calculate weight
switch (entry.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: {
entry.mIntent = c.getString(indexIntent);
verifyIntent(c.getString(indexIntent));
break;
}
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: {
int total = getFolderItemsCount(entry);
if (total == 0) {
throw new Exception("Folder is empty");
}
break;
}
default:
throw new Exception("Invalid item type");
}
} catch (Exception e) {
if (DEBUG) {
Log.d(TAG, "Removing item " + entry.id, e);
}
entriesToRemove.add(entry.id);
continue;
}
mHotseatEntries.add(entry);
}
removeEntryFromDb(mDb, entriesToRemove);
c.close();
return mHotseatEntries;
}
protected ArrayList<DbEntry> loadAllWorkspaceEntries() {
Cursor c = queryWorkspace(
new String[]{
LauncherSettings.Favorites._ID, // 0
LauncherSettings.Favorites.ITEM_TYPE, // 1
LauncherSettings.Favorites.SCREEN, // 2
LauncherSettings.Favorites.CELLX, // 3
LauncherSettings.Favorites.CELLY, // 4
LauncherSettings.Favorites.SPANX, // 5
LauncherSettings.Favorites.SPANY, // 6
LauncherSettings.Favorites.INTENT, // 7
LauncherSettings.Favorites.APPWIDGET_PROVIDER, // 8
LauncherSettings.Favorites.APPWIDGET_ID}, // 9
LauncherSettings.Favorites.CONTAINER + " = "
+ LauncherSettings.Favorites.CONTAINER_DESKTOP);
return loadWorkspaceEntries(c);
}
protected ArrayList<DbEntry> loadWorkspaceEntries(int screen) {
Cursor c = queryWorkspace(
new String[]{
LauncherSettings.Favorites._ID, // 0
LauncherSettings.Favorites.ITEM_TYPE, // 1
LauncherSettings.Favorites.SCREEN, // 2
LauncherSettings.Favorites.CELLX, // 3
LauncherSettings.Favorites.CELLY, // 4
LauncherSettings.Favorites.SPANX, // 5
LauncherSettings.Favorites.SPANY, // 6
LauncherSettings.Favorites.INTENT, // 7
LauncherSettings.Favorites.APPWIDGET_PROVIDER, // 8
LauncherSettings.Favorites.APPWIDGET_ID}, // 9
LauncherSettings.Favorites.CONTAINER + " = "
+ LauncherSettings.Favorites.CONTAINER_DESKTOP
+ " AND " + LauncherSettings.Favorites.SCREEN + " = " + screen);
return loadWorkspaceEntries(c);
}
private ArrayList<DbEntry> loadWorkspaceEntries(Cursor c) {
final int indexId = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
final int indexItemType = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
final int indexScreen = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
final int indexCellX = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
final int indexCellY = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
final int indexSpanX = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
final int indexSpanY = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
final int indexIntent = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
final int indexAppWidgetProvider = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.APPWIDGET_PROVIDER);
final int indexAppWidgetId = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.APPWIDGET_ID);
IntArray entriesToRemove = new IntArray();
WidgetManagerHelper widgetManagerHelper = new WidgetManagerHelper(mContext);
while (c.moveToNext()) {
DbEntry entry = new DbEntry();
entry.id = c.getInt(indexId);
entry.itemType = c.getInt(indexItemType);
entry.screenId = c.getInt(indexScreen);
mLastScreenId = Math.max(mLastScreenId, entry.screenId);
entry.cellX = c.getInt(indexCellX);
entry.cellY = c.getInt(indexCellY);
entry.spanX = c.getInt(indexSpanX);
entry.spanY = c.getInt(indexSpanY);
try {
// calculate weight
switch (entry.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: {
entry.mIntent = c.getString(indexIntent);
verifyIntent(entry.mIntent);
break;
}
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: {
entry.mProvider = c.getString(indexAppWidgetProvider);
ComponentName cn = ComponentName.unflattenFromString(entry.mProvider);
verifyPackage(cn.getPackageName());
int widgetId = c.getInt(indexAppWidgetId);
LauncherAppWidgetProviderInfo pInfo =
widgetManagerHelper.getLauncherAppWidgetInfo(widgetId);
Point spans = null;
if (pInfo != null) {
spans = pInfo.getMinSpans();
}
if (spans != null) {
entry.minSpanX = spans.x > 0 ? spans.x : entry.spanX;
entry.minSpanY = spans.y > 0 ? spans.y : entry.spanY;
} else {
// Assume that the widget be resized down to 2x2
entry.minSpanX = entry.minSpanY = 2;
}
break;
}
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: {
int total = getFolderItemsCount(entry);
if (total == 0) {
throw new Exception("Folder is empty");
}
break;
}
default:
throw new Exception("Invalid item type");
}
} catch (Exception e) {
if (DEBUG) {
Log.d(TAG, "Removing item " + entry.id, e);
}
entriesToRemove.add(entry.id);
continue;
}
mWorkspaceEntries.add(entry);
}
removeEntryFromDb(mDb, entriesToRemove);
c.close();
return mWorkspaceEntries;
}
private int getFolderItemsCount(DbEntry entry) {
Cursor c = queryWorkspace(
new String[]{LauncherSettings.Favorites._ID, LauncherSettings.Favorites.INTENT},
LauncherSettings.Favorites.CONTAINER + " = " + entry.id);
int total = 0;
while (c.moveToNext()) {
try {
String intent = c.getString(1);
verifyIntent(intent);
total++;
entry.mFolderItems.add(intent);
} catch (Exception e) {
removeEntryFromDb(mDb, IntArray.wrap(c.getInt(0)));
}
}
c.close();
return total;
}
private Cursor queryWorkspace(String[] columns, String where) {
return mDb.query(mTableName, columns, where, null, null, null, null);
}
/** Verifies if the mIntent should be restored. */
private void verifyIntent(String intentStr)
throws Exception {
Intent intent = Intent.parseUri(intentStr, 0);
if (intent.getComponent() != null) {
verifyPackage(intent.getComponent().getPackageName());
} else if (intent.getPackage() != null) {
// Only verify package if the component was null.
verifyPackage(intent.getPackage());
}
}
/** Verifies if the package should be restored */
private void verifyPackage(String packageName)
throws Exception {
if (!mValidPackages.contains(packageName)) {
// TODO(b/151468819): Handle promise app icon restoration during grid migration.
throw new Exception("Package not available");
}
}
}
protected static class DbEntry extends ItemInfo implements Comparable<DbEntry> {
private String mIntent;
private String mProvider;
private Set<String> mFolderItems = new HashSet<>();
/** Comparator according to the reading order */
@Override
public int compareTo(DbEntry another) {
if (screenId != another.screenId) {
return Integer.compare(screenId, another.screenId);
}
if (cellY != another.cellY) {
return -Integer.compare(cellY, another.cellY);
}
return Integer.compare(cellX, another.cellX);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DbEntry entry = (DbEntry) o;
return Objects.equals(mIntent, entry.mIntent);
}
@Override
public int hashCode() {
return Objects.hash(mIntent);
}
public void updateContentValues(ContentValues values) {
values.put(LauncherSettings.Favorites.SCREEN, screenId);
values.put(LauncherSettings.Favorites.CELLX, cellX);
values.put(LauncherSettings.Favorites.CELLY, cellY);
values.put(LauncherSettings.Favorites.SPANX, spanX);
values.put(LauncherSettings.Favorites.SPANY, spanY);
}
public String getIntentStr() {
return mIntent;
}
}
}
@@ -118,13 +118,20 @@ public class LauncherDbUtils {
db.execSQL("DROP TABLE IF EXISTS " + tableName);
}
/** Copy from table to the to table. */
public static void copyTable(SQLiteDatabase db, String from, String to, Context context) {
/** Copy fromTable in fromDb to toTable in toDb. */
public static void copyTable(SQLiteDatabase fromDb, String fromTable, SQLiteDatabase toDb,
String toTable, Context context) {
long userSerial = UserCache.INSTANCE.get(context).getSerialNumberForUser(
Process.myUserHandle());
dropTable(db, to);
Favorites.addTableToDb(db, userSerial, false, to);
db.execSQL("INSERT INTO " + to + " SELECT * FROM " + from);
dropTable(toDb, toTable);
Favorites.addTableToDb(toDb, userSerial, false, toTable);
if (fromDb != toDb) {
toDb.execSQL("ATTACH DATABASE '" + fromDb.getPath() + "' AS from_db");
toDb.execSQL(
"INSERT INTO " + toTable + " SELECT * FROM from_db." + fromTable);
} else {
toDb.execSQL("INSERT INTO " + toTable + " SELECT * FROM " + fromTable);
}
}
/**
@@ -0,0 +1,155 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.states;
import android.view.animation.Interpolator;
import androidx.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Utility class for building animator set
*/
public class StateAnimationConfig {
// We separate the state animations into "atomic" and "non-atomic" components. The atomic
// components may be run atomically - that is, all at once, instead of user-controlled. However,
// atomic components are not restricted to this purpose; they can be user-controlled alongside
// non atomic components as well. Note that each gesture model has exactly one atomic component,
// PLAY_ATOMIC_OVERVIEW_SCALE *or* PLAY_ATOMIC_OVERVIEW_PEEK.
@IntDef(flag = true, value = {
PLAY_NON_ATOMIC,
PLAY_ATOMIC_OVERVIEW_SCALE,
PLAY_ATOMIC_OVERVIEW_PEEK,
SKIP_OVERVIEW,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AnimationFlags {}
public static final int PLAY_NON_ATOMIC = 1 << 0;
public static final int PLAY_ATOMIC_OVERVIEW_SCALE = 1 << 1;
public static final int PLAY_ATOMIC_OVERVIEW_PEEK = 1 << 2;
public static final int SKIP_OVERVIEW = 1 << 3;
public long duration;
public boolean userControlled;
public @AnimationFlags int animFlags = ANIM_ALL_COMPONENTS;
public static final int ANIM_ALL_COMPONENTS = PLAY_NON_ATOMIC | PLAY_ATOMIC_OVERVIEW_SCALE
| PLAY_ATOMIC_OVERVIEW_PEEK;
// Various types of animation state transition
@IntDef(value = {
ANIM_VERTICAL_PROGRESS,
ANIM_WORKSPACE_SCALE,
ANIM_WORKSPACE_TRANSLATE,
ANIM_WORKSPACE_FADE,
ANIM_HOTSEAT_SCALE,
ANIM_HOTSEAT_TRANSLATE,
ANIM_OVERVIEW_SCALE,
ANIM_OVERVIEW_TRANSLATE_X,
ANIM_OVERVIEW_TRANSLATE_Y,
ANIM_OVERVIEW_FADE,
ANIM_ALL_APPS_FADE,
ANIM_OVERVIEW_SCRIM_FADE,
ANIM_ALL_APPS_HEADER_FADE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AnimType {}
public static final int ANIM_VERTICAL_PROGRESS = 0;
public static final int ANIM_WORKSPACE_SCALE = 1;
public static final int ANIM_WORKSPACE_TRANSLATE = 2;
public static final int ANIM_WORKSPACE_FADE = 3;
public static final int ANIM_HOTSEAT_SCALE = 4;
public static final int ANIM_HOTSEAT_TRANSLATE = 5;
public static final int ANIM_OVERVIEW_SCALE = 6;
public static final int ANIM_OVERVIEW_TRANSLATE_X = 7;
public static final int ANIM_OVERVIEW_TRANSLATE_Y = 8;
public static final int ANIM_OVERVIEW_FADE = 9;
public static final int ANIM_ALL_APPS_FADE = 10;
public static final int ANIM_OVERVIEW_SCRIM_FADE = 11;
public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions
private static final int ANIM_TYPES_COUNT = 13;
private final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
public StateAnimationConfig() { }
/**
* Copies the config to target
*/
public void copyTo(StateAnimationConfig target) {
target.duration = duration;
target.animFlags = animFlags;
target.userControlled = userControlled;
for (int i = 0; i < ANIM_TYPES_COUNT; i++) {
target.mInterpolators[i] = mInterpolators[i];
}
}
/**
* Returns the interpolator set for animId or fallback if nothing is set
*
* @see #setInterpolator(int, Interpolator)
*/
public Interpolator getInterpolator(@AnimType int animId, Interpolator fallback) {
return mInterpolators[animId] == null ? fallback : mInterpolators[animId];
}
/**
* Sets an interpolator for a given animation type
*/
public void setInterpolator(@AnimType int animId, Interpolator interpolator) {
mInterpolators[animId] = interpolator;
}
/**
* @return Whether Overview is scaling as part of this animation. If this is the only
* component (i.e. NON_ATOMIC_COMPONENT isn't included), then this scaling is happening
* atomically, rather than being part of a normal state animation. StateHandlers can use
* this to designate part of their animation that should scale with Overview.
*/
public boolean playAtomicOverviewScaleComponent() {
return hasAnimationFlag(StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE);
}
/**
* @return Whether this animation will play atomically at the same time as a different,
* user-controlled state transition. StateHandlers, which contribute to both animations, can
* use this to avoid animating the same properties in both animations, since they'd conflict
* with one another.
*/
public boolean onlyPlayAtomicComponent() {
return getAnimComponents() == StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE
|| getAnimComponents() == StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
}
/**
* Returns true if the config and any of the provided component flags
*/
public boolean hasAnimationFlag(@AnimationFlags int a) {
return (animFlags & a) != 0;
}
/**
* @return Only the flags that determine which animation components to play.
*/
public @AnimationFlags int getAnimComponents() {
return animFlags & StateAnimationConfig.ANIM_ALL_COMPONENTS;
}
}
@@ -19,11 +19,11 @@ import static com.android.launcher3.LauncherAnimUtils.MIN_PROGRESS_TO_ALL_APPS;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherStateManager.ANIM_ALL_COMPONENTS;
import static com.android.launcher3.LauncherStateManager.PLAY_ATOMIC_OVERVIEW_SCALE;
import static com.android.launcher3.LauncherStateManager.PLAY_NON_ATOMIC;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_NON_ATOMIC;
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
import android.animation.Animator;
@@ -37,12 +37,12 @@ import android.view.MotionEvent;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationFlags;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
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;
@@ -358,14 +358,18 @@ public abstract class AbstractStateChangeTouchController
private AnimatorSet createAtomicAnimForState(LauncherState fromState, LauncherState targetState,
long duration) {
AnimatorSetBuilder builder = getAnimatorSetBuilderForStates(fromState, targetState);
return mLauncher.getStateManager().createAtomicAnimation(fromState, targetState, builder,
PLAY_ATOMIC_OVERVIEW_SCALE, duration);
StateAnimationConfig config = getConfigForStates(fromState, targetState);
config.animFlags = PLAY_ATOMIC_OVERVIEW_SCALE;
config.duration = duration;
return mLauncher.getStateManager().createAtomicAnimation(fromState, targetState, config);
}
protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState,
LauncherState toState) {
return new AnimatorSetBuilder();
/**
* Returns animation config for state transition between provided states
*/
protected StateAnimationConfig getConfigForStates(
LauncherState fromState, LauncherState toState) {
return new StateAnimationConfig();
}
@Override
@@ -23,7 +23,7 @@ import android.view.MotionEvent;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationFlags;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
@@ -16,8 +16,8 @@
package com.android.launcher3.widget;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Rect;
@@ -28,16 +28,15 @@ import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.android.launcher3.Insettable;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.ResourceUtils;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.util.PackageUserKey;
@@ -156,7 +155,7 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable {
setupNavBarColor();
mOpenCloseAnimator.setValues(
PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
mOpenCloseAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mOpenCloseAnimator.setInterpolator(FAST_OUT_SLOW_IN);
mOpenCloseAnimator.start();
}
@@ -191,9 +190,9 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable {
mIsOpen ? R.string.widgets_list : R.string.widgets_list_closed));
}
@Nullable
@Override
public Animator createHintCloseAnim(float distanceToMove) {
return ObjectAnimator.ofInt(this, PADDING_BOTTOM, (int) (distanceToMove + mInsets.bottom));
public void addHintCloseAnim(
float distanceToMove, Interpolator interpolator, PendingAnimation target) {
target.setInt(this, PADDING_BOTTOM, (int) (distanceToMove + mInsets.bottom), interpolator);
}
}
@@ -15,12 +15,11 @@
*/
package com.android.launcher3.widget;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.testing.TestProtocol.NORMAL_STATE_ORDINAL;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Rect;
@@ -30,8 +29,8 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Insettable;
@@ -39,6 +38,7 @@ import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.R;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.TopRoundedCornerView;
@@ -242,13 +242,11 @@ public class WidgetsFullSheet extends BaseWidgetSheet
return mAdapter.getItemCount();
}
@Nullable
@Override
public Animator createHintCloseAnim(float distanceToMove) {
AnimatorSet anim = new AnimatorSet();
anim.play(ObjectAnimator.ofFloat(mRecyclerView, TRANSLATION_Y, -distanceToMove));
anim.play(ObjectAnimator.ofFloat(mRecyclerView, ALPHA, 0.5f));
return anim;
public void addHintCloseAnim(
float distanceToMove, Interpolator interpolator, PendingAnimation target) {
target.setFloat(mRecyclerView, VIEW_TRANSLATE_Y, -distanceToMove, interpolator);
target.setViewAlpha(mRecyclerView, 0.5f, interpolator);
}
@Override
@@ -19,10 +19,12 @@ package com.android.launcher3.uioverrides;
import android.util.IntProperty;
import android.view.View;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.states.StateAnimationConfig;
/**
* Controls the blur, for the Launcher surface only.
@@ -52,6 +54,6 @@ public class BackgroundBlurController implements LauncherStateManager.StateHandl
public void setState(LauncherState toState) {}
@Override
public void setStateWithAnimation(LauncherState toState, AnimatorSetBuilder builder,
LauncherStateManager.AnimationConfig config) {}
public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
PendingAnimation animation) { }
}
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.uioverrides;
import android.content.Context;
import android.os.Bundle;
/** Render preview using surface view. */
public class PreviewSurfaceRenderer {
/** Handle a received surface view request. */
public static void render(Context context, Bundle bundle) { }
}