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
17package com.android.launcher3;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ObjectAnimator;
22import android.animation.ValueAnimator;
23import android.content.Context;
24import android.graphics.Rect;
25import android.util.AttributeSet;
26import android.view.View;
27import android.view.animation.AccelerateInterpolator;
28import android.widget.FrameLayout;
29
30/*
31 * Ths bar will manage the transition between the QSB search bar and the delete drop
32 * targets so that each of the individual IconDropTargets don't have to.
33 */
34public class SearchDropTargetBar extends FrameLayout implements DragController.DragListener {
35
36    private static final int TRANSITION_DURATION = 200;
37
38    private ObjectAnimator mShowDropTargetBarAnim;
39    private ValueAnimator mHideSearchBarAnim;
40    private static final AccelerateInterpolator sAccelerateInterpolator =
41            new AccelerateInterpolator();
42
43    private boolean mIsSearchBarHidden;
44    private View mQSBSearchBar;
45    private View mDropTargetBar;
46    private boolean mDeferOnDragEnd = false;
47
48    // Drop targets
49    private ButtonDropTarget mInfoDropTarget;
50    private ButtonDropTarget mDeleteDropTarget;
51    private ButtonDropTarget mUninstallDropTarget;
52
53    public SearchDropTargetBar(Context context, AttributeSet attrs) {
54        this(context, attrs, 0);
55    }
56
57    public SearchDropTargetBar(Context context, AttributeSet attrs, int defStyle) {
58        super(context, attrs, defStyle);
59    }
60
61    public void setup(Launcher launcher, DragController dragController) {
62        dragController.addDragListener(this);
63        dragController.setFlingToDeleteDropTarget(mDeleteDropTarget);
64
65        dragController.addDragListener(mInfoDropTarget);
66        dragController.addDragListener(mDeleteDropTarget);
67        dragController.addDragListener(mUninstallDropTarget);
68
69        dragController.addDropTarget(mInfoDropTarget);
70        dragController.addDropTarget(mDeleteDropTarget);
71        dragController.addDropTarget(mUninstallDropTarget);
72
73        mInfoDropTarget.setLauncher(launcher);
74        mDeleteDropTarget.setLauncher(launcher);
75        mUninstallDropTarget.setLauncher(launcher);
76    }
77
78    public void setQsbSearchBar(View qsb) {
79        mQSBSearchBar = qsb;
80        if (mQSBSearchBar != null) {
81            mHideSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "alpha", 1f, 0f);
82            setupAnimation(mHideSearchBarAnim, mQSBSearchBar);
83        } else {
84            // Create a no-op animation of the search bar is null
85            mHideSearchBarAnim = ValueAnimator.ofFloat(0, 0);
86            mHideSearchBarAnim.setDuration(TRANSITION_DURATION);
87        }
88    }
89
90    private void prepareStartAnimation(View v) {
91        // Enable the hw layers before the animation starts (will be disabled in the onAnimationEnd
92        // callback below)
93        if (v != null) {
94            v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
95        }
96    }
97
98    private void setupAnimation(ValueAnimator anim, final View v) {
99        anim.setInterpolator(sAccelerateInterpolator);
100        anim.setDuration(TRANSITION_DURATION);
101        anim.addListener(new AnimatorListenerAdapter() {
102            @Override
103            public void onAnimationEnd(Animator animation) {
104                if (v != null) {
105                    v.setLayerType(View.LAYER_TYPE_NONE, null);
106                }
107            }
108        });
109    }
110
111    @Override
112    protected void onFinishInflate() {
113        super.onFinishInflate();
114
115        // Get the individual components
116        mDropTargetBar = findViewById(R.id.drag_target_bar);
117        mInfoDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.info_target_text);
118        mDeleteDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.delete_target_text);
119        mUninstallDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.uninstall_target_text);
120
121        mInfoDropTarget.setSearchDropTargetBar(this);
122        mDeleteDropTarget.setSearchDropTargetBar(this);
123        mUninstallDropTarget.setSearchDropTargetBar(this);
124
125        // Create the various fade animations
126        mDropTargetBar.setAlpha(0f);
127        mShowDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "alpha", 0f, 1f);
128        setupAnimation(mShowDropTargetBarAnim, mDropTargetBar);
129    }
130
131    /**
132     * Finishes all the animations on the search and drop target bars.
133     */
134    public void finishAnimations() {
135        prepareStartAnimation(mDropTargetBar);
136        mShowDropTargetBarAnim.reverse();
137        prepareStartAnimation(mQSBSearchBar);
138        mHideSearchBarAnim.reverse();
139    }
140
141    /**
142     * Shows the search bar.
143     */
144    public void showSearchBar(boolean animated) {
145        if (!mIsSearchBarHidden) return;
146        if (animated) {
147            prepareStartAnimation(mQSBSearchBar);
148            mHideSearchBarAnim.reverse();
149        } else {
150            mHideSearchBarAnim.cancel();
151            if (mQSBSearchBar != null) {
152                mQSBSearchBar.setAlpha(1f);
153            }
154        }
155        mIsSearchBarHidden = false;
156    }
157
158    /**
159     * Hides the search bar.  We only use this for clings.
160     */
161    public void hideSearchBar(boolean animated) {
162        if (mIsSearchBarHidden) return;
163        if (animated) {
164            prepareStartAnimation(mQSBSearchBar);
165            mHideSearchBarAnim.start();
166        } else {
167            mHideSearchBarAnim.cancel();
168            if (mQSBSearchBar != null) {
169                mQSBSearchBar.setAlpha(0f);
170            }
171        }
172        mIsSearchBarHidden = true;
173    }
174
175    /**
176     * Shows the drop target bar.
177     */
178    public void showDeleteTarget() {
179        // Animate out the QSB search bar, and animate in the drop target bar
180        prepareStartAnimation(mDropTargetBar);
181        mShowDropTargetBarAnim.start();
182        hideSearchBar(true);
183    }
184
185    /**
186     * Hides the drop target bar.
187     */
188    public void hideDeleteTarget() {
189        // Restore the QSB search bar, and animate out the drop target bar
190        prepareStartAnimation(mDropTargetBar);
191        mShowDropTargetBarAnim.reverse();
192        showSearchBar(true);
193    }
194
195    /*
196     * DragController.DragListener implementation
197     */
198    @Override
199    public void onDragStart(DragSource source, Object info, int dragAction) {
200        showDeleteTarget();
201    }
202
203    public void deferOnDragEnd() {
204        mDeferOnDragEnd = true;
205    }
206
207    @Override
208    public void onDragEnd() {
209        if (!mDeferOnDragEnd) {
210            hideDeleteTarget();
211        } else {
212            mDeferOnDragEnd = false;
213        }
214    }
215
216    public Rect getSearchBarBounds() {
217        if (mQSBSearchBar != null) {
218            final int[] pos = new int[2];
219            mQSBSearchBar.getLocationOnScreen(pos);
220
221            final Rect rect = new Rect();
222            rect.left = pos[0];
223            rect.top = pos[1];
224            rect.right = pos[0] + mQSBSearchBar.getWidth();
225            rect.bottom = pos[1] + mQSBSearchBar.getHeight();
226            return rect;
227        } else {
228            return null;
229        }
230    }
231
232    public void enableAccessibleDrag(boolean enable) {
233        if (mQSBSearchBar != null) {
234            mQSBSearchBar.setVisibility(enable ? View.GONE : View.VISIBLE);
235        }
236        mInfoDropTarget.enableAccessibleDrag(enable);
237        mDeleteDropTarget.enableAccessibleDrag(enable);
238        mUninstallDropTarget.enableAccessibleDrag(enable);
239    }
240}
241