• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.content.Context;
22 import android.graphics.Rect;
23 import android.util.AttributeSet;
24 import android.view.View;
25 import android.view.accessibility.AccessibilityManager;
26 import android.view.animation.AccelerateInterpolator;
27 import android.widget.FrameLayout;
28 
29 import com.android.launcher3.util.Thunk;
30 
31 /*
32  * Ths bar will manage the transition between the QSB search bar and the delete drop
33  * targets so that each of the individual IconDropTargets don't have to.
34  */
35 public class SearchDropTargetBar extends FrameLayout implements DragController.DragListener {
36 
37     /** The different states that the search bar space can be in. */
38     public enum State {
39         INVISIBLE   (0f, 0f),
40         SEARCH_BAR  (1f, 0f),
41         DROP_TARGET (0f, 1f);
42 
43         private final float mSearchBarAlpha;
44         private final float mDropTargetBarAlpha;
45 
State(float sbAlpha, float dtbAlpha)46         State(float sbAlpha, float dtbAlpha) {
47             mSearchBarAlpha = sbAlpha;
48             mDropTargetBarAlpha = dtbAlpha;
49         }
50 
getSearchBarAlpha()51         float getSearchBarAlpha() {
52             return mSearchBarAlpha;
53         }
54 
getDropTargetBarAlpha()55         float getDropTargetBarAlpha() {
56             return mDropTargetBarAlpha;
57         }
58     }
59 
60     private static int DEFAULT_DRAG_FADE_DURATION = 175;
61 
62     private LauncherViewPropertyAnimator mDropTargetBarAnimator;
63     private LauncherViewPropertyAnimator mQSBSearchBarAnimator;
64     private static final AccelerateInterpolator sAccelerateInterpolator =
65             new AccelerateInterpolator();
66 
67     private State mState = State.SEARCH_BAR;
68     @Thunk View mQSB;
69     @Thunk View mDropTargetBar;
70     private boolean mDeferOnDragEnd = false;
71     @Thunk boolean mAccessibilityEnabled = false;
72 
73     // Drop targets
74     private ButtonDropTarget mInfoDropTarget;
75     private ButtonDropTarget mDeleteDropTarget;
76     private ButtonDropTarget mUninstallDropTarget;
77 
SearchDropTargetBar(Context context, AttributeSet attrs)78     public SearchDropTargetBar(Context context, AttributeSet attrs) {
79         this(context, attrs, 0);
80     }
81 
SearchDropTargetBar(Context context, AttributeSet attrs, int defStyle)82     public SearchDropTargetBar(Context context, AttributeSet attrs, int defStyle) {
83         super(context, attrs, defStyle);
84     }
85 
setup(Launcher launcher, DragController dragController)86     public void setup(Launcher launcher, DragController dragController) {
87         dragController.addDragListener(this);
88         dragController.setFlingToDeleteDropTarget(mDeleteDropTarget);
89 
90         dragController.addDragListener(mInfoDropTarget);
91         dragController.addDragListener(mDeleteDropTarget);
92         dragController.addDragListener(mUninstallDropTarget);
93 
94         dragController.addDropTarget(mInfoDropTarget);
95         dragController.addDropTarget(mDeleteDropTarget);
96         dragController.addDropTarget(mUninstallDropTarget);
97 
98         mInfoDropTarget.setLauncher(launcher);
99         mDeleteDropTarget.setLauncher(launcher);
100         mUninstallDropTarget.setLauncher(launcher);
101     }
102 
103     @Override
onFinishInflate()104     protected void onFinishInflate() {
105         super.onFinishInflate();
106 
107         // Get the individual components
108         mDropTargetBar = findViewById(R.id.drag_target_bar);
109         mInfoDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.info_target_text);
110         mDeleteDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.delete_target_text);
111         mUninstallDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.uninstall_target_text);
112 
113         mInfoDropTarget.setSearchDropTargetBar(this);
114         mDeleteDropTarget.setSearchDropTargetBar(this);
115         mUninstallDropTarget.setSearchDropTargetBar(this);
116 
117         // Create the various fade animations
118         mDropTargetBar.setAlpha(0f);
119         mDropTargetBarAnimator = new LauncherViewPropertyAnimator(mDropTargetBar);
120         mDropTargetBarAnimator.setInterpolator(sAccelerateInterpolator);
121         mDropTargetBarAnimator.addListener(new AnimatorListenerAdapter() {
122             @Override
123             public void onAnimationStart(Animator animation) {
124                 // Ensure that the view is visible for the animation
125                 mDropTargetBar.setVisibility(View.VISIBLE);
126             }
127 
128             @Override
129             public void onAnimationEnd(Animator animation) {
130                 if (mDropTargetBar != null) {
131                     AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled);
132                 }
133             }
134         });
135     }
136 
setQsbSearchBar(View qsb)137     public void setQsbSearchBar(View qsb) {
138         mQSB = qsb;
139         if (mQSB != null) {
140             // Update the search ber animation
141             mQSBSearchBarAnimator = new LauncherViewPropertyAnimator(mQSB);
142             mQSBSearchBarAnimator.setInterpolator(sAccelerateInterpolator);
143             mQSBSearchBarAnimator.addListener(new AnimatorListenerAdapter() {
144                 @Override
145                 public void onAnimationStart(Animator animation) {
146                     // Ensure that the view is visible for the animation
147                     if (mQSB != null) {
148                         mQSB.setVisibility(View.VISIBLE);
149                     }
150                 }
151 
152                 @Override
153                 public void onAnimationEnd(Animator animation) {
154                     if (mQSB != null) {
155                         AlphaUpdateListener.updateVisibility(mQSB, mAccessibilityEnabled);
156                     }
157                 }
158             });
159         } else {
160             mQSBSearchBarAnimator = null;
161         }
162     }
163 
164     /**
165      * Animates the current search bar state to a new state.  If the {@param duration} is 0, then
166      * the state is applied immediately.
167      */
animateToState(State newState, int duration)168     public void animateToState(State newState, int duration) {
169         if (mState != newState) {
170             mState = newState;
171 
172             // Update the accessibility state
173             AccessibilityManager am = (AccessibilityManager)
174                     getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
175             mAccessibilityEnabled = am.isEnabled();
176 
177             animateViewAlpha(mQSBSearchBarAnimator, mQSB, newState.getSearchBarAlpha(),
178                     duration);
179             animateViewAlpha(mDropTargetBarAnimator, mDropTargetBar, newState.getDropTargetBarAlpha(),
180                     duration);
181         }
182     }
183 
184     /**
185      * Convenience method to animate the alpha of a view using hardware layers.
186      */
animateViewAlpha(LauncherViewPropertyAnimator animator, View v, float alpha, int duration)187     private void animateViewAlpha(LauncherViewPropertyAnimator animator, View v, float alpha,
188             int duration) {
189         if (v == null) {
190             return;
191         }
192 
193         animator.cancel();
194         if (Float.compare(v.getAlpha(), alpha) != 0) {
195             if (duration > 0) {
196                 animator.alpha(alpha).withLayer().setDuration(duration).start();
197             } else {
198                 v.setAlpha(alpha);
199                 AlphaUpdateListener.updateVisibility(v, mAccessibilityEnabled);
200             }
201         }
202     }
203 
204     /*
205      * DragController.DragListener implementation
206      */
207     @Override
onDragStart(DragSource source, Object info, int dragAction)208     public void onDragStart(DragSource source, Object info, int dragAction) {
209         animateToState(State.DROP_TARGET, DEFAULT_DRAG_FADE_DURATION);
210     }
211 
212     /**
213      * This is called to defer hiding the delete drop target until the drop animation has completed,
214      * instead of hiding immediately when the drag has ended.
215      */
deferOnDragEnd()216     public void deferOnDragEnd() {
217         mDeferOnDragEnd = true;
218     }
219 
220     @Override
onDragEnd()221     public void onDragEnd() {
222         if (!mDeferOnDragEnd) {
223             animateToState(State.SEARCH_BAR, DEFAULT_DRAG_FADE_DURATION);
224         } else {
225             mDeferOnDragEnd = false;
226         }
227     }
228 
229     /**
230      * @return the bounds of the QSB search bar.
231      */
getSearchBarBounds()232     public Rect getSearchBarBounds() {
233         if (mQSB != null) {
234             final int[] pos = new int[2];
235             mQSB.getLocationOnScreen(pos);
236 
237             final Rect rect = new Rect();
238             rect.left = pos[0];
239             rect.top = pos[1];
240             rect.right = pos[0] + mQSB.getWidth();
241             rect.bottom = pos[1] + mQSB.getHeight();
242             return rect;
243         } else {
244             return null;
245         }
246     }
247 
enableAccessibleDrag(boolean enable)248     public void enableAccessibleDrag(boolean enable) {
249         if (mQSB != null) {
250             mQSB.setVisibility(enable ? View.GONE : View.VISIBLE);
251         }
252         mInfoDropTarget.enableAccessibleDrag(enable);
253         mDeleteDropTarget.enableAccessibleDrag(enable);
254         mUninstallDropTarget.enableAccessibleDrag(enable);
255     }
256 }
257