mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-19 02:38:20 +00:00
Initial changes to break out AllApps into its own view.
- Moves launcher state-transition code into its own class - Moves all-apps related code into a separate view/set of classes - Implements a basic list view for all apps Change-Id: I68f174aa9e1bf82c4e46ce9549c78a8dc4623f46
This commit is contained in:
832
src/com/android/launcher3/LauncherStateTransitionAnimation.java
Normal file
832
src/com/android/launcher3/LauncherStateTransitionAnimation.java
Normal file
@@ -0,0 +1,832 @@
|
||||
/*
|
||||
* 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 android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.content.res.Resources;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewAnimationUtils;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* TODO: figure out what kind of tests we can write for this
|
||||
*
|
||||
* Things to test when changing the following class.
|
||||
* - Home from workspace
|
||||
* - from center screen
|
||||
* - from other screens
|
||||
* - Home from all apps
|
||||
* - from center screen
|
||||
* - from other screens
|
||||
* - Back from all apps
|
||||
* - from center screen
|
||||
* - from other screens
|
||||
* - Launch app from workspace and quit
|
||||
* - with back
|
||||
* - with home
|
||||
* - Launch app from all apps and quit
|
||||
* - with back
|
||||
* - with home
|
||||
* - Go to a screen that's not the default, then all
|
||||
* apps, and launch and app, and go back
|
||||
* - with back
|
||||
* -with home
|
||||
* - On workspace, long press power and go back
|
||||
* - with back
|
||||
* - with home
|
||||
* - On all apps, long press power and go back
|
||||
* - with back
|
||||
* - with home
|
||||
* - On workspace, power off
|
||||
* - On all apps, power off
|
||||
* - Launch an app and turn off the screen while in that app
|
||||
* - Go back with home key
|
||||
* - Go back with back key TODO: make this not go to workspace
|
||||
* - From all apps
|
||||
* - From workspace
|
||||
* - Enter and exit car mode (becuase it causes an extra configuration changed)
|
||||
* - From all apps
|
||||
* - From the center workspace
|
||||
* - From another workspace
|
||||
*/
|
||||
public class LauncherStateTransitionAnimation {
|
||||
|
||||
/**
|
||||
* Callbacks made during the state transition
|
||||
*/
|
||||
interface Callbacks {
|
||||
public void onStateTransitionHideSearchBar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Private callbacks made during transition setup.
|
||||
*/
|
||||
static abstract class PrivateTransitionCallbacks {
|
||||
void onRevealViewVisible(View revealView, View contentView, View allAppsButtonView) {}
|
||||
void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {}
|
||||
float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||
return 0;
|
||||
}
|
||||
float getMaterialRevealViewFinalXDrift(View revealView) {
|
||||
return 0;
|
||||
}
|
||||
float getMaterialRevealViewFinalYDrift(View revealView) {
|
||||
return 0;
|
||||
}
|
||||
float getMaterialRevealViewStartFinalRadius() {
|
||||
return 0;
|
||||
}
|
||||
AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(View revealView,
|
||||
View allAppsButtonView) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static final String TAG = "LauncherStateTransitionAnimation";
|
||||
|
||||
// Flags to determine how to set the layers on views before the transition animation
|
||||
public static final int BUILD_LAYER = 0;
|
||||
public static final int BUILD_AND_SET_LAYER = 1;
|
||||
public static final int SINGLE_FRAME_DELAY = 16;
|
||||
|
||||
private Launcher mLauncher;
|
||||
private Callbacks mCb;
|
||||
private AnimatorSet mStateAnimation;
|
||||
|
||||
public LauncherStateTransitionAnimation(Launcher l, Callbacks cb) {
|
||||
mLauncher = l;
|
||||
mCb = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an animation to the apps view.
|
||||
*/
|
||||
public void startAnimationToAllApps(final boolean animated) {
|
||||
final AppsContainerView toView = mLauncher.getAppsView();
|
||||
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
|
||||
private int[] mAllAppsToPanelDelta;
|
||||
|
||||
@Override
|
||||
public void onRevealViewVisible(View revealView, View contentView,
|
||||
View allAppsButtonView) {
|
||||
toView.setBackground(null);
|
||||
// Get the y delta between the center of the page and the center of the all apps
|
||||
// button
|
||||
mAllAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
|
||||
allAppsButtonView, null);
|
||||
}
|
||||
@Override
|
||||
public float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||
return 1f;
|
||||
}
|
||||
@Override
|
||||
public float getMaterialRevealViewFinalXDrift(View revealView) {
|
||||
return mAllAppsToPanelDelta[0];
|
||||
}
|
||||
@Override
|
||||
public float getMaterialRevealViewFinalYDrift(View revealView) {
|
||||
return mAllAppsToPanelDelta[1];
|
||||
}
|
||||
@Override
|
||||
public float getMaterialRevealViewStartFinalRadius() {
|
||||
int allAppsButtonSize = LauncherAppState.getInstance().
|
||||
getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
|
||||
return allAppsButtonSize / 2;
|
||||
}
|
||||
@Override
|
||||
public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
|
||||
final View revealView, final View allAppsButtonView) {
|
||||
return new AnimatorListenerAdapter() {
|
||||
public void onAnimationStart(Animator animation) {
|
||||
allAppsButtonView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
allAppsButtonView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
startAnimationToOverlay(Workspace.State.NORMAL_HIDDEN, toView, toView.getContentView(),
|
||||
toView.getRevealView(), null, animated, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an animation to the widgets view.
|
||||
*/
|
||||
public void startAnimationToWidgets(final boolean animated) {
|
||||
final AppsCustomizeTabHost toView = mLauncher.getWidgetsView();
|
||||
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
|
||||
@Override
|
||||
public void onRevealViewVisible(View revealView, View contentView,
|
||||
View allAppsButtonView) {
|
||||
// Hide the real page background, and swap in the fake one
|
||||
((AppsCustomizePagedView) contentView).setPageBackgroundsVisible(false);
|
||||
revealView.setBackground(mLauncher.getDrawable(R.drawable.quantum_panel_dark));
|
||||
}
|
||||
@Override
|
||||
public void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {
|
||||
// Show the real page background
|
||||
((AppsCustomizePagedView) contentView).setPageBackgroundsVisible(true);
|
||||
}
|
||||
@Override
|
||||
public float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||
return 0.3f;
|
||||
}
|
||||
@Override
|
||||
public float getMaterialRevealViewFinalYDrift(View revealView) {
|
||||
return revealView.getMeasuredHeight() / 2;
|
||||
}
|
||||
};
|
||||
startAnimationToOverlay(Workspace.State.OVERVIEW_HIDDEN, toView, toView.getContentView(),
|
||||
toView.getRevealView(), toView.getPageIndicators(), animated, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts and animation to the workspace from the current overlay view.
|
||||
*/
|
||||
public void startAnimationToWorkspace(final Launcher.State fromState,
|
||||
final Workspace.State toWorkspaceState, final boolean animated,
|
||||
final Runnable onCompleteRunnable) {
|
||||
if (toWorkspaceState != Workspace.State.NORMAL &&
|
||||
toWorkspaceState != Workspace.State.SPRING_LOADED &&
|
||||
toWorkspaceState != Workspace.State.OVERVIEW) {
|
||||
Log.e(TAG, "Unexpected call to startAnimationToWorkspace");
|
||||
}
|
||||
|
||||
if (fromState == Launcher.State.APPS || fromState == Launcher.State.APPS_SPRING_LOADED) {
|
||||
startAnimationToWorkspaceFromAllApps(fromState, toWorkspaceState, animated,
|
||||
onCompleteRunnable);
|
||||
} else {
|
||||
startAnimationToWorkspaceFromWidgets(fromState, toWorkspaceState, animated,
|
||||
onCompleteRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and starts a new animation to a particular overlay view.
|
||||
*/
|
||||
private void startAnimationToOverlay(final Workspace.State toWorkspaceState, final View toView,
|
||||
final View contentView, final View revealView, final View pageIndicatorsView,
|
||||
final boolean animated, final PrivateTransitionCallbacks pCb) {
|
||||
final Resources res = mLauncher.getResources();
|
||||
final boolean material = Utilities.isLmpOrAbove();
|
||||
final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
|
||||
final int itemsAlphaStagger =
|
||||
res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
|
||||
|
||||
final View allAppsButtonView = mLauncher.getAllAppsButton();
|
||||
final View fromView = mLauncher.getWorkspace();
|
||||
|
||||
final HashMap<View, Integer> layerViews = new HashMap<>();
|
||||
|
||||
// If for some reason our views aren't initialized, don't animate
|
||||
boolean initialized = allAppsButtonView != null;
|
||||
|
||||
// Cancel the current animation
|
||||
cancelAnimation();
|
||||
|
||||
// Create the workspace animation.
|
||||
// NOTE: this call apparently also sets the state for the workspace if !animated
|
||||
Animator workspaceAnim = mLauncher.getWorkspace().getChangeStateAnimation(
|
||||
toWorkspaceState, animated, layerViews);
|
||||
|
||||
if (animated && initialized) {
|
||||
mStateAnimation = LauncherAnimUtils.createAnimatorSet();
|
||||
|
||||
// Setup the reveal view animation
|
||||
int width = revealView.getMeasuredWidth();
|
||||
int height = revealView.getMeasuredHeight();
|
||||
float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
|
||||
revealView.setVisibility(View.VISIBLE);
|
||||
revealView.setAlpha(0f);
|
||||
revealView.setTranslationY(0f);
|
||||
revealView.setTranslationX(0f);
|
||||
pCb.onRevealViewVisible(revealView, contentView, allAppsButtonView);
|
||||
|
||||
// Calculate the final animation values
|
||||
final float revealViewToAlpha;
|
||||
final float revealViewToXDrift;
|
||||
final float revealViewToYDrift;
|
||||
if (material) {
|
||||
revealViewToAlpha = pCb.getMaterialRevealViewFinalAlpha(revealView);
|
||||
revealViewToYDrift = pCb.getMaterialRevealViewFinalYDrift(revealView);
|
||||
revealViewToXDrift = pCb.getMaterialRevealViewFinalXDrift(revealView);
|
||||
} else {
|
||||
revealViewToAlpha = 0f;
|
||||
revealViewToYDrift = 2 * height / 3;
|
||||
revealViewToXDrift = 0;
|
||||
}
|
||||
|
||||
// Create the animators
|
||||
PropertyValuesHolder panelAlpha =
|
||||
PropertyValuesHolder.ofFloat("alpha", revealViewToAlpha, 1f);
|
||||
PropertyValuesHolder panelDriftY =
|
||||
PropertyValuesHolder.ofFloat("translationY", revealViewToYDrift, 0);
|
||||
PropertyValuesHolder panelDriftX =
|
||||
PropertyValuesHolder.ofFloat("translationX", revealViewToXDrift, 0);
|
||||
ObjectAnimator panelAlphaAndDrift = ObjectAnimator.ofPropertyValuesHolder(revealView,
|
||||
panelAlpha, panelDriftY, panelDriftX);
|
||||
panelAlphaAndDrift.setDuration(revealDuration);
|
||||
panelAlphaAndDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
|
||||
|
||||
// Play the animation
|
||||
layerViews.put(revealView, BUILD_AND_SET_LAYER);
|
||||
mStateAnimation.play(panelAlphaAndDrift);
|
||||
|
||||
// Setup the animation for the page indicators
|
||||
if (pageIndicatorsView != null) {
|
||||
pageIndicatorsView.setAlpha(0.01f);
|
||||
ObjectAnimator indicatorsAlpha =
|
||||
ObjectAnimator.ofFloat(pageIndicatorsView, "alpha", 1f);
|
||||
indicatorsAlpha.setDuration(revealDuration);
|
||||
mStateAnimation.play(indicatorsAlpha);
|
||||
}
|
||||
|
||||
// Setup the animation for the content view
|
||||
contentView.setVisibility(View.VISIBLE);
|
||||
contentView.setAlpha(0f);
|
||||
contentView.setTranslationY(revealViewToYDrift);
|
||||
layerViews.put(contentView, BUILD_AND_SET_LAYER);
|
||||
|
||||
// Create the individual animators
|
||||
ObjectAnimator pageDrift = ObjectAnimator.ofFloat(contentView, "translationY",
|
||||
revealViewToYDrift, 0);
|
||||
pageDrift.setDuration(revealDuration);
|
||||
pageDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
|
||||
pageDrift.setStartDelay(itemsAlphaStagger);
|
||||
mStateAnimation.play(pageDrift);
|
||||
|
||||
ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(contentView, "alpha", 0f, 1f);
|
||||
itemsAlpha.setDuration(revealDuration);
|
||||
itemsAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
|
||||
itemsAlpha.setStartDelay(itemsAlphaStagger);
|
||||
mStateAnimation.play(itemsAlpha);
|
||||
|
||||
if (material) {
|
||||
// Animate the all apps button
|
||||
float startRadius = pCb.getMaterialRevealViewStartFinalRadius();
|
||||
AnimatorListenerAdapter listener = pCb.getMaterialRevealViewAnimatorListener(
|
||||
revealView, allAppsButtonView);
|
||||
Animator reveal = ViewAnimationUtils.createCircularReveal(revealView, width / 2,
|
||||
height / 2, startRadius, revealRadius);
|
||||
reveal.setDuration(revealDuration);
|
||||
reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
|
||||
if (listener != null) {
|
||||
reveal.addListener(listener);
|
||||
}
|
||||
mStateAnimation.play(reveal);
|
||||
}
|
||||
|
||||
mStateAnimation.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
dispatchOnLauncherTransitionEnd(fromView, animated, false);
|
||||
dispatchOnLauncherTransitionEnd(toView, animated, false);
|
||||
|
||||
// Hide the reveal view
|
||||
revealView.setVisibility(View.INVISIBLE);
|
||||
pCb.onAnimationComplete(revealView, contentView, allAppsButtonView);
|
||||
|
||||
// Disable all necessary layers
|
||||
for (View v : layerViews.keySet()) {
|
||||
if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
|
||||
v.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Hide the search bar
|
||||
mCb.onStateTransitionHideSearchBar();
|
||||
|
||||
// This can hold unnecessary references to views.
|
||||
mStateAnimation = null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Play the workspace animation
|
||||
if (workspaceAnim != null) {
|
||||
mStateAnimation.play(workspaceAnim);
|
||||
}
|
||||
|
||||
// Dispatch the prepare transition signal
|
||||
dispatchOnLauncherTransitionPrepare(fromView, animated, false);
|
||||
dispatchOnLauncherTransitionPrepare(toView, animated, false);
|
||||
|
||||
|
||||
final AnimatorSet stateAnimation = mStateAnimation;
|
||||
final Runnable startAnimRunnable = new Runnable() {
|
||||
public void run() {
|
||||
// Check that mStateAnimation hasn't changed while
|
||||
// we waited for a layout/draw pass
|
||||
if (mStateAnimation != stateAnimation)
|
||||
return;
|
||||
dispatchOnLauncherTransitionStart(fromView, animated, false);
|
||||
dispatchOnLauncherTransitionStart(toView, animated, false);
|
||||
|
||||
// Enable all necessary layers
|
||||
for (View v : layerViews.keySet()) {
|
||||
if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
|
||||
v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
}
|
||||
if (Utilities.isViewAttachedToWindow(v)) {
|
||||
v.buildLayer();
|
||||
}
|
||||
}
|
||||
|
||||
// Focus the new view
|
||||
toView.requestFocus();
|
||||
|
||||
mStateAnimation.start();
|
||||
}
|
||||
};
|
||||
|
||||
toView.bringToFront();
|
||||
toView.setVisibility(View.VISIBLE);
|
||||
toView.post(startAnimRunnable);
|
||||
} else {
|
||||
toView.setTranslationX(0.0f);
|
||||
toView.setTranslationY(0.0f);
|
||||
toView.setScaleX(1.0f);
|
||||
toView.setScaleY(1.0f);
|
||||
toView.setVisibility(View.VISIBLE);
|
||||
toView.bringToFront();
|
||||
|
||||
// Show the content view
|
||||
contentView.setVisibility(View.VISIBLE);
|
||||
|
||||
// Hide the search bar
|
||||
mCb.onStateTransitionHideSearchBar();
|
||||
|
||||
dispatchOnLauncherTransitionPrepare(fromView, animated, false);
|
||||
dispatchOnLauncherTransitionStart(fromView, animated, false);
|
||||
dispatchOnLauncherTransitionEnd(fromView, animated, false);
|
||||
dispatchOnLauncherTransitionPrepare(toView, animated, false);
|
||||
dispatchOnLauncherTransitionStart(toView, animated, false);
|
||||
dispatchOnLauncherTransitionEnd(toView, animated, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts and animation to the workspace from the apps view.
|
||||
*/
|
||||
private void startAnimationToWorkspaceFromAllApps(final Launcher.State fromState,
|
||||
final Workspace.State toWorkspaceState, final boolean animated,
|
||||
final Runnable onCompleteRunnable) {
|
||||
AppsContainerView appsView = mLauncher.getAppsView();
|
||||
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
|
||||
int[] mAllAppsToPanelDelta;
|
||||
|
||||
@Override
|
||||
public void onRevealViewVisible(View revealView, View contentView,
|
||||
View allAppsButtonView) {
|
||||
// Get the y delta between the center of the page and the center of the all apps
|
||||
// button
|
||||
mAllAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
|
||||
allAppsButtonView, null);
|
||||
}
|
||||
@Override
|
||||
public float getMaterialRevealViewFinalXDrift(View revealView) {
|
||||
return mAllAppsToPanelDelta[0];
|
||||
}
|
||||
@Override
|
||||
public float getMaterialRevealViewFinalYDrift(View revealView) {
|
||||
return mAllAppsToPanelDelta[1];
|
||||
}
|
||||
@Override
|
||||
float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||
// No alpha anim from all apps
|
||||
return 1f;
|
||||
}
|
||||
@Override
|
||||
float getMaterialRevealViewStartFinalRadius() {
|
||||
int allAppsButtonSize = LauncherAppState.getInstance().
|
||||
getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
|
||||
return allAppsButtonSize / 2;
|
||||
}
|
||||
@Override
|
||||
public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
|
||||
final View revealView, final View allAppsButtonView) {
|
||||
return new AnimatorListenerAdapter() {
|
||||
public void onAnimationStart(Animator animation) {
|
||||
// We set the alpha instead of visibility to ensure that the focus does not
|
||||
// get taken from the all apps view
|
||||
allAppsButtonView.setVisibility(View.VISIBLE);
|
||||
allAppsButtonView.setAlpha(0f);
|
||||
}
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
// Hide the reveal view
|
||||
revealView.setVisibility(View.INVISIBLE);
|
||||
|
||||
// Show the all apps button, and focus it
|
||||
allAppsButtonView.setAlpha(1f);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
startAnimationToWorkspaceFromOverlay(toWorkspaceState, appsView, appsView.getContentView(),
|
||||
appsView.getRevealView(), null /* pageIndicatorsView */, animated,
|
||||
onCompleteRunnable, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts and animation to the workspace from the widgets view.
|
||||
*/
|
||||
private void startAnimationToWorkspaceFromWidgets(final Launcher.State fromState,
|
||||
final Workspace.State toWorkspaceState, final boolean animated,
|
||||
final Runnable onCompleteRunnable) {
|
||||
AppsCustomizeTabHost widgetsView = mLauncher.getWidgetsView();
|
||||
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
|
||||
@Override
|
||||
public void onRevealViewVisible(View revealView, View contentView, View allAppsButtonView) {
|
||||
AppsCustomizePagedView pagedView = ((AppsCustomizePagedView) contentView);
|
||||
|
||||
// Hide the real page background, and swap in the fake one
|
||||
pagedView.stopScrolling();
|
||||
pagedView.setPageBackgroundsVisible(false);
|
||||
revealView.setBackground(mLauncher.getDrawable(R.drawable.quantum_panel_dark));
|
||||
|
||||
// Hide the side pages of the Widget tray to avoid some ugly edge cases
|
||||
final View currentPage = pagedView.getPageAt(pagedView.getNextPage());
|
||||
int count = pagedView.getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
View child = pagedView.getChildAt(i);
|
||||
if (child != currentPage) {
|
||||
child.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {
|
||||
AppsCustomizePagedView pagedView = ((AppsCustomizePagedView) contentView);
|
||||
|
||||
// Show the real page background and force-update the page
|
||||
pagedView.setPageBackgroundsVisible(true);
|
||||
pagedView.setCurrentPage(pagedView.getNextPage());
|
||||
pagedView.updateCurrentPageScroll();
|
||||
|
||||
// Unhide the side pages
|
||||
int count = pagedView.getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
View child = pagedView.getChildAt(i);
|
||||
child.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public float getMaterialRevealViewFinalYDrift(View revealView) {
|
||||
return revealView.getMeasuredHeight() / 2;
|
||||
}
|
||||
@Override
|
||||
float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||
return 0.4f;
|
||||
}
|
||||
@Override
|
||||
public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
|
||||
final View revealView, final View allAppsButtonView) {
|
||||
return new AnimatorListenerAdapter() {
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
// Hide the reveal view
|
||||
revealView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
startAnimationToWorkspaceFromOverlay(toWorkspaceState, widgetsView,
|
||||
widgetsView.getContentView(), widgetsView.getRevealView(),
|
||||
widgetsView.getPageIndicators(), animated, onCompleteRunnable, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and starts a new animation to the workspace.
|
||||
*/
|
||||
private void startAnimationToWorkspaceFromOverlay(final Workspace.State toWorkspaceState,
|
||||
final View fromView, final View contentView, final View revealView,
|
||||
final View pageIndicatorsView, final boolean animated,
|
||||
final Runnable onCompleteRunnable, final PrivateTransitionCallbacks pCb) {
|
||||
final Resources res = mLauncher.getResources();
|
||||
final boolean material = Utilities.isLmpOrAbove();
|
||||
final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
|
||||
final int itemsAlphaStagger =
|
||||
res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
|
||||
|
||||
final View allAppsButtonView = mLauncher.getAllAppsButton();
|
||||
final View toView = mLauncher.getWorkspace();
|
||||
|
||||
final HashMap<View, Integer> layerViews = new HashMap<>();
|
||||
|
||||
// If for some reason our views aren't initialized, don't animate
|
||||
boolean initialized = allAppsButtonView != null;
|
||||
|
||||
// Cancel the current animation
|
||||
cancelAnimation();
|
||||
|
||||
// Create the workspace animation.
|
||||
// NOTE: this call apparently also sets the state for the workspace if !animated
|
||||
Animator workspaceAnim = mLauncher.getWorkspace().getChangeStateAnimation(
|
||||
toWorkspaceState, animated, layerViews);
|
||||
|
||||
if (animated && initialized) {
|
||||
mStateAnimation = LauncherAnimUtils.createAnimatorSet();
|
||||
|
||||
// Play the workspace animation
|
||||
if (workspaceAnim != null) {
|
||||
mStateAnimation.play(workspaceAnim);
|
||||
}
|
||||
|
||||
// hideAppsCustomizeHelper is called in some cases when it is already hidden
|
||||
// don't perform all these no-op animations. In particularly, this was causing
|
||||
// the all-apps button to pop in and out.
|
||||
if (fromView.getVisibility() == View.VISIBLE) {
|
||||
int width = revealView.getMeasuredWidth();
|
||||
int height = revealView.getMeasuredHeight();
|
||||
float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
|
||||
revealView.setVisibility(View.VISIBLE);
|
||||
revealView.setAlpha(1f);
|
||||
revealView.setTranslationY(0);
|
||||
layerViews.put(revealView, BUILD_AND_SET_LAYER);
|
||||
pCb.onRevealViewVisible(revealView, contentView, allAppsButtonView);
|
||||
|
||||
// Calculate the final animation values
|
||||
final float revealViewToXDrift;
|
||||
final float revealViewToYDrift;
|
||||
if (material) {
|
||||
revealViewToYDrift = pCb.getMaterialRevealViewFinalYDrift(revealView);
|
||||
revealViewToXDrift = pCb.getMaterialRevealViewFinalXDrift(revealView);
|
||||
} else {
|
||||
revealViewToYDrift = 2 * height / 3;
|
||||
revealViewToXDrift = 0;
|
||||
}
|
||||
|
||||
// The vertical motion of the apps panel should be delayed by one frame
|
||||
// from the conceal animation in order to give the right feel. We correspondingly
|
||||
// shorten the duration so that the slide and conceal end at the same time.
|
||||
TimeInterpolator decelerateInterpolator = material ?
|
||||
new LogDecelerateInterpolator(100, 0) :
|
||||
new DecelerateInterpolator(1f);
|
||||
ObjectAnimator panelDriftY = LauncherAnimUtils.ofFloat(revealView, "translationY",
|
||||
0, revealViewToYDrift);
|
||||
panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY);
|
||||
panelDriftY.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
|
||||
panelDriftY.setInterpolator(decelerateInterpolator);
|
||||
mStateAnimation.play(panelDriftY);
|
||||
|
||||
ObjectAnimator panelDriftX = LauncherAnimUtils.ofFloat(revealView, "translationX",
|
||||
0, revealViewToXDrift);
|
||||
panelDriftX.setDuration(revealDuration - SINGLE_FRAME_DELAY);
|
||||
panelDriftX.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
|
||||
panelDriftX.setInterpolator(decelerateInterpolator);
|
||||
mStateAnimation.play(panelDriftX);
|
||||
|
||||
// Setup animation for the reveal panel alpha
|
||||
final float revealViewToAlpha = !material ? 0f :
|
||||
pCb.getMaterialRevealViewFinalAlpha(revealView);
|
||||
if (revealViewToAlpha != 1f) {
|
||||
ObjectAnimator panelAlpha = LauncherAnimUtils.ofFloat(revealView, "alpha",
|
||||
1f, revealViewToAlpha);
|
||||
panelAlpha.setDuration(material ? revealDuration : 150);
|
||||
panelAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY);
|
||||
panelAlpha.setInterpolator(decelerateInterpolator);
|
||||
mStateAnimation.play(panelAlpha);
|
||||
}
|
||||
|
||||
// Setup the animation for the content view
|
||||
layerViews.put(contentView, BUILD_AND_SET_LAYER);
|
||||
|
||||
// Create the individual animators
|
||||
ObjectAnimator pageDrift = LauncherAnimUtils.ofFloat(contentView, "translationY",
|
||||
0, revealViewToYDrift);
|
||||
contentView.setTranslationY(0);
|
||||
pageDrift.setDuration(revealDuration - SINGLE_FRAME_DELAY);
|
||||
pageDrift.setInterpolator(decelerateInterpolator);
|
||||
pageDrift.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
|
||||
mStateAnimation.play(pageDrift);
|
||||
|
||||
contentView.setAlpha(1f);
|
||||
ObjectAnimator itemsAlpha = LauncherAnimUtils.ofFloat(contentView, "alpha", 1f, 0f);
|
||||
itemsAlpha.setDuration(100);
|
||||
itemsAlpha.setInterpolator(decelerateInterpolator);
|
||||
mStateAnimation.play(itemsAlpha);
|
||||
|
||||
// Setup the page indicators animation
|
||||
if (pageIndicatorsView != null) {
|
||||
pageIndicatorsView.setAlpha(1f);
|
||||
ObjectAnimator indicatorsAlpha =
|
||||
LauncherAnimUtils.ofFloat(pageIndicatorsView, "alpha", 0f);
|
||||
indicatorsAlpha.setDuration(revealDuration);
|
||||
indicatorsAlpha.setInterpolator(new DecelerateInterpolator(1.5f));
|
||||
mStateAnimation.play(indicatorsAlpha);
|
||||
}
|
||||
|
||||
if (material) {
|
||||
// Animate the all apps button
|
||||
float finalRadius = pCb.getMaterialRevealViewStartFinalRadius();
|
||||
AnimatorListenerAdapter listener =
|
||||
pCb.getMaterialRevealViewAnimatorListener(revealView, allAppsButtonView);
|
||||
Animator reveal =
|
||||
LauncherAnimUtils.createCircularReveal(revealView, width / 2,
|
||||
height / 2, revealRadius, finalRadius);
|
||||
reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
|
||||
reveal.setDuration(revealDuration);
|
||||
reveal.setStartDelay(itemsAlphaStagger);
|
||||
if (listener != null) {
|
||||
reveal.addListener(listener);
|
||||
}
|
||||
mStateAnimation.play(reveal);
|
||||
}
|
||||
|
||||
dispatchOnLauncherTransitionPrepare(fromView, animated, true);
|
||||
dispatchOnLauncherTransitionPrepare(toView, animated, true);
|
||||
}
|
||||
|
||||
mStateAnimation.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
fromView.setVisibility(View.GONE);
|
||||
dispatchOnLauncherTransitionEnd(fromView, animated, true);
|
||||
dispatchOnLauncherTransitionEnd(toView, animated, true);
|
||||
|
||||
// Run any queued runnables
|
||||
if (onCompleteRunnable != null) {
|
||||
onCompleteRunnable.run();
|
||||
}
|
||||
|
||||
// Animation complete callback
|
||||
pCb.onAnimationComplete(revealView, contentView, allAppsButtonView);
|
||||
|
||||
// Disable all necessary layers
|
||||
for (View v : layerViews.keySet()) {
|
||||
if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
|
||||
v.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset page transforms
|
||||
if (contentView != null) {
|
||||
contentView.setTranslationX(0);
|
||||
contentView.setTranslationY(0);
|
||||
contentView.setAlpha(1);
|
||||
}
|
||||
|
||||
// This can hold unnecessary references to views.
|
||||
mStateAnimation = null;
|
||||
}
|
||||
});
|
||||
|
||||
final AnimatorSet stateAnimation = mStateAnimation;
|
||||
final Runnable startAnimRunnable = new Runnable() {
|
||||
public void run() {
|
||||
// Check that mStateAnimation hasn't changed while
|
||||
// we waited for a layout/draw pass
|
||||
if (mStateAnimation != stateAnimation)
|
||||
return;
|
||||
dispatchOnLauncherTransitionStart(fromView, animated, false);
|
||||
dispatchOnLauncherTransitionStart(toView, animated, false);
|
||||
|
||||
// Enable all necessary layers
|
||||
for (View v : layerViews.keySet()) {
|
||||
if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
|
||||
v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
}
|
||||
if (Utilities.isLmpOrAbove()) {
|
||||
v.buildLayer();
|
||||
}
|
||||
}
|
||||
mStateAnimation.start();
|
||||
}
|
||||
};
|
||||
fromView.post(startAnimRunnable);
|
||||
} else {
|
||||
fromView.setVisibility(View.GONE);
|
||||
dispatchOnLauncherTransitionPrepare(fromView, animated, true);
|
||||
dispatchOnLauncherTransitionStart(fromView, animated, true);
|
||||
dispatchOnLauncherTransitionEnd(fromView, animated, true);
|
||||
dispatchOnLauncherTransitionPrepare(toView, animated, true);
|
||||
dispatchOnLauncherTransitionStart(toView, animated, true);
|
||||
dispatchOnLauncherTransitionEnd(toView, animated, true);
|
||||
|
||||
// Run any queued runnables
|
||||
if (onCompleteRunnable != null) {
|
||||
onCompleteRunnable.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches the prepare-transition event to suitable views.
|
||||
*/
|
||||
void dispatchOnLauncherTransitionPrepare(View v, boolean animated, boolean toWorkspace) {
|
||||
if (v instanceof LauncherTransitionable) {
|
||||
((LauncherTransitionable) v).onLauncherTransitionPrepare(mLauncher, animated,
|
||||
toWorkspace);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the start-transition event to suitable views.
|
||||
*/
|
||||
void dispatchOnLauncherTransitionStart(View v, boolean animated, boolean toWorkspace) {
|
||||
if (v instanceof LauncherTransitionable) {
|
||||
((LauncherTransitionable) v).onLauncherTransitionStart(mLauncher, animated,
|
||||
toWorkspace);
|
||||
}
|
||||
|
||||
// Update the workspace transition step as well
|
||||
dispatchOnLauncherTransitionStep(v, 0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the step-transition event to suitable views.
|
||||
*/
|
||||
void dispatchOnLauncherTransitionStep(View v, float t) {
|
||||
if (v instanceof LauncherTransitionable) {
|
||||
((LauncherTransitionable) v).onLauncherTransitionStep(mLauncher, t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the end-transition event to suitable views.
|
||||
*/
|
||||
void dispatchOnLauncherTransitionEnd(View v, boolean animated, boolean toWorkspace) {
|
||||
if (v instanceof LauncherTransitionable) {
|
||||
((LauncherTransitionable) v).onLauncherTransitionEnd(mLauncher, animated,
|
||||
toWorkspace);
|
||||
}
|
||||
|
||||
// Update the workspace transition step as well
|
||||
dispatchOnLauncherTransitionStep(v, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the current animation.
|
||||
*/
|
||||
private void cancelAnimation() {
|
||||
if (mStateAnimation != null) {
|
||||
mStateAnimation.setDuration(0);
|
||||
mStateAnimation.cancel();
|
||||
mStateAnimation = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user