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