• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.launcher3.allapps;
18 
19 import static com.android.launcher3.LauncherState.NORMAL;
20 
21 import android.animation.Animator;
22 import android.animation.AnimatorInflater;
23 import android.os.Handler;
24 import android.os.UserManager;
25 import android.view.MotionEvent;
26 import android.view.View;
27 
28 import com.android.launcher3.AbstractFloatingView;
29 import com.android.launcher3.Launcher;
30 import com.android.launcher3.LauncherState;
31 import com.android.launcher3.R;
32 import com.android.launcher3.Utilities;
33 import com.android.launcher3.anim.AnimatorListeners;
34 import com.android.launcher3.statemanager.StateManager.StateListener;
35 import com.android.launcher3.util.OnboardingPrefs;
36 
37 /**
38  * Abstract base class of floating view responsible for showing discovery bounce animation
39  */
40 public class DiscoveryBounce extends AbstractFloatingView {
41 
42     private static final long DELAY_MS = 450;
43 
44     private final Launcher mLauncher;
45     private final Animator mDiscoBounceAnimation;
46 
47     private final StateListener<LauncherState> mStateListener = new StateListener<LauncherState>() {
48         @Override
49         public void onStateTransitionStart(LauncherState toState) {
50             handleClose(false);
51         }
52 
53         @Override
54         public void onStateTransitionComplete(LauncherState finalState) {}
55     };
56 
DiscoveryBounce(Launcher launcher)57     public DiscoveryBounce(Launcher launcher) {
58         super(launcher, null);
59         mLauncher = launcher;
60 
61         mDiscoBounceAnimation =
62                 AnimatorInflater.loadAnimator(launcher, R.animator.discovery_bounce);
63         mDiscoBounceAnimation.setTarget(new VerticalProgressWrapper(
64                 launcher.getHotseat(), mLauncher.getDragLayer().getHeight()));
65         mDiscoBounceAnimation.addListener(AnimatorListeners.forEndCallback(this::handleClose));
66         launcher.getStateManager().addStateListener(mStateListener);
67     }
68 
69     @Override
onAttachedToWindow()70     protected void onAttachedToWindow() {
71         super.onAttachedToWindow();
72         mDiscoBounceAnimation.start();
73     }
74 
75     @Override
onDetachedFromWindow()76     protected void onDetachedFromWindow() {
77         super.onDetachedFromWindow();
78         if (mDiscoBounceAnimation.isRunning()) {
79             mDiscoBounceAnimation.end();
80         }
81     }
82 
83     @Override
onBackPressed()84     public boolean onBackPressed() {
85         super.onBackPressed();
86         // Go back to the previous state (from a user's perspective this floating view isn't
87         // something to go back from).
88         return false;
89     }
90 
91     @Override
onControllerInterceptTouchEvent(MotionEvent ev)92     public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
93         handleClose(false);
94         return false;
95     }
96 
97     @Override
handleClose(boolean animate)98     protected void handleClose(boolean animate) {
99         if (mIsOpen) {
100             mIsOpen = false;
101             mLauncher.getDragLayer().removeView(this);
102             // Reset the translation to what ever it was previously.
103             mLauncher.getHotseat().setTranslationY(mLauncher.getStateManager().getState()
104                     .getHotseatScaleAndTranslation(mLauncher).translationY);
105             mLauncher.getStateManager().removeStateListener(mStateListener);
106         }
107     }
108 
109     @Override
isOfType(int type)110     protected boolean isOfType(int type) {
111         return (type & TYPE_DISCOVERY_BOUNCE) != 0;
112     }
113 
show()114     private void show() {
115         mIsOpen = true;
116         mLauncher.getDragLayer().addView(this);
117         // TODO: add WW log for discovery bounce tip show event.
118     }
119 
showForHomeIfNeeded(Launcher launcher)120     public static void showForHomeIfNeeded(Launcher launcher) {
121         showForHomeIfNeeded(launcher, true);
122     }
123 
showForHomeIfNeeded(Launcher launcher, boolean withDelay)124     private static void showForHomeIfNeeded(Launcher launcher, boolean withDelay) {
125         OnboardingPrefs onboardingPrefs = launcher.getOnboardingPrefs();
126         if (!launcher.isInState(NORMAL)
127                 || onboardingPrefs.getBoolean(OnboardingPrefs.HOME_BOUNCE_SEEN)
128                 || AbstractFloatingView.getTopOpenView(launcher) != null
129                 || launcher.getSystemService(UserManager.class).isDemoUser()
130                 || Utilities.IS_RUNNING_IN_TEST_HARNESS) {
131             return;
132         }
133 
134         if (withDelay) {
135             new Handler().postDelayed(() -> showForHomeIfNeeded(launcher, false), DELAY_MS);
136             return;
137         }
138         onboardingPrefs.incrementEventCount(OnboardingPrefs.HOME_BOUNCE_COUNT);
139         new DiscoveryBounce(launcher).show();
140     }
141 
142     /**
143      * A wrapper around hotseat animator allowing a fixed shift in the value.
144      */
145     public static class VerticalProgressWrapper {
146 
147         private final View mView;
148         private final float mLimit;
149 
VerticalProgressWrapper(View view, float limit)150         private VerticalProgressWrapper(View view, float limit) {
151             mView = view;
152             mLimit = limit;
153         }
154 
getProgress()155         public float getProgress() {
156             return 1 + mView.getTranslationY() / mLimit;
157         }
158 
setProgress(float progress)159         public void setProgress(float progress) {
160             mView.setTranslationY(mLimit * (progress - 1));
161         }
162     }
163 }
164