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.content.Context; 22 import android.graphics.Rect; 23 import android.util.AttributeSet; 24 import android.view.View; 25 import android.view.accessibility.AccessibilityManager; 26 import android.view.animation.AccelerateInterpolator; 27 import android.widget.FrameLayout; 28 29 import com.android.launcher3.util.Thunk; 30 31 /* 32 * Ths bar will manage the transition between the QSB search bar and the delete drop 33 * targets so that each of the individual IconDropTargets don't have to. 34 */ 35 public class SearchDropTargetBar extends FrameLayout implements DragController.DragListener { 36 37 /** The different states that the search bar space can be in. */ 38 public enum State { 39 INVISIBLE (0f, 0f), 40 SEARCH_BAR (1f, 0f), 41 DROP_TARGET (0f, 1f); 42 43 private final float mSearchBarAlpha; 44 private final float mDropTargetBarAlpha; 45 State(float sbAlpha, float dtbAlpha)46 State(float sbAlpha, float dtbAlpha) { 47 mSearchBarAlpha = sbAlpha; 48 mDropTargetBarAlpha = dtbAlpha; 49 } 50 getSearchBarAlpha()51 float getSearchBarAlpha() { 52 return mSearchBarAlpha; 53 } 54 getDropTargetBarAlpha()55 float getDropTargetBarAlpha() { 56 return mDropTargetBarAlpha; 57 } 58 } 59 60 private static int DEFAULT_DRAG_FADE_DURATION = 175; 61 62 private LauncherViewPropertyAnimator mDropTargetBarAnimator; 63 private LauncherViewPropertyAnimator mQSBSearchBarAnimator; 64 private static final AccelerateInterpolator sAccelerateInterpolator = 65 new AccelerateInterpolator(); 66 67 private State mState = State.SEARCH_BAR; 68 @Thunk View mQSB; 69 @Thunk View mDropTargetBar; 70 private boolean mDeferOnDragEnd = false; 71 @Thunk boolean mAccessibilityEnabled = false; 72 73 // Drop targets 74 private ButtonDropTarget mInfoDropTarget; 75 private ButtonDropTarget mDeleteDropTarget; 76 private ButtonDropTarget mUninstallDropTarget; 77 SearchDropTargetBar(Context context, AttributeSet attrs)78 public SearchDropTargetBar(Context context, AttributeSet attrs) { 79 this(context, attrs, 0); 80 } 81 SearchDropTargetBar(Context context, AttributeSet attrs, int defStyle)82 public SearchDropTargetBar(Context context, AttributeSet attrs, int defStyle) { 83 super(context, attrs, defStyle); 84 } 85 setup(Launcher launcher, DragController dragController)86 public void setup(Launcher launcher, DragController dragController) { 87 dragController.addDragListener(this); 88 dragController.setFlingToDeleteDropTarget(mDeleteDropTarget); 89 90 dragController.addDragListener(mInfoDropTarget); 91 dragController.addDragListener(mDeleteDropTarget); 92 dragController.addDragListener(mUninstallDropTarget); 93 94 dragController.addDropTarget(mInfoDropTarget); 95 dragController.addDropTarget(mDeleteDropTarget); 96 dragController.addDropTarget(mUninstallDropTarget); 97 98 mInfoDropTarget.setLauncher(launcher); 99 mDeleteDropTarget.setLauncher(launcher); 100 mUninstallDropTarget.setLauncher(launcher); 101 } 102 103 @Override onFinishInflate()104 protected void onFinishInflate() { 105 super.onFinishInflate(); 106 107 // Get the individual components 108 mDropTargetBar = findViewById(R.id.drag_target_bar); 109 mInfoDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.info_target_text); 110 mDeleteDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.delete_target_text); 111 mUninstallDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.uninstall_target_text); 112 113 mInfoDropTarget.setSearchDropTargetBar(this); 114 mDeleteDropTarget.setSearchDropTargetBar(this); 115 mUninstallDropTarget.setSearchDropTargetBar(this); 116 117 // Create the various fade animations 118 mDropTargetBar.setAlpha(0f); 119 mDropTargetBarAnimator = new LauncherViewPropertyAnimator(mDropTargetBar); 120 mDropTargetBarAnimator.setInterpolator(sAccelerateInterpolator); 121 mDropTargetBarAnimator.addListener(new AnimatorListenerAdapter() { 122 @Override 123 public void onAnimationStart(Animator animation) { 124 // Ensure that the view is visible for the animation 125 mDropTargetBar.setVisibility(View.VISIBLE); 126 } 127 128 @Override 129 public void onAnimationEnd(Animator animation) { 130 if (mDropTargetBar != null) { 131 AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled); 132 } 133 } 134 }); 135 } 136 setQsbSearchBar(View qsb)137 public void setQsbSearchBar(View qsb) { 138 mQSB = qsb; 139 if (mQSB != null) { 140 // Update the search ber animation 141 mQSBSearchBarAnimator = new LauncherViewPropertyAnimator(mQSB); 142 mQSBSearchBarAnimator.setInterpolator(sAccelerateInterpolator); 143 mQSBSearchBarAnimator.addListener(new AnimatorListenerAdapter() { 144 @Override 145 public void onAnimationStart(Animator animation) { 146 // Ensure that the view is visible for the animation 147 if (mQSB != null) { 148 mQSB.setVisibility(View.VISIBLE); 149 } 150 } 151 152 @Override 153 public void onAnimationEnd(Animator animation) { 154 if (mQSB != null) { 155 AlphaUpdateListener.updateVisibility(mQSB, mAccessibilityEnabled); 156 } 157 } 158 }); 159 } else { 160 mQSBSearchBarAnimator = null; 161 } 162 } 163 164 /** 165 * Animates the current search bar state to a new state. If the {@param duration} is 0, then 166 * the state is applied immediately. 167 */ animateToState(State newState, int duration)168 public void animateToState(State newState, int duration) { 169 if (mState != newState) { 170 mState = newState; 171 172 // Update the accessibility state 173 AccessibilityManager am = (AccessibilityManager) 174 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); 175 mAccessibilityEnabled = am.isEnabled(); 176 177 animateViewAlpha(mQSBSearchBarAnimator, mQSB, newState.getSearchBarAlpha(), 178 duration); 179 animateViewAlpha(mDropTargetBarAnimator, mDropTargetBar, newState.getDropTargetBarAlpha(), 180 duration); 181 } 182 } 183 184 /** 185 * Convenience method to animate the alpha of a view using hardware layers. 186 */ animateViewAlpha(LauncherViewPropertyAnimator animator, View v, float alpha, int duration)187 private void animateViewAlpha(LauncherViewPropertyAnimator animator, View v, float alpha, 188 int duration) { 189 if (v == null) { 190 return; 191 } 192 193 animator.cancel(); 194 if (Float.compare(v.getAlpha(), alpha) != 0) { 195 if (duration > 0) { 196 animator.alpha(alpha).withLayer().setDuration(duration).start(); 197 } else { 198 v.setAlpha(alpha); 199 AlphaUpdateListener.updateVisibility(v, mAccessibilityEnabled); 200 } 201 } 202 } 203 204 /* 205 * DragController.DragListener implementation 206 */ 207 @Override onDragStart(DragSource source, Object info, int dragAction)208 public void onDragStart(DragSource source, Object info, int dragAction) { 209 animateToState(State.DROP_TARGET, DEFAULT_DRAG_FADE_DURATION); 210 } 211 212 /** 213 * This is called to defer hiding the delete drop target until the drop animation has completed, 214 * instead of hiding immediately when the drag has ended. 215 */ deferOnDragEnd()216 public void deferOnDragEnd() { 217 mDeferOnDragEnd = true; 218 } 219 220 @Override onDragEnd()221 public void onDragEnd() { 222 if (!mDeferOnDragEnd) { 223 animateToState(State.SEARCH_BAR, DEFAULT_DRAG_FADE_DURATION); 224 } else { 225 mDeferOnDragEnd = false; 226 } 227 } 228 229 /** 230 * @return the bounds of the QSB search bar. 231 */ getSearchBarBounds()232 public Rect getSearchBarBounds() { 233 if (mQSB != null) { 234 final int[] pos = new int[2]; 235 mQSB.getLocationOnScreen(pos); 236 237 final Rect rect = new Rect(); 238 rect.left = pos[0]; 239 rect.top = pos[1]; 240 rect.right = pos[0] + mQSB.getWidth(); 241 rect.bottom = pos[1] + mQSB.getHeight(); 242 return rect; 243 } else { 244 return null; 245 } 246 } 247 enableAccessibleDrag(boolean enable)248 public void enableAccessibleDrag(boolean enable) { 249 if (mQSB != null) { 250 mQSB.setVisibility(enable ? View.GONE : View.VISIBLE); 251 } 252 mInfoDropTarget.enableAccessibleDrag(enable); 253 mDeleteDropTarget.enableAccessibleDrag(enable); 254 mUninstallDropTarget.enableAccessibleDrag(enable); 255 } 256 } 257