Remove hotseat space from workspace in DeviceProfile if taskbar is present, and instantly swap between taskbar and hotseat when entering SpringLoadedMode. To allow for an exact handoff, we also scale up the TaskbarView such that its icons match the hotseat icon size when on the home screen. Note that this CL only supports dragging to the taskbar, not out of it (which still triggers system drag and drop instead). Test: In RTL and LTR, drag a workspace item and ensure hotseat seamlessly swaps with the taskbar hotseat and allows drops. Bug: 179886115 Bug: 171917176 Change-Id: Id6462075b9b0b66b06d51a78c9c0b3e11e83e84d
244 lines
12 KiB
Java
244 lines
12 KiB
Java
/*
|
|
* Copyright (C) 2015 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 static androidx.dynamicanimation.animation.DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE;
|
|
|
|
import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
|
|
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.LauncherState.FLAG_HAS_SYS_UI_SCRIM;
|
|
import static com.android.launcher3.LauncherState.FLAG_WORKSPACE_HAS_BACKGROUNDS;
|
|
import static com.android.launcher3.LauncherState.HINT_STATE;
|
|
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
|
|
import static com.android.launcher3.LauncherState.NORMAL;
|
|
import static com.android.launcher3.LauncherState.WORKSPACE_PAGE_INDICATOR;
|
|
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.Scrim.SCRIM_PROGRESS;
|
|
import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS;
|
|
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_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_WORKSPACE_FADE;
|
|
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
|
|
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
|
|
|
|
import android.animation.ValueAnimator;
|
|
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.allapps.AllAppsContainerView;
|
|
import com.android.launcher3.anim.PendingAnimation;
|
|
import com.android.launcher3.anim.PropertySetter;
|
|
import com.android.launcher3.anim.SpringAnimationBuilder;
|
|
import com.android.launcher3.graphics.SysUiScrim;
|
|
import com.android.launcher3.graphics.WorkspaceDragScrim;
|
|
import com.android.launcher3.states.StateAnimationConfig;
|
|
import com.android.launcher3.util.DynamicResource;
|
|
import com.android.systemui.plugins.ResourceProvider;
|
|
|
|
/**
|
|
* Manages the animations between each of the workspace states.
|
|
*/
|
|
public class WorkspaceStateTransitionAnimation {
|
|
|
|
private final Launcher mLauncher;
|
|
private final Workspace mWorkspace;
|
|
|
|
private float mNewScale;
|
|
|
|
public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace workspace) {
|
|
mLauncher = launcher;
|
|
mWorkspace = workspace;
|
|
}
|
|
|
|
public void setState(LauncherState toState) {
|
|
setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig());
|
|
}
|
|
|
|
/**
|
|
* @see com.android.launcher3.statemanager.StateManager.StateHandler#setStateWithAnimation
|
|
*/
|
|
public void setStateWithAnimation(
|
|
LauncherState toState, StateAnimationConfig config, PendingAnimation animation) {
|
|
setWorkspaceProperty(toState, animation, config);
|
|
}
|
|
|
|
public float getFinalScale() {
|
|
return mNewScale;
|
|
}
|
|
|
|
/**
|
|
* Starts a transition animation for the workspace.
|
|
*/
|
|
private void setWorkspaceProperty(LauncherState state, PropertySetter propertySetter,
|
|
StateAnimationConfig config) {
|
|
ScaleAndTranslation scaleAndTranslation = state.getWorkspaceScaleAndTranslation(mLauncher);
|
|
ScaleAndTranslation hotseatScaleAndTranslation = state.getHotseatScaleAndTranslation(
|
|
mLauncher);
|
|
ScaleAndTranslation qsbScaleAndTranslation = state.getQsbScaleAndTranslation(mLauncher);
|
|
mNewScale = scaleAndTranslation.scale;
|
|
PageAlphaProvider pageAlphaProvider = state.getWorkspacePageAlphaProvider(mLauncher);
|
|
final int childCount = mWorkspace.getChildCount();
|
|
for (int i = 0; i < childCount; i++) {
|
|
applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, pageAlphaProvider,
|
|
propertySetter, config);
|
|
}
|
|
|
|
int elements = state.getVisibleElements(mLauncher);
|
|
Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
|
|
pageAlphaProvider.interpolator);
|
|
boolean playAtomicComponent = config.playAtomicOverviewScaleComponent();
|
|
Hotseat hotseat = mWorkspace.getHotseat();
|
|
// Since we set the pivot relative to mWorkspace, we need to scale a sibling of Workspace.
|
|
AllAppsContainerView qsbScaleView = mLauncher.getAppsView();
|
|
View qsbView = qsbScaleView.getSearchView();
|
|
if (playAtomicComponent) {
|
|
Interpolator scaleInterpolator = config.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
|
|
LauncherState fromState = mLauncher.getStateManager().getState();
|
|
boolean shouldSpring = propertySetter instanceof PendingAnimation
|
|
&& fromState == HINT_STATE && state == NORMAL;
|
|
if (shouldSpring) {
|
|
((PendingAnimation) propertySetter).add(getSpringScaleAnimator(mLauncher,
|
|
mWorkspace, mNewScale));
|
|
} else {
|
|
propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
|
|
}
|
|
|
|
setPivotToScaleWithWorkspace(hotseat);
|
|
setPivotToScaleWithWorkspace(qsbScaleView);
|
|
float hotseatScale = hotseatScaleAndTranslation.scale;
|
|
if (shouldSpring) {
|
|
PendingAnimation pa = (PendingAnimation) propertySetter;
|
|
pa.add(getSpringScaleAnimator(mLauncher, hotseat, hotseatScale));
|
|
pa.add(getSpringScaleAnimator(mLauncher, qsbScaleView,
|
|
qsbScaleAndTranslation.scale));
|
|
} else {
|
|
Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE,
|
|
scaleInterpolator);
|
|
propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale,
|
|
hotseatScaleInterpolator);
|
|
propertySetter.setFloat(qsbScaleView, SCALE_PROPERTY, qsbScaleAndTranslation.scale,
|
|
hotseatScaleInterpolator);
|
|
}
|
|
|
|
float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
|
|
propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha,
|
|
config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator));
|
|
float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;
|
|
propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
|
|
workspacePageIndicatorAlpha, fadeInterpolator);
|
|
}
|
|
|
|
if (config.onlyPlayAtomicComponent()) {
|
|
// Only the alpha and scale, handled above, are included in the atomic animation.
|
|
return;
|
|
}
|
|
|
|
Interpolator translationInterpolator = !playAtomicComponent
|
|
? LINEAR
|
|
: 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 = config.getInterpolator(
|
|
ANIM_HOTSEAT_TRANSLATE, translationInterpolator);
|
|
propertySetter.setFloat(hotseat, VIEW_TRANSLATE_Y,
|
|
hotseatScaleAndTranslation.translationY, hotseatTranslationInterpolator);
|
|
propertySetter.setFloat(mWorkspace.getPageIndicator(), VIEW_TRANSLATE_Y,
|
|
hotseatScaleAndTranslation.translationY, hotseatTranslationInterpolator);
|
|
propertySetter.setFloat(qsbView, VIEW_TRANSLATE_Y,
|
|
qsbScaleAndTranslation.translationY, hotseatTranslationInterpolator);
|
|
|
|
setScrim(propertySetter, state);
|
|
}
|
|
|
|
/**
|
|
* Set the given view's pivot point to match the workspace's, so that it scales together. Since
|
|
* both this view and workspace can move, transform the point manually instead of using
|
|
* dragLayer.getDescendantCoordRelativeToSelf and related methods.
|
|
*/
|
|
private void setPivotToScaleWithWorkspace(View sibling) {
|
|
sibling.setPivotY(mWorkspace.getPivotY() + mWorkspace.getTop()
|
|
- sibling.getTop() - sibling.getTranslationY());
|
|
sibling.setPivotX(mWorkspace.getPivotX() + mWorkspace.getLeft()
|
|
- sibling.getLeft() - sibling.getTranslationX());
|
|
}
|
|
|
|
public void setScrim(PropertySetter propertySetter, LauncherState state) {
|
|
WorkspaceDragScrim workspaceDragScrim = mLauncher.getDragLayer().getWorkspaceDragScrim();
|
|
propertySetter.setFloat(workspaceDragScrim, SCRIM_PROGRESS,
|
|
state.getWorkspaceScrimAlpha(mLauncher), LINEAR);
|
|
|
|
SysUiScrim sysUiScrim = mLauncher.getDragLayer().getSysUiScrim();
|
|
propertySetter.setFloat(sysUiScrim, SYSUI_PROGRESS,
|
|
state.hasFlag(FLAG_HAS_SYS_UI_SCRIM) ? 1 : 0, LINEAR);
|
|
}
|
|
|
|
public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
|
|
applyChildState(state, cl, childIndex, state.getWorkspacePageAlphaProvider(mLauncher),
|
|
NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig());
|
|
}
|
|
|
|
private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
|
|
PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter,
|
|
StateAnimationConfig config) {
|
|
float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex);
|
|
int drawableAlpha = state.hasFlag(FLAG_WORKSPACE_HAS_BACKGROUNDS)
|
|
? Math.round(pageAlpha * 255) : 0;
|
|
|
|
if (!config.onlyPlayAtomicComponent()) {
|
|
// Don't update the scrim during the atomic animation.
|
|
propertySetter.setInt(cl.getScrimBackground(),
|
|
DRAWABLE_ALPHA, drawableAlpha, ZOOM_OUT);
|
|
}
|
|
if (config.playAtomicOverviewScaleComponent()) {
|
|
Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
|
|
pageAlphaProvider.interpolator);
|
|
propertySetter.setFloat(cl.getShortcutsAndWidgets(), VIEW_ALPHA,
|
|
pageAlpha, fadeInterpolator);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a spring based animator for the scale property of {@param v}.
|
|
*/
|
|
public static ValueAnimator getSpringScaleAnimator(Launcher launcher, View v, float scale) {
|
|
ResourceProvider rp = DynamicResource.provider(launcher);
|
|
float damping = rp.getFloat(R.dimen.hint_scale_damping_ratio);
|
|
float stiffness = rp.getFloat(R.dimen.hint_scale_stiffness);
|
|
float velocityPxPerS = rp.getDimension(R.dimen.hint_scale_velocity_dp_per_s);
|
|
|
|
return new SpringAnimationBuilder(v.getContext())
|
|
.setStiffness(stiffness)
|
|
.setDampingRatio(damping)
|
|
.setMinimumVisibleChange(MIN_VISIBLE_CHANGE_SCALE)
|
|
.setEndValue(scale)
|
|
.setStartValue(SCALE_PROPERTY.get(v))
|
|
.setStartVelocity(velocityPxPerS)
|
|
.build(v, SCALE_PROPERTY);
|
|
|
|
}
|
|
} |