blob: 7a94a58297b38326000a9625c0511ed22a0bbc06 [file] [log] [blame]
Chris Wren51c75102013-07-16 20:49:17 -04001/*
2 * Copyright (C) 2013 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;
18
Selim Cineka6c6bfb2015-10-29 16:27:08 -070019import android.app.Notification;
Chris Wren51c75102013-07-16 20:49:17 -040020import android.content.Context;
Selim Cinekcab4a602014-09-03 14:47:57 +020021import android.graphics.drawable.AnimatedVectorDrawable;
22import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010023import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020024import android.graphics.drawable.Drawable;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020025import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040026import android.util.AttributeSet;
Selim Cinek1a521f32014-11-03 17:39:29 +010027import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080028import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050029import android.view.View;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020030import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020031import android.view.accessibility.AccessibilityEvent;
Selim Cinekb5605e52015-02-20 18:21:41 +010032import android.view.animation.LinearInterpolator;
Selim Cinek98713a42015-09-21 15:47:20 +020033import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020034import android.widget.ImageView;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080035import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010036
Dan Sandlera5e0f412014-01-23 15:11:54 -050037import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070038import com.android.systemui.classifier.FalsingManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010039import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010040import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
41import com.android.systemui.statusbar.stack.StackScrollState;
42import com.android.systemui.statusbar.stack.StackStateAnimator;
43import com.android.systemui.statusbar.stack.StackViewState;
44
45import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050046
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020047public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010048
49 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
50 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
51 private final LinearInterpolator mLinearInterpolator = new LinearInterpolator();
Selim Cinek1685e632014-04-08 02:27:49 +020052 private int mRowMinHeight;
Chris Wren51c75102013-07-16 20:49:17 -040053
Selim Cinek1685e632014-04-08 02:27:49 +020054 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040055 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020056 /** Has the user actively changed the expansion state of this row */
57 private boolean mHasUserChangedExpansion;
58 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040059 private boolean mUserExpanded;
Selim Cinek1685e632014-04-08 02:27:49 +020060 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040061 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020062 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050063 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020064 private boolean mSensitive;
65 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -070066 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -040067
Selim Cinek1685e632014-04-08 02:27:49 +020068 /**
69 * Is this notification expanded by the system. The expansion state can be overridden by the
70 * user expansion.
71 */
72 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020073
74 /**
Selim Cinek83bc7832015-10-22 13:26:54 -070075 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020076 */
Selim Cinek83bc7832015-10-22 13:26:54 -070077 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020078
Jorim Jaggibe565df2014-04-28 17:51:23 +020079 private NotificationContentView mPublicLayout;
80 private NotificationContentView mPrivateLayout;
Selim Cinek1685e632014-04-08 02:27:49 +020081 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -070082 private int mHeadsUpHeight;
Selim Cinek863834b2014-05-20 04:20:25 +020083 private View mVetoButton;
Dan Sandler0d3e62f2014-07-14 17:13:50 -040084 private boolean mClearable;
Chris Wren78403d72014-07-28 10:23:24 +010085 private ExpansionLogger mLogger;
86 private String mLoggingKey;
Selim Cineka5e211b2014-08-11 17:35:48 +020087 private boolean mWasReset;
Selim Cinek8d490d42015-04-10 00:05:50 -070088 private NotificationGuts mGuts;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020089 private StatusBarNotification mStatusBarNotification;
Selim Cinek1a521f32014-11-03 17:39:29 +010090 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +020091 private boolean mLastChronometerRunning = true;
Selim Cinekeef84282015-10-30 16:28:00 -070092 private NotificationHeaderView mNotificationHeader;
Selim Cinekb5605e52015-02-20 18:21:41 +010093 private ViewStub mChildrenContainerStub;
94 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010095 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -070096 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +010097 private NotificationChildrenContainer mChildrenContainer;
Selim Cinekab29aeb2015-02-20 18:18:32 +010098 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +010099 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700100 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700101 private FalsingManager mFalsingManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200102
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700103 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800104 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700105 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700106 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800107 private OnExpandClickListener mOnExpandClickListener;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800108 private OnClickListener mExpandClickListener = new OnClickListener() {
109 @Override
110 public void onClick(View v) {
111 if (mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
112 mGroupManager.toggleGroupExpansion(mStatusBarNotification);
Selim Cinek570981d2015-12-01 11:37:01 -0800113 mOnExpandClickListener.onExpandClicked(ExpandableNotificationRow.this,
114 mGroupManager.isGroupExpanded(mStatusBarNotification));
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800115 } else {
Selim Cinek570981d2015-12-01 11:37:01 -0800116 boolean nowExpanded = !isExpanded();
117 setUserExpanded(nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800118 notifyHeightChanged(true);
Selim Cinek570981d2015-12-01 11:37:01 -0800119 mOnExpandClickListener.onExpandClicked(ExpandableNotificationRow.this,
120 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800121 }
122 }
123 };
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700124
Selim Cinek8d490d42015-04-10 00:05:50 -0700125 public NotificationContentView getPrivateLayout() {
126 return mPrivateLayout;
127 }
128
129 public NotificationContentView getPublicLayout() {
130 return mPublicLayout;
131 }
132
Selim Cinekcab4a602014-09-03 14:47:57 +0200133 public void setIconAnimationRunning(boolean running) {
134 setIconAnimationRunning(running, mPublicLayout);
135 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800136 setIconAnimationRunningForChild(running, mNotificationHeader);
137 if (mIsSummaryWithChildren) {
138 List<ExpandableNotificationRow> notificationChildren =
139 mChildrenContainer.getNotificationChildren();
140 for (int i = 0; i < notificationChildren.size(); i++) {
141 ExpandableNotificationRow child = notificationChildren.get(i);
142 child.setIconAnimationRunning(running);
143 }
144 }
145 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200146 }
147
148 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
149 if (layout != null) {
150 View contractedChild = layout.getContractedChild();
151 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700152 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200153 setIconAnimationRunningForChild(running, contractedChild);
154 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700155 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200156 }
157 }
158
159 private void setIconAnimationRunningForChild(boolean running, View child) {
160 if (child != null) {
161 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
162 setIconRunning(icon, running);
163 ImageView rightIcon = (ImageView) child.findViewById(
164 com.android.internal.R.id.right_icon);
165 setIconRunning(rightIcon, running);
166 }
167 }
168
169 private void setIconRunning(ImageView imageView, boolean running) {
170 if (imageView != null) {
171 Drawable drawable = imageView.getDrawable();
172 if (drawable instanceof AnimationDrawable) {
173 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
174 if (running) {
175 animationDrawable.start();
176 } else {
177 animationDrawable.stop();
178 }
179 } else if (drawable instanceof AnimatedVectorDrawable) {
180 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
181 if (running) {
182 animationDrawable.start();
183 } else {
184 animationDrawable.stop();
185 }
186 }
187 }
188 }
189
Selim Cinek8fc93c92015-11-23 17:48:07 -0800190 public void updateStatusBarNotification(StatusBarNotification statusBarNotification) {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200191 mStatusBarNotification = statusBarNotification;
Selim Cinek8fc93c92015-11-23 17:48:07 -0800192 mPrivateLayout.onNotificationUpdated(statusBarNotification);
193 mPublicLayout.onNotificationUpdated(statusBarNotification);
Selim Cineka37774f2014-11-11 19:16:18 +0100194 updateVetoButton();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800195 if (mIsSummaryWithChildren) {
196 recreateNotificationHeader();
197 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800198 if (mIconAnimationRunning) {
199 setIconAnimationRunning(true);
200 }
Selim Cinek263398f2015-10-21 17:40:23 -0700201 onChildrenCountChanged();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200202 }
203
204 public StatusBarNotification getStatusBarNotification() {
205 return mStatusBarNotification;
206 }
207
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700208 public boolean isHeadsUp() {
209 return mIsHeadsUp;
210 }
211
Selim Cinek1a521f32014-11-03 17:39:29 +0100212 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700213 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100214 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700215 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekc80fdb12015-04-13 15:09:08 -0700216 if (intrinsicBefore != getIntrinsicHeight()) {
217 notifyHeightChanged(false /* needsAnimation */);
218 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100219 }
220
Selim Cinekb5605e52015-02-20 18:21:41 +0100221 public void setGroupManager(NotificationGroupManager groupManager) {
222 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700223 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100224 }
225
226 public void addChildNotification(ExpandableNotificationRow row) {
227 addChildNotification(row, -1);
228 }
229
230 /**
231 * Add a child notification to this view.
232 *
233 * @param row the row to add
234 * @param childIndex the index to add it at, if -1 it will be added at the end
235 */
236 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
237 if (mChildrenContainer == null) {
238 mChildrenContainerStub.inflate();
239 }
240 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700241 onChildrenCountChanged();
242 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100243 }
244
245 public void removeChildNotification(ExpandableNotificationRow row) {
246 if (mChildrenContainer != null) {
247 mChildrenContainer.removeNotification(row);
248 }
Selim Cinek263398f2015-10-21 17:40:23 -0700249 onChildrenCountChanged();
250 row.setIsChildInGroup(false, null);
251 }
252
253 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700254 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700255 }
256
Selim Cinek388df6d2015-10-22 13:25:11 -0700257 public ExpandableNotificationRow getNotificationParent() {
258 return mNotificationParent;
259 }
260
Selim Cinek263398f2015-10-21 17:40:23 -0700261 /**
262 * @param isChildInGroup Is this notification now in a group
263 * @param parent the new parent notification
264 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700265 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
266 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
267 mNotificationParent = childInGroup ? parent : null;
268 mPrivateLayout.setIsChildInGroup(childInGroup);
269 updateNoBackgroundState();
Selim Cinek34d93b02015-10-22 12:30:38 -0700270 }
271
272 @Override
273 protected boolean shouldHideBackground() {
274 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700275 }
276
277 @Override
278 public boolean isSummaryWithChildren() {
279 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100280 }
281
282 @Override
283 public boolean areChildrenExpanded() {
284 return mChildrenExpanded;
285 }
286
287 public List<ExpandableNotificationRow> getNotificationChildren() {
288 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
289 }
290
Selim Cinekeef84282015-10-30 16:28:00 -0700291 public int getNumberOfNotificationChildren() {
292 if (mChildrenContainer == null) {
293 return 0;
294 }
295 return mChildrenContainer.getNotificationChildren().size();
296 }
297
Selim Cinekb5605e52015-02-20 18:21:41 +0100298 /**
299 * Apply the order given in the list to the children.
300 *
301 * @param childOrder the new list order
302 * @return whether the list order has changed
303 */
304 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
305 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
306 }
307
308 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700309 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100310 StackViewState parentState = resultState.getViewStateForView(this);
311 mChildrenContainer.getState(resultState, parentState);
312 }
313 }
314
315 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700316 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100317 mChildrenContainer.applyState(state);
318 }
319 }
320
321 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700322 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100323 mChildrenContainer.prepareExpansionChanged(state);
324 }
325 }
326
327 public void startChildAnimation(StackScrollState finalState,
328 StackStateAnimator stateAnimator, boolean withDelays, long delay, long duration) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700329 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100330 mChildrenContainer.startAnimationToState(finalState, stateAnimator, withDelays, delay,
331 duration);
332 }
333 }
334
335 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700336 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100337 return this;
338 } else {
339 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
340 return view == null ? this : view;
341 }
342 }
343
Selim Cinekab29aeb2015-02-20 18:18:32 +0100344 public NotificationGuts getGuts() {
345 return mGuts;
346 }
347
Selim Cinek684a4422015-04-15 16:18:39 -0700348 /**
349 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
350 * the notification will be rendered on top of the screen.
351 *
352 * @param pinned whether it is pinned
353 */
354 public void setPinned(boolean pinned) {
355 mIsPinned = pinned;
Selim Cinek98713a42015-09-21 15:47:20 +0200356 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700357 }
358
Selim Cinek684a4422015-04-15 16:18:39 -0700359 public boolean isPinned() {
360 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700361 }
362
363 public int getHeadsUpHeight() {
Selim Cinek8d490d42015-04-10 00:05:50 -0700364 return mHeadsUpHeight;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700365 }
366
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700367 /**
368 * Mark whether this notification was just clicked, i.e. the user has just clicked this
369 * notification in this frame.
370 */
371 public void setJustClicked(boolean justClicked) {
372 mJustClicked = justClicked;
373 }
374
375 /**
376 * @return true if this notification has been clicked in this frame, false otherwise
377 */
378 public boolean wasJustClicked() {
379 return mJustClicked;
380 }
381
Selim Cinek98713a42015-09-21 15:47:20 +0200382 public void setChronometerRunning(boolean running) {
383 mLastChronometerRunning = running;
384 setChronometerRunning(running, mPrivateLayout);
385 setChronometerRunning(running, mPublicLayout);
386 if (mChildrenContainer != null) {
387 List<ExpandableNotificationRow> notificationChildren =
388 mChildrenContainer.getNotificationChildren();
389 for (int i = 0; i < notificationChildren.size(); i++) {
390 ExpandableNotificationRow child = notificationChildren.get(i);
391 child.setChronometerRunning(running);
392 }
393 }
394 }
395
396 private void setChronometerRunning(boolean running, NotificationContentView layout) {
397 if (layout != null) {
398 running = running || isPinned();
399 View contractedChild = layout.getContractedChild();
400 View expandedChild = layout.getExpandedChild();
401 View headsUpChild = layout.getHeadsUpChild();
402 setChronometerRunningForChild(running, contractedChild);
403 setChronometerRunningForChild(running, expandedChild);
404 setChronometerRunningForChild(running, headsUpChild);
405 }
406 }
407
408 private void setChronometerRunningForChild(boolean running, View child) {
409 if (child != null) {
410 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
411 if (chronometer instanceof Chronometer) {
412 ((Chronometer) chronometer).setStarted(running);
413 }
414 }
415 }
416
Selim Cinek8d6440d2015-10-22 13:00:05 -0700417 public CharSequence getSubText() {
418 Notification notification = mStatusBarNotification.getNotification();
419 CharSequence subText = notification.extras.getCharSequence(Notification.EXTRA_SUMMARY_TEXT);
420 if (subText == null) {
421 subText = notification.extras.getCharSequence(Notification.EXTRA_SUB_TEXT);
422 }
423 return subText;
424 }
425
426 public void setContentSubTextVisible(boolean visible) {
427 mPrivateLayout.setSubTextVisible(visible);
428 }
429
Selim Cinek570981d2015-12-01 11:37:01 -0800430 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
431 mOnExpandClickListener = onExpandClickListener;
432 }
433
Chris Wren78403d72014-07-28 10:23:24 +0100434 public interface ExpansionLogger {
435 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
436 }
Selim Cinek1685e632014-04-08 02:27:49 +0200437
Chris Wren51c75102013-07-16 20:49:17 -0400438 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
439 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700440 mFalsingManager = FalsingManager.getInstance(context);
Chris Wren51c75102013-07-16 20:49:17 -0400441 }
442
Christoph Studera7fe6312014-06-27 19:32:44 +0200443 /**
444 * Resets this view so it can be re-used for an updated notification.
445 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200446 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200447 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200448 super.reset();
Christoph Studera7fe6312014-06-27 19:32:44 +0200449 mRowMinHeight = 0;
Chris Wren78403d72014-07-28 10:23:24 +0100450 final boolean wasExpanded = isExpanded();
Selim Cinek379ff8f2015-02-20 17:03:16 +0100451 mMaxViewHeight = 0;
Christoph Studera7fe6312014-06-27 19:32:44 +0200452 mExpandable = false;
453 mHasUserChangedExpansion = false;
454 mUserLocked = false;
455 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200456 mSensitive = false;
457 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200458 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700459 mOnKeyguard = false;
Selim Cinek1a521f32014-11-03 17:39:29 +0100460 mPublicLayout.reset(mIsHeadsUp);
461 mPrivateLayout.reset(mIsHeadsUp);
Selim Cinek31094df2014-08-14 19:28:15 +0200462 resetHeight();
463 logExpansionEvent(false, wasExpanded);
464 }
465
466 public void resetHeight() {
Selim Cinek1a521f32014-11-03 17:39:29 +0100467 if (mIsHeadsUp) {
468 resetActualHeight();
469 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200470 mMaxExpandHeight = 0;
Selim Cinek8d490d42015-04-10 00:05:50 -0700471 mHeadsUpHeight = 0;
Selim Cineka5e211b2014-08-11 17:35:48 +0200472 mWasReset = true;
Selim Cinek31094df2014-08-14 19:28:15 +0200473 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200474 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200475 }
476
Jorim Jaggi251957d2014-04-09 04:24:09 +0200477 @Override
Selim Cinek1a521f32014-11-03 17:39:29 +0100478 protected boolean filterMotionEvent(MotionEvent event) {
479 return mIsHeadsUp || super.filterMotionEvent(event);
480 }
481
482 @Override
Jorim Jaggi251957d2014-04-09 04:24:09 +0200483 protected void onFinishInflate() {
484 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200485 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
486 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800487 mPrivateLayout.setExpandClickListener(mExpandClickListener);
488 mPublicLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekab29aeb2015-02-20 18:18:32 +0100489 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
490 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200491 @Override
492 public void onInflate(ViewStub stub, View inflated) {
493 mGuts = (NotificationGuts) inflated;
494 mGuts.setClipTopAmount(getClipTopAmount());
495 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100496 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200497 }
498 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100499 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
500 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
501
502 @Override
503 public void onInflate(ViewStub stub, View inflated) {
504 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -0700505 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100506 }
507 });
Selim Cinek863834b2014-05-20 04:20:25 +0200508 mVetoButton = findViewById(R.id.veto);
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200509 }
510
Selim Cinekab29aeb2015-02-20 18:18:32 +0100511 public void inflateGuts() {
512 if (mGuts == null) {
513 mGutsStub.inflate();
514 }
515 }
516
Selim Cinekb5605e52015-02-20 18:21:41 +0100517 private void updateChildrenVisibility(boolean animated) {
518 if (mChildrenContainer == null) {
519 return;
520 }
Selim Cinekeef84282015-10-30 16:28:00 -0700521 mChildrenContainer.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800522 mNotificationHeader.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekeef84282015-10-30 16:28:00 -0700523 mPrivateLayout.setVisibility(!mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekb5605e52015-02-20 18:21:41 +0100524 }
525
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200526 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800527 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
528 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200529 // Add a record for the entire layout since its content is somehow small.
530 // The event comes from a leaf view that is interacted with.
531 AccessibilityEvent record = AccessibilityEvent.obtain();
532 onInitializeAccessibilityEvent(record);
533 dispatchPopulateAccessibilityEvent(record);
534 event.appendRecord(record);
535 return true;
536 }
537 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200538 }
Chris Wren51c75102013-07-16 20:49:17 -0400539
John Spurlocke15452b2014-08-21 09:44:39 -0400540 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100541 public void setDark(boolean dark, boolean fade, long delay) {
542 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400543 final NotificationContentView showing = getShowingLayout();
544 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100545 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400546 }
547 }
548
Selim Cinek1685e632014-04-08 02:27:49 +0200549 public void setHeightRange(int rowMinHeight, int rowMaxHeight) {
550 mRowMinHeight = rowMinHeight;
Selim Cinek379ff8f2015-02-20 17:03:16 +0100551 mMaxViewHeight = rowMaxHeight;
Selim Cinek816c8e42015-11-19 12:00:45 -0800552 mPrivateLayout.setSmallHeight(mRowMinHeight);
553 mPublicLayout.setSmallHeight(mRowMinHeight);
Chris Wren51c75102013-07-16 20:49:17 -0400554 }
555
556 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -0700557 if (mIsSummaryWithChildren && !mShowingPublic) {
558 return !mChildrenExpanded;
559 }
Chris Wren51c75102013-07-16 20:49:17 -0400560 return mExpandable;
561 }
562
563 public void setExpandable(boolean expandable) {
564 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800565 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -0400566 }
567
Selim Cinek1685e632014-04-08 02:27:49 +0200568 /**
569 * @return whether the user has changed the expansion state
570 */
571 public boolean hasUserChangedExpansion() {
572 return mHasUserChangedExpansion;
573 }
574
Chris Wren51c75102013-07-16 20:49:17 -0400575 public boolean isUserExpanded() {
576 return mUserExpanded;
577 }
578
Selim Cinek1685e632014-04-08 02:27:49 +0200579 /**
580 * Set this notification to be expanded by the user
581 *
582 * @param userExpanded whether the user wants this notification to be expanded
583 */
Chris Wren51c75102013-07-16 20:49:17 -0400584 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -0700585 setUserExpanded(userExpanded, false /* allowChildExpansion */);
586 }
587
588 /**
589 * Set this notification to be expanded by the user
590 *
591 * @param userExpanded whether the user wants this notification to be expanded
592 * @param allowChildExpansion whether a call to this method allows expanding children
593 */
594 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700595 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -0700596 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
597 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
598 return;
599 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200600 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +0100601 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +0200602 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -0400603 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +0100604 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -0400605 }
606
Selim Cinekccd14fb2014-08-12 18:53:24 +0200607 public void resetUserExpansion() {
608 mHasUserChangedExpansion = false;
609 mUserExpanded = false;
610 }
611
Chris Wren51c75102013-07-16 20:49:17 -0400612 public boolean isUserLocked() {
613 return mUserLocked;
614 }
615
616 public void setUserLocked(boolean userLocked) {
617 mUserLocked = userLocked;
618 }
619
Selim Cinek1685e632014-04-08 02:27:49 +0200620 /**
621 * @return has the system set this notification to be expanded
622 */
623 public boolean isSystemExpanded() {
624 return mIsSystemExpanded;
625 }
626
627 /**
628 * Set this notification to be expanded by the system.
629 *
630 * @param expand whether the system wants this notification to be expanded.
631 */
632 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +0200633 if (expand != mIsSystemExpanded) {
634 final boolean wasExpanded = isExpanded();
635 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +0100636 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +0200637 logExpansionEvent(false, wasExpanded);
Selim Cinek83bc7832015-10-22 13:26:54 -0700638 if (mChildrenContainer != null) {
639 mChildrenContainer.updateGroupOverflow();
640 }
Selim Cinek31094df2014-08-14 19:28:15 +0200641 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200642 }
643
644 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700645 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200646 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700647 public void setOnKeyguard(boolean onKeyguard) {
648 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +0200649 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -0700650 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +0200651 logExpansionEvent(false, wasExpanded);
652 if (wasExpanded != isExpanded()) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100653 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +0200654 }
655 }
Selim Cinek1685e632014-04-08 02:27:49 +0200656 }
657
658 /**
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400659 * @return Can the underlying notification be cleared?
660 */
661 public boolean isClearable() {
Selim Cineka37774f2014-11-11 19:16:18 +0100662 return mStatusBarNotification != null && mStatusBarNotification.isClearable();
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400663 }
664
665 /**
Selim Cinek1685e632014-04-08 02:27:49 +0200666 * Apply an expansion state to the layout.
Selim Cinek1685e632014-04-08 02:27:49 +0200667 */
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200668 public void applyExpansionToLayout() {
669 boolean expand = isExpanded();
Chris Wren51c75102013-07-16 20:49:17 -0400670 if (expand && mExpandable) {
Selim Cinekeef84282015-10-30 16:28:00 -0700671 setActualHeight(mMaxExpandHeight);
Chris Wren51c75102013-07-16 20:49:17 -0400672 } else {
Selim Cinekeef84282015-10-30 16:28:00 -0700673 setActualHeight(mRowMinHeight);
Chris Wren51c75102013-07-16 20:49:17 -0400674 }
Chris Wren51c75102013-07-16 20:49:17 -0400675 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500676
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200677 @Override
678 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +0200679 if (isUserLocked()) {
680 return getActualHeight();
681 }
Selim Cinek1685e632014-04-08 02:27:49 +0200682 boolean inExpansionState = isExpanded();
Selim Cinek60122be2015-04-15 18:16:50 -0700683 if (mSensitive && mHideSensitiveForIntrinsicHeight) {
684 return mRowMinHeight;
Selim Cinek83bc7832015-10-22 13:26:54 -0700685 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800686 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek60122be2015-04-15 18:16:50 -0700687 } else if (mIsHeadsUp) {
Selim Cinek8d490d42015-04-10 00:05:50 -0700688 if (inExpansionState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700689 return Math.max(mMaxExpandHeight, mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -0700690 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -0700691 return Math.max(mRowMinHeight, mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -0700692 }
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700693 } else if (!inExpansionState || (isChildInGroup() && !isGroupExpanded())) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700694 return getMinHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +0100695 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -0700696 return getMaxExpandHeight();
Selim Cinek1685e632014-04-08 02:27:49 +0200697 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100698 }
Selim Cinek1685e632014-04-08 02:27:49 +0200699
Selim Cinekeef84282015-10-30 16:28:00 -0700700 private boolean isGroupExpanded() {
701 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +0100702 }
703
Selim Cinekeef84282015-10-30 16:28:00 -0700704 /**
705 * @return whether this view has a header on the top of the content
706 */
707 private boolean hasNotificationHeader() {
708 return mIsSummaryWithChildren;
Selim Cinek1685e632014-04-08 02:27:49 +0200709 }
710
Selim Cinek263398f2015-10-21 17:40:23 -0700711 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -0800712 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Selim Cinek263398f2015-10-21 17:40:23 -0700713 && mGroupManager.hasGroupChildren(mStatusBarNotification);
Selim Cinek8fc93c92015-11-23 17:48:07 -0800714 if (mIsSummaryWithChildren) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800715 if (mChildrenContainer == null) {
716 mChildrenContainerStub.inflate();
717 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800718 if (mNotificationHeader == null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800719 recreateNotificationHeader();
720 }
Selim Cinek263398f2015-10-21 17:40:23 -0700721 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800722 mPrivateLayout.updateExpandButtons(isExpandable());
723 updateHeaderChildCount();
Selim Cinek263398f2015-10-21 17:40:23 -0700724 updateChildrenVisibility(true);
725 }
726
Selim Cinek1685e632014-04-08 02:27:49 +0200727 /**
728 * Check whether the view state is currently expanded. This is given by the system in {@link
729 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
730 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
731 * view can differ from this state, if layout params are modified from outside.
732 *
733 * @return whether the view state is currently expanded.
734 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700735 public boolean isExpanded() {
736 return !mOnKeyguard
Selim Cinekb5605e52015-02-20 18:21:41 +0100737 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
738 || isUserExpanded());
739 }
740
741 private boolean isSystemChildExpanded() {
742 return mIsSystemChildExpanded;
743 }
744
745 public void setSystemChildExpanded(boolean expanded) {
746 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +0200747 }
748
749 @Override
750 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
751 super.onLayout(changed, left, top, right, bottom);
Selim Cineka5e211b2014-08-11 17:35:48 +0200752 boolean updateExpandHeight = mMaxExpandHeight == 0 && !mWasReset;
Selim Cinek8d490d42015-04-10 00:05:50 -0700753 updateMaxHeights();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200754 if (updateExpandHeight) {
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200755 applyExpansionToLayout();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200756 }
Selim Cineka5e211b2014-08-11 17:35:48 +0200757 mWasReset = false;
Selim Cinek1685e632014-04-08 02:27:49 +0200758 }
759
Selim Cinek8d490d42015-04-10 00:05:50 -0700760 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +0200761 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -0700762 View expandedChild = mPrivateLayout.getExpandedChild();
763 if (expandedChild == null) {
764 expandedChild = mPrivateLayout.getContractedChild();
765 }
766 mMaxExpandHeight = expandedChild.getHeight();
767 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -0700768 if (headsUpChild == null) {
769 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700770 }
Selim Cinek1f3f5442015-04-10 17:54:46 -0700771 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +0200772 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100773 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +0200774 }
775 }
776
Jorim Jaggiae441282014-08-01 02:45:18 +0200777 public void setSensitive(boolean sensitive) {
778 mSensitive = sensitive;
779 }
780
781 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -0700782 mHideSensitiveForIntrinsicHeight = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +0200783 }
784
785 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
786 long duration) {
787 boolean oldShowingPublic = mShowingPublic;
788 mShowingPublic = mSensitive && hideSensitive;
789 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
790 return;
791 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500792
793 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +0200794 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500795
Jorim Jaggiae441282014-08-01 02:45:18 +0200796 if (!animated) {
797 mPublicLayout.animate().cancel();
798 mPrivateLayout.animate().cancel();
799 mPublicLayout.setAlpha(1f);
800 mPrivateLayout.setAlpha(1f);
801 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinek263398f2015-10-21 17:40:23 -0700802 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? View.VISIBLE
803 : View.INVISIBLE);
Jorim Jaggiae441282014-08-01 02:45:18 +0200804 } else {
805 animateShowingPublic(delay, duration);
806 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400807
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800808 mPrivateLayout.updateExpandButtons(isExpandable());
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400809 updateVetoButton();
Jorim Jaggiae441282014-08-01 02:45:18 +0200810 mShowingPublicInitialized = true;
811 }
812
813 private void animateShowingPublic(long delay, long duration) {
814 final View source = mShowingPublic ? mPrivateLayout : mPublicLayout;
815 View target = mShowingPublic ? mPublicLayout : mPrivateLayout;
816 source.setVisibility(View.VISIBLE);
817 target.setVisibility(View.VISIBLE);
818 target.setAlpha(0f);
819 source.animate().cancel();
820 target.animate().cancel();
821 source.animate()
822 .alpha(0f)
Jorim Jaggiae441282014-08-01 02:45:18 +0200823 .setStartDelay(delay)
824 .setDuration(duration)
825 .withEndAction(new Runnable() {
826 @Override
827 public void run() {
828 source.setVisibility(View.INVISIBLE);
829 }
830 });
831 target.animate()
832 .alpha(1f)
Jorim Jaggiae441282014-08-01 02:45:18 +0200833 .setStartDelay(delay)
834 .setDuration(duration);
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400835 }
836
837 private void updateVetoButton() {
838 // public versions cannot be dismissed
839 mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE);
Dan Sandlera5e0f412014-01-23 15:11:54 -0500840 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200841
Selim Cinekb5605e52015-02-20 18:21:41 +0100842 public void setChildrenExpanded(boolean expanded, boolean animate) {
843 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -0700844 if (mChildrenContainer != null) {
845 mChildrenContainer.setChildrenExpanded(expanded);
846 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100847 }
848
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800849 public void updateHeaderChildCount() {
850 if (mIsSummaryWithChildren) {
851 mNotificationHeader.setChildCount(
852 mChildrenContainer.getNotificationChildren().size());
Selim Cinekb5605e52015-02-20 18:21:41 +0100853 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100854 }
855
856 public static void applyTint(View v, int color) {
857 int alpha;
858 if (color != 0) {
859 alpha = COLORED_DIVIDER_ALPHA;
860 } else {
861 color = 0xff000000;
862 alpha = DEFAULT_DIVIDER_ALPHA;
863 }
864 if (v.getBackground() instanceof ColorDrawable) {
865 ColorDrawable background = (ColorDrawable) v.getBackground();
866 background.mutate();
867 background.setColor(color);
868 background.setAlpha(alpha);
869 }
870 }
871
Selim Cinek1685e632014-04-08 02:27:49 +0200872 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +0100873 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400874 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +0200875
Jorim Jaggibe565df2014-04-28 17:51:23 +0200876 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200877 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200878 NotificationContentView showingLayout = getShowingLayout();
879 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200880 }
881
882 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -0700883 protected View getContentView() {
884 return getShowingLayout();
885 }
886
887 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200888 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100889 super.setActualHeight(height, notifyListeners);
Selim Cinekeef84282015-10-30 16:28:00 -0700890 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +0100891 mPrivateLayout.setContentHeight(contentHeight);
892 mPublicLayout.setContentHeight(contentHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200893 if (mGuts != null) {
894 mGuts.setActualHeight(height);
895 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200896 invalidate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200897 }
898
899 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +0100900 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700901 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800902 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700903 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200904 NotificationContentView showingLayout = getShowingLayout();
905 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200906 }
907
908 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200909 public int getMinHeight() {
Selim Cinek816c8e42015-11-19 12:00:45 -0800910 NotificationContentView showingLayout = getShowingLayout();
911 return showingLayout.getMinHeight();
912 }
913
914 @Override
915 public int getMinExpandHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700916 if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800917 return mChildrenContainer.getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700918 }
Selim Cinek816c8e42015-11-19 12:00:45 -0800919 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200920 }
921
922 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700923 protected boolean shouldLimitViewHeight() {
924 return !mIsSummaryWithChildren;
925 }
926
927 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +0200928 public void setClipTopAmount(int clipTopAmount) {
929 super.setClipTopAmount(clipTopAmount);
930 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200931 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200932 if (mGuts != null) {
933 mGuts.setClipTopAmount(clipTopAmount);
934 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200935 }
936
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800937 private void recreateNotificationHeader() {
938 final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
939 getStatusBarNotification().getNotification());
940 final RemoteViews header = builder.makeNotificationHeader();
941 if (mNotificationHeader == null) {
942 mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
943 final View expandButton = mNotificationHeader.findViewById(
944 com.android.internal.R.id.expand_button);
945 expandButton.setVisibility(VISIBLE);
946 mNotificationHeader.setOnClickListener(mExpandClickListener);
947 addView(mNotificationHeader);
948 } else {
949 header.reapply(getContext(), mNotificationHeader);
950 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800951 updateHeaderChildCount();
Selim Cinek343e6e22014-04-11 21:23:30 +0200952 }
Selim Cinek7d447722014-06-10 15:51:59 +0200953
Selim Cinek31094df2014-08-14 19:28:15 +0200954 public boolean isMaxExpandHeightInitialized() {
955 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +0200956 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200957
958 private NotificationContentView getShowingLayout() {
959 return mShowingPublic ? mPublicLayout : mPrivateLayout;
960 }
Chris Wren78403d72014-07-28 10:23:24 +0100961
Jorim Jaggi59ec3042015-06-05 15:18:43 -0700962 @Override
963 public void setShowingLegacyBackground(boolean showing) {
964 super.setShowingLegacyBackground(showing);
965 mPrivateLayout.setShowingLegacyBackground(showing);
966 mPublicLayout.setShowingLegacyBackground(showing);
967 }
968
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700969 @Override
970 protected void updateBackgroundTint() {
971 super.updateBackgroundTint();
972 updateNoBackgroundState();
973 if (mIsSummaryWithChildren) {
974 List<ExpandableNotificationRow> notificationChildren =
975 mChildrenContainer.getNotificationChildren();
976 for (int i = 0; i < notificationChildren.size(); i++) {
977 ExpandableNotificationRow child = notificationChildren.get(i);
978 child.updateNoBackgroundState();
979 }
980 }
981 }
982
983 private void updateNoBackgroundState() {
984 mShowNoBackground = isChildInGroup() && hasSameBgColor(mNotificationParent);
985 updateBackground();
986 }
987
Chris Wren78403d72014-07-28 10:23:24 +0100988 public void setExpansionLogger(ExpansionLogger logger, String key) {
989 mLogger = logger;
990 mLoggingKey = key;
991 }
992
Chris Wren78403d72014-07-28 10:23:24 +0100993 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
994 final boolean nowExpanded = isExpanded();
995 if (wasExpanded != nowExpanded && mLogger != null) {
996 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
997 }
998 }
Selim Cinek570981d2015-12-01 11:37:01 -0800999
1000 public interface OnExpandClickListener {
1001 void onExpandClicked(View clickedView, boolean nowExpanded);
1002 }
Chris Wren51c75102013-07-16 20:49:17 -04001003}