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.TimeInterpolator; 20 import android.content.Context; 21 import android.util.AttributeSet; 22 import android.view.View; 23 import android.view.ViewDebug; 24 import android.view.ViewGroup; 25 import android.view.ViewPropertyAnimator; 26 import android.view.accessibility.AccessibilityManager; 27 import android.view.animation.AccelerateInterpolator; 28 import android.widget.LinearLayout; 29 30 import com.android.launcher3.dragndrop.DragController; 31 import com.android.launcher3.dragndrop.DragOptions; 32 33 /* 34 * The top bar containing various drop targets: Delete/App Info/Uninstall. 35 */ 36 public class DropTargetBar extends LinearLayout implements DragController.DragListener { 37 38 protected static final int DEFAULT_DRAG_FADE_DURATION = 175; 39 protected static final TimeInterpolator DEFAULT_INTERPOLATOR = new AccelerateInterpolator(); 40 41 private final Runnable mFadeAnimationEndRunnable = new Runnable() { 42 43 @Override 44 public void run() { 45 AccessibilityManager am = (AccessibilityManager) 46 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); 47 boolean accessibilityEnabled = am.isEnabled(); 48 AlphaUpdateListener.updateVisibility(DropTargetBar.this, accessibilityEnabled); 49 } 50 }; 51 52 @ViewDebug.ExportedProperty(category = "launcher") 53 protected boolean mDeferOnDragEnd; 54 55 @ViewDebug.ExportedProperty(category = "launcher") 56 protected boolean mVisible = false; 57 58 private ViewPropertyAnimator mCurrentAnimation; 59 60 public DropTargetBar(Context context, AttributeSet attrs) { 61 super(context, attrs); 62 } 63 64 public DropTargetBar(Context context, AttributeSet attrs, int defStyle) { 65 super(context, attrs, defStyle); 66 } 67 68 @Override 69 protected void onFinishInflate() { 70 super.onFinishInflate(); 71 72 // Initialize with hidden state 73 setAlpha(0f); 74 } 75 76 public void setup(DragController dragController) { 77 dragController.addDragListener(this); 78 setupButtonDropTarget(this, dragController); 79 } 80 81 @Override 82 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 83 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 84 85 boolean hideText = hideTextHelper(false /* shouldUpdateText */, false /* no-op */); 86 if (hideTextHelper(true /* shouldUpdateText */, hideText)) { 87 // Text has changed, so we need to re-measure. 88 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 89 } 90 } 91 92 /** 93 * Helper method that iterates through the children and returns whether any of the visible 94 * {@link ButtonDropTarget} has truncated text. 95 * 96 * @param shouldUpdateText If True, updates the text of all children. 97 * @param hideText If True and {@param shouldUpdateText} is True, clears the text of all 98 * children; otherwise it sets the original text value. 99 * 100 * 101 * @return If shouldUpdateText is True, returns whether any of the children updated their text. 102 * Else, returns whether any of the children have truncated their text. 103 */ 104 private boolean hideTextHelper(boolean shouldUpdateText, boolean hideText) { 105 boolean result = false; 106 View visibleView; 107 ButtonDropTarget dropTarget; 108 for (int i = getChildCount() - 1; i >= 0; --i) { 109 if (getChildAt(i) instanceof ButtonDropTarget) { 110 visibleView = dropTarget = (ButtonDropTarget) getChildAt(i); 111 } else if (getChildAt(i) instanceof ViewGroup) { 112 // The Drop Target is wrapped in a FrameLayout. 113 visibleView = getChildAt(i); 114 dropTarget = (ButtonDropTarget) ((ViewGroup) visibleView).getChildAt(0); 115 } else { 116 // Ignore other views. 117 continue; 118 } 119 120 if (visibleView.getVisibility() == View.VISIBLE) { 121 if (shouldUpdateText) { 122 result |= dropTarget.updateText(hideText); 123 } else if (dropTarget.isTextTruncated()) { 124 result = true; 125 break; 126 } 127 } 128 } 129 130 return result; 131 } 132 133 private void setupButtonDropTarget(View view, DragController dragController) { 134 if (view instanceof ButtonDropTarget) { 135 ButtonDropTarget bdt = (ButtonDropTarget) view; 136 bdt.setDropTargetBar(this); 137 dragController.addDragListener(bdt); 138 dragController.addDropTarget(bdt); 139 } else if (view instanceof ViewGroup) { 140 ViewGroup vg = (ViewGroup) view; 141 for (int i = vg.getChildCount() - 1; i >= 0; i--) { 142 setupButtonDropTarget(vg.getChildAt(i), dragController); 143 } 144 } 145 } 146 147 private void animateToVisibility(boolean isVisible) { 148 if (mVisible != isVisible) { 149 mVisible = isVisible; 150 151 // Cancel any existing animation 152 if (mCurrentAnimation != null) { 153 mCurrentAnimation.cancel(); 154 mCurrentAnimation = null; 155 } 156 157 float finalAlpha = mVisible ? 1 : 0; 158 if (Float.compare(getAlpha(), finalAlpha) != 0) { 159 setVisibility(View.VISIBLE); 160 mCurrentAnimation = animate().alpha(finalAlpha) 161 .setInterpolator(DEFAULT_INTERPOLATOR) 162 .setDuration(DEFAULT_DRAG_FADE_DURATION) 163 .withEndAction(mFadeAnimationEndRunnable); 164 } 165 166 } 167 } 168 169 /* 170 * DragController.DragListener implementation 171 */ 172 @Override 173 public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { 174 animateToVisibility(true); 175 } 176 177 /** 178 * This is called to defer hiding the delete drop target until the drop animation has completed, 179 * instead of hiding immediately when the drag has ended. 180 */ 181 protected void deferOnDragEnd() { 182 mDeferOnDragEnd = true; 183 } 184 185 @Override 186 public void onDragEnd() { 187 if (!mDeferOnDragEnd) { 188 animateToVisibility(false); 189 } else { 190 mDeferOnDragEnd = false; 191 } 192 } 193 } 194