From c001cf562017d08cd48b67de8f377ca08881e70e Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Thu, 21 Jul 2016 17:32:43 -0700 Subject: Animate discovery bounce for all apps pull up interaction b/30221381 > Will not support landscape case. If the user knows how to enable rotation, it's very unlikely they don't know how to bring up apps drawer > If unlocked using finger unlock immediately after screen is turned off, bounce is not shown due to delay in ACTION_SCREEN_OFF broadcast Change-Id: Ia8b7e572eaa4aeab8b1add1e5660fee3a63ba21c --- src/com/android/launcher3/Launcher.java | 35 ++++- src/com/android/launcher3/LauncherCallbacks.java | 2 + .../allapps/AllAppsTransitionController.java | 157 +++++++++++++-------- src/com/android/launcher3/dragndrop/DragLayer.java | 4 + .../launcher3/testing/LauncherExtension.java | 5 + 5 files changed, 143 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 7423e2004..2cfe319ad 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -198,6 +198,7 @@ public class Launcher extends Activity static final String INTRO_SCREEN_DISMISSED = "launcher.intro_screen_dismissed"; static final String FIRST_RUN_ACTIVITY_DISPLAYED = "launcher.first_run_activity_displayed"; + static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown"; /** The different states that Launcher can be in. */ enum State { NONE, WORKSPACE, WORKSPACE_SPRING_LOADED, APPS, APPS_SPRING_LOADED, @@ -288,6 +289,7 @@ public class Launcher extends Activity private IconCache mIconCache; private ExtractedColors mExtractedColors; private LauncherAccessibilityDelegate mAccessibilityDelegate; + private boolean mIsResumeFromActionScreenOff; @Thunk boolean mUserPresent = true; private boolean mVisible = false; private boolean mHasFocus = false; @@ -1079,6 +1081,10 @@ public class Launcher extends Activity InstallShortcutReceiver.disableAndFlushInstallQueue(this); } + if (shouldShowDiscoveryBounce()) { + mAllAppsController.showDiscoveryBounce(); + } + mIsResumeFromActionScreenOff = false; if (mLauncherCallbacks != null) { mLauncherCallbacks.onResume(); } @@ -1623,6 +1629,7 @@ public class Launcher extends Activity mAppsView.reset(); } } + mIsResumeFromActionScreenOff = true; } else if (Intent.ACTION_USER_PRESENT.equals(action)) { mUserPresent = true; updateAutoAdvanceState(); @@ -3348,6 +3355,7 @@ public class Launcher extends Activity */ public void showAppsView(boolean animated, boolean resetListToTop, boolean updatePredictedApps, boolean focusSearchBar) { + markAppsViewShown(); if (resetListToTop) { mAppsView.scrollToTop(); } @@ -4358,10 +4366,6 @@ public class Launcher extends Activity !mSharedPrefs.getBoolean(FIRST_RUN_ACTIVITY_DISPLAYED, false); } - protected boolean hasRunFirstRunActivity() { - return mSharedPrefs.getBoolean(FIRST_RUN_ACTIVITY_DISPLAYED, false); - } - public boolean showFirstRunActivity() { if (shouldRunFirstRunActivity() && hasFirstRunActivity()) { @@ -4381,6 +4385,29 @@ public class Launcher extends Activity editor.apply(); } + private void markAppsViewShown() { + if (mSharedPrefs.getBoolean(APPS_VIEW_SHOWN, false)) { + return; + } + mSharedPrefs.edit().putBoolean(APPS_VIEW_SHOWN, true).apply(); + } + + private boolean shouldShowDiscoveryBounce() { + if (mState != mState.WORKSPACE) { + return false; + } + if (mLauncherCallbacks != null && mLauncherCallbacks.shouldShowDiscoveryBounce()) { + return true; + } + if (!mIsResumeFromActionScreenOff) { + return false; + } + if (mSharedPrefs.getBoolean(APPS_VIEW_SHOWN, false)) { + return false; + } + return true; + } + /** * To be overridden by subclasses to indicate that there is an in-activity full-screen intro * screen that must be displayed and dismissed. diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java index e97163133..2bbe0fbf3 100644 --- a/src/com/android/launcher3/LauncherCallbacks.java +++ b/src/com/android/launcher3/LauncherCallbacks.java @@ -110,4 +110,6 @@ public interface LauncherCallbacks { * but for implementation purposes is passed around as an object. */ public void setLauncherSearchCallback(Object callbacks); + + public boolean shouldShowDiscoveryBounce(); } diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 136308bb1..78280f724 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -1,6 +1,7 @@ package com.android.launcher3.allapps; import android.animation.Animator; +import android.animation.AnimatorInflater; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ArgbEvaluator; @@ -13,15 +14,15 @@ import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; -import com.android.launcher3.pageindicators.CaretDrawable; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Hotseat; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.PagedView; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; -import com.android.launcher3.Workspace.Direction; +import com.android.launcher3.pageindicators.CaretDrawable; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.util.TouchController; @@ -64,15 +65,15 @@ public class AllAppsTransitionController implements TouchController, VerticalPul private final VerticalPullDetector mDetector; private final ArgbEvaluator mEvaluator; - // Animation in this class is controlled by a single variable {@link mShiftCurrent}. - // Visually, it represents top y coordinate of the all apps container. Using the - // {@link mShiftRange} as the denominator, this fraction value ranges in [0, 1]. - // - // When {@link mShiftCurrent} is 0, all apps container is pulled up. - // When {@link mShiftCurrent} is {@link mShirtRange}, all apps container is pulled down. + // Animation in this class is controlled by a single variable {@link mProgress}. + // Visually, it represents top y coordinate of the all apps container if multiplied with + // {@link mShiftRange}. + + // When {@link mProgress} is 0, all apps container is pulled up. + // When {@link mProgress} is 1, all apps container is pulled down. private float mShiftStart; // [0, mShiftRange] - private float mShiftCurrent; // [0, mShiftRange] private float mShiftRange; // changes depending on the orientation + private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent private static final float DEFAULT_SHIFT_RANGE = 10; @@ -86,20 +87,26 @@ public class AllAppsTransitionController implements TouchController, VerticalPul private boolean mLightStatusBar; - public AllAppsTransitionController(Launcher launcher) { - mLauncher = launcher; - mDetector = new VerticalPullDetector(launcher); + // Used in discovery bounce animation to provide the transition without workspace changing. + private boolean mIsTranslateWithoutWorkspace = false; + private AnimatorSet mDiscoBounceAnimation; + + public AllAppsTransitionController(Launcher l) { + mLauncher = l; + mDetector = new VerticalPullDetector(l); mDetector.setListener(this); - mShiftCurrent = mShiftRange = DEFAULT_SHIFT_RANGE; - mBezelSwipeUpHeight = launcher.getResources().getDimensionPixelSize( + mShiftRange = DEFAULT_SHIFT_RANGE; + mProgress = 1f; + mBezelSwipeUpHeight = l.getResources().getDimensionPixelSize( R.dimen.all_apps_bezel_swipe_height); - mCaretAnimationDuration = launcher.getResources().getInteger( + mCaretAnimationDuration = l.getResources().getInteger( R.integer.config_caretAnimationDuration); - mCaretInterpolator = AnimationUtils.loadInterpolator(launcher, + mCaretInterpolator = AnimationUtils.loadInterpolator(l, R.interpolator.caret_animation_interpolator); + mEvaluator = new ArgbEvaluator(); - mAllAppsBackgroundColor = launcher.getColor(R.color.all_apps_container_color); + mAllAppsBackgroundColor = l.getColor(R.color.all_apps_container_color); } @Override @@ -175,11 +182,11 @@ public class AllAppsTransitionController implements TouchController, VerticalPul } private boolean isInDisallowRecatchTopZone() { - return mShiftCurrent / mShiftRange < RECATCH_REJECTION_FRACTION; + return mProgress < RECATCH_REJECTION_FRACTION; } private boolean isInDisallowRecatchBottomZone() { - return mShiftCurrent / mShiftRange > 1 - RECATCH_REJECTION_FRACTION; + return mProgress > 1 - RECATCH_REJECTION_FRACTION; } @Override @@ -195,8 +202,8 @@ public class AllAppsTransitionController implements TouchController, VerticalPul if (mAppsView == null) { return false; // early termination. } - float progress = Math.min(Math.max(0, mShiftStart + displacement), mShiftRange); - setProgress(progress); + float shift = Math.min(Math.max(0, mShiftStart + displacement), mShiftRange); + setProgress(shift / mShiftRange); return true; } @@ -271,13 +278,11 @@ public class AllAppsTransitionController implements TouchController, VerticalPul mAppsView.getRevealView().setVisibility(View.VISIBLE); mAppsView.setRevealDrawableColor(mHotseatBackgroundColor); } - } else { - setProgress(mShiftCurrent); } } - private void updateLightStatusBar(float progress) { - boolean enable = progress <= mStatusBarHeight / 2; + private void updateLightStatusBar(float shift) { + boolean enable = shift <= mStatusBarHeight / 2; // Do not modify status bar on landscape as all apps is not full bleed. if (mLauncher.getDeviceProfile().isVerticalBarLayout()) { return; @@ -300,38 +305,43 @@ public class AllAppsTransitionController implements TouchController, VerticalPul } /** - * @param progress y value of the border between hotseat and all apps + * @param progress value between 0 and 1 */ public void setProgress(float progress) { - updateLightStatusBar(progress); - mShiftCurrent = progress; - float alpha = calcAlphaAllApps(progress); - float workspaceHotseatAlpha = 1 - alpha; + mProgress = progress; + float shiftCurrent = progress * mShiftRange; + + float workspaceHotseatAlpha = Utilities.boundToRange(progress, 0f, 1f); + float alpha = 1 - workspaceHotseatAlpha; + float interpolation = mAccelInterpolator.getInterpolation(workspaceHotseatAlpha); - int color = (Integer) mEvaluator.evaluate(mDecelInterpolator.getInterpolation(alpha), + int color = (Integer) mEvaluator.evaluate(alpha, mHotseatBackgroundColor, mAllAppsBackgroundColor); mAppsView.setRevealDrawableColor(color); mAppsView.getContentView().setAlpha(alpha); - mAppsView.setTranslationY(progress); - mWorkspace.setWorkspaceYTranslationAndAlpha( - PARALLAX_COEFFICIENT * (-mShiftRange + progress), - interpolation); - if (mLauncher.getDeviceProfile().isVerticalBarLayout()) { - mWorkspace.setHotseatTranslationAndAlpha(Direction.Y, - PARALLAX_COEFFICIENT * (-mShiftRange + progress), interpolation); + mAppsView.setTranslationY(shiftCurrent); + + if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) { + mWorkspace.setHotseatTranslationAndAlpha(Workspace.Direction.Y, -mShiftRange + shiftCurrent, + interpolation); } else { - mWorkspace.setHotseatTranslationAndAlpha(Direction.Y, - -mShiftRange + progress, interpolation); + mWorkspace.setHotseatTranslationAndAlpha(Workspace.Direction.Y, + PARALLAX_COEFFICIENT * (-mShiftRange + shiftCurrent), + interpolation); } - } - public float getProgress() { - return mShiftCurrent; + if (mIsTranslateWithoutWorkspace) { + return; + } + mWorkspace.setWorkspaceYTranslationAndAlpha( + PARALLAX_COEFFICIENT * (-mShiftRange + shiftCurrent), + interpolation); + updateLightStatusBar(shiftCurrent); } - private float calcAlphaAllApps(float progress) { - return ((mShiftRange - progress) / mShiftRange); + public float getProgress() { + return mProgress; } private void calculateDuration(float velocity, float disp) { @@ -354,10 +364,8 @@ public class AllAppsTransitionController implements TouchController, VerticalPul mShiftStart = mAppsView.getTranslationY(); } final float fromAllAppsTop = mAppsView.getTranslationY(); - final float toAllAppsTop = 0; - ObjectAnimator driftAndAlpha = ObjectAnimator.ofFloat(this, "progress", - fromAllAppsTop, toAllAppsTop); + fromAllAppsTop / mShiftRange, 0f); driftAndAlpha.setDuration(mAnimationDuration); driftAndAlpha.setInterpolator(new PagedView.ScrollInterpolator()); animationOut.play(driftAndAlpha); @@ -387,6 +395,36 @@ public class AllAppsTransitionController implements TouchController, VerticalPul } } + public void showDiscoveryBounce() { + // cancel existing animation in case user locked and unlocked at a super human speed. + cancelDiscoveryAnimation(); + + // assumption is that this variable is always null + mDiscoBounceAnimation = (AnimatorSet) AnimatorInflater.loadAnimator(mLauncher, + R.anim.discovery_bounce); + mDiscoBounceAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animator) { + mIsTranslateWithoutWorkspace = true; + preparePull(true); + } + + @Override + public void onAnimationEnd(Animator animator) { + finishPullDown(false); + mDiscoBounceAnimation = null; + mIsTranslateWithoutWorkspace = false; + } + }); + mDiscoBounceAnimation.setTarget(this); + mAppsView.post(new Runnable() { + @Override + public void run() { + mDiscoBounceAnimation.start(); + } + }); + } + public void animateToWorkspace(AnimatorSet animationOut, long duration, boolean start) { if (animationOut == null) { return; @@ -397,10 +435,9 @@ public class AllAppsTransitionController implements TouchController, VerticalPul mShiftStart = mAppsView.getTranslationY(); } final float fromAllAppsTop = mAppsView.getTranslationY(); - final float toAllAppsTop = mShiftRange; ObjectAnimator driftAndAlpha = ObjectAnimator.ofFloat(this, "progress", - fromAllAppsTop, toAllAppsTop); + fromAllAppsTop / mShiftRange, 1f); driftAndAlpha.setDuration(mAnimationDuration); driftAndAlpha.setInterpolator(new PagedView.ScrollInterpolator()); animationOut.play(driftAndAlpha); @@ -411,7 +448,6 @@ public class AllAppsTransitionController implements TouchController, VerticalPul @Override public void onAnimationCancel(Animator animation) { canceled = true; - setProgress(mShiftCurrent); } @Override @@ -442,7 +478,7 @@ public class AllAppsTransitionController implements TouchController, VerticalPul mHotseat.setBackgroundTransparent(false /* transparent */); mHotseat.setVisibility(View.VISIBLE); mAppsView.reset(); - setProgress(mShiftRange); + setProgress(1f); if (animated) { animateCaret(); } else { @@ -453,10 +489,18 @@ public class AllAppsTransitionController implements TouchController, VerticalPul private void cancelAnimation() { if (mCurrentAnimation != null) { - mCurrentAnimation.setDuration(0); mCurrentAnimation.cancel(); mCurrentAnimation = null; } + cancelDiscoveryAnimation(); + } + + public void cancelDiscoveryAnimation() { + if (mDiscoBounceAnimation == null) { + return; + } + mDiscoBounceAnimation.cancel(); + mDiscoBounceAnimation = null; } private void cleanUpAnimation() { @@ -490,13 +534,14 @@ public class AllAppsTransitionController implements TouchController, VerticalPul @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, - int oldLeft, int oldTop, int oldRight, int oldBottom) { - float prevShiftRatio = mShiftCurrent / mShiftRange; + int oldLeft, int oldTop, int oldRight, int oldBottom) { if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) { mShiftRange = top; } else { mShiftRange = bottom; } - setProgress(mShiftRange * prevShiftRatio); + setProgress(mProgress); } + + } diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java index 5f8faab3d..28b6f3ead 100644 --- a/src/com/android/launcher3/dragndrop/DragLayer.java +++ b/src/com/android/launcher3/dragndrop/DragLayer.java @@ -280,6 +280,10 @@ public class DragLayer extends InsettableFrameLayout { int action = ev.getAction(); if (action == MotionEvent.ACTION_DOWN) { + // Cancel discovery bounce animation when a user start interacting on anywhere on + // dray layer even if mAllAppsController is NOT the active controller. + // TODO: handle other input other than touch + mAllAppsController.cancelDiscoveryAnimation(); if (handleTouchDown(ev, true)) { return true; } diff --git a/src/com/android/launcher3/testing/LauncherExtension.java b/src/com/android/launcher3/testing/LauncherExtension.java index c62ce0e57..ae552d284 100644 --- a/src/com/android/launcher3/testing/LauncherExtension.java +++ b/src/com/android/launcher3/testing/LauncherExtension.java @@ -255,5 +255,10 @@ public class LauncherExtension extends Launcher { @Override public void onDetachedFromWindow() { } + + @Override + public boolean shouldShowDiscoveryBounce() { + return false; + } } } -- cgit v1.2.3