Adding state manager to fallback recents activity

Bug: 156398988
Change-Id: Id0a106ef888ade5223940ac8243108c39b4d6b98
This commit is contained in:
Sunny Goyal
2020-05-11 20:34:17 -07:00
parent 7dcd4d6ed6
commit 3f948e3f42
11 changed files with 508 additions and 340 deletions
@@ -17,6 +17,7 @@ package com.android.launcher3.uioverrides.states;
import android.content.Context;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -54,11 +55,7 @@ public class BackgroundAppState extends OverviewState {
@Override
public float[] getOverviewScaleAndOffset(Launcher launcher) {
return new float[] {getOverviewScale(launcher), NO_OFFSET};
}
private float getOverviewScale(Launcher launcher) {
return ((RecentsView) launcher.getOverviewPanel()).getMaxScaleForFullScreen();
return getOverviewScaleAndOffsetForBackgroundState(launcher);
}
@Override
@@ -88,4 +85,11 @@ public class BackgroundAppState extends OverviewState {
protected float getDepthUnchecked(Context context) {
return 1f;
}
public static float[] getOverviewScaleAndOffsetForBackgroundState(
BaseDraggingActivity activity) {
return new float[] {
((RecentsView) activity.getOverviewPanel()).getMaxScaleForFullScreen(),
NO_OFFSET};
}
}
@@ -19,6 +19,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -49,22 +50,25 @@ public class OverviewModalTaskState extends OverviewState {
@Override
public float[] getOverviewScaleAndOffset(Launcher launcher) {
Resources res = launcher.getBaseContext().getResources();
Rect out = new Rect();
launcher.<RecentsView>getOverviewPanel().getTaskSize(out);
int taskHeight = out.height();
float topMargin = res.getDimension(R.dimen.task_thumbnail_top_margin);
float bottomMargin = res.getDimension(R.dimen.overview_actions_top_margin);
float newHeight = taskHeight + topMargin + bottomMargin;
float scale = newHeight / taskHeight;
return new float[] {scale, 0};
return getOverviewScaleAndOffsetForModalState(launcher);
}
@Override
public float getOverviewModalness() {
return 1.0f;
}
public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) {
Resources res = activity.getResources();
Rect out = new Rect();
activity.<RecentsView>getOverviewPanel().getTaskSize(out);
int taskHeight = out.height();
float topMargin = res.getDimension(R.dimen.task_thumbnail_top_margin);
float bottomMargin = res.getDimension(R.dimen.overview_actions_top_margin);
float newHeight = taskHeight + topMargin + bottomMargin;
float scale = newHeight / taskHeight;
return new float[] {scale, NO_OFFSET};
}
}
@@ -15,14 +15,15 @@
*/
package com.android.quickstep;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.fallback.FallbackRecentsView.ZOOM_PROGRESS;
import static com.android.quickstep.fallback.RecentsState.BACKGROUND_APP;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.util.WindowSizeStrategy.FALLBACK_RECENTS_SIZE_STRATEGY;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
@@ -30,6 +31,7 @@ import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.util.ActivityInitListener;
@@ -89,15 +91,13 @@ public final class FallbackActivityInterface implements
public AnimationFactory prepareRecentsUI(
boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
RecentsActivity activity = getCreatedActivity();
if (activityVisible) {
if (activity == null) {
return (transitionLength) -> { };
}
activity.getStateManager().goToState(BACKGROUND_APP);
FallbackRecentsView rv = activity.getOverviewPanel();
rv.setContentAlpha(0);
rv.getClearAllButton().setVisibilityAlpha(0);
rv.setDisallowScrollToClearAll(true);
rv.setInOverviewState(false);
return new AnimationFactory() {
@@ -115,23 +115,19 @@ public final class FallbackActivityInterface implements
@Override
public void createActivityInterface(long transitionLength) {
AnimatorSet animatorSet = new AnimatorSet();
PendingAnimation pa = new PendingAnimation(transitionLength * 2);
if (isAnimatingToRecents) {
ObjectAnimator anim = ObjectAnimator.ofFloat(rv, CONTENT_ALPHA, 0, 1);
anim.setDuration(transitionLength).setInterpolator(LINEAR);
animatorSet.play(anim);
pa.addFloat(rv, CONTENT_ALPHA, 0, 1, LINEAR);
}
ObjectAnimator anim = ObjectAnimator.ofFloat(rv, ZOOM_PROGRESS, 1, 0);
anim.setDuration(transitionLength).setInterpolator(LINEAR);
animatorSet.play(anim);
AnimatorPlaybackController controller =
AnimatorPlaybackController.wrap(animatorSet, transitionLength);
pa.addFloat(rv, SCALE_PROPERTY, rv.getMaxScaleForFullScreen(), 1, LINEAR);
pa.addFloat(rv, FULLSCREEN_PROGRESS, 1, 0, LINEAR);
AnimatorPlaybackController controller = pa.createPlaybackController();
// Since we are changing the start position of the UI, reapply the state, at the end
controller.setEndAction(() ->
rv.setInOverviewState(controller.getInterpolatedProgress() > 0.5));
controller.setEndAction(() -> activity.getStateManager().goToState(
controller.getInterpolatedProgress() > 0.5 ? DEFAULT : BACKGROUND_APP));
callback.accept(controller);
}
};
@@ -147,7 +143,7 @@ public final class FallbackActivityInterface implements
@Nullable
@Override
public RecentsActivity getCreatedActivity() {
return BaseRecentsActivity.ACTIVITY_TRACKER.getCreatedActivity();
return RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity();
}
@Nullable
@@ -37,10 +37,12 @@ import android.os.Bundle;
import android.util.ArrayMap;
import android.view.MotionEvent;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.util.ObjectWrapper;
import com.android.quickstep.BaseActivityInterface.AnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.util.RectFSpringAnim;
@@ -103,6 +105,12 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
private final PointF mEndVelocityPxPerMs = new PointF(0, 0.5f);
private RunningWindowAnim mFinishAnimation;
// Used to control Recents components throughout the swipe gesture.
private AnimatorPlaybackController mLauncherTransitionController;
private boolean mHasLauncherTransitionControllerStarted;
private AnimationFactory mAnimationFactory = (t) -> { };
public FallbackSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
GestureState gestureState, InputConsumerController inputConsumer,
boolean isLikelyToStartNewTask, boolean continuingLastGesture) {
@@ -165,10 +173,6 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
mRecentsView = mActivity.getOverviewPanel();
mRecentsView.setOnPageTransitionEndCallback(null);
linkRecentsViewScroll();
mRecentsView.setDisallowScrollToClearAll(true);
mRecentsView.getClearAllButton().setVisibilityAlpha(0);
mRecentsView.setZoomProgress(1);
if (!mContinuingLastGesture) {
if (mRunningOverHome) {
mRecentsView.onGestureAnimationStart(mGestureState.getRunningTask());
@@ -178,9 +182,48 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
}
mStateCallback.setStateOnUiThread(STATE_RECENTS_PRESENT);
mDeviceState.enableMultipleRegions(false);
mAnimationFactory = mActivityInterface.prepareRecentsUI(alreadyOnHome,
this::onAnimatorPlaybackControllerCreated);
mAnimationFactory.createActivityInterface(mTransitionDragLength);
return true;
}
@Override
protected void initTransitionEndpoints(DeviceProfile dp) {
super.initTransitionEndpoints(dp);
if (canCreateNewOrUpdateExistingLauncherTransitionController()) {
mAnimationFactory.createActivityInterface(mTransitionDragLength);
}
}
private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) {
mLauncherTransitionController = anim;
mLauncherTransitionController.dispatchSetInterpolator(t -> t * mDragLengthFactor);
mLauncherTransitionController.dispatchOnStart();
updateLauncherTransitionProgress();
}
private void updateLauncherTransitionProgress() {
if (mLauncherTransitionController == null
|| !canCreateNewOrUpdateExistingLauncherTransitionController()) {
return;
}
// Normalize the progress to 0 to 1, as the animation controller will clamp it to that
// anyway. The controller mimics the drag length factor by applying it to its interpolators.
float progress = mCurrentShift.value / mDragLengthFactor;
mLauncherTransitionController.setPlayFraction(progress);
}
/**
* We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME
* (it has its own animation) or if we're already animating the current controller.
* @return Whether we can create the launcher controller or update its progress.
*/
private boolean canCreateNewOrUpdateExistingLauncherTransitionController() {
return mGestureState.getEndTarget() != HOME && !mHasLauncherTransitionControllerStarted;
}
@Override
protected boolean moveWindowWithRecentsScroll() {
return mInQuickSwitchMode;
@@ -260,6 +303,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
}
applyWindowTransform();
updateLauncherTransitionProgress();
}
@Override
@@ -15,6 +15,9 @@
*/
package com.android.quickstep;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR_TRANSITION_DURATION;
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR_TRANSITION_PRE_DELAY;
@@ -29,21 +32,32 @@ import android.animation.AnimatorSet;
import android.app.ActivityOptions;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.view.View;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAnimationRunner;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.ObjectWrapper;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.fallback.FallbackRecentsStateController;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsRootView;
import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityOptionsCompat;
@@ -51,26 +65,40 @@ import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
* A recents activity that shows the recently launched tasks as swipable task cards.
* See {@link com.android.quickstep.views.RecentsView}.
*/
public final class RecentsActivity extends BaseRecentsActivity {
public final class RecentsActivity extends StatefulActivity<RecentsState> {
public static final String EXTRA_THUMBNAIL = "thumbnailData";
public static final String EXTRA_TASK_ID = "taskID";
public static final ActivityTracker<RecentsActivity> ACTIVITY_TRACKER =
new ActivityTracker<>();
private Handler mUiHandler = new Handler(Looper.getMainLooper());
private RecentsRootView mRecentsRootView;
private FallbackRecentsView mFallbackRecentsView;
private OverviewActionsView mActionsView;
@Override
private Configuration mOldConfig;
private StateManager<RecentsState> mStateManager;
/**
* Init drag layer and overview panel views.
*/
protected void initViews() {
setContentView(R.layout.fallback_recents_activity);
mRecentsRootView = findViewById(R.id.drag_layer);
mFallbackRecentsView = findViewById(R.id.overview_panel);
mActionsView = findViewById(R.id.overview_actions_view);
mRecentsRootView.recreateControllers();
mFallbackRecentsView.init(findViewById(R.id.overview_actions_view));
mFallbackRecentsView.init(mActionsView);
}
@Override
@@ -103,25 +131,38 @@ public final class RecentsActivity extends BaseRecentsActivity {
intent.removeExtra(EXTRA_TASK_ID);
intent.removeExtra(EXTRA_THUMBNAIL);
super.onNewIntent(intent);
ACTIVITY_TRACKER.handleNewIntent(this, intent);
}
@Override
/**
* Logic for when device configuration changes (rotation, screen size change, multi-window,
* etc.)
*/
protected void onHandleConfigChanged() {
super.onHandleConfigChanged();
mUserEventDispatcher = null;
initDeviceProfile();
AbstractFloatingView.closeOpenViews(this, true,
AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
dispatchDeviceProfileChanged();
reapplyUi();
mRecentsRootView.recreateControllers();
}
@Override
protected void reapplyUi() {
mRecentsRootView.dispatchInsets();
}
@Override
/**
* Generate the device profile to use in this activity.
* @return device profile
*/
protected DeviceProfile createDeviceProfile() {
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
DeviceProfile dp1 = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
// In case we are reusing IDP, create a copy so that we don't conflict with Launcher
// activity.
return (mRecentsRootView != null) && isInMultiWindowMode()
? dp.getMultiWindowProfile(this, getMultiWindowDisplaySize())
: super.createDeviceProfile();
: dp1.copy(this);
}
@Override
@@ -139,6 +180,10 @@ public final class RecentsActivity extends BaseRecentsActivity {
return (T) mFallbackRecentsView;
}
public OverviewActionsView getActionsView() {
return mActionsView;
}
@Override
public void returnToHomescreen() {
super.returnToHomescreen();
@@ -160,12 +205,7 @@ public final class RecentsActivity extends BaseRecentsActivity {
RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) {
AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets,
wallpaperTargets);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mFallbackRecentsView.resetViewUI();
}
});
anim.addListener(resetStateListener());
result.setAnimation(anim, RecentsActivity.this);
}
};
@@ -193,12 +233,7 @@ public final class RecentsActivity extends BaseRecentsActivity {
.createAdjacentPageAnimForTaskLaunch(taskView);
adjacentAnimation.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
adjacentAnimation.setDuration(RECENTS_LAUNCH_DURATION);
adjacentAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mFallbackRecentsView.resetTaskVisuals();
}
});
adjacentAnimation.addListener(resetStateListener());
target.play(adjacentAnimation);
}
return target;
@@ -210,13 +245,14 @@ public final class RecentsActivity extends BaseRecentsActivity {
// onActivityStart callback.
mFallbackRecentsView.setContentAlpha(1);
super.onStart();
mFallbackRecentsView.resetTaskVisuals();
}
@Override
protected void onStop() {
super.onStop();
mFallbackRecentsView.reset();
// Workaround for b/78520668, explicitly trim memory once UI is hidden
onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
}
@Override
@@ -228,4 +264,98 @@ public final class RecentsActivity extends BaseRecentsActivity {
public void onTaskLaunched() {
mFallbackRecentsView.resetTaskVisuals();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mStateManager = new StateManager<>(this, RecentsState.DEFAULT);
mOldConfig = new Configuration(getResources().getConfiguration());
initDeviceProfile();
initViews();
getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
ACTIVITY_TRACKER.handleCreate(this);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
int diff = newConfig.diff(mOldConfig);
if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) {
onHandleConfigChanged();
}
mOldConfig.setTo(newConfig);
super.onConfigurationChanged(newConfig);
}
/**
* Initialize/update the device profile.
*/
private void initDeviceProfile() {
mDeviceProfile = createDeviceProfile();
onDeviceProfileInitiated();
}
@Override
public void onEnterAnimationComplete() {
super.onEnterAnimationComplete();
// After the transition to home, enable the high-res thumbnail loader if it wasn't enabled
// as a part of quickstep, so that high-res thumbnails can load the next time we enter
// overview
RecentsModel.INSTANCE.get(this).getThumbnailCache()
.getHighResLoadingState().setVisible(true);
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
RecentsModel.INSTANCE.get(this).onTrimMemory(level);
}
@Override
protected void onDestroy() {
super.onDestroy();
ACTIVITY_TRACKER.onActivityDestroyed(this);
}
@Override
public void onBackPressed() {
// TODO: Launch the task we came from
startHome();
}
public void startHome() {
startActivity(new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
@Override
protected StateHandler<RecentsState>[] createStateHandlers() {
return new StateHandler[] { new FallbackRecentsStateController(this) };
}
@Override
public StateManager<RecentsState> getStateManager() {
return mStateManager;
}
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
super.dump(prefix, fd, writer, args);
writer.println(prefix + "Misc:");
dumpMisc(prefix + "\t", writer);
}
private AnimatorListenerAdapter resetStateListener() {
return new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mFallbackRecentsView.resetTaskVisuals();
mStateManager.reapplyState();
}
};
}
}
@@ -0,0 +1,94 @@
/*
* 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.quickstep.fallback;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL;
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.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 static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.views.ClearAllButton;
/**
* State controller for fallback recents activity
*/
public class FallbackRecentsStateController implements StateHandler<RecentsState> {
private final StateAnimationConfig mNoConfig = new StateAnimationConfig();
private final RecentsActivity mActivity;
private final FallbackRecentsView mRecentsView;
public FallbackRecentsStateController(RecentsActivity activity) {
mActivity = activity;
mRecentsView = activity.getOverviewPanel();
}
@Override
public void setState(RecentsState state) {
mRecentsView.updateEmptyMessage();
mRecentsView.resetTaskVisuals();
setProperties(state, mNoConfig, PropertySetter.NO_ANIM_PROPERTY_SETTER);
}
@Override
public void setStateWithAnimation(RecentsState toState, StateAnimationConfig config,
PendingAnimation setter) {
if (!config.hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_PEEK | PLAY_ATOMIC_OVERVIEW_SCALE)) {
// The entire recents animation is played atomically.
return;
}
if (config.hasAnimationFlag(SKIP_OVERVIEW)) {
return;
}
// While animating into recents, update the visible task data as needed
setter.addOnFrameCallback(mRecentsView::loadVisibleTaskData);
mRecentsView.updateEmptyMessage();
setProperties(toState, config, setter);
}
private void setProperties(RecentsState state, StateAnimationConfig config,
PropertySetter setter) {
float buttonAlpha = state.hasButtons() ? 1 : 0;
setter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
buttonAlpha, LINEAR);
setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(),
MultiValueAlpha.VALUE, buttonAlpha, LINEAR);
float[] scaleAndOffset = state.getOverviewScaleAndOffset(mActivity);
setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndOffset[0],
config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
setter.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1],
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
setter.setFloat(mRecentsView, TASK_MODALNESS, state.getOverviewModalness(),
config.getInterpolator(ANIM_OVERVIEW_MODAL, LINEAR));
setter.setFloat(mRecentsView, FULLSCREEN_PROGRESS, state.isFullScreen() ? 1 : 0, LINEAR);
}
}
@@ -15,17 +15,17 @@
*/
package com.android.quickstep.fallback;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.fallback.RecentsState.MODAL_TASK;
import static com.android.quickstep.util.WindowSizeStrategy.FALLBACK_RECENTS_SIZE_STRATEGY;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.view.View;
import com.android.launcher3.Utilities;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
@@ -34,26 +34,9 @@ import com.android.systemui.shared.recents.model.Task.TaskKey;
import java.util.ArrayList;
public class FallbackRecentsView extends RecentsView<RecentsActivity> {
public static final FloatProperty<FallbackRecentsView> ZOOM_PROGRESS =
new FloatProperty<FallbackRecentsView> ("zoomInProgress") {
@Override
public void setValue(FallbackRecentsView view, float value) {
view.setZoomProgress(value);
}
@Override
public Float get(FallbackRecentsView view) {
return view.mZoomInProgress;
}
};
private float mZoomInProgress = 0;
private boolean mInOverviewState = true;
private float mZoomScale = 1f;
@TargetApi(Build.VERSION_CODES.R)
public class FallbackRecentsView extends RecentsView<RecentsActivity>
implements StateListener<RecentsState> {
private RunningTaskInfo mRunningTaskInfo;
@@ -63,6 +46,7 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
public FallbackRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr, FALLBACK_RECENTS_SIZE_STRATEGY);
mActivity.getStateManager().addStateListener(this);
}
@Override
@@ -77,71 +61,12 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
mActivity.startHome();
}
@Override
public void onViewAdded(View child) {
super.onViewAdded(child);
updateEmptyMessage();
}
@Override
public void onViewRemoved(View child) {
super.onViewRemoved(child);
updateEmptyMessage();
}
@Override
public void draw(Canvas canvas) {
maybeDrawEmptyMessage(canvas);
super.draw(canvas);
}
@Override
public void reset() {
super.reset();
resetViewUI();
}
@Override
public boolean shouldUseMultiWindowTaskSizeStrategy() {
// Just use the activity task size for multi-window as well.
return false;
}
public void resetViewUI() {
setZoomProgress(0);
resetTaskVisuals();
}
public void setInOverviewState(boolean inOverviewState) {
if (mInOverviewState != inOverviewState) {
mInOverviewState = inOverviewState;
if (mInOverviewState) {
resetTaskVisuals();
} else {
setZoomProgress(1);
}
}
}
@Override
public void resetTaskVisuals() {
super.resetTaskVisuals();
setFullscreenProgress(mFullscreenProgress);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mZoomScale = getMaxScaleForFullScreen();
setZoomProgress(mZoomInProgress);
}
public void setZoomProgress(float progress) {
mZoomInProgress = progress;
SCALE_PROPERTY.set(this, Utilities.mapRange(mZoomInProgress, 1, mZoomScale));
FULLSCREEN_PROGRESS.set(this, mZoomInProgress);
}
public void onGestureAnimationStart(RunningTaskInfo runningTaskInfo) {
mRunningTaskInfo = runningTaskInfo;
onGestureAnimationStart(runningTaskInfo == null ? -1 : runningTaskInfo.taskId);
@@ -178,4 +103,37 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
}
super.applyLoadPlan(tasks);
}
@Override
public void setModalStateEnabled(boolean isModalState) {
super.setModalStateEnabled(isModalState);
if (isModalState) {
mActivity.getStateManager().goToState(RecentsState.MODAL_TASK);
} else {
if (mActivity.isInState(RecentsState.MODAL_TASK)) {
mActivity.getStateManager().goToState(DEFAULT);
}
}
}
@Override
public void onStateTransitionStart(RecentsState toState) {
setOverviewStateEnabled(true);
setFreezeViewVisibility(true);
}
@Override
public void onStateTransitionComplete(RecentsState finalState) {
setOverlayEnabled(finalState == DEFAULT || finalState == MODAL_TASK);
setFreezeViewVisibility(false);
}
@Override
public void setOverviewStateEnabled(boolean enabled) {
super.setOverviewStateEnabled(enabled);
if (enabled) {
RecentsState state = mActivity.getStateManager().getState();
setDisallowScrollToClearAll(!state.hasButtons());
}
}
}
@@ -0,0 +1,116 @@
/*
* 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.quickstep.fallback;
import static com.android.launcher3.uioverrides.states.BackgroundAppState.getOverviewScaleAndOffsetForBackgroundState;
import static com.android.launcher3.uioverrides.states.OverviewModalTaskState.getOverviewScaleAndOffsetForModalState;
import android.content.Context;
import com.android.launcher3.statemanager.BaseState;
import com.android.quickstep.RecentsActivity;
/**
* State definition for Fallback recents
*/
public class RecentsState implements BaseState<RecentsState> {
private static final int FLAG_MODAL = BaseState.getFlag(0);
private static final int FLAG_HAS_BUTTONS = BaseState.getFlag(1);
private static final int FLAG_FULL_SCREEN = BaseState.getFlag(2);
public static final RecentsState DEFAULT = new RecentsState(0, FLAG_HAS_BUTTONS);
public static final RecentsState MODAL_TASK = new ModalState(1,
FLAG_DISABLE_RESTORE | FLAG_HAS_BUTTONS | FLAG_MODAL);
public static final RecentsState BACKGROUND_APP = new BackgroundAppState(2,
FLAG_DISABLE_RESTORE | FLAG_NON_INTERACTIVE | FLAG_FULL_SCREEN);
public final int ordinal;
private final int mFlags;
private static final float NO_OFFSET = 0;
private static final float NO_SCALE = 1;
public RecentsState(int id, int flags) {
this.ordinal = id;
this.mFlags = flags;
}
@Override
public String toString() {
return "Ordinal-" + ordinal;
}
@Override
public final boolean hasFlag(int mask) {
return (mFlags & mask) != 0;
}
@Override
public int getTransitionDuration(Context context) {
return 250;
}
@Override
public RecentsState getHistoryForState(RecentsState previousState) {
return DEFAULT;
}
/**
* For this state, how modal should over view been shown. 0 modalness means all tasks drawn,
* 1 modalness means the current task is show on its own.
*/
public float getOverviewModalness() {
return hasFlag(FLAG_MODAL) ? 1 : 0;
}
public boolean isFullScreen() {
return hasFlag(FLAG_FULL_SCREEN);
}
public boolean hasButtons() {
return hasFlag(FLAG_HAS_BUTTONS);
}
public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
return new float[] { NO_SCALE, NO_OFFSET };
}
private static class ModalState extends RecentsState {
public ModalState(int id, int flags) {
super(id, flags);
}
@Override
public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
return getOverviewScaleAndOffsetForModalState(activity);
}
}
private static class BackgroundAppState extends RecentsState {
public BackgroundAppState(int id, int flags) {
super(id, flags);
}
@Override
public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
return getOverviewScaleAndOffsetForBackgroundState(activity);
}
}
}
@@ -31,11 +31,9 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import com.android.launcher3.BaseQuickstepLauncher;
@@ -123,24 +121,6 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
}
}
@Override
public void draw(Canvas canvas) {
maybeDrawEmptyMessage(canvas);
super.draw(canvas);
}
@Override
public void onViewAdded(View child) {
super.onViewAdded(child);
updateEmptyMessage();
}
@Override
protected void onTaskStackUpdated() {
// Lazily update the empty message only when the task stack is reapplied
updateEmptyMessage();
}
/**
* Animates adjacent tasks and translate hotseat off screen as well.
*/
@@ -550,6 +550,13 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
child.setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_LTR : View.LAYOUT_DIRECTION_RTL);
updateTaskStartIndex(child);
mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, false);
updateEmptyMessage();
}
@Override
public void draw(Canvas canvas) {
maybeDrawEmptyMessage(canvas);
super.draw(canvas);
}
private void updateTaskStartIndex(View affectingView) {
@@ -762,7 +769,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
return taskViewCount;
}
protected void onTaskStackUpdated() { }
protected void onTaskStackUpdated() {
// Lazily update the empty message only when the task stack is reapplied
updateEmptyMessage();
}
public void resetTaskVisuals() {
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
@@ -1,168 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
* A base fallback recents activity that provides support for device profile changes, activity
* lifecycle tracking, and basic input handling from recents.
*
* This class is only used as a fallback in case the default launcher does not have a recents
* implementation.
*/
public abstract class BaseRecentsActivity extends BaseDraggingActivity {
public static final ActivityTracker<BaseRecentsActivity> ACTIVITY_TRACKER =
new ActivityTracker<>();
private Configuration mOldConfig;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mOldConfig = new Configuration(getResources().getConfiguration());
initDeviceProfile();
initViews();
getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
ACTIVITY_TRACKER.handleCreate(this);
}
/**
* Init drag layer and overview panel views.
*/
abstract protected void initViews();
@Override
public void onConfigurationChanged(Configuration newConfig) {
int diff = newConfig.diff(mOldConfig);
if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) {
onHandleConfigChanged();
}
mOldConfig.setTo(newConfig);
super.onConfigurationChanged(newConfig);
}
/**
* Logic for when device configuration changes (rotation, screen size change, multi-window,
* etc.)
*/
protected void onHandleConfigChanged() {
mUserEventDispatcher = null;
initDeviceProfile();
AbstractFloatingView.closeOpenViews(this, true,
AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
dispatchDeviceProfileChanged();
reapplyUi();
}
/**
* Initialize/update the device profile.
*/
private void initDeviceProfile() {
mDeviceProfile = createDeviceProfile();
onDeviceProfileInitiated();
}
/**
* Generate the device profile to use in this activity.
* @return device profile
*/
protected DeviceProfile createDeviceProfile() {
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
// In case we are reusing IDP, create a copy so that we don't conflict with Launcher
// activity.
return dp.copy(this);
}
@Override
protected void onStop() {
super.onStop();
// Workaround for b/78520668, explicitly trim memory once UI is hidden
onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
}
@Override
public void onEnterAnimationComplete() {
super.onEnterAnimationComplete();
// After the transition to home, enable the high-res thumbnail loader if it wasn't enabled
// as a part of quickstep, so that high-res thumbnails can load the next time we enter
// overview
RecentsModel.INSTANCE.get(this).getThumbnailCache()
.getHighResLoadingState().setVisible(true);
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
RecentsModel.INSTANCE.get(this).onTrimMemory(level);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
ACTIVITY_TRACKER.handleNewIntent(this, intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
ACTIVITY_TRACKER.onActivityDestroyed(this);
}
@Override
public void onBackPressed() {
// TODO: Launch the task we came from
startHome();
}
public void startHome() {
startActivity(new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
super.dump(prefix, fd, writer, args);
writer.println(prefix + "Misc:");
dumpMisc(prefix + "\t", writer);
}
}