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