blob: e7192ca8ccc38bb8bb73144fbed51fdc31c68be3 [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 Cinekb5605e52015-02-20 18:21:41 +010098 private ViewStub mChildrenContainerStub;
99 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100100 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700101 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100102 private NotificationChildrenContainer mChildrenContainer;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100103 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100104 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700105 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700106 private FalsingManager mFalsingManager;
Selim Cinekea4bef72015-12-02 15:51:10 -0800107 private NotificationHeaderUtil mHeaderUtil = new NotificationHeaderUtil(this);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200108
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700109 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800110 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700111 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700112 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800113 private OnExpandClickListener mOnExpandClickListener;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800114 private OnClickListener mExpandClickListener = new OnClickListener() {
115 @Override
116 public void onClick(View v) {
117 if (mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
118 mGroupManager.toggleGroupExpansion(mStatusBarNotification);
Selim Cinek570981d2015-12-01 11:37:01 -0800119 mOnExpandClickListener.onExpandClicked(ExpandableNotificationRow.this,
120 mGroupManager.isGroupExpanded(mStatusBarNotification));
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800121 } else {
Selim Cinek570981d2015-12-01 11:37:01 -0800122 boolean nowExpanded = !isExpanded();
123 setUserExpanded(nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800124 notifyHeightChanged(true);
Selim Cinek570981d2015-12-01 11:37:01 -0800125 mOnExpandClickListener.onExpandClicked(ExpandableNotificationRow.this,
126 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800127 }
128 }
129 };
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700130
Selim Cinek8d490d42015-04-10 00:05:50 -0700131 public NotificationContentView getPrivateLayout() {
132 return mPrivateLayout;
133 }
134
135 public NotificationContentView getPublicLayout() {
136 return mPublicLayout;
137 }
138
Selim Cinekcab4a602014-09-03 14:47:57 +0200139 public void setIconAnimationRunning(boolean running) {
140 setIconAnimationRunning(running, mPublicLayout);
141 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800142 setIconAnimationRunningForChild(running, mNotificationHeader);
143 if (mIsSummaryWithChildren) {
144 List<ExpandableNotificationRow> notificationChildren =
145 mChildrenContainer.getNotificationChildren();
146 for (int i = 0; i < notificationChildren.size(); i++) {
147 ExpandableNotificationRow child = notificationChildren.get(i);
148 child.setIconAnimationRunning(running);
149 }
150 }
151 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200152 }
153
154 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
155 if (layout != null) {
156 View contractedChild = layout.getContractedChild();
157 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700158 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200159 setIconAnimationRunningForChild(running, contractedChild);
160 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700161 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200162 }
163 }
164
165 private void setIconAnimationRunningForChild(boolean running, View child) {
166 if (child != null) {
167 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
168 setIconRunning(icon, running);
169 ImageView rightIcon = (ImageView) child.findViewById(
170 com.android.internal.R.id.right_icon);
171 setIconRunning(rightIcon, running);
172 }
173 }
174
175 private void setIconRunning(ImageView imageView, boolean running) {
176 if (imageView != null) {
177 Drawable drawable = imageView.getDrawable();
178 if (drawable instanceof AnimationDrawable) {
179 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
180 if (running) {
181 animationDrawable.start();
182 } else {
183 animationDrawable.stop();
184 }
185 } else if (drawable instanceof AnimatedVectorDrawable) {
186 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
187 if (running) {
188 animationDrawable.start();
189 } else {
190 animationDrawable.stop();
191 }
192 }
193 }
194 }
195
Selim Cinekda42d652015-12-04 15:51:16 -0800196 public void onNotificationUpdated(NotificationData.Entry entry) {
197 mEntry = entry;
198 mStatusBarNotification = entry.notification;
199 mPrivateLayout.onNotificationUpdated(entry.notification);
200 mPublicLayout.onNotificationUpdated(entry.notification);
Selim Cineka37774f2014-11-11 19:16:18 +0100201 updateVetoButton();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800202 if (mIsSummaryWithChildren) {
203 recreateNotificationHeader();
204 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800205 if (mIconAnimationRunning) {
206 setIconAnimationRunning(true);
207 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800208 if (mNotificationParent != null) {
209 mNotificationParent.updateChildrenHeaderAppearance();
210 }
Selim Cinek263398f2015-10-21 17:40:23 -0700211 onChildrenCountChanged();
Selim Cinekda42d652015-12-04 15:51:16 -0800212 updateLimits();
213 }
214
215 private void updateLimits() {
216 boolean customView = getPrivateLayout().getContractedChild().getId()
217 != com.android.internal.R.id.status_bar_latest_event_content;
218 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
219 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
220 mNotificationMinHeightLegacy : mNotificationMinHeight;
221 mRowMinHeight = minHeight;
222 mMaxViewHeight = mNotificationMaxHeight;
223 mPrivateLayout.setSmallHeight(mRowMinHeight);
224 mPublicLayout.setSmallHeight(mRowMinHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200225 }
226
227 public StatusBarNotification getStatusBarNotification() {
228 return mStatusBarNotification;
229 }
230
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700231 public boolean isHeadsUp() {
232 return mIsHeadsUp;
233 }
234
Selim Cinek1a521f32014-11-03 17:39:29 +0100235 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700236 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100237 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700238 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekc80fdb12015-04-13 15:09:08 -0700239 if (intrinsicBefore != getIntrinsicHeight()) {
240 notifyHeightChanged(false /* needsAnimation */);
241 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100242 }
243
Selim Cinekb5605e52015-02-20 18:21:41 +0100244 public void setGroupManager(NotificationGroupManager groupManager) {
245 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700246 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100247 }
248
249 public void addChildNotification(ExpandableNotificationRow row) {
250 addChildNotification(row, -1);
251 }
252
253 /**
254 * Add a child notification to this view.
255 *
256 * @param row the row to add
257 * @param childIndex the index to add it at, if -1 it will be added at the end
258 */
259 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
260 if (mChildrenContainer == null) {
261 mChildrenContainerStub.inflate();
262 }
263 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700264 onChildrenCountChanged();
265 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100266 }
267
268 public void removeChildNotification(ExpandableNotificationRow row) {
269 if (mChildrenContainer != null) {
270 mChildrenContainer.removeNotification(row);
271 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800272 mHeaderUtil.restoreNotificationHeader(row);
Selim Cinek263398f2015-10-21 17:40:23 -0700273 onChildrenCountChanged();
274 row.setIsChildInGroup(false, null);
275 }
276
277 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700278 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700279 }
280
Selim Cinek388df6d2015-10-22 13:25:11 -0700281 public ExpandableNotificationRow getNotificationParent() {
282 return mNotificationParent;
283 }
284
Selim Cinek263398f2015-10-21 17:40:23 -0700285 /**
286 * @param isChildInGroup Is this notification now in a group
287 * @param parent the new parent notification
288 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700289 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
290 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
291 mNotificationParent = childInGroup ? parent : null;
292 mPrivateLayout.setIsChildInGroup(childInGroup);
293 updateNoBackgroundState();
Selim Cinek34d93b02015-10-22 12:30:38 -0700294 }
295
296 @Override
297 protected boolean shouldHideBackground() {
298 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700299 }
300
301 @Override
302 public boolean isSummaryWithChildren() {
303 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100304 }
305
306 @Override
307 public boolean areChildrenExpanded() {
308 return mChildrenExpanded;
309 }
310
311 public List<ExpandableNotificationRow> getNotificationChildren() {
312 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
313 }
314
Selim Cinekeef84282015-10-30 16:28:00 -0700315 public int getNumberOfNotificationChildren() {
316 if (mChildrenContainer == null) {
317 return 0;
318 }
319 return mChildrenContainer.getNotificationChildren().size();
320 }
321
Selim Cinekb5605e52015-02-20 18:21:41 +0100322 /**
323 * Apply the order given in the list to the children.
324 *
325 * @param childOrder the new list order
326 * @return whether the list order has changed
327 */
328 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
329 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
330 }
331
332 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700333 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100334 StackViewState parentState = resultState.getViewStateForView(this);
335 mChildrenContainer.getState(resultState, parentState);
336 }
337 }
338
339 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700340 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100341 mChildrenContainer.applyState(state);
342 }
343 }
344
345 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700346 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100347 mChildrenContainer.prepareExpansionChanged(state);
348 }
349 }
350
351 public void startChildAnimation(StackScrollState finalState,
352 StackStateAnimator stateAnimator, boolean withDelays, long delay, long duration) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700353 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100354 mChildrenContainer.startAnimationToState(finalState, stateAnimator, withDelays, delay,
355 duration);
356 }
357 }
358
359 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700360 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100361 return this;
362 } else {
363 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
364 return view == null ? this : view;
365 }
366 }
367
Selim Cinekab29aeb2015-02-20 18:18:32 +0100368 public NotificationGuts getGuts() {
369 return mGuts;
370 }
371
Selim Cinek684a4422015-04-15 16:18:39 -0700372 /**
373 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
374 * the notification will be rendered on top of the screen.
375 *
376 * @param pinned whether it is pinned
377 */
378 public void setPinned(boolean pinned) {
379 mIsPinned = pinned;
Selim Cinek98713a42015-09-21 15:47:20 +0200380 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700381 }
382
Selim Cinek684a4422015-04-15 16:18:39 -0700383 public boolean isPinned() {
384 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700385 }
386
387 public int getHeadsUpHeight() {
Selim Cinek8d490d42015-04-10 00:05:50 -0700388 return mHeadsUpHeight;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700389 }
390
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700391 /**
392 * Mark whether this notification was just clicked, i.e. the user has just clicked this
393 * notification in this frame.
394 */
395 public void setJustClicked(boolean justClicked) {
396 mJustClicked = justClicked;
397 }
398
399 /**
400 * @return true if this notification has been clicked in this frame, false otherwise
401 */
402 public boolean wasJustClicked() {
403 return mJustClicked;
404 }
405
Selim Cinek98713a42015-09-21 15:47:20 +0200406 public void setChronometerRunning(boolean running) {
407 mLastChronometerRunning = running;
408 setChronometerRunning(running, mPrivateLayout);
409 setChronometerRunning(running, mPublicLayout);
410 if (mChildrenContainer != null) {
411 List<ExpandableNotificationRow> notificationChildren =
412 mChildrenContainer.getNotificationChildren();
413 for (int i = 0; i < notificationChildren.size(); i++) {
414 ExpandableNotificationRow child = notificationChildren.get(i);
415 child.setChronometerRunning(running);
416 }
417 }
418 }
419
420 private void setChronometerRunning(boolean running, NotificationContentView layout) {
421 if (layout != null) {
422 running = running || isPinned();
423 View contractedChild = layout.getContractedChild();
424 View expandedChild = layout.getExpandedChild();
425 View headsUpChild = layout.getHeadsUpChild();
426 setChronometerRunningForChild(running, contractedChild);
427 setChronometerRunningForChild(running, expandedChild);
428 setChronometerRunningForChild(running, headsUpChild);
429 }
430 }
431
432 private void setChronometerRunningForChild(boolean running, View child) {
433 if (child != null) {
434 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
435 if (chronometer instanceof Chronometer) {
436 ((Chronometer) chronometer).setStarted(running);
437 }
438 }
439 }
440
Selim Cinekea4bef72015-12-02 15:51:10 -0800441 public NotificationHeaderView getNotificationHeader() {
442 if (mNotificationHeader != null) {
443 return mNotificationHeader;
Selim Cinek8d6440d2015-10-22 13:00:05 -0700444 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800445 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700446 }
447
Selim Cinek570981d2015-12-01 11:37:01 -0800448 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
449 mOnExpandClickListener = onExpandClickListener;
450 }
451
Chris Wren78403d72014-07-28 10:23:24 +0100452 public interface ExpansionLogger {
453 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
454 }
Selim Cinek1685e632014-04-08 02:27:49 +0200455
Chris Wren51c75102013-07-16 20:49:17 -0400456 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
457 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700458 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinekda42d652015-12-04 15:51:16 -0800459 mNotificationMinHeightLegacy = getResources().getDimensionPixelSize(
460 R.dimen.notification_min_height_legacy);
461 mNotificationMinHeight = getResources().getDimensionPixelSize(
462 R.dimen.notification_min_height);
463 mNotificationMaxHeight = getResources().getDimensionPixelSize(
464 R.dimen.notification_max_height);
Chris Wren51c75102013-07-16 20:49:17 -0400465 }
466
Christoph Studera7fe6312014-06-27 19:32:44 +0200467 /**
468 * Resets this view so it can be re-used for an updated notification.
469 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200470 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200471 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200472 super.reset();
Christoph Studera7fe6312014-06-27 19:32:44 +0200473 mRowMinHeight = 0;
Chris Wren78403d72014-07-28 10:23:24 +0100474 final boolean wasExpanded = isExpanded();
Selim Cinek379ff8f2015-02-20 17:03:16 +0100475 mMaxViewHeight = 0;
Christoph Studera7fe6312014-06-27 19:32:44 +0200476 mExpandable = false;
477 mHasUserChangedExpansion = false;
478 mUserLocked = false;
479 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200480 mSensitive = false;
481 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200482 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700483 mOnKeyguard = false;
Selim Cinek1a521f32014-11-03 17:39:29 +0100484 mPublicLayout.reset(mIsHeadsUp);
485 mPrivateLayout.reset(mIsHeadsUp);
Selim Cinek31094df2014-08-14 19:28:15 +0200486 resetHeight();
487 logExpansionEvent(false, wasExpanded);
488 }
489
490 public void resetHeight() {
Selim Cinek1a521f32014-11-03 17:39:29 +0100491 if (mIsHeadsUp) {
492 resetActualHeight();
493 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200494 mMaxExpandHeight = 0;
Selim Cinek8d490d42015-04-10 00:05:50 -0700495 mHeadsUpHeight = 0;
Selim Cineka5e211b2014-08-11 17:35:48 +0200496 mWasReset = true;
Selim Cinek31094df2014-08-14 19:28:15 +0200497 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200498 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200499 }
500
Jorim Jaggi251957d2014-04-09 04:24:09 +0200501 @Override
Selim Cinek1a521f32014-11-03 17:39:29 +0100502 protected boolean filterMotionEvent(MotionEvent event) {
503 return mIsHeadsUp || super.filterMotionEvent(event);
504 }
505
506 @Override
Jorim Jaggi251957d2014-04-09 04:24:09 +0200507 protected void onFinishInflate() {
508 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200509 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
510 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800511 mPrivateLayout.setExpandClickListener(mExpandClickListener);
512 mPublicLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekab29aeb2015-02-20 18:18:32 +0100513 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
514 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200515 @Override
516 public void onInflate(ViewStub stub, View inflated) {
517 mGuts = (NotificationGuts) inflated;
518 mGuts.setClipTopAmount(getClipTopAmount());
519 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100520 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200521 }
522 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100523 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
524 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
525
526 @Override
527 public void onInflate(ViewStub stub, View inflated) {
528 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -0700529 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100530 }
531 });
Selim Cinek863834b2014-05-20 04:20:25 +0200532 mVetoButton = findViewById(R.id.veto);
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200533 }
534
Selim Cinekab29aeb2015-02-20 18:18:32 +0100535 public void inflateGuts() {
536 if (mGuts == null) {
537 mGutsStub.inflate();
538 }
539 }
540
Selim Cinekda42d652015-12-04 15:51:16 -0800541 private void updateChildrenVisibility() {
Selim Cinekb5605e52015-02-20 18:21:41 +0100542 if (mChildrenContainer == null) {
543 return;
544 }
Selim Cinekeef84282015-10-30 16:28:00 -0700545 mChildrenContainer.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800546 mNotificationHeader.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekeef84282015-10-30 16:28:00 -0700547 mPrivateLayout.setVisibility(!mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekda42d652015-12-04 15:51:16 -0800548 // The limits might have changed if the view suddenly became a group or vice versa
549 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +0100550 }
551
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200552 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800553 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
554 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200555 // Add a record for the entire layout since its content is somehow small.
556 // The event comes from a leaf view that is interacted with.
557 AccessibilityEvent record = AccessibilityEvent.obtain();
558 onInitializeAccessibilityEvent(record);
559 dispatchPopulateAccessibilityEvent(record);
560 event.appendRecord(record);
561 return true;
562 }
563 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200564 }
Chris Wren51c75102013-07-16 20:49:17 -0400565
John Spurlocke15452b2014-08-21 09:44:39 -0400566 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100567 public void setDark(boolean dark, boolean fade, long delay) {
568 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400569 final NotificationContentView showing = getShowingLayout();
570 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100571 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400572 }
573 }
574
Chris Wren51c75102013-07-16 20:49:17 -0400575 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -0700576 if (mIsSummaryWithChildren && !mShowingPublic) {
577 return !mChildrenExpanded;
578 }
Chris Wren51c75102013-07-16 20:49:17 -0400579 return mExpandable;
580 }
581
582 public void setExpandable(boolean expandable) {
583 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800584 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -0400585 }
586
Selim Cinek1685e632014-04-08 02:27:49 +0200587 /**
588 * @return whether the user has changed the expansion state
589 */
590 public boolean hasUserChangedExpansion() {
591 return mHasUserChangedExpansion;
592 }
593
Chris Wren51c75102013-07-16 20:49:17 -0400594 public boolean isUserExpanded() {
595 return mUserExpanded;
596 }
597
Selim Cinek1685e632014-04-08 02:27:49 +0200598 /**
599 * Set this notification to be expanded by the user
600 *
601 * @param userExpanded whether the user wants this notification to be expanded
602 */
Chris Wren51c75102013-07-16 20:49:17 -0400603 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -0700604 setUserExpanded(userExpanded, false /* allowChildExpansion */);
605 }
606
607 /**
608 * Set this notification to be expanded by the user
609 *
610 * @param userExpanded whether the user wants this notification to be expanded
611 * @param allowChildExpansion whether a call to this method allows expanding children
612 */
613 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700614 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -0700615 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
616 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
617 return;
618 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200619 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +0100620 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +0200621 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -0400622 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +0100623 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -0400624 }
625
Selim Cinekccd14fb2014-08-12 18:53:24 +0200626 public void resetUserExpansion() {
627 mHasUserChangedExpansion = false;
628 mUserExpanded = false;
629 }
630
Chris Wren51c75102013-07-16 20:49:17 -0400631 public boolean isUserLocked() {
632 return mUserLocked;
633 }
634
635 public void setUserLocked(boolean userLocked) {
636 mUserLocked = userLocked;
637 }
638
Selim Cinek1685e632014-04-08 02:27:49 +0200639 /**
640 * @return has the system set this notification to be expanded
641 */
642 public boolean isSystemExpanded() {
643 return mIsSystemExpanded;
644 }
645
646 /**
647 * Set this notification to be expanded by the system.
648 *
649 * @param expand whether the system wants this notification to be expanded.
650 */
651 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +0200652 if (expand != mIsSystemExpanded) {
653 final boolean wasExpanded = isExpanded();
654 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +0100655 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +0200656 logExpansionEvent(false, wasExpanded);
Selim Cinek83bc7832015-10-22 13:26:54 -0700657 if (mChildrenContainer != null) {
658 mChildrenContainer.updateGroupOverflow();
659 }
Selim Cinek31094df2014-08-14 19:28:15 +0200660 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200661 }
662
663 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700664 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200665 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700666 public void setOnKeyguard(boolean onKeyguard) {
667 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +0200668 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -0700669 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +0200670 logExpansionEvent(false, wasExpanded);
671 if (wasExpanded != isExpanded()) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100672 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +0200673 }
674 }
Selim Cinek1685e632014-04-08 02:27:49 +0200675 }
676
677 /**
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400678 * @return Can the underlying notification be cleared?
679 */
680 public boolean isClearable() {
Selim Cineka37774f2014-11-11 19:16:18 +0100681 return mStatusBarNotification != null && mStatusBarNotification.isClearable();
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400682 }
683
684 /**
Selim Cinek1685e632014-04-08 02:27:49 +0200685 * Apply an expansion state to the layout.
Selim Cinek1685e632014-04-08 02:27:49 +0200686 */
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200687 public void applyExpansionToLayout() {
688 boolean expand = isExpanded();
Chris Wren51c75102013-07-16 20:49:17 -0400689 if (expand && mExpandable) {
Selim Cinekeef84282015-10-30 16:28:00 -0700690 setActualHeight(mMaxExpandHeight);
Chris Wren51c75102013-07-16 20:49:17 -0400691 } else {
Selim Cinekeef84282015-10-30 16:28:00 -0700692 setActualHeight(mRowMinHeight);
Chris Wren51c75102013-07-16 20:49:17 -0400693 }
Chris Wren51c75102013-07-16 20:49:17 -0400694 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500695
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200696 @Override
697 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +0200698 if (isUserLocked()) {
699 return getActualHeight();
700 }
Selim Cinek1685e632014-04-08 02:27:49 +0200701 boolean inExpansionState = isExpanded();
Selim Cinek60122be2015-04-15 18:16:50 -0700702 if (mSensitive && mHideSensitiveForIntrinsicHeight) {
703 return mRowMinHeight;
Selim Cinek83bc7832015-10-22 13:26:54 -0700704 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800705 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek60122be2015-04-15 18:16:50 -0700706 } else if (mIsHeadsUp) {
Selim Cinek8d490d42015-04-10 00:05:50 -0700707 if (inExpansionState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700708 return Math.max(mMaxExpandHeight, mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -0700709 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -0700710 return Math.max(mRowMinHeight, mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -0700711 }
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700712 } else if (!inExpansionState || (isChildInGroup() && !isGroupExpanded())) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700713 return getMinHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +0100714 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -0700715 return getMaxExpandHeight();
Selim Cinek1685e632014-04-08 02:27:49 +0200716 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100717 }
Selim Cinek1685e632014-04-08 02:27:49 +0200718
Selim Cinekeef84282015-10-30 16:28:00 -0700719 private boolean isGroupExpanded() {
720 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +0100721 }
722
Selim Cinekeef84282015-10-30 16:28:00 -0700723 /**
724 * @return whether this view has a header on the top of the content
725 */
726 private boolean hasNotificationHeader() {
727 return mIsSummaryWithChildren;
Selim Cinek1685e632014-04-08 02:27:49 +0200728 }
729
Selim Cinek263398f2015-10-21 17:40:23 -0700730 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -0800731 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Selim Cinek263398f2015-10-21 17:40:23 -0700732 && mGroupManager.hasGroupChildren(mStatusBarNotification);
Selim Cinek8fc93c92015-11-23 17:48:07 -0800733 if (mIsSummaryWithChildren) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800734 if (mChildrenContainer == null) {
735 mChildrenContainerStub.inflate();
736 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800737 if (mNotificationHeader == null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800738 recreateNotificationHeader();
739 }
Selim Cinek263398f2015-10-21 17:40:23 -0700740 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800741 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -0800742 updateChildrenHeaderAppearance();
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800743 updateHeaderChildCount();
Selim Cinekda42d652015-12-04 15:51:16 -0800744 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -0700745 }
746
Selim Cinek1685e632014-04-08 02:27:49 +0200747 /**
748 * Check whether the view state is currently expanded. This is given by the system in {@link
749 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
750 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
751 * view can differ from this state, if layout params are modified from outside.
752 *
753 * @return whether the view state is currently expanded.
754 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700755 public boolean isExpanded() {
756 return !mOnKeyguard
Selim Cinekb5605e52015-02-20 18:21:41 +0100757 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
758 || isUserExpanded());
759 }
760
761 private boolean isSystemChildExpanded() {
762 return mIsSystemChildExpanded;
763 }
764
765 public void setSystemChildExpanded(boolean expanded) {
766 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +0200767 }
768
769 @Override
770 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
771 super.onLayout(changed, left, top, right, bottom);
Selim Cineka5e211b2014-08-11 17:35:48 +0200772 boolean updateExpandHeight = mMaxExpandHeight == 0 && !mWasReset;
Selim Cinek8d490d42015-04-10 00:05:50 -0700773 updateMaxHeights();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200774 if (updateExpandHeight) {
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200775 applyExpansionToLayout();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200776 }
Selim Cineka5e211b2014-08-11 17:35:48 +0200777 mWasReset = false;
Selim Cinek1685e632014-04-08 02:27:49 +0200778 }
779
Selim Cinek8d490d42015-04-10 00:05:50 -0700780 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +0200781 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -0700782 View expandedChild = mPrivateLayout.getExpandedChild();
783 if (expandedChild == null) {
784 expandedChild = mPrivateLayout.getContractedChild();
785 }
786 mMaxExpandHeight = expandedChild.getHeight();
787 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -0700788 if (headsUpChild == null) {
789 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700790 }
Selim Cinek1f3f5442015-04-10 17:54:46 -0700791 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +0200792 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100793 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +0200794 }
795 }
796
Jorim Jaggiae441282014-08-01 02:45:18 +0200797 public void setSensitive(boolean sensitive) {
798 mSensitive = sensitive;
799 }
800
801 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -0700802 mHideSensitiveForIntrinsicHeight = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +0200803 }
804
805 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
806 long duration) {
807 boolean oldShowingPublic = mShowingPublic;
808 mShowingPublic = mSensitive && hideSensitive;
809 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
810 return;
811 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500812
813 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +0200814 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500815
Jorim Jaggiae441282014-08-01 02:45:18 +0200816 if (!animated) {
817 mPublicLayout.animate().cancel();
818 mPrivateLayout.animate().cancel();
819 mPublicLayout.setAlpha(1f);
820 mPrivateLayout.setAlpha(1f);
821 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinek263398f2015-10-21 17:40:23 -0700822 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? View.VISIBLE
823 : View.INVISIBLE);
Jorim Jaggiae441282014-08-01 02:45:18 +0200824 } else {
825 animateShowingPublic(delay, duration);
826 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400827
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800828 mPrivateLayout.updateExpandButtons(isExpandable());
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400829 updateVetoButton();
Jorim Jaggiae441282014-08-01 02:45:18 +0200830 mShowingPublicInitialized = true;
831 }
832
833 private void animateShowingPublic(long delay, long duration) {
834 final View source = mShowingPublic ? mPrivateLayout : mPublicLayout;
835 View target = mShowingPublic ? mPublicLayout : mPrivateLayout;
836 source.setVisibility(View.VISIBLE);
837 target.setVisibility(View.VISIBLE);
838 target.setAlpha(0f);
839 source.animate().cancel();
840 target.animate().cancel();
841 source.animate()
842 .alpha(0f)
Jorim Jaggiae441282014-08-01 02:45:18 +0200843 .setStartDelay(delay)
844 .setDuration(duration)
845 .withEndAction(new Runnable() {
846 @Override
847 public void run() {
848 source.setVisibility(View.INVISIBLE);
849 }
850 });
851 target.animate()
852 .alpha(1f)
Jorim Jaggiae441282014-08-01 02:45:18 +0200853 .setStartDelay(delay)
854 .setDuration(duration);
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400855 }
856
857 private void updateVetoButton() {
858 // public versions cannot be dismissed
859 mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE);
Dan Sandlera5e0f412014-01-23 15:11:54 -0500860 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200861
Selim Cinekb5605e52015-02-20 18:21:41 +0100862 public void setChildrenExpanded(boolean expanded, boolean animate) {
863 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -0700864 if (mChildrenContainer != null) {
865 mChildrenContainer.setChildrenExpanded(expanded);
866 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100867 }
868
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800869 public void updateHeaderChildCount() {
870 if (mIsSummaryWithChildren) {
871 mNotificationHeader.setChildCount(
872 mChildrenContainer.getNotificationChildren().size());
Selim Cinekb5605e52015-02-20 18:21:41 +0100873 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100874 }
875
876 public static void applyTint(View v, int color) {
877 int alpha;
878 if (color != 0) {
879 alpha = COLORED_DIVIDER_ALPHA;
880 } else {
881 color = 0xff000000;
882 alpha = DEFAULT_DIVIDER_ALPHA;
883 }
884 if (v.getBackground() instanceof ColorDrawable) {
885 ColorDrawable background = (ColorDrawable) v.getBackground();
886 background.mutate();
887 background.setColor(color);
888 background.setAlpha(alpha);
889 }
890 }
891
Selim Cinek1685e632014-04-08 02:27:49 +0200892 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +0100893 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400894 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +0200895
Jorim Jaggibe565df2014-04-28 17:51:23 +0200896 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200897 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200898 NotificationContentView showingLayout = getShowingLayout();
899 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200900 }
901
902 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -0700903 protected View getContentView() {
904 return getShowingLayout();
905 }
906
907 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200908 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100909 super.setActualHeight(height, notifyListeners);
Selim Cinekeef84282015-10-30 16:28:00 -0700910 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +0100911 mPrivateLayout.setContentHeight(contentHeight);
912 mPublicLayout.setContentHeight(contentHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200913 if (mGuts != null) {
914 mGuts.setActualHeight(height);
915 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200916 invalidate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200917 }
918
919 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +0100920 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700921 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800922 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700923 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200924 NotificationContentView showingLayout = getShowingLayout();
925 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200926 }
927
928 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200929 public int getMinHeight() {
Selim Cinek816c8e42015-11-19 12:00:45 -0800930 NotificationContentView showingLayout = getShowingLayout();
931 return showingLayout.getMinHeight();
932 }
933
934 @Override
935 public int getMinExpandHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700936 if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800937 return mChildrenContainer.getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700938 }
Selim Cinek816c8e42015-11-19 12:00:45 -0800939 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200940 }
941
942 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700943 protected boolean shouldLimitViewHeight() {
944 return !mIsSummaryWithChildren;
945 }
946
947 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +0200948 public void setClipTopAmount(int clipTopAmount) {
949 super.setClipTopAmount(clipTopAmount);
950 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200951 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200952 if (mGuts != null) {
953 mGuts.setClipTopAmount(clipTopAmount);
954 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200955 }
956
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800957 private void recreateNotificationHeader() {
958 final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
959 getStatusBarNotification().getNotification());
960 final RemoteViews header = builder.makeNotificationHeader();
961 if (mNotificationHeader == null) {
962 mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
963 final View expandButton = mNotificationHeader.findViewById(
964 com.android.internal.R.id.expand_button);
965 expandButton.setVisibility(VISIBLE);
966 mNotificationHeader.setOnClickListener(mExpandClickListener);
967 addView(mNotificationHeader);
968 } else {
969 header.reapply(getContext(), mNotificationHeader);
970 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800971 updateChildrenHeaderAppearance();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800972 updateHeaderChildCount();
Selim Cinek343e6e22014-04-11 21:23:30 +0200973 }
Selim Cinek7d447722014-06-10 15:51:59 +0200974
Selim Cinekea4bef72015-12-02 15:51:10 -0800975 public void updateChildrenHeaderAppearance() {
976 if (mIsSummaryWithChildren) {
977 mHeaderUtil.updateChildrenHeaderAppearance();
978 }
979 }
980
Selim Cinek31094df2014-08-14 19:28:15 +0200981 public boolean isMaxExpandHeightInitialized() {
982 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +0200983 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200984
985 private NotificationContentView getShowingLayout() {
986 return mShowingPublic ? mPublicLayout : mPrivateLayout;
987 }
Chris Wren78403d72014-07-28 10:23:24 +0100988
Jorim Jaggi59ec3042015-06-05 15:18:43 -0700989 @Override
990 public void setShowingLegacyBackground(boolean showing) {
991 super.setShowingLegacyBackground(showing);
992 mPrivateLayout.setShowingLegacyBackground(showing);
993 mPublicLayout.setShowingLegacyBackground(showing);
994 }
995
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700996 @Override
997 protected void updateBackgroundTint() {
998 super.updateBackgroundTint();
999 updateNoBackgroundState();
1000 if (mIsSummaryWithChildren) {
1001 List<ExpandableNotificationRow> notificationChildren =
1002 mChildrenContainer.getNotificationChildren();
1003 for (int i = 0; i < notificationChildren.size(); i++) {
1004 ExpandableNotificationRow child = notificationChildren.get(i);
1005 child.updateNoBackgroundState();
1006 }
1007 }
1008 }
1009
1010 private void updateNoBackgroundState() {
1011 mShowNoBackground = isChildInGroup() && hasSameBgColor(mNotificationParent);
1012 updateBackground();
1013 }
1014
Chris Wren78403d72014-07-28 10:23:24 +01001015 public void setExpansionLogger(ExpansionLogger logger, String key) {
1016 mLogger = logger;
1017 mLoggingKey = key;
1018 }
1019
Chris Wren78403d72014-07-28 10:23:24 +01001020 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
1021 final boolean nowExpanded = isExpanded();
1022 if (wasExpanded != nowExpanded && mLogger != null) {
1023 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1024 }
1025 }
Selim Cinek570981d2015-12-01 11:37:01 -08001026
1027 public interface OnExpandClickListener {
1028 void onExpandClicked(View clickedView, boolean nowExpanded);
1029 }
Chris Wren51c75102013-07-16 20:49:17 -04001030}