diff options
author | Hyunyoung Song <hyunyoungs@google.com> | 2016-07-21 17:32:43 -0700 |
---|---|---|
committer | Hyunyoung Song <hyunyoungs@google.com> | 2016-07-21 17:32:43 -0700 |
commit | c001cf562017d08cd48b67de8f377ca08881e70e (patch) | |
tree | 5509e5ea66ae98d0008e13a4929e4ee5138df3ba | |
parent | 1ce0e30451f28e6e5c42c068d520e16abeb257dd (diff) | |
download | android_packages_apps_Trebuchet-c001cf562017d08cd48b67de8f377ca08881e70e.tar.gz android_packages_apps_Trebuchet-c001cf562017d08cd48b67de8f377ca08881e70e.tar.bz2 android_packages_apps_Trebuchet-c001cf562017d08cd48b67de8f377ca08881e70e.zip |
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
-rw-r--r-- | res/anim/discovery_bounce.xml | 45 | ||||
-rw-r--r-- | res/interpolator/disco_bounce_section1.xml | 22 | ||||
-rw-r--r-- | res/interpolator/disco_bounce_section2.xml | 22 | ||||
-rw-r--r-- | res/interpolator/disco_bounce_section3.xml | 22 | ||||
-rw-r--r-- | src/com/android/launcher3/Launcher.java | 35 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherCallbacks.java | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/allapps/AllAppsTransitionController.java | 157 | ||||
-rw-r--r-- | src/com/android/launcher3/dragndrop/DragLayer.java | 4 | ||||
-rw-r--r-- | src/com/android/launcher3/testing/LauncherExtension.java | 5 |
9 files changed, 254 insertions, 60 deletions
diff --git a/res/anim/discovery_bounce.xml b/res/anim/discovery_bounce.xml new file mode 100644 index 000000000..1f7d46618 --- /dev/null +++ b/res/anim/discovery_bounce.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2016, 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. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:ordering="sequentially" + android:startOffset="200"> + + <objectAnimator + android:propertyName="progress" + android:duration="250" + android:interpolator="@interpolator/disco_bounce_section1" + android:valueFrom="1f" + android:valueTo=".94f" + android:valueType="floatType"/> + <objectAnimator + android:propertyName="progress" + android:duration="216" + android:interpolator="@interpolator/disco_bounce_section2" + android:valueFrom=".94f" + android:valueTo="1.012f" + android:valueType="floatType"/> + <objectAnimator + android:propertyName="progress" + android:duration="234" + android:interpolator="@interpolator/disco_bounce_section3" + android:valueFrom="1.012f" + android:valueTo="1f" + android:valueType="floatType"/> +</set> diff --git a/res/interpolator/disco_bounce_section1.xml b/res/interpolator/disco_bounce_section1.xml new file mode 100644 index 000000000..21562165c --- /dev/null +++ b/res/interpolator/disco_bounce_section1.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2016 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 + --> + +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:controlX1="0.9" + android:controlY1="0" + android:controlX2="0.5" + android:controlY2="1"/> diff --git a/res/interpolator/disco_bounce_section2.xml b/res/interpolator/disco_bounce_section2.xml new file mode 100644 index 000000000..86cc789fe --- /dev/null +++ b/res/interpolator/disco_bounce_section2.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2016 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 + --> + +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:controlX1="0.9" + android:controlY1="0" + android:controlX2="0.6" + android:controlY2="1"/> diff --git a/res/interpolator/disco_bounce_section3.xml b/res/interpolator/disco_bounce_section3.xml new file mode 100644 index 000000000..1acef037c --- /dev/null +++ b/res/interpolator/disco_bounce_section3.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2016 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 + --> + +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:controlX1="0.1" + android:controlY1="0" + android:controlX2="0.7" + android:controlY2="1"/> 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; + } } } |