blob: 29a1349d5c8e6b8a9e945676f9cc3850ed5a604b [file] [log] [blame]
Sunny Goyal47328fd2016-05-25 18:56:41 -07001/*
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.TimeInterpolator;
20import android.content.Context;
21import android.util.AttributeSet;
22import android.view.View;
23import android.view.ViewDebug;
Sunny Goyal0f76b562016-12-13 19:37:10 -080024import android.view.ViewGroup;
Sunny Goyal47328fd2016-05-25 18:56:41 -070025import android.view.ViewPropertyAnimator;
26import android.view.accessibility.AccessibilityManager;
27import android.view.animation.AccelerateInterpolator;
28import android.widget.LinearLayout;
29
30import com.android.launcher3.dragndrop.DragController;
Sunny Goyal94b510c2016-08-16 15:36:48 -070031import com.android.launcher3.dragndrop.DragOptions;
Sunny Goyal47328fd2016-05-25 18:56:41 -070032
33/*
34 * The top bar containing various drop targets: Delete/App Info/Uninstall.
35 */
36public 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
Sunny Goyal47328fd2016-05-25 18:56:41 -070060 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
Sunny Goyal47328fd2016-05-25 18:56:41 -070072 // Initialize with hidden state
73 setAlpha(0f);
74 }
75
76 public void setup(DragController dragController) {
77 dragController.addDragListener(this);
Sunny Goyal0f76b562016-12-13 19:37:10 -080078 setupButtonDropTarget(this, dragController);
79 }
Sunny Goyal47328fd2016-05-25 18:56:41 -070080
Jon Mirandabfaa4a42017-08-21 15:31:51 -070081 @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
Sunny Goyal0f76b562016-12-13 19:37:10 -0800133 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 }
Sunny Goyal47328fd2016-05-25 18:56:41 -0700145 }
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
Sunny Goyal47328fd2016-05-25 18:56:41 -0700169 /*
170 * DragController.DragListener implementation
171 */
172 @Override
Sunny Goyal94b510c2016-08-16 15:36:48 -0700173 public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
Sunny Goyal47328fd2016-05-25 18:56:41 -0700174 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}