blob: 4cc8bc1b374152368925bc391d4f263e70f6f11f [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;
Selim Cinekda42d652015-12-04 15:51:16 -080025import android.os.Build;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020026import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040027import android.util.AttributeSet;
Selim Cinek1a521f32014-11-03 17:39:29 +010028import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080029import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050030import android.view.View;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020031import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020032import android.view.accessibility.AccessibilityEvent;
Selim Cinekb5605e52015-02-20 18:21:41 +010033import android.view.animation.LinearInterpolator;
Selim Cinek98713a42015-09-21 15:47:20 +020034import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020035import android.widget.ImageView;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080036import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010037
Dan Sandlera5e0f412014-01-23 15:11:54 -050038import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070039import com.android.systemui.classifier.FalsingManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010040import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010041import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
42import com.android.systemui.statusbar.stack.StackScrollState;
43import com.android.systemui.statusbar.stack.StackStateAnimator;
44import com.android.systemui.statusbar.stack.StackViewState;
45
46import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050047
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020048public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010049
50 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
51 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
52 private final LinearInterpolator mLinearInterpolator = new LinearInterpolator();
Selim Cinekda42d652015-12-04 15:51:16 -080053 private final int mNotificationMinHeightLegacy;
54 private final int mNotificationMinHeight;
55 private final int mNotificationMaxHeight;
Selim Cinek1685e632014-04-08 02:27:49 +020056 private int mRowMinHeight;
Chris Wren51c75102013-07-16 20:49:17 -040057
Selim Cinek1685e632014-04-08 02:27:49 +020058 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040059 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020060 /** Has the user actively changed the expansion state of this row */
61 private boolean mHasUserChangedExpansion;
62 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040063 private boolean mUserExpanded;
Selim Cinek1685e632014-04-08 02:27:49 +020064 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040065 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020066 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050067 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020068 private boolean mSensitive;
69 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -070070 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -040071
Selim Cinek1685e632014-04-08 02:27:49 +020072 /**
73 * Is this notification expanded by the system. The expansion state can be overridden by the
74 * user expansion.
75 */
76 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020077
78 /**
Selim Cinek83bc7832015-10-22 13:26:54 -070079 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020080 */
Selim Cinek83bc7832015-10-22 13:26:54 -070081 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020082
Jorim Jaggibe565df2014-04-28 17:51:23 +020083 private NotificationContentView mPublicLayout;
84 private NotificationContentView mPrivateLayout;
Selim Cinek1685e632014-04-08 02:27:49 +020085 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -070086 private int mHeadsUpHeight;
Selim Cinek863834b2014-05-20 04:20:25 +020087 private View mVetoButton;
Dan Sandler0d3e62f2014-07-14 17:13:50 -040088 private boolean mClearable;
Chris Wren78403d72014-07-28 10:23:24 +010089 private ExpansionLogger mLogger;
90 private String mLoggingKey;
Selim Cineka5e211b2014-08-11 17:35:48 +020091 private boolean mWasReset;
Selim Cinek8d490d42015-04-10 00:05:50 -070092 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -080093 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020094 private StatusBarNotification mStatusBarNotification;
Selim Cinek1a521f32014-11-03 17:39:29 +010095 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +020096 private boolean mLastChronometerRunning = true;
Selim Cinekeef84282015-10-30 16:28:00 -070097 private NotificationHeaderView mNotificationHeader;
Selim Cinek9c7712d2015-12-08 19:19:48 -080098 private NotificationViewWrapper mNotificationHeaderWrapper;
Selim Cinekb5605e52015-02-20 18:21:41 +010099 private ViewStub mChildrenContainerStub;
100 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100101 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700102 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100103 private NotificationChildrenContainer mChildrenContainer;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100104 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100105 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700106 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700107 private FalsingManager mFalsingManager;
Selim Cinekea4bef72015-12-02 15:51:10 -0800108 private NotificationHeaderUtil mHeaderUtil = new NotificationHeaderUtil(this);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200109
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700110 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800111 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700112 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700113 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800114 private OnExpandClickListener mOnExpandClickListener;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800115 private OnClickListener mExpandClickListener = new OnClickListener() {
116 @Override
117 public void onClick(View v) {
118 if (mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
119 mGroupManager.toggleGroupExpansion(mStatusBarNotification);
Selim Cinek570981d2015-12-01 11:37:01 -0800120 mOnExpandClickListener.onExpandClicked(ExpandableNotificationRow.this,
121 mGroupManager.isGroupExpanded(mStatusBarNotification));
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800122 } else {
Selim Cinek570981d2015-12-01 11:37:01 -0800123 boolean nowExpanded = !isExpanded();
124 setUserExpanded(nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800125 notifyHeightChanged(true);
Selim Cinek570981d2015-12-01 11:37:01 -0800126 mOnExpandClickListener.onExpandClicked(ExpandableNotificationRow.this,
127 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800128 }
129 }
130 };
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700131
Selim Cinek8d490d42015-04-10 00:05:50 -0700132 public NotificationContentView getPrivateLayout() {
133 return mPrivateLayout;
134 }
135
136 public NotificationContentView getPublicLayout() {
137 return mPublicLayout;
138 }
139
Selim Cinekcab4a602014-09-03 14:47:57 +0200140 public void setIconAnimationRunning(boolean running) {
141 setIconAnimationRunning(running, mPublicLayout);
142 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800143 setIconAnimationRunningForChild(running, mNotificationHeader);
144 if (mIsSummaryWithChildren) {
145 List<ExpandableNotificationRow> notificationChildren =
146 mChildrenContainer.getNotificationChildren();
147 for (int i = 0; i < notificationChildren.size(); i++) {
148 ExpandableNotificationRow child = notificationChildren.get(i);
149 child.setIconAnimationRunning(running);
150 }
151 }
152 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200153 }
154
155 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
156 if (layout != null) {
157 View contractedChild = layout.getContractedChild();
158 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700159 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200160 setIconAnimationRunningForChild(running, contractedChild);
161 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700162 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200163 }
164 }
165
166 private void setIconAnimationRunningForChild(boolean running, View child) {
167 if (child != null) {
168 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
169 setIconRunning(icon, running);
170 ImageView rightIcon = (ImageView) child.findViewById(
171 com.android.internal.R.id.right_icon);
172 setIconRunning(rightIcon, running);
173 }
174 }
175
176 private void setIconRunning(ImageView imageView, boolean running) {
177 if (imageView != null) {
178 Drawable drawable = imageView.getDrawable();
179 if (drawable instanceof AnimationDrawable) {
180 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
181 if (running) {
182 animationDrawable.start();
183 } else {
184 animationDrawable.stop();
185 }
186 } else if (drawable instanceof AnimatedVectorDrawable) {
187 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
188 if (running) {
189 animationDrawable.start();
190 } else {
191 animationDrawable.stop();
192 }
193 }
194 }
195 }
196
Selim Cinekda42d652015-12-04 15:51:16 -0800197 public void onNotificationUpdated(NotificationData.Entry entry) {
198 mEntry = entry;
199 mStatusBarNotification = entry.notification;
200 mPrivateLayout.onNotificationUpdated(entry.notification);
201 mPublicLayout.onNotificationUpdated(entry.notification);
Selim Cineka37774f2014-11-11 19:16:18 +0100202 updateVetoButton();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800203 if (mIsSummaryWithChildren) {
204 recreateNotificationHeader();
205 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800206 if (mIconAnimationRunning) {
207 setIconAnimationRunning(true);
208 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800209 if (mNotificationParent != null) {
210 mNotificationParent.updateChildrenHeaderAppearance();
211 }
Selim Cinek263398f2015-10-21 17:40:23 -0700212 onChildrenCountChanged();
Selim Cinekda42d652015-12-04 15:51:16 -0800213 updateLimits();
214 }
215
216 private void updateLimits() {
217 boolean customView = getPrivateLayout().getContractedChild().getId()
218 != com.android.internal.R.id.status_bar_latest_event_content;
219 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
220 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
221 mNotificationMinHeightLegacy : mNotificationMinHeight;
222 mRowMinHeight = minHeight;
223 mMaxViewHeight = mNotificationMaxHeight;
224 mPrivateLayout.setSmallHeight(mRowMinHeight);
225 mPublicLayout.setSmallHeight(mRowMinHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200226 }
227
228 public StatusBarNotification getStatusBarNotification() {
229 return mStatusBarNotification;
230 }
231
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700232 public boolean isHeadsUp() {
233 return mIsHeadsUp;
234 }
235
Selim Cinek1a521f32014-11-03 17:39:29 +0100236 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700237 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100238 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700239 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekc80fdb12015-04-13 15:09:08 -0700240 if (intrinsicBefore != getIntrinsicHeight()) {
241 notifyHeightChanged(false /* needsAnimation */);
242 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100243 }
244
Selim Cinekb5605e52015-02-20 18:21:41 +0100245 public void setGroupManager(NotificationGroupManager groupManager) {
246 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700247 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100248 }
249
250 public void addChildNotification(ExpandableNotificationRow row) {
251 addChildNotification(row, -1);
252 }
253
254 /**
255 * Add a child notification to this view.
256 *
257 * @param row the row to add
258 * @param childIndex the index to add it at, if -1 it will be added at the end
259 */
260 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
261 if (mChildrenContainer == null) {
262 mChildrenContainerStub.inflate();
263 }
264 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700265 onChildrenCountChanged();
266 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100267 }
268
269 public void removeChildNotification(ExpandableNotificationRow row) {
270 if (mChildrenContainer != null) {
271 mChildrenContainer.removeNotification(row);
272 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800273 mHeaderUtil.restoreNotificationHeader(row);
Selim Cinek263398f2015-10-21 17:40:23 -0700274 onChildrenCountChanged();
275 row.setIsChildInGroup(false, null);
276 }
277
278 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700279 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700280 }
281
Selim Cinek388df6d2015-10-22 13:25:11 -0700282 public ExpandableNotificationRow getNotificationParent() {
283 return mNotificationParent;
284 }
285
Selim Cinek263398f2015-10-21 17:40:23 -0700286 /**
287 * @param isChildInGroup Is this notification now in a group
288 * @param parent the new parent notification
289 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700290 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
291 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
292 mNotificationParent = childInGroup ? parent : null;
293 mPrivateLayout.setIsChildInGroup(childInGroup);
294 updateNoBackgroundState();
Selim Cinek34d93b02015-10-22 12:30:38 -0700295 }
296
297 @Override
298 protected boolean shouldHideBackground() {
299 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700300 }
301
302 @Override
303 public boolean isSummaryWithChildren() {
304 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100305 }
306
307 @Override
308 public boolean areChildrenExpanded() {
309 return mChildrenExpanded;
310 }
311
312 public List<ExpandableNotificationRow> getNotificationChildren() {
313 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
314 }
315
Selim Cinekeef84282015-10-30 16:28:00 -0700316 public int getNumberOfNotificationChildren() {
317 if (mChildrenContainer == null) {
318 return 0;
319 }
320 return mChildrenContainer.getNotificationChildren().size();
321 }
322
Selim Cinekb5605e52015-02-20 18:21:41 +0100323 /**
324 * Apply the order given in the list to the children.
325 *
326 * @param childOrder the new list order
327 * @return whether the list order has changed
328 */
329 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
330 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
331 }
332
333 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700334 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100335 StackViewState parentState = resultState.getViewStateForView(this);
336 mChildrenContainer.getState(resultState, parentState);
337 }
338 }
339
340 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700341 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100342 mChildrenContainer.applyState(state);
343 }
344 }
345
346 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700347 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100348 mChildrenContainer.prepareExpansionChanged(state);
349 }
350 }
351
352 public void startChildAnimation(StackScrollState finalState,
353 StackStateAnimator stateAnimator, boolean withDelays, long delay, long duration) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700354 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100355 mChildrenContainer.startAnimationToState(finalState, stateAnimator, withDelays, delay,
356 duration);
357 }
358 }
359
360 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700361 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100362 return this;
363 } else {
364 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
365 return view == null ? this : view;
366 }
367 }
368
Selim Cinekab29aeb2015-02-20 18:18:32 +0100369 public NotificationGuts getGuts() {
370 return mGuts;
371 }
372
Selim Cinek684a4422015-04-15 16:18:39 -0700373 /**
374 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
375 * the notification will be rendered on top of the screen.
376 *
377 * @param pinned whether it is pinned
378 */
379 public void setPinned(boolean pinned) {
380 mIsPinned = pinned;
Selim Cinek98713a42015-09-21 15:47:20 +0200381 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700382 }
383
Selim Cinek684a4422015-04-15 16:18:39 -0700384 public boolean isPinned() {
385 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700386 }
387
388 public int getHeadsUpHeight() {
Selim Cinek8d490d42015-04-10 00:05:50 -0700389 return mHeadsUpHeight;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700390 }
391
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700392 /**
393 * Mark whether this notification was just clicked, i.e. the user has just clicked this
394 * notification in this frame.
395 */
396 public void setJustClicked(boolean justClicked) {
397 mJustClicked = justClicked;
398 }
399
400 /**
401 * @return true if this notification has been clicked in this frame, false otherwise
402 */
403 public boolean wasJustClicked() {
404 return mJustClicked;
405 }
406
Selim Cinek98713a42015-09-21 15:47:20 +0200407 public void setChronometerRunning(boolean running) {
408 mLastChronometerRunning = running;
409 setChronometerRunning(running, mPrivateLayout);
410 setChronometerRunning(running, mPublicLayout);
411 if (mChildrenContainer != null) {
412 List<ExpandableNotificationRow> notificationChildren =
413 mChildrenContainer.getNotificationChildren();
414 for (int i = 0; i < notificationChildren.size(); i++) {
415 ExpandableNotificationRow child = notificationChildren.get(i);
416 child.setChronometerRunning(running);
417 }
418 }
419 }
420
421 private void setChronometerRunning(boolean running, NotificationContentView layout) {
422 if (layout != null) {
423 running = running || isPinned();
424 View contractedChild = layout.getContractedChild();
425 View expandedChild = layout.getExpandedChild();
426 View headsUpChild = layout.getHeadsUpChild();
427 setChronometerRunningForChild(running, contractedChild);
428 setChronometerRunningForChild(running, expandedChild);
429 setChronometerRunningForChild(running, headsUpChild);
430 }
431 }
432
433 private void setChronometerRunningForChild(boolean running, View child) {
434 if (child != null) {
435 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
436 if (chronometer instanceof Chronometer) {
437 ((Chronometer) chronometer).setStarted(running);
438 }
439 }
440 }
441
Selim Cinekea4bef72015-12-02 15:51:10 -0800442 public NotificationHeaderView getNotificationHeader() {
443 if (mNotificationHeader != null) {
444 return mNotificationHeader;
Selim Cinek8d6440d2015-10-22 13:00:05 -0700445 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800446 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700447 }
448
Selim Cinek570981d2015-12-01 11:37:01 -0800449 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
450 mOnExpandClickListener = onExpandClickListener;
451 }
452
Chris Wren78403d72014-07-28 10:23:24 +0100453 public interface ExpansionLogger {
454 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
455 }
Selim Cinek1685e632014-04-08 02:27:49 +0200456
Chris Wren51c75102013-07-16 20:49:17 -0400457 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
458 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700459 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinekda42d652015-12-04 15:51:16 -0800460 mNotificationMinHeightLegacy = getResources().getDimensionPixelSize(
461 R.dimen.notification_min_height_legacy);
462 mNotificationMinHeight = getResources().getDimensionPixelSize(
463 R.dimen.notification_min_height);
464 mNotificationMaxHeight = getResources().getDimensionPixelSize(
465 R.dimen.notification_max_height);
Chris Wren51c75102013-07-16 20:49:17 -0400466 }
467
Christoph Studera7fe6312014-06-27 19:32:44 +0200468 /**
469 * Resets this view so it can be re-used for an updated notification.
470 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200471 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200472 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200473 super.reset();
Christoph Studera7fe6312014-06-27 19:32:44 +0200474 mRowMinHeight = 0;
Chris Wren78403d72014-07-28 10:23:24 +0100475 final boolean wasExpanded = isExpanded();
Selim Cinek379ff8f2015-02-20 17:03:16 +0100476 mMaxViewHeight = 0;
Christoph Studera7fe6312014-06-27 19:32:44 +0200477 mExpandable = false;
478 mHasUserChangedExpansion = false;
479 mUserLocked = false;
480 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200481 mSensitive = false;
482 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200483 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700484 mOnKeyguard = false;
Selim Cinek1a521f32014-11-03 17:39:29 +0100485 mPublicLayout.reset(mIsHeadsUp);
486 mPrivateLayout.reset(mIsHeadsUp);
Selim Cinek31094df2014-08-14 19:28:15 +0200487 resetHeight();
488 logExpansionEvent(false, wasExpanded);
489 }
490
491 public void resetHeight() {
Selim Cinek1a521f32014-11-03 17:39:29 +0100492 if (mIsHeadsUp) {
493 resetActualHeight();
494 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200495 mMaxExpandHeight = 0;
Selim Cinek8d490d42015-04-10 00:05:50 -0700496 mHeadsUpHeight = 0;
Selim Cineka5e211b2014-08-11 17:35:48 +0200497 mWasReset = true;
Selim Cinek31094df2014-08-14 19:28:15 +0200498 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200499 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200500 }
501
Jorim Jaggi251957d2014-04-09 04:24:09 +0200502 @Override
Selim Cinek1a521f32014-11-03 17:39:29 +0100503 protected boolean filterMotionEvent(MotionEvent event) {
504 return mIsHeadsUp || super.filterMotionEvent(event);
505 }
506
507 @Override
Jorim Jaggi251957d2014-04-09 04:24:09 +0200508 protected void onFinishInflate() {
509 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200510 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
511 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800512 mPrivateLayout.setExpandClickListener(mExpandClickListener);
513 mPublicLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekab29aeb2015-02-20 18:18:32 +0100514 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
515 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200516 @Override
517 public void onInflate(ViewStub stub, View inflated) {
518 mGuts = (NotificationGuts) inflated;
519 mGuts.setClipTopAmount(getClipTopAmount());
520 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100521 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200522 }
523 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100524 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
525 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
526
527 @Override
528 public void onInflate(ViewStub stub, View inflated) {
529 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -0700530 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100531 }
532 });
Selim Cinek863834b2014-05-20 04:20:25 +0200533 mVetoButton = findViewById(R.id.veto);
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200534 }
535
Selim Cinekab29aeb2015-02-20 18:18:32 +0100536 public void inflateGuts() {
537 if (mGuts == null) {
538 mGutsStub.inflate();
539 }
540 }
541
Selim Cinekda42d652015-12-04 15:51:16 -0800542 private void updateChildrenVisibility() {
Selim Cinekb5605e52015-02-20 18:21:41 +0100543 if (mChildrenContainer == null) {
544 return;
545 }
Selim Cinekeef84282015-10-30 16:28:00 -0700546 mChildrenContainer.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800547 mNotificationHeader.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekeef84282015-10-30 16:28:00 -0700548 mPrivateLayout.setVisibility(!mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekda42d652015-12-04 15:51:16 -0800549 // The limits might have changed if the view suddenly became a group or vice versa
550 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +0100551 }
552
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200553 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800554 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
555 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200556 // Add a record for the entire layout since its content is somehow small.
557 // The event comes from a leaf view that is interacted with.
558 AccessibilityEvent record = AccessibilityEvent.obtain();
559 onInitializeAccessibilityEvent(record);
560 dispatchPopulateAccessibilityEvent(record);
561 event.appendRecord(record);
562 return true;
563 }
564 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200565 }
Chris Wren51c75102013-07-16 20:49:17 -0400566
John Spurlocke15452b2014-08-21 09:44:39 -0400567 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100568 public void setDark(boolean dark, boolean fade, long delay) {
569 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400570 final NotificationContentView showing = getShowingLayout();
571 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100572 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400573 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800574 if (mIsSummaryWithChildren) {
575 mChildrenContainer.setDark(dark, fade, delay);
576 mNotificationHeaderWrapper.setDark(dark, fade, delay);
577 }
John Spurlocke15452b2014-08-21 09:44:39 -0400578 }
579
Chris Wren51c75102013-07-16 20:49:17 -0400580 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -0700581 if (mIsSummaryWithChildren && !mShowingPublic) {
582 return !mChildrenExpanded;
583 }
Chris Wren51c75102013-07-16 20:49:17 -0400584 return mExpandable;
585 }
586
587 public void setExpandable(boolean expandable) {
588 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800589 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -0400590 }
591
Selim Cinek1685e632014-04-08 02:27:49 +0200592 /**
593 * @return whether the user has changed the expansion state
594 */
595 public boolean hasUserChangedExpansion() {
596 return mHasUserChangedExpansion;
597 }
598
Chris Wren51c75102013-07-16 20:49:17 -0400599 public boolean isUserExpanded() {
600 return mUserExpanded;
601 }
602
Selim Cinek1685e632014-04-08 02:27:49 +0200603 /**
604 * Set this notification to be expanded by the user
605 *
606 * @param userExpanded whether the user wants this notification to be expanded
607 */
Chris Wren51c75102013-07-16 20:49:17 -0400608 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -0700609 setUserExpanded(userExpanded, false /* allowChildExpansion */);
610 }
611
612 /**
613 * Set this notification to be expanded by the user
614 *
615 * @param userExpanded whether the user wants this notification to be expanded
616 * @param allowChildExpansion whether a call to this method allows expanding children
617 */
618 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700619 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -0700620 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
621 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
622 return;
623 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200624 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +0100625 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +0200626 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -0400627 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +0100628 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -0400629 }
630
Selim Cinekccd14fb2014-08-12 18:53:24 +0200631 public void resetUserExpansion() {
632 mHasUserChangedExpansion = false;
633 mUserExpanded = false;
634 }
635
Chris Wren51c75102013-07-16 20:49:17 -0400636 public boolean isUserLocked() {
637 return mUserLocked;
638 }
639
640 public void setUserLocked(boolean userLocked) {
641 mUserLocked = userLocked;
642 }
643
Selim Cinek1685e632014-04-08 02:27:49 +0200644 /**
645 * @return has the system set this notification to be expanded
646 */
647 public boolean isSystemExpanded() {
648 return mIsSystemExpanded;
649 }
650
651 /**
652 * Set this notification to be expanded by the system.
653 *
654 * @param expand whether the system wants this notification to be expanded.
655 */
656 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +0200657 if (expand != mIsSystemExpanded) {
658 final boolean wasExpanded = isExpanded();
659 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +0100660 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +0200661 logExpansionEvent(false, wasExpanded);
Selim Cinek83bc7832015-10-22 13:26:54 -0700662 if (mChildrenContainer != null) {
663 mChildrenContainer.updateGroupOverflow();
664 }
Selim Cinek31094df2014-08-14 19:28:15 +0200665 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200666 }
667
668 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700669 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200670 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700671 public void setOnKeyguard(boolean onKeyguard) {
672 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +0200673 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -0700674 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +0200675 logExpansionEvent(false, wasExpanded);
676 if (wasExpanded != isExpanded()) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100677 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +0200678 }
679 }
Selim Cinek1685e632014-04-08 02:27:49 +0200680 }
681
682 /**
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400683 * @return Can the underlying notification be cleared?
684 */
685 public boolean isClearable() {
Selim Cineka37774f2014-11-11 19:16:18 +0100686 return mStatusBarNotification != null && mStatusBarNotification.isClearable();
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400687 }
688
689 /**
Selim Cinek1685e632014-04-08 02:27:49 +0200690 * Apply an expansion state to the layout.
Selim Cinek1685e632014-04-08 02:27:49 +0200691 */
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200692 public void applyExpansionToLayout() {
693 boolean expand = isExpanded();
Chris Wren51c75102013-07-16 20:49:17 -0400694 if (expand && mExpandable) {
Selim Cinekeef84282015-10-30 16:28:00 -0700695 setActualHeight(mMaxExpandHeight);
Chris Wren51c75102013-07-16 20:49:17 -0400696 } else {
Selim Cinekeef84282015-10-30 16:28:00 -0700697 setActualHeight(mRowMinHeight);
Chris Wren51c75102013-07-16 20:49:17 -0400698 }
Chris Wren51c75102013-07-16 20:49:17 -0400699 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500700
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200701 @Override
702 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +0200703 if (isUserLocked()) {
704 return getActualHeight();
705 }
Selim Cinek1685e632014-04-08 02:27:49 +0200706 boolean inExpansionState = isExpanded();
Selim Cinek60122be2015-04-15 18:16:50 -0700707 if (mSensitive && mHideSensitiveForIntrinsicHeight) {
708 return mRowMinHeight;
Selim Cinek83bc7832015-10-22 13:26:54 -0700709 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800710 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek60122be2015-04-15 18:16:50 -0700711 } else if (mIsHeadsUp) {
Selim Cinek8d490d42015-04-10 00:05:50 -0700712 if (inExpansionState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700713 return Math.max(mMaxExpandHeight, mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -0700714 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -0700715 return Math.max(mRowMinHeight, mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -0700716 }
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700717 } else if (!inExpansionState || (isChildInGroup() && !isGroupExpanded())) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700718 return getMinHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +0100719 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -0700720 return getMaxExpandHeight();
Selim Cinek1685e632014-04-08 02:27:49 +0200721 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100722 }
Selim Cinek1685e632014-04-08 02:27:49 +0200723
Selim Cinekeef84282015-10-30 16:28:00 -0700724 private boolean isGroupExpanded() {
725 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +0100726 }
727
Selim Cinekeef84282015-10-30 16:28:00 -0700728 /**
729 * @return whether this view has a header on the top of the content
730 */
731 private boolean hasNotificationHeader() {
732 return mIsSummaryWithChildren;
Selim Cinek1685e632014-04-08 02:27:49 +0200733 }
734
Selim Cinek263398f2015-10-21 17:40:23 -0700735 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -0800736 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Selim Cinek263398f2015-10-21 17:40:23 -0700737 && mGroupManager.hasGroupChildren(mStatusBarNotification);
Selim Cinek8fc93c92015-11-23 17:48:07 -0800738 if (mIsSummaryWithChildren) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800739 if (mChildrenContainer == null) {
740 mChildrenContainerStub.inflate();
741 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800742 if (mNotificationHeader == null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800743 recreateNotificationHeader();
744 }
Selim Cinek263398f2015-10-21 17:40:23 -0700745 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800746 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -0800747 updateChildrenHeaderAppearance();
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800748 updateHeaderChildCount();
Selim Cinekda42d652015-12-04 15:51:16 -0800749 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -0700750 }
751
Selim Cinek1685e632014-04-08 02:27:49 +0200752 /**
753 * Check whether the view state is currently expanded. This is given by the system in {@link
754 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
755 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
756 * view can differ from this state, if layout params are modified from outside.
757 *
758 * @return whether the view state is currently expanded.
759 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700760 public boolean isExpanded() {
761 return !mOnKeyguard
Selim Cinekb5605e52015-02-20 18:21:41 +0100762 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
763 || isUserExpanded());
764 }
765
766 private boolean isSystemChildExpanded() {
767 return mIsSystemChildExpanded;
768 }
769
770 public void setSystemChildExpanded(boolean expanded) {
771 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +0200772 }
773
774 @Override
775 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
776 super.onLayout(changed, left, top, right, bottom);
Selim Cineka5e211b2014-08-11 17:35:48 +0200777 boolean updateExpandHeight = mMaxExpandHeight == 0 && !mWasReset;
Selim Cinek8d490d42015-04-10 00:05:50 -0700778 updateMaxHeights();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200779 if (updateExpandHeight) {
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200780 applyExpansionToLayout();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200781 }
Selim Cineka5e211b2014-08-11 17:35:48 +0200782 mWasReset = false;
Selim Cinek1685e632014-04-08 02:27:49 +0200783 }
784
Selim Cinek8d490d42015-04-10 00:05:50 -0700785 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +0200786 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -0700787 View expandedChild = mPrivateLayout.getExpandedChild();
788 if (expandedChild == null) {
789 expandedChild = mPrivateLayout.getContractedChild();
790 }
791 mMaxExpandHeight = expandedChild.getHeight();
792 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -0700793 if (headsUpChild == null) {
794 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700795 }
Selim Cinek1f3f5442015-04-10 17:54:46 -0700796 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +0200797 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100798 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +0200799 }
800 }
801
Jorim Jaggiae441282014-08-01 02:45:18 +0200802 public void setSensitive(boolean sensitive) {
803 mSensitive = sensitive;
804 }
805
806 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -0700807 mHideSensitiveForIntrinsicHeight = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +0200808 }
809
810 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
811 long duration) {
812 boolean oldShowingPublic = mShowingPublic;
813 mShowingPublic = mSensitive && hideSensitive;
814 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
815 return;
816 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500817
818 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +0200819 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500820
Jorim Jaggiae441282014-08-01 02:45:18 +0200821 if (!animated) {
822 mPublicLayout.animate().cancel();
823 mPrivateLayout.animate().cancel();
824 mPublicLayout.setAlpha(1f);
825 mPrivateLayout.setAlpha(1f);
826 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinek263398f2015-10-21 17:40:23 -0700827 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? View.VISIBLE
828 : View.INVISIBLE);
Jorim Jaggiae441282014-08-01 02:45:18 +0200829 } else {
830 animateShowingPublic(delay, duration);
831 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400832
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800833 mPrivateLayout.updateExpandButtons(isExpandable());
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400834 updateVetoButton();
Jorim Jaggiae441282014-08-01 02:45:18 +0200835 mShowingPublicInitialized = true;
836 }
837
838 private void animateShowingPublic(long delay, long duration) {
839 final View source = mShowingPublic ? mPrivateLayout : mPublicLayout;
840 View target = mShowingPublic ? mPublicLayout : mPrivateLayout;
841 source.setVisibility(View.VISIBLE);
842 target.setVisibility(View.VISIBLE);
843 target.setAlpha(0f);
844 source.animate().cancel();
845 target.animate().cancel();
846 source.animate()
847 .alpha(0f)
Jorim Jaggiae441282014-08-01 02:45:18 +0200848 .setStartDelay(delay)
849 .setDuration(duration)
850 .withEndAction(new Runnable() {
851 @Override
852 public void run() {
853 source.setVisibility(View.INVISIBLE);
854 }
855 });
856 target.animate()
857 .alpha(1f)
Jorim Jaggiae441282014-08-01 02:45:18 +0200858 .setStartDelay(delay)
859 .setDuration(duration);
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400860 }
861
862 private void updateVetoButton() {
863 // public versions cannot be dismissed
864 mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE);
Dan Sandlera5e0f412014-01-23 15:11:54 -0500865 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200866
Selim Cinekb5605e52015-02-20 18:21:41 +0100867 public void setChildrenExpanded(boolean expanded, boolean animate) {
868 mChildrenExpanded = expanded;
Selim Cinek7b836392015-12-04 20:02:59 -0800869 if (mNotificationHeader != null) {
870 mNotificationHeader.setExpanded(expanded);
871 }
Selim Cinek83bc7832015-10-22 13:26:54 -0700872 if (mChildrenContainer != null) {
873 mChildrenContainer.setChildrenExpanded(expanded);
874 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100875 }
876
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800877 public void updateHeaderChildCount() {
878 if (mIsSummaryWithChildren) {
879 mNotificationHeader.setChildCount(
880 mChildrenContainer.getNotificationChildren().size());
Selim Cinekb5605e52015-02-20 18:21:41 +0100881 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100882 }
883
884 public static void applyTint(View v, int color) {
885 int alpha;
886 if (color != 0) {
887 alpha = COLORED_DIVIDER_ALPHA;
888 } else {
889 color = 0xff000000;
890 alpha = DEFAULT_DIVIDER_ALPHA;
891 }
892 if (v.getBackground() instanceof ColorDrawable) {
893 ColorDrawable background = (ColorDrawable) v.getBackground();
894 background.mutate();
895 background.setColor(color);
896 background.setAlpha(alpha);
897 }
898 }
899
Selim Cinek1685e632014-04-08 02:27:49 +0200900 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +0100901 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400902 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +0200903
Jorim Jaggibe565df2014-04-28 17:51:23 +0200904 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200905 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200906 NotificationContentView showingLayout = getShowingLayout();
907 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200908 }
909
910 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -0700911 protected View getContentView() {
912 return getShowingLayout();
913 }
914
915 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200916 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100917 super.setActualHeight(height, notifyListeners);
Selim Cinekeef84282015-10-30 16:28:00 -0700918 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +0100919 mPrivateLayout.setContentHeight(contentHeight);
920 mPublicLayout.setContentHeight(contentHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200921 if (mGuts != null) {
922 mGuts.setActualHeight(height);
923 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200924 invalidate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200925 }
926
927 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +0100928 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700929 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800930 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700931 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200932 NotificationContentView showingLayout = getShowingLayout();
933 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200934 }
935
936 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200937 public int getMinHeight() {
Selim Cinek816c8e42015-11-19 12:00:45 -0800938 NotificationContentView showingLayout = getShowingLayout();
939 return showingLayout.getMinHeight();
940 }
941
942 @Override
943 public int getMinExpandHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700944 if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800945 return mChildrenContainer.getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700946 }
Selim Cinek816c8e42015-11-19 12:00:45 -0800947 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200948 }
949
950 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700951 protected boolean shouldLimitViewHeight() {
952 return !mIsSummaryWithChildren;
953 }
954
955 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +0200956 public void setClipTopAmount(int clipTopAmount) {
957 super.setClipTopAmount(clipTopAmount);
958 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200959 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200960 if (mGuts != null) {
961 mGuts.setClipTopAmount(clipTopAmount);
962 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200963 }
964
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800965 private void recreateNotificationHeader() {
966 final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
967 getStatusBarNotification().getNotification());
968 final RemoteViews header = builder.makeNotificationHeader();
969 if (mNotificationHeader == null) {
970 mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
971 final View expandButton = mNotificationHeader.findViewById(
972 com.android.internal.R.id.expand_button);
973 expandButton.setVisibility(VISIBLE);
974 mNotificationHeader.setOnClickListener(mExpandClickListener);
Selim Cinek9c7712d2015-12-08 19:19:48 -0800975 mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
976 mNotificationHeader);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800977 addView(mNotificationHeader);
978 } else {
979 header.reapply(getContext(), mNotificationHeader);
Selim Cinek9c7712d2015-12-08 19:19:48 -0800980 mNotificationHeaderWrapper.notifyContentUpdated();
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800981 }
Selim Cinek7b836392015-12-04 20:02:59 -0800982 updateHeaderExpandButton();
Selim Cinekea4bef72015-12-02 15:51:10 -0800983 updateChildrenHeaderAppearance();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800984 updateHeaderChildCount();
Selim Cinek343e6e22014-04-11 21:23:30 +0200985 }
Selim Cinek7d447722014-06-10 15:51:59 +0200986
Selim Cinek7b836392015-12-04 20:02:59 -0800987 private void updateHeaderExpandButton() {
988 if (mIsSummaryWithChildren) {
989 mNotificationHeader.setIsGroupHeader(true /* isGroupHeader*/);
990 }
991 }
992
Selim Cinekea4bef72015-12-02 15:51:10 -0800993 public void updateChildrenHeaderAppearance() {
994 if (mIsSummaryWithChildren) {
995 mHeaderUtil.updateChildrenHeaderAppearance();
996 }
997 }
998
Selim Cinek31094df2014-08-14 19:28:15 +0200999 public boolean isMaxExpandHeightInitialized() {
1000 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001001 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001002
1003 private NotificationContentView getShowingLayout() {
1004 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1005 }
Chris Wren78403d72014-07-28 10:23:24 +01001006
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001007 @Override
1008 public void setShowingLegacyBackground(boolean showing) {
1009 super.setShowingLegacyBackground(showing);
1010 mPrivateLayout.setShowingLegacyBackground(showing);
1011 mPublicLayout.setShowingLegacyBackground(showing);
1012 }
1013
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001014 @Override
1015 protected void updateBackgroundTint() {
1016 super.updateBackgroundTint();
1017 updateNoBackgroundState();
1018 if (mIsSummaryWithChildren) {
1019 List<ExpandableNotificationRow> notificationChildren =
1020 mChildrenContainer.getNotificationChildren();
1021 for (int i = 0; i < notificationChildren.size(); i++) {
1022 ExpandableNotificationRow child = notificationChildren.get(i);
1023 child.updateNoBackgroundState();
1024 }
1025 }
1026 }
1027
1028 private void updateNoBackgroundState() {
1029 mShowNoBackground = isChildInGroup() && hasSameBgColor(mNotificationParent);
1030 updateBackground();
1031 }
1032
Chris Wren78403d72014-07-28 10:23:24 +01001033 public void setExpansionLogger(ExpansionLogger logger, String key) {
1034 mLogger = logger;
1035 mLoggingKey = key;
1036 }
1037
Chris Wren78403d72014-07-28 10:23:24 +01001038 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
1039 final boolean nowExpanded = isExpanded();
1040 if (wasExpanded != nowExpanded && mLogger != null) {
1041 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1042 }
1043 }
Selim Cinek570981d2015-12-01 11:37:01 -08001044
1045 public interface OnExpandClickListener {
1046 void onExpandClicked(View clickedView, boolean nowExpanded);
1047 }
Chris Wren51c75102013-07-16 20:49:17 -04001048}