Merge "Merging from ub-launcher3-master @ build 6304996" into rvc-dev am: c83758f223 am: cd41f278a6
Change-Id: Ic181e659b711829f07716f5fc6547b162d1b2541
This commit is contained in:
+15
-13
@@ -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:
|
||||
|
||||
+10
-14
@@ -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) {
|
||||
|
||||
+9
-8
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-17
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+25
-19
@@ -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;
|
||||
|
||||
+18
-31
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -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();
|
||||
|
||||
+20
-21
@@ -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 */)
|
||||
|
||||
+26
-27
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+10
-1
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
+17
-4
@@ -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) {
|
||||
|
||||
+16
-20
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+21
-23
@@ -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()));
|
||||
});
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+34
-32
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) { }
|
||||
}
|
||||
Reference in New Issue
Block a user