blob: 266cecfe8d43721fbec58dc1daf0a76870612f5c [file] [log] [blame]
Daniel Sandlerd42497e2011-06-04 00:32:50 -04001/*
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.systemui.statusbar.policy;
18
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050019import android.animation.LayoutTransition;
Daniel Sandler1cdf0672011-09-07 22:13:29 -040020import android.animation.ValueAnimator;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040021import android.content.Context;
Michael Jurka07d40462011-07-19 10:54:38 -070022import android.content.res.Configuration;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040023import android.graphics.Rect;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040024import android.util.AttributeSet;
Michael Jurka07d40462011-07-19 10:54:38 -070025import android.util.Log;
Daniel Sandlerad6352b2011-06-13 11:43:45 -040026import android.view.MotionEvent;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040027import android.view.View;
Michael Jurka07d40462011-07-19 10:54:38 -070028import android.view.ViewConfiguration;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040029import android.view.ViewGroup;
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050030import android.widget.LinearLayout;
Michael Jurka07d40462011-07-19 10:54:38 -070031
Daniel Sandler6a858c32012-03-12 14:38:58 -040032import com.android.systemui.ExpandHelper;
Michael Jurka07d40462011-07-19 10:54:38 -070033import com.android.systemui.R;
34import com.android.systemui.SwipeHelper;
Chris Wren51c75102013-07-16 20:49:17 -040035import com.android.systemui.statusbar.ExpandableNotificationRow;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040036
Daniel Sandler1cdf0672011-09-07 22:13:29 -040037import java.util.HashMap;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040038
John Spurlock209bede2013-07-17 12:23:27 -040039public class NotificationRowLayout
40 extends LinearLayout
Daniel Sandler3d32a242012-06-05 13:44:14 -040041 implements SwipeHelper.Callback, ExpandHelper.Callback
Daniel Sandler6a858c32012-03-12 14:38:58 -040042{
Daniel Sandlerd42497e2011-06-04 00:32:50 -040043 private static final String TAG = "NotificationRowLayout";
44 private static final boolean DEBUG = false;
Daniel Sandler1cdf0672011-09-07 22:13:29 -040045 private static final boolean SLOW_ANIMATIONS = DEBUG;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040046
Daniel Sandlerad6352b2011-06-13 11:43:45 -040047 private static final int APPEAR_ANIM_LEN = SLOW_ANIMATIONS ? 5000 : 250;
48 private static final int DISAPPEAR_ANIM_LEN = APPEAR_ANIM_LEN;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040049
Daniel Sandler8ba33c92011-10-04 21:49:30 -040050 boolean mAnimateBounds = true;
51
Daniel Sandlerd42497e2011-06-04 00:32:50 -040052 Rect mTmpRect = new Rect();
Daniel Sandlerd42497e2011-06-04 00:32:50 -040053
Daniel Sandler1cdf0672011-09-07 22:13:29 -040054 HashMap<View, ValueAnimator> mAppearingViews = new HashMap<View, ValueAnimator>();
55 HashMap<View, ValueAnimator> mDisappearingViews = new HashMap<View, ValueAnimator>();
Daniel Sandlerd42497e2011-06-04 00:32:50 -040056
Michael Jurka07d40462011-07-19 10:54:38 -070057 private SwipeHelper mSwipeHelper;
John Spurlock209bede2013-07-17 12:23:27 -040058
Daniel Sandler3d32a242012-06-05 13:44:14 -040059 private OnSizeChangedListener mOnSizeChangedListener;
Daniel Sandlerad6352b2011-06-13 11:43:45 -040060
Chet Haase2f2022a2011-10-11 06:41:59 -070061 // Flag set during notification removal animation to avoid causing too much work until
62 // animation is done
63 boolean mRemoveViews = true;
64
Daniel Sandlere5011a32012-06-11 16:07:52 -040065 private LayoutTransition mRealLayoutTransition;
66
Daniel Sandlerd42497e2011-06-04 00:32:50 -040067 public NotificationRowLayout(Context context, AttributeSet attrs) {
68 this(context, attrs, 0);
69 }
70
71 public NotificationRowLayout(Context context, AttributeSet attrs, int defStyle) {
72 super(context, attrs, defStyle);
73
Daniel Sandlere5011a32012-06-11 16:07:52 -040074 mRealLayoutTransition = new LayoutTransition();
Daniel Sandler50508132012-08-16 14:10:53 -040075 mRealLayoutTransition.setAnimateParentHierarchy(true);
Daniel Sandlere5011a32012-06-11 16:07:52 -040076 setLayoutTransitionsEnabled(true);
John Spurlock209bede2013-07-17 12:23:27 -040077
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050078 setOrientation(LinearLayout.VERTICAL);
Daniel Sandlerd42497e2011-06-04 00:32:50 -040079
80 if (DEBUG) {
81 setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
82 @Override
83 public void onChildViewAdded(View parent, View child) {
John Spurlockcd686b52013-06-05 10:13:46 -040084 Log.d(TAG, "view added: " + child + "; new count: " + getChildCount());
Daniel Sandlerd42497e2011-06-04 00:32:50 -040085 }
86 @Override
87 public void onChildViewRemoved(View parent, View child) {
John Spurlockcd686b52013-06-05 10:13:46 -040088 Log.d(TAG, "view removed: " + child + "; new count: " + (getChildCount() - 1));
Daniel Sandlerd42497e2011-06-04 00:32:50 -040089 }
90 });
91
92 setBackgroundColor(0x80FF8000);
93 }
94
Michael Jurka07d40462011-07-19 10:54:38 -070095 float densityScale = getResources().getDisplayMetrics().density;
John Spurlock01534782014-01-13 11:59:22 -050096 float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
Michael Jurka07d40462011-07-19 10:54:38 -070097 mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
Daniel Sandlerd42497e2011-06-04 00:32:50 -040098 }
99
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400100 public void setLongPressListener(View.OnLongClickListener listener) {
101 mSwipeHelper.setLongPressListener(listener);
102 }
103
Daniel Sandler3d32a242012-06-05 13:44:14 -0400104 public void setOnSizeChangedListener(OnSizeChangedListener l) {
105 mOnSizeChangedListener = l;
106 }
107
Daniel Sandler469e96e2012-05-04 15:56:19 -0400108 @Override
109 public void onWindowFocusChanged(boolean hasWindowFocus) {
110 super.onWindowFocusChanged(hasWindowFocus);
111 if (!hasWindowFocus) {
112 mSwipeHelper.removeLongPressCallback();
113 }
114 }
115
Daniel Sandler8ba33c92011-10-04 21:49:30 -0400116 public void setAnimateBounds(boolean anim) {
117 mAnimateBounds = anim;
118 }
119
Daniel Sandler6a858c32012-03-12 14:38:58 -0400120 private void logLayoutTransition() {
121 Log.v(TAG, "layout " +
Daniel Sandlere5011a32012-06-11 16:07:52 -0400122 (mRealLayoutTransition.isChangingLayout() ? "is " : "is not ") +
Daniel Sandler6a858c32012-03-12 14:38:58 -0400123 "in transition and animations " +
Daniel Sandlere5011a32012-06-11 16:07:52 -0400124 (mRealLayoutTransition.isRunning() ? "are " : "are not ") +
Daniel Sandler6a858c32012-03-12 14:38:58 -0400125 "running.");
126 }
127
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400128 @Override
129 public boolean onInterceptTouchEvent(MotionEvent ev) {
Michael Jurka07d40462011-07-19 10:54:38 -0700130 if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
Daniel Sandler6a858c32012-03-12 14:38:58 -0400131 if (DEBUG) logLayoutTransition();
132
Chris Wren5de6e942012-05-16 14:22:21 -0400133 return mSwipeHelper.onInterceptTouchEvent(ev) ||
134 super.onInterceptTouchEvent(ev);
Daniel Sandlerebce0112011-06-16 16:44:51 -0400135 }
136
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400137 @Override
138 public boolean onTouchEvent(MotionEvent ev) {
Daniel Sandler6a858c32012-03-12 14:38:58 -0400139 if (DEBUG) Log.v(TAG, "onTouchEvent()");
140 if (DEBUG) logLayoutTransition();
Chris Wren5de6e942012-05-16 14:22:21 -0400141
142 return mSwipeHelper.onTouchEvent(ev) ||
143 super.onTouchEvent(ev);
Michael Jurka07d40462011-07-19 10:54:38 -0700144 }
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400145
Michael Jurka07d40462011-07-19 10:54:38 -0700146 public boolean canChildBeDismissed(View v) {
147 final View veto = v.findViewById(R.id.veto);
148 return (veto != null && veto.getVisibility() != View.GONE);
149 }
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400150
Chris Wren80a76272012-04-18 10:52:18 -0400151 public boolean canChildBeExpanded(View v) {
Chris Wren51c75102013-07-16 20:49:17 -0400152 return v instanceof ExpandableNotificationRow
153 && ((ExpandableNotificationRow) v).isExpandable();
Chris Wren8fd12652012-05-09 21:25:57 -0400154 }
155
Chris Wren51c75102013-07-16 20:49:17 -0400156 public void setUserExpandedChild(View v, boolean userExpanded) {
157 if (v instanceof ExpandableNotificationRow) {
158 ((ExpandableNotificationRow) v).setUserExpanded(userExpanded);
159 }
Chris Wren80a76272012-04-18 10:52:18 -0400160 }
161
Chris Wren51c75102013-07-16 20:49:17 -0400162 public void setUserLockedChild(View v, boolean userLocked) {
163 if (v instanceof ExpandableNotificationRow) {
164 ((ExpandableNotificationRow) v).setUserLocked(userLocked);
165 }
Chris Wren3ddab0d2012-08-02 16:52:21 -0400166 }
167
Michael Jurka07d40462011-07-19 10:54:38 -0700168 public void onChildDismissed(View v) {
John Spurlockcd686b52013-06-05 10:13:46 -0400169 if (DEBUG) Log.v(TAG, "onChildDismissed: " + v + " mRemoveViews=" + mRemoveViews);
Michael Jurka07d40462011-07-19 10:54:38 -0700170 final View veto = v.findViewById(R.id.veto);
Chet Haase2f2022a2011-10-11 06:41:59 -0700171 if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) {
Michael Jurka07d40462011-07-19 10:54:38 -0700172 veto.performClick();
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400173 }
Michael Jurka07d40462011-07-19 10:54:38 -0700174 }
175
176 public void onBeginDrag(View v) {
177 // We need to prevent the surrounding ScrollView from intercepting us now;
178 // the scroll position will be locked while we swipe
179 requestDisallowInterceptTouchEvent(true);
180 }
181
Peter Ng622a9762011-08-29 10:56:53 -0700182 public void onDragCancelled(View v) {
183 }
184
Michael Jurka07d40462011-07-19 10:54:38 -0700185 public View getChildAtPosition(MotionEvent ev) {
Daniel Sandler6a858c32012-03-12 14:38:58 -0400186 return getChildAtPosition(ev.getX(), ev.getY());
187 }
Chris Wren5de6e942012-05-16 14:22:21 -0400188
189 public View getChildAtRawPosition(float touchX, float touchY) {
190 int[] location = new int[2];
191 getLocationOnScreen(location);
192 return getChildAtPosition((float) (touchX - location[0]), (float) (touchY - location[1]));
193 }
194
Daniel Sandler6a858c32012-03-12 14:38:58 -0400195 public View getChildAtPosition(float touchX, float touchY) {
Michael Jurka07d40462011-07-19 10:54:38 -0700196 // find the view under the pointer, accounting for GONE views
197 final int count = getChildCount();
198 int y = 0;
Michael Jurka07d40462011-07-19 10:54:38 -0700199 int childIdx = 0;
200 View slidingChild;
201 for (; childIdx < count; childIdx++) {
202 slidingChild = getChildAt(childIdx);
203 if (slidingChild.getVisibility() == GONE) {
204 continue;
205 }
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500206 y += slidingChild.getMeasuredHeight();
Michael Jurka07d40462011-07-19 10:54:38 -0700207 if (touchY < y) return slidingChild;
208 }
209 return null;
210 }
211
212 public View getChildContentView(View v) {
213 return v;
214 }
215
216 @Override
217 protected void onConfigurationChanged(Configuration newConfig) {
218 super.onConfigurationChanged(newConfig);
219 float densityScale = getResources().getDisplayMetrics().density;
220 mSwipeHelper.setDensityScale(densityScale);
John Spurlock01534782014-01-13 11:59:22 -0500221 float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
Michael Jurka07d40462011-07-19 10:54:38 -0700222 mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400223 }
224
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400225
Chet Haase2f2022a2011-10-11 06:41:59 -0700226 /**
227 * Sets a flag to tell us whether to actually remove views. Removal is delayed by setting this
228 * to false during some animations to smooth out performance. Callers should restore the
229 * flag to true after the animation is done, and then they should make sure that the views
230 * get removed properly.
231 */
232 public void setViewRemoval(boolean removeViews) {
John Spurlockcd686b52013-06-05 10:13:46 -0400233 if (DEBUG) Log.v(TAG, "setViewRemoval: " + removeViews);
Chet Haase2f2022a2011-10-11 06:41:59 -0700234 mRemoveViews = removeViews;
235 }
236
Daniel Sandlere5011a32012-06-11 16:07:52 -0400237 // Suppress layout transitions for a little while.
238 public void setLayoutTransitionsEnabled(boolean b) {
239 if (b) {
240 setLayoutTransition(mRealLayoutTransition);
241 } else {
242 if (mRealLayoutTransition.isRunning()) {
243 mRealLayoutTransition.cancel();
244 }
245 setLayoutTransition(null);
246 }
247 }
248
Daniel Sandler8ba33c92011-10-04 21:49:30 -0400249 public void dismissRowAnimated(View child) {
250 dismissRowAnimated(child, 0);
251 }
252
253 public void dismissRowAnimated(View child, int vel) {
254 mSwipeHelper.dismissChild(child, vel);
255 }
256
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400257 @Override
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400258 public void onFinishInflate() {
259 super.onFinishInflate();
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500260 if (DEBUG) setWillNotDraw(false);
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400261 }
262
263 @Override
264 public void onDraw(android.graphics.Canvas c) {
265 super.onDraw(c);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400266 if (DEBUG) logLayoutTransition();
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400267 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400268 //Log.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400269 // + getMeasuredHeight() + "px");
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400270 c.save();
271 c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6,
272 android.graphics.Region.Op.DIFFERENCE);
273 c.drawColor(0xFFFF8000);
274 c.restore();
275 }
276 }
Daniel Sandler3d32a242012-06-05 13:44:14 -0400277
278 @Override
279 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
280 if (mOnSizeChangedListener != null) {
281 mOnSizeChangedListener.onSizeChanged(this, w, h, oldw, oldh);
282 }
283 }
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400284}