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