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    }
81
82    private void setupAnimation(ObjectAnimator anim, final View v) {
83        anim.setInterpolator(sAccelerateInterpolator);
84        anim.setDuration(sTransitionInDuration);
85        anim.addListener(new AnimatorListenerAdapter() {
86            @Override
87            public void onAnimationEnd(Animator animation) {
88                v.setLayerType(View.LAYER_TYPE_NONE, null);
89            }
90        });
91    }
92
93    @Override
94    protected void onFinishInflate() {
95        super.onFinishInflate();
96
97        // Get the individual components
98        mQSBSearchBar = findViewById(R.id.qsb_search_bar);
99        mDropTargetBar = findViewById(R.id.drag_target_bar);
100        mInfoDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.info_target_text);
101        mDeleteDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.delete_target_text);
102        mBarHeight = getResources().getDimensionPixelSize(R.dimen.qsb_bar_height);
103
104        mInfoDropTarget.setSearchDropTargetBar(this);
105        mDeleteDropTarget.setSearchDropTargetBar(this);
106
107        mEnableDropDownDropTargets =
108            getResources().getBoolean(R.bool.config_useDropTargetDownTransition);
109
110        // Create the various fade animations
111        if (mEnableDropDownDropTargets) {
112            mDropTargetBar.setTranslationY(-mBarHeight);
113            mDropTargetBarAnim = ObjectAnimator.ofFloat(mDropTargetBar, "translationY", -mBarHeight, 0f);
114            mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "translationY", 0f, -mBarHeight);
115        } else {
116            mDropTargetBar.setAlpha(0f);
117            mDropTargetBarAnim = ObjectAnimator.ofFloat(mDropTargetBar, "alpha", 0f, 1f);
118            mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "alpha", 1f, 0f);
119        }
120        setupAnimation(mDropTargetBarAnim, mDropTargetBar);
121        setupAnimation(mQSBSearchBarAnim, mQSBSearchBar);
122    }
123
124    public void finishAnimations() {
125        prepareStartAnimation(mDropTargetBar);
126        mDropTargetBarAnim.reverse();
127        prepareStartAnimation(mQSBSearchBar);
128        mQSBSearchBarAnim.reverse();
129    }
130
131    /*
132     * Shows and hides the search bar.
133     */
134    public void showSearchBar(boolean animated) {
135        if (!mIsSearchBarHidden) return;
136        if (animated) {
137            prepareStartAnimation(mQSBSearchBar);
138            mQSBSearchBarAnim.reverse();
139        } else {
140            mQSBSearchBarAnim.cancel();
141            if (mEnableDropDownDropTargets) {
142                mQSBSearchBar.setTranslationY(0);
143            } else {
144                mQSBSearchBar.setAlpha(1f);
145            }
146        }
147        mIsSearchBarHidden = false;
148    }
149    public void hideSearchBar(boolean animated) {
150        if (mIsSearchBarHidden) return;
151        if (animated) {
152            prepareStartAnimation(mQSBSearchBar);
153            mQSBSearchBarAnim.start();
154        } else {
155            mQSBSearchBarAnim.cancel();
156            if (mEnableDropDownDropTargets) {
157                mQSBSearchBar.setTranslationY(-mBarHeight);
158            } else {
159                mQSBSearchBar.setAlpha(0f);
160            }
161        }
162        mIsSearchBarHidden = true;
163    }
164
165    /*
166     * Gets various transition durations.
167     */
168    public int getTransitionInDuration() {
169        return sTransitionInDuration;
170    }
171    public int getTransitionOutDuration() {
172        return sTransitionOutDuration;
173    }
174
175    /*
176     * DragController.DragListener implementation
177     */
178    @Override
179    public void onDragStart(DragSource source, Object info, int dragAction) {
180        // Animate out the QSB search bar, and animate in the drop target bar
181        prepareStartAnimation(mDropTargetBar);
182        mDropTargetBarAnim.start();
183        if (!mIsSearchBarHidden) {
184            prepareStartAnimation(mQSBSearchBar);
185            mQSBSearchBarAnim.start();
186        }
187    }
188
189    public void deferOnDragEnd() {
190        mDeferOnDragEnd = true;
191    }
192
193    @Override
194    public void onDragEnd() {
195        if (!mDeferOnDragEnd) {
196            // Restore the QSB search bar, and animate out the drop target bar
197            prepareStartAnimation(mDropTargetBar);
198            mDropTargetBarAnim.reverse();
199            if (!mIsSearchBarHidden) {
200                prepareStartAnimation(mQSBSearchBar);
201                mQSBSearchBarAnim.reverse();
202            }
203        } else {
204            mDeferOnDragEnd = false;
205        }
206    }
207
208    public void onSearchPackagesChanged(boolean searchVisible, boolean voiceVisible) {
209        if (mQSBSearchBar != null) {
210            Drawable bg = mQSBSearchBar.getBackground();
211            if (bg != null && (!searchVisible && !voiceVisible)) {
212                // Save the background and disable it
213                mPreviousBackground = bg;
214                mQSBSearchBar.setBackgroundResource(0);
215            } else if (mPreviousBackground != null && (searchVisible || voiceVisible)) {
216                // Restore the background
217                mQSBSearchBar.setBackground(mPreviousBackground);
218            }
219        }
220    }
221
222    public Rect getSearchBarBounds() {
223        if (mQSBSearchBar != null) {
224            final int[] pos = new int[2];
225            mQSBSearchBar.getLocationOnScreen(pos);
226
227            final Rect rect = new Rect();
228            rect.left = pos[0];
229            rect.top = pos[1];
230            rect.right = pos[0] + mQSBSearchBar.getWidth();
231            rect.bottom = pos[1] + mQSBSearchBar.getHeight();
232            return rect;
233        } else {
234            return null;
235        }
236    }
237}
238