blob: 89eed1bd6138f85c0014d7bed0faaf5283a36bcc [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
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050021import android.animation.LayoutTransition;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040022import android.animation.ObjectAnimator;
Daniel Sandler1cdf0672011-09-07 22:13:29 -040023import android.animation.ValueAnimator;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040024import android.content.Context;
Michael Jurka07d40462011-07-19 10:54:38 -070025import android.content.res.Configuration;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040026import android.content.res.TypedArray;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040027import android.graphics.Rect;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040028import android.util.AttributeSet;
Michael Jurka07d40462011-07-19 10:54:38 -070029import android.util.Log;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040030import android.util.Slog;
Daniel Sandlerad6352b2011-06-13 11:43:45 -040031import android.view.MotionEvent;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040032import android.view.View;
Michael Jurka07d40462011-07-19 10:54:38 -070033import android.view.ViewConfiguration;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040034import android.view.ViewGroup;
Daniel Sandler469e96e2012-05-04 15:56:19 -040035import android.view.inputmethod.InputMethodManager;
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050036import android.widget.LinearLayout;
Michael Jurka07d40462011-07-19 10:54:38 -070037
Daniel Sandler6a858c32012-03-12 14:38:58 -040038import com.android.systemui.ExpandHelper;
Michael Jurka07d40462011-07-19 10:54:38 -070039import com.android.systemui.R;
40import com.android.systemui.SwipeHelper;
Chris Wren8fd12652012-05-09 21:25:57 -040041import com.android.systemui.statusbar.NotificationData;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040042
Daniel Sandler1cdf0672011-09-07 22:13:29 -040043import java.util.HashMap;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040044
Daniel Sandler6a858c32012-03-12 14:38:58 -040045public class NotificationRowLayout
46 extends LinearLayout
Daniel Sandler3d32a242012-06-05 13:44:14 -040047 implements SwipeHelper.Callback, ExpandHelper.Callback
Daniel Sandler6a858c32012-03-12 14:38:58 -040048{
Daniel Sandlerd42497e2011-06-04 00:32:50 -040049 private static final String TAG = "NotificationRowLayout";
50 private static final boolean DEBUG = false;
Daniel Sandler1cdf0672011-09-07 22:13:29 -040051 private static final boolean SLOW_ANIMATIONS = DEBUG;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040052
Daniel Sandlerad6352b2011-06-13 11:43:45 -040053 private static final int APPEAR_ANIM_LEN = SLOW_ANIMATIONS ? 5000 : 250;
54 private static final int DISAPPEAR_ANIM_LEN = APPEAR_ANIM_LEN;
Daniel Sandlerd42497e2011-06-04 00:32:50 -040055
Daniel Sandler8ba33c92011-10-04 21:49:30 -040056 boolean mAnimateBounds = true;
57
Daniel Sandlerd42497e2011-06-04 00:32:50 -040058 Rect mTmpRect = new Rect();
Daniel Sandlerd42497e2011-06-04 00:32:50 -040059
Daniel Sandler1cdf0672011-09-07 22:13:29 -040060 HashMap<View, ValueAnimator> mAppearingViews = new HashMap<View, ValueAnimator>();
61 HashMap<View, ValueAnimator> mDisappearingViews = new HashMap<View, ValueAnimator>();
Daniel Sandlerd42497e2011-06-04 00:32:50 -040062
Michael Jurka07d40462011-07-19 10:54:38 -070063 private SwipeHelper mSwipeHelper;
Daniel Sandler3d32a242012-06-05 13:44:14 -040064
65 private OnSizeChangedListener mOnSizeChangedListener;
Daniel Sandlerad6352b2011-06-13 11:43:45 -040066
Chet Haase2f2022a2011-10-11 06:41:59 -070067 // Flag set during notification removal animation to avoid causing too much work until
68 // animation is done
69 boolean mRemoveViews = true;
70
Daniel Sandlere5011a32012-06-11 16:07:52 -040071 private LayoutTransition mRealLayoutTransition;
72
Daniel Sandlerd42497e2011-06-04 00:32:50 -040073 public NotificationRowLayout(Context context, AttributeSet attrs) {
74 this(context, attrs, 0);
75 }
76
77 public NotificationRowLayout(Context context, AttributeSet attrs, int defStyle) {
78 super(context, attrs, defStyle);
79
Daniel Sandlere5011a32012-06-11 16:07:52 -040080 mRealLayoutTransition = new LayoutTransition();
Daniel Sandler50508132012-08-16 14:10:53 -040081 mRealLayoutTransition.setAnimateParentHierarchy(true);
Daniel Sandlere5011a32012-06-11 16:07:52 -040082 setLayoutTransitionsEnabled(true);
Daniel Sandlerc6d29fc2012-02-25 00:33:12 -050083
84 setOrientation(LinearLayout.VERTICAL);
Daniel Sandlerd42497e2011-06-04 00:32:50 -040085
86 if (DEBUG) {
87 setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
88 @Override
89 public void onChildViewAdded(View parent, View child) {
90 Slog.d(TAG, "view added: " + child + "; new count: " + getChildCount());
91 }
92 @Override
93 public void onChildViewRemoved(View parent, View child) {
94 Slog.d(TAG, "view removed: " + child + "; new count: " + (getChildCount() - 1));
95 }
96 });
97
98 setBackgroundColor(0x80FF8000);
99 }
100
Michael Jurka07d40462011-07-19 10:54:38 -0700101 float densityScale = getResources().getDisplayMetrics().density;
102 float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
103 mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
Daniel Sandlerd42497e2011-06-04 00:32:50 -0400104 }
105
Daniel Sandlerf7a19562012-04-04 14:04:21 -0400106 public void setLongPressListener(View.OnLongClickListener listener) {
107 mSwipeHelper.setLongPressListener(listener);
108 }
109
Daniel Sandler3d32a242012-06-05 13:44:14 -0400110 public void setOnSizeChangedListener(OnSizeChangedListener l) {
111 mOnSizeChangedListener = l;
112 }
113
Daniel Sandler469e96e2012-05-04 15:56:19 -0400114 @Override
115 public void onWindowFocusChanged(boolean hasWindowFocus) {
116 super.onWindowFocusChanged(hasWindowFocus);
117 if (!hasWindowFocus) {
118 mSwipeHelper.removeLongPressCallback();
119 }
120 }
121
Daniel Sandler8ba33c92011-10-04 21:49:30 -0400122 public void setAnimateBounds(boolean anim) {
123 mAnimateBounds = anim;
124 }
125
Daniel Sandler6a858c32012-03-12 14:38:58 -0400126 private void logLayoutTransition() {
127 Log.v(TAG, "layout " +
Daniel Sandlere5011a32012-06-11 16:07:52 -0400128 (mRealLayoutTransition.isChangingLayout() ? "is " : "is not ") +
Daniel Sandler6a858c32012-03-12 14:38:58 -0400129 "in transition and animations " +
Daniel Sandlere5011a32012-06-11 16:07:52 -0400130 (mRealLayoutTransition.isRunning() ? "are " : "are not ") +
Daniel Sandler6a858c32012-03-12 14:38:58 -0400131 "running.");
132 }
133
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400134 @Override
135 public boolean onInterceptTouchEvent(MotionEvent ev) {
Michael Jurka07d40462011-07-19 10:54:38 -0700136 if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
Daniel Sandler6a858c32012-03-12 14:38:58 -0400137 if (DEBUG) logLayoutTransition();
138
Chris Wren5de6e942012-05-16 14:22:21 -0400139 return mSwipeHelper.onInterceptTouchEvent(ev) ||
140 super.onInterceptTouchEvent(ev);
Daniel Sandlerebce0112011-06-16 16:44:51 -0400141 }
142
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400143 @Override
144 public boolean onTouchEvent(MotionEvent ev) {
Daniel Sandler6a858c32012-03-12 14:38:58 -0400145 if (DEBUG) Log.v(TAG, "onTouchEvent()");
146 if (DEBUG) logLayoutTransition();
Chris Wren5de6e942012-05-16 14:22:21 -0400147
148 return mSwipeHelper.onTouchEvent(ev) ||
149 super.onTouchEvent(ev);
Michael Jurka07d40462011-07-19 10:54:38 -0700150 }
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400151
Michael Jurka07d40462011-07-19 10:54:38 -0700152 public boolean canChildBeDismissed(View v) {
153 final View veto = v.findViewById(R.id.veto);
154 return (veto != null && veto.getVisibility() != View.GONE);
155 }
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400156
Chris Wren80a76272012-04-18 10:52:18 -0400157 public boolean canChildBeExpanded(View v) {
Chris Wren8fd12652012-05-09 21:25:57 -0400158 return NotificationData.getIsExpandable(v);
159 }
160
161 public boolean setUserExpandedChild(View v, boolean userExpanded) {
162 return NotificationData.setUserExpanded(v, userExpanded);
Chris Wren80a76272012-04-18 10:52:18 -0400163 }
164
Chris Wren3ddab0d2012-08-02 16:52:21 -0400165 public boolean setUserLockedChild(View v, boolean userLocked) {
166 return NotificationData.setUserLocked(v, userLocked);
167 }
168
Michael Jurka07d40462011-07-19 10:54:38 -0700169 public void onChildDismissed(View v) {
Daniel Sandlere7237fc2012-08-14 16:08:27 -0400170 if (DEBUG) Slog.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) {
Daniel Sandlere7237fc2012-08-14 16:08:27 -0400234 if (DEBUG) Slog.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) {
Daniel Sandlerad6352b2011-06-13 11:43:45 -0400269 //Slog.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
270 // + 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}