blob: 92c57c8e5c5f3ba2d51ca9bd6fbd669ed9ad5e84 [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 Wren8fd12652012-05-09 21:25:57 -040035import com.android.systemui.statusbar.NotificationData;
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;
96 float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
97 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 Wren8fd12652012-05-09 21:25:57 -0400152 return NotificationData.getIsExpandable(v);
153 }
154
155 public boolean setUserExpandedChild(View v, boolean userExpanded) {
156 return NotificationData.setUserExpanded(v, userExpanded);
Chris Wren80a76272012-04-18 10:52:18 -0400157 }
158
Chris Wren3ddab0d2012-08-02 16:52:21 -0400159 public boolean setUserLockedChild(View v, boolean userLocked) {
160 return NotificationData.setUserLocked(v, userLocked);
161 }
162
Michael Jurka07d40462011-07-19 10:54:38 -0700163 public void onChildDismissed(View v) {
John Spurlockcd686b52013-06-05 10:13:46 -0400164 if (DEBUG) Log.v(TAG, "onChildDismissed: " + v + " mRemoveViews=" + mRemoveViews);
Michael Jurka07d40462011-07-19 10:54:38 -0700165 final View veto = v.findViewById(R.id.veto);
Chet Haase2f2022a2011-10-11 06:41:59 -0700166 if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) {
Michael Jurka07d40462011-07-19 10:54:38 -0700167 veto.performClick();
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400168 }
Michael Jurka07d40462011-07-19 10:54:38 -0700169 }
170
171 public void onBeginDrag(View v) {
172 // We need to prevent the surrounding ScrollView from intercepting us now;
173 // the scroll position will be locked while we swipe
174 requestDisallowInterceptTouchEvent(true);
175 }
176
Peter Ng622a9762011-08-29 10:56:53 -0700177 public void onDragCancelled(View v) {
178 }
179
Michael Jurka07d40462011-07-19 10:54:38 -0700180 public View getChildAtPosition(MotionEvent ev) {
Daniel Sandler6a858c32012-03-12 14:38:58 -0400181 return getChildAtPosition(ev.getX(), ev.getY());
182 }
Chris Wren5de6e942012-05-16 14:22:21 -0400183
184 public View getChildAtRawPosition(float touchX, float touchY) {
185 int[] location = new int[2];
186 getLocationOnScreen(location);
187 return getChildAtPosition((float) (touchX - location[0]), (float) (touchY - location[1]));
188 }
189
Daniel Sandler6a858c32012-03-12 14:38:58 -0400190 public View getChildAtPosition(float touchX, float touchY) {
Michael Jurka07d40462011-07-19 10:54:38 -0700191 // find the view under the pointer, accounting for GONE views
192 final int count = getChildCount();
193 int y = 0;
Michael Jurka07d40462011-07-19 10:54:38 -0700194 int childIdx = 0;
195 View slidingChild;
196 for (; childIdx < count; childIdx++) {
197 slidingChild = getChildAt(childIdx);
198 if (slidingChild.getVisibility() == GONE) {
199 continue;
200 }
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500201 y += slidingChild.getMeasuredHeight();
Michael Jurka07d40462011-07-19 10:54:38 -0700202 if (touchY < y) return slidingChild;
203 }
204 return null;
205 }
206
207 public View getChildContentView(View v) {
208 return v;
209 }
210
211 @Override
212 protected void onConfigurationChanged(Configuration newConfig) {
213 super.onConfigurationChanged(newConfig);
214 float densityScale = getResources().getDisplayMetrics().density;
215 mSwipeHelper.setDensityScale(densityScale);
216 float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
217 mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400218 }
219
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400220
Chet Haase2f2022a2011-10-11 06:41:59 -0700221 /**
222 * Sets a flag to tell us whether to actually remove views. Removal is delayed by setting this
223 * to false during some animations to smooth out performance. Callers should restore the
224 * flag to true after the animation is done, and then they should make sure that the views
225 * get removed properly.
226 */
227 public void setViewRemoval(boolean removeViews) {
John Spurlockcd686b52013-06-05 10:13:46 -0400228 if (DEBUG) Log.v(TAG, "setViewRemoval: " + removeViews);
Chet Haase2f2022a2011-10-11 06:41:59 -0700229 mRemoveViews = removeViews;
230 }
231
Daniel Sandlere5011a32012-06-11 16:07:52 -0400232 // Suppress layout transitions for a little while.
233 public void setLayoutTransitionsEnabled(boolean b) {
234 if (b) {
235 setLayoutTransition(mRealLayoutTransition);
236 } else {
237 if (mRealLayoutTransition.isRunning()) {
238 mRealLayoutTransition.cancel();
239 }
240 setLayoutTransition(null);
241 }
242 }
243
Daniel Sandler8ba33c92011-10-04 21:49:30 -0400244 public void dismissRowAnimated(View child) {
245 dismissRowAnimated(child, 0);
246 }
247
248 public void dismissRowAnimated(View child, int vel) {
249 mSwipeHelper.dismissChild(child, vel);
250 }
251
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400252 @Override
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400253 public void onFinishInflate() {
254 super.onFinishInflate();
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -0500255 if (DEBUG) setWillNotDraw(false);
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400256 }
257
258 @Override
259 public void onDraw(android.graphics.Canvas c) {
260 super.onDraw(c);
Daniel Sandler6a858c32012-03-12 14:38:58 -0400261 if (DEBUG) logLayoutTransition();
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400262 if (DEBUG) {
John Spurlockcd686b52013-06-05 10:13:46 -0400263 //Log.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400264 // + getMeasuredHeight() + "px");
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400265 c.save();
266 c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6,
267 android.graphics.Region.Op.DIFFERENCE);
268 c.drawColor(0xFFFF8000);
269 c.restore();
270 }
271 }
Daniel Sandler3d32a242012-06-05 13:44:14 -0400272
273 @Override
274 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
275 if (mOnSizeChangedListener != null) {
276 mOnSizeChangedListener.onSizeChanged(this, w, h, oldw, oldh);
277 }
278 }
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400279}