blob: 259422d0ba370feff07295364673889d6276548e [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;
Chris Wren8fd12652012-05-09 21:25:57 -040036import com.android.systemui.statusbar.NotificationData;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040037
Daniel Sandler1cdf0672011-09-07 22:13:29 -040038import java.util.HashMap;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040039
John Spurlock209bede2013-07-17 12:23:27 -040040public class NotificationRowLayout
41 extends LinearLayout
Daniel Sandler3d32a242012-06-05 13:44:14 -040042 implements SwipeHelper.Callback, ExpandHelper.Callback
Daniel Sandler6a858c32012-03-12 14:38:58 -040043{
Daniel Sandlerd42497e2011-06-04 00:32:50 -040044 private static final String TAG = "NotificationRowLayout";
45 private static final boolean DEBUG = false;
Daniel Sandler1cdf0672011-09-07 22:13:29 -040046 private static final boolean SLOW_ANIMATIONS = DEBUG;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040047
Daniel Sandlerad6352b2011-06-13 11:43:45 -040048 private static final int APPEAR_ANIM_LEN = SLOW_ANIMATIONS ? 5000 : 250;
49 private static final int DISAPPEAR_ANIM_LEN = APPEAR_ANIM_LEN;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040050
Daniel Sandler8ba33c92011-10-04 21:49:30 -040051 boolean mAnimateBounds = true;
52
Daniel Sandlerd42497e2011-06-04 00:32:50 -040053 Rect mTmpRect = new Rect();
Daniel Sandlerd42497e2011-06-04 00:32:50 -040054
Daniel Sandler1cdf0672011-09-07 22:13:29 -040055 HashMap<View, ValueAnimator> mAppearingViews = new HashMap<View, ValueAnimator>();
56 HashMap<View, ValueAnimator> mDisappearingViews = new HashMap<View, ValueAnimator>();
Daniel Sandlerd42497e2011-06-04 00:32:50 -040057
Michael Jurka07d40462011-07-19 10:54:38 -070058 private SwipeHelper mSwipeHelper;
John Spurlock209bede2013-07-17 12:23:27 -040059
Daniel Sandler3d32a242012-06-05 13:44:14 -040060 private OnSizeChangedListener mOnSizeChangedListener;
Daniel Sandlerad6352b2011-06-13 11:43:45 -040061
Chet Haase2f2022a2011-10-11 06:41:59 -070062 // Flag set during notification removal animation to avoid causing too much work until
63 // animation is done
64 boolean mRemoveViews = true;
65
Daniel Sandlere5011a32012-06-11 16:07:52 -040066 private LayoutTransition mRealLayoutTransition;
67
Daniel Sandlerd42497e2011-06-04 00:32:50 -040068 public NotificationRowLayout(Context context, AttributeSet attrs) {
69 this(context, attrs, 0);
70 }
71
72 public NotificationRowLayout(Context context, AttributeSet attrs, int defStyle) {
73 super(context, attrs, defStyle);
74
Daniel Sandlere5011a32012-06-11 16:07:52 -040075 mRealLayoutTransition = new LayoutTransition();
Daniel Sandler50508132012-08-16 14:10:53 -040076 mRealLayoutTransition.setAnimateParentHierarchy(true);
Daniel Sandlere5011a32012-06-11 16:07:52 -040077 setLayoutTransitionsEnabled(true);
John Spurlock209bede2013-07-17 12:23:27 -040078
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050079 setOrientation(LinearLayout.VERTICAL);
Daniel Sandlerd42497e2011-06-04 00:32:50 -040080
81 if (DEBUG) {
82 setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
83 @Override
84 public void onChildViewAdded(View parent, View child) {
John Spurlockcd686b52013-06-05 10:13:46 -040085 Log.d(TAG, "view added: " + child + "; new count: " + getChildCount());
Daniel Sandlerd42497e2011-06-04 00:32:50 -040086 }
87 @Override
88 public void onChildViewRemoved(View parent, View child) {
John Spurlockcd686b52013-06-05 10:13:46 -040089 Log.d(TAG, "view removed: " + child + "; new count: " + (getChildCount() - 1));
Daniel Sandlerd42497e2011-06-04 00:32:50 -040090 }
91 });
92
93 setBackgroundColor(0x80FF8000);
94 }
95
Michael Jurka07d40462011-07-19 10:54:38 -070096 float densityScale = getResources().getDisplayMetrics().density;
97 float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
98 mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
Daniel Sandlerd42497e2011-06-04 00:32:50 -040099 }
100
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400101 public void setLongPressListener(View.OnLongClickListener listener) {
102 mSwipeHelper.setLongPressListener(listener);
103 }
104
Daniel Sandler3d32a242012-06-05 13:44:14 -0400105 public void setOnSizeChangedListener(OnSizeChangedListener l) {
106 mOnSizeChangedListener = l;
107 }
108
Daniel Sandler469e96e2012-05-04 15:56:19 -0400109 @Override
110 public void onWindowFocusChanged(boolean hasWindowFocus) {
111 super.onWindowFocusChanged(hasWindowFocus);
112 if (!hasWindowFocus) {
113 mSwipeHelper.removeLongPressCallback();
114 }
115 }
116
Daniel Sandler8ba33c92011-10-04 21:49:30 -0400117 public void setAnimateBounds(boolean anim) {
118 mAnimateBounds = anim;
119 }
120
Daniel Sandler6a858c32012-03-12 14:38:58 -0400121 private void logLayoutTransition() {
122 Log.v(TAG, "layout " +
Daniel Sandlere5011a32012-06-11 16:07:52 -0400123 (mRealLayoutTransition.isChangingLayout() ? "is " : "is not ") +
Daniel Sandler6a858c32012-03-12 14:38:58 -0400124 "in transition and animations " +
Daniel Sandlere5011a32012-06-11 16:07:52 -0400125 (mRealLayoutTransition.isRunning() ? "are " : "are not ") +
Daniel Sandler6a858c32012-03-12 14:38:58 -0400126 "running.");
127 }
128
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400129 @Override
130 public boolean onInterceptTouchEvent(MotionEvent ev) {
Michael Jurka07d40462011-07-19 10:54:38 -0700131 if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
Daniel Sandler6a858c32012-03-12 14:38:58 -0400132 if (DEBUG) logLayoutTransition();
133
Chris Wren5de6e942012-05-16 14:22:21 -0400134 return mSwipeHelper.onInterceptTouchEvent(ev) ||
135 super.onInterceptTouchEvent(ev);
Daniel Sandlerebce0112011-06-16 16:44:51 -0400136 }
137
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400138 @Override
139 public boolean onTouchEvent(MotionEvent ev) {
Daniel Sandler6a858c32012-03-12 14:38:58 -0400140 if (DEBUG) Log.v(TAG, "onTouchEvent()");
141 if (DEBUG) logLayoutTransition();
Chris Wren5de6e942012-05-16 14:22:21 -0400142
143 return mSwipeHelper.onTouchEvent(ev) ||
144 super.onTouchEvent(ev);
Michael Jurka07d40462011-07-19 10:54:38 -0700145 }
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400146
Michael Jurka07d40462011-07-19 10:54:38 -0700147 public boolean canChildBeDismissed(View v) {
148 final View veto = v.findViewById(R.id.veto);
149 return (veto != null && veto.getVisibility() != View.GONE);
150 }
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400151
Chris Wren80a76272012-04-18 10:52:18 -0400152 public boolean canChildBeExpanded(View v) {
Chris Wren51c75102013-07-16 20:49:17 -0400153 return v instanceof ExpandableNotificationRow
154 && ((ExpandableNotificationRow) v).isExpandable();
Chris Wren8fd12652012-05-09 21:25:57 -0400155 }
156
Chris Wren51c75102013-07-16 20:49:17 -0400157 public void setUserExpandedChild(View v, boolean userExpanded) {
158 if (v instanceof ExpandableNotificationRow) {
159 ((ExpandableNotificationRow) v).setUserExpanded(userExpanded);
160 }
Chris Wren80a76272012-04-18 10:52:18 -0400161 }
162
Chris Wren51c75102013-07-16 20:49:17 -0400163 public void setUserLockedChild(View v, boolean userLocked) {
164 if (v instanceof ExpandableNotificationRow) {
165 ((ExpandableNotificationRow) v).setUserLocked(userLocked);
166 }
Chris Wren3ddab0d2012-08-02 16:52:21 -0400167 }
168
Michael Jurka07d40462011-07-19 10:54:38 -0700169 public void onChildDismissed(View v) {
John Spurlockcd686b52013-06-05 10:13:46 -0400170 if (DEBUG) Log.v(TAG, "onChildDismissed: " + v + " mRemoveViews=" + mRemoveViews);
Michael Jurka07d40462011-07-19 10:54:38 -0700171 final View veto = v.findViewById(R.id.veto);
Chet Haase2f2022a2011-10-11 06:41:59 -0700172 if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) {
Michael Jurka07d40462011-07-19 10:54:38 -0700173 veto.performClick();
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400174 }
Michael Jurka07d40462011-07-19 10:54:38 -0700175 }
176
177 public void onBeginDrag(View v) {
178 // We need to prevent the surrounding ScrollView from intercepting us now;
179 // the scroll position will be locked while we swipe
180 requestDisallowInterceptTouchEvent(true);
181 }
182
Peter Ng622a9762011-08-29 10:56:53 -0700183 public void onDragCancelled(View v) {
184 }
185
Michael Jurka07d40462011-07-19 10:54:38 -0700186 public View getChildAtPosition(MotionEvent ev) {
Daniel Sandler6a858c32012-03-12 14:38:58 -0400187 return getChildAtPosition(ev.getX(), ev.getY());
188 }
Chris Wren5de6e942012-05-16 14:22:21 -0400189
190 public View getChildAtRawPosition(float touchX, float touchY) {
191 int[] location = new int[2];
192 getLocationOnScreen(location);
193 return getChildAtPosition((float) (touchX - location[0]), (float) (touchY - location[1]));
194 }
195
Daniel Sandler6a858c32012-03-12 14:38:58 -0400196 public View getChildAtPosition(float touchX, float touchY) {
Michael Jurka07d40462011-07-19 10:54:38 -0700197 // find the view under the pointer, accounting for GONE views
198 final int count = getChildCount();
199 int y = 0;
Michael Jurka07d40462011-07-19 10:54:38 -0700200 int childIdx = 0;
201 View slidingChild;
202 for (; childIdx < count; childIdx++) {
203 slidingChild = getChildAt(childIdx);
204 if (slidingChild.getVisibility() == GONE) {
205 continue;
206 }
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500207 y += slidingChild.getMeasuredHeight();
Michael Jurka07d40462011-07-19 10:54:38 -0700208 if (touchY < y) return slidingChild;
209 }
210 return null;
211 }
212
213 public View getChildContentView(View v) {
214 return v;
215 }
216
217 @Override
218 protected void onConfigurationChanged(Configuration newConfig) {
219 super.onConfigurationChanged(newConfig);
220 float densityScale = getResources().getDisplayMetrics().density;
221 mSwipeHelper.setDensityScale(densityScale);
222 float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
223 mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400224 }
225
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400226
Chet Haase2f2022a2011-10-11 06:41:59 -0700227 /**
228 * Sets a flag to tell us whether to actually remove views. Removal is delayed by setting this
229 * to false during some animations to smooth out performance. Callers should restore the
230 * flag to true after the animation is done, and then they should make sure that the views
231 * get removed properly.
232 */
233 public void setViewRemoval(boolean removeViews) {
John Spurlockcd686b52013-06-05 10:13:46 -0400234 if (DEBUG) Log.v(TAG, "setViewRemoval: " + removeViews);
Chet Haase2f2022a2011-10-11 06:41:59 -0700235 mRemoveViews = removeViews;
236 }
237
Daniel Sandlere5011a32012-06-11 16:07:52 -0400238 // Suppress layout transitions for a little while.
239 public void setLayoutTransitionsEnabled(boolean b) {
240 if (b) {
241 setLayoutTransition(mRealLayoutTransition);
242 } else {
243 if (mRealLayoutTransition.isRunning()) {
244 mRealLayoutTransition.cancel();
245 }
246 setLayoutTransition(null);
247 }
248 }
249
Daniel Sandler8ba33c92011-10-04 21:49:30 -0400250 public void dismissRowAnimated(View child) {
251 dismissRowAnimated(child, 0);
252 }
253
254 public void dismissRowAnimated(View child, int vel) {
255 mSwipeHelper.dismissChild(child, vel);
256 }
257
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400258 @Override
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400259 public void onFinishInflate() {
260 super.onFinishInflate();
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500261 if (DEBUG) setWillNotDraw(false);
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400262 }
263
264 @Override
265 public void onDraw(android.graphics.Canvas c) {
266 super.onDraw(c);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400267 if (DEBUG) logLayoutTransition();
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400268 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400269 //Log.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400270 // + getMeasuredHeight() + "px");
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400271 c.save();
272 c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6,
273 android.graphics.Region.Op.DIFFERENCE);
274 c.drawColor(0xFFFF8000);
275 c.restore();
276 }
277 }
Daniel Sandler3d32a242012-06-05 13:44:14 -0400278
279 @Override
280 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
281 if (mOnSizeChangedListener != null) {
282 mOnSizeChangedListener.onSizeChanged(this, w, h, oldw, oldh);
283 }
284 }
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400285}