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.animation.ObjectAnimator; 22 import android.animation.ValueAnimator; 23 import android.content.Context; 24 import android.graphics.Rect; 25 import android.util.AttributeSet; 26 import android.view.View; 27 import android.view.animation.AccelerateInterpolator; 28 import 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 */ 34 public class SearchDropTargetBar extends FrameLayout implements DragController.DragListener { 35 36 private static final int sTransitionInDuration = 200; 37 private static final int sTransitionOutDuration = 175; 38 39 private ObjectAnimator mDropTargetBarAnim; 40 private ValueAnimator mQSBSearchBarAnim; 41 private static final AccelerateInterpolator sAccelerateInterpolator = 42 new AccelerateInterpolator(); 43 44 private boolean mIsSearchBarHidden; 45 private View mQSBSearchBar; 46 private View mDropTargetBar; 47 private ButtonDropTarget mInfoDropTarget; 48 private ButtonDropTarget mDeleteDropTarget; 49 private int mBarHeight; 50 private boolean mDeferOnDragEnd = false; 51 52 private boolean mEnableDropDownDropTargets; 53 54 public SearchDropTargetBar(Context context, AttributeSet attrs) { 55 this(context, attrs, 0); 56 } 57 58 public SearchDropTargetBar(Context context, AttributeSet attrs, int defStyle) { 59 super(context, attrs, defStyle); 60 } 61 62 public void setup(Launcher launcher, DragController dragController) { 63 dragController.addDragListener(this); 64 dragController.addDragListener(mInfoDropTarget); 65 dragController.addDragListener(mDeleteDropTarget); 66 dragController.addDropTarget(mInfoDropTarget); 67 dragController.addDropTarget(mDeleteDropTarget); 68 dragController.setFlingToDeleteDropTarget(mDeleteDropTarget); 69 mInfoDropTarget.setLauncher(launcher); 70 mDeleteDropTarget.setLauncher(launcher); 71 } 72 73 public void setQsbSearchBar(View qsb) { 74 mQSBSearchBar = qsb; 75 if (mQSBSearchBar != null) { 76 if (mEnableDropDownDropTargets) { 77 mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "translationY", 0, 78 -mBarHeight); 79 } else { 80 mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "alpha", 1f, 0f); 81 } 82 setupAnimation(mQSBSearchBarAnim, mQSBSearchBar); 83 } else { 84 // Create a no-op animation of the search bar is null 85 mQSBSearchBarAnim = ValueAnimator.ofFloat(0, 0); 86 mQSBSearchBarAnim.setDuration(sTransitionInDuration); 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(sTransitionInDuration); 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 120 mInfoDropTarget.setSearchDropTargetBar(this); 121 mDeleteDropTarget.setSearchDropTargetBar(this); 122 123 mEnableDropDownDropTargets = 124 getResources().getBoolean(R.bool.config_useDropTargetDownTransition); 125 126 // Create the various fade animations 127 if (mEnableDropDownDropTargets) { 128 LauncherAppState app = LauncherAppState.getInstance(); 129 DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); 130 mBarHeight = grid.searchBarSpaceHeightPx; 131 mDropTargetBar.setTranslationY(-mBarHeight); 132 mDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "translationY", 133 -mBarHeight, 0f); 134 135 } else { 136 mDropTargetBar.setAlpha(0f); 137 mDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "alpha", 0f, 1f); 138 } 139 setupAnimation(mDropTargetBarAnim, mDropTargetBar); 140 } 141 142 public void finishAnimations() { 143 prepareStartAnimation(mDropTargetBar); 144 mDropTargetBarAnim.reverse(); 145 prepareStartAnimation(mQSBSearchBar); 146 mQSBSearchBarAnim.reverse(); 147 } 148 149 /* 150 * Shows and hides the search bar. 151 */ 152 public void showSearchBar(boolean animated) { 153 boolean needToCancelOngoingAnimation = mQSBSearchBarAnim.isRunning() && !animated; 154 if (!mIsSearchBarHidden && !needToCancelOngoingAnimation) return; 155 if (animated) { 156 prepareStartAnimation(mQSBSearchBar); 157 mQSBSearchBarAnim.reverse(); 158 } else { 159 mQSBSearchBarAnim.cancel(); 160 if (mQSBSearchBar != null && mEnableDropDownDropTargets) { 161 mQSBSearchBar.setTranslationY(0); 162 } else if (mQSBSearchBar != null) { 163 mQSBSearchBar.setAlpha(1f); 164 } 165 } 166 mIsSearchBarHidden = false; 167 } 168 public void hideSearchBar(boolean animated) { 169 boolean needToCancelOngoingAnimation = mQSBSearchBarAnim.isRunning() && !animated; 170 if (mIsSearchBarHidden && !needToCancelOngoingAnimation) return; 171 if (animated) { 172 prepareStartAnimation(mQSBSearchBar); 173 mQSBSearchBarAnim.start(); 174 } else { 175 mQSBSearchBarAnim.cancel(); 176 if (mQSBSearchBar != null && mEnableDropDownDropTargets) { 177 mQSBSearchBar.setTranslationY(-mBarHeight); 178 } else if (mQSBSearchBar != null) { 179 mQSBSearchBar.setAlpha(0f); 180 } 181 } 182 mIsSearchBarHidden = true; 183 } 184 185 /* 186 * Gets various transition durations. 187 */ 188 public int getTransitionInDuration() { 189 return sTransitionInDuration; 190 } 191 public int getTransitionOutDuration() { 192 return sTransitionOutDuration; 193 } 194 195 /* 196 * DragController.DragListener implementation 197 */ 198 @Override 199 public void onDragStart(DragSource source, Object info, int dragAction) { 200 // Animate out the QSB search bar, and animate in the drop target bar 201 prepareStartAnimation(mDropTargetBar); 202 mDropTargetBarAnim.start(); 203 if (!mIsSearchBarHidden) { 204 prepareStartAnimation(mQSBSearchBar); 205 mQSBSearchBarAnim.start(); 206 } 207 } 208 209 public void deferOnDragEnd() { 210 mDeferOnDragEnd = true; 211 } 212 213 @Override 214 public void onDragEnd() { 215 if (!mDeferOnDragEnd) { 216 // Restore the QSB search bar, and animate out the drop target bar 217 prepareStartAnimation(mDropTargetBar); 218 mDropTargetBarAnim.reverse(); 219 if (!mIsSearchBarHidden) { 220 prepareStartAnimation(mQSBSearchBar); 221 mQSBSearchBarAnim.reverse(); 222 } 223 } else { 224 mDeferOnDragEnd = false; 225 } 226 } 227 228 public Rect getSearchBarBounds() { 229 if (mQSBSearchBar != null) { 230 final int[] pos = new int[2]; 231 mQSBSearchBar.getLocationOnScreen(pos); 232 233 final Rect rect = new Rect(); 234 rect.left = pos[0]; 235 rect.top = pos[1]; 236 rect.right = pos[0] + mQSBSearchBar.getWidth(); 237 rect.bottom = pos[1] + mQSBSearchBar.getHeight(); 238 return rect; 239 } else { 240 return null; 241 } 242 } 243 } 244