blob: 84b2031491fde386be130cfba6a519efac95adf6 [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 Cinek6183d122016-01-14 18:48:41 -080028import 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 Cinek98713a42015-09-21 15:47:20 +020033import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020034import android.widget.ImageView;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080035import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010036
Dan Sandlera5e0f412014-01-23 15:11:54 -050037import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070038import com.android.systemui.classifier.FalsingManager;
Selim Cinek0ffbda62016-01-01 20:29:12 +010039import com.android.systemui.statusbar.notification.NotificationViewWrapper;
Selim Cinekb5605e52015-02-20 18:21:41 +010040import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinek31aada42015-12-18 17:51:15 -080041import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010042import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
43import com.android.systemui.statusbar.stack.StackScrollState;
44import com.android.systemui.statusbar.stack.StackStateAnimator;
45import com.android.systemui.statusbar.stack.StackViewState;
46
47import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050048
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020049public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010050
51 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
52 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Selim Cinekda42d652015-12-04 15:51:16 -080053 private final int mNotificationMinHeightLegacy;
Selim Cinek77019c72015-12-09 10:18:02 -080054 private final int mMaxHeadsUpHeightLegacy;
55 private final int mMaxHeadsUpHeight;
Selim Cinekda42d652015-12-04 15:51:16 -080056 private final int mNotificationMinHeight;
57 private final int mNotificationMaxHeight;
Chris Wren51c75102013-07-16 20:49:17 -040058
Selim Cinek1685e632014-04-08 02:27:49 +020059 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040060 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020061 /** Has the user actively changed the expansion state of this row */
62 private boolean mHasUserChangedExpansion;
63 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040064 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -080065
66 /**
67 * Has this notification been expanded while it was pinned
68 */
69 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +020070 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040071 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020072 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050073 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020074 private boolean mSensitive;
75 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -070076 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -040077
Selim Cinek1685e632014-04-08 02:27:49 +020078 /**
79 * Is this notification expanded by the system. The expansion state can be overridden by the
80 * user expansion.
81 */
82 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020083
84 /**
Selim Cinek83bc7832015-10-22 13:26:54 -070085 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020086 */
Selim Cinek83bc7832015-10-22 13:26:54 -070087 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020088
Jorim Jaggibe565df2014-04-28 17:51:23 +020089 private NotificationContentView mPublicLayout;
90 private NotificationContentView mPrivateLayout;
Selim Cinek1685e632014-04-08 02:27:49 +020091 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -070092 private int mHeadsUpHeight;
Selim Cinek863834b2014-05-20 04:20:25 +020093 private View mVetoButton;
Dan Sandler0d3e62f2014-07-14 17:13:50 -040094 private boolean mClearable;
Chris Wren78403d72014-07-28 10:23:24 +010095 private ExpansionLogger mLogger;
96 private String mLoggingKey;
Selim Cineka5e211b2014-08-11 17:35:48 +020097 private boolean mWasReset;
Selim Cinek8d490d42015-04-10 00:05:50 -070098 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -080099 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200100 private StatusBarNotification mStatusBarNotification;
Selim Cinek1a521f32014-11-03 17:39:29 +0100101 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200102 private boolean mLastChronometerRunning = true;
Selim Cinekeef84282015-10-30 16:28:00 -0700103 private NotificationHeaderView mNotificationHeader;
Selim Cinek9c7712d2015-12-08 19:19:48 -0800104 private NotificationViewWrapper mNotificationHeaderWrapper;
Selim Cinekb5605e52015-02-20 18:21:41 +0100105 private ViewStub mChildrenContainerStub;
106 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100107 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700108 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100109 private NotificationChildrenContainer mChildrenContainer;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100110 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100111 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700112 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700113 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800114 private HeadsUpManager mHeadsUpManager;
Selim Cinekea4bef72015-12-02 15:51:10 -0800115 private NotificationHeaderUtil mHeaderUtil = new NotificationHeaderUtil(this);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200116
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700117 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800118 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700119 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700120 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800121 private OnExpandClickListener mOnExpandClickListener;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800122 private OnClickListener mExpandClickListener = new OnClickListener() {
123 @Override
124 public void onClick(View v) {
Selim Cinek624c02db2015-12-14 21:00:02 -0800125 if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800126 mGroupManager.toggleGroupExpansion(mStatusBarNotification);
Selim Cinek31aada42015-12-18 17:51:15 -0800127 mOnExpandClickListener.onExpandClicked(mEntry,
Selim Cinek570981d2015-12-01 11:37:01 -0800128 mGroupManager.isGroupExpanded(mStatusBarNotification));
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800129 } else {
Selim Cinek31aada42015-12-18 17:51:15 -0800130 boolean nowExpanded;
131 if (isPinned()) {
132 nowExpanded = !mExpandedWhenPinned;
133 mExpandedWhenPinned = nowExpanded;
134 } else {
135 nowExpanded = !isExpanded();
136 setUserExpanded(nowExpanded);
137 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800138 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800139 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800140 }
141 }
142 };
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700143
Selim Cinek8d490d42015-04-10 00:05:50 -0700144 public NotificationContentView getPrivateLayout() {
145 return mPrivateLayout;
146 }
147
148 public NotificationContentView getPublicLayout() {
149 return mPublicLayout;
150 }
151
Selim Cinekcab4a602014-09-03 14:47:57 +0200152 public void setIconAnimationRunning(boolean running) {
153 setIconAnimationRunning(running, mPublicLayout);
154 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800155 setIconAnimationRunningForChild(running, mNotificationHeader);
156 if (mIsSummaryWithChildren) {
157 List<ExpandableNotificationRow> notificationChildren =
158 mChildrenContainer.getNotificationChildren();
159 for (int i = 0; i < notificationChildren.size(); i++) {
160 ExpandableNotificationRow child = notificationChildren.get(i);
161 child.setIconAnimationRunning(running);
162 }
163 }
164 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200165 }
166
167 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
168 if (layout != null) {
169 View contractedChild = layout.getContractedChild();
170 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700171 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200172 setIconAnimationRunningForChild(running, contractedChild);
173 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700174 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200175 }
176 }
177
178 private void setIconAnimationRunningForChild(boolean running, View child) {
179 if (child != null) {
180 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
181 setIconRunning(icon, running);
182 ImageView rightIcon = (ImageView) child.findViewById(
183 com.android.internal.R.id.right_icon);
184 setIconRunning(rightIcon, running);
185 }
186 }
187
188 private void setIconRunning(ImageView imageView, boolean running) {
189 if (imageView != null) {
190 Drawable drawable = imageView.getDrawable();
191 if (drawable instanceof AnimationDrawable) {
192 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
193 if (running) {
194 animationDrawable.start();
195 } else {
196 animationDrawable.stop();
197 }
198 } else if (drawable instanceof AnimatedVectorDrawable) {
199 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
200 if (running) {
201 animationDrawable.start();
202 } else {
203 animationDrawable.stop();
204 }
205 }
206 }
207 }
208
Selim Cinekda42d652015-12-04 15:51:16 -0800209 public void onNotificationUpdated(NotificationData.Entry entry) {
210 mEntry = entry;
211 mStatusBarNotification = entry.notification;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800212 mPrivateLayout.onNotificationUpdated(entry);
213 mPublicLayout.onNotificationUpdated(entry);
Selim Cinek757d8792016-01-28 16:21:08 -0800214 mShowingPublicInitialized = false;
215 updateClearability();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800216 if (mIsSummaryWithChildren) {
217 recreateNotificationHeader();
218 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800219 if (mIconAnimationRunning) {
220 setIconAnimationRunning(true);
221 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800222 if (mNotificationParent != null) {
223 mNotificationParent.updateChildrenHeaderAppearance();
224 }
Selim Cinek263398f2015-10-21 17:40:23 -0700225 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800226 // The public layouts expand button is always visible
227 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800228 updateLimits();
229 }
230
231 private void updateLimits() {
232 boolean customView = getPrivateLayout().getContractedChild().getId()
233 != com.android.internal.R.id.status_bar_latest_event_content;
234 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
235 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
236 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cinek77019c72015-12-09 10:18:02 -0800237 boolean headsUpCustom = getPrivateLayout().getHeadsUpChild() != null &&
238 getPrivateLayout().getHeadsUpChild().getId()
239 != com.android.internal.R.id.status_bar_latest_event_content;
240 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
241 : mMaxHeadsUpHeight;
Selim Cinekda42d652015-12-04 15:51:16 -0800242 mMaxViewHeight = mNotificationMaxHeight;
Selim Cinek860b6da2015-12-16 19:02:19 -0800243 mPrivateLayout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
244 mPublicLayout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200245 }
246
247 public StatusBarNotification getStatusBarNotification() {
248 return mStatusBarNotification;
249 }
250
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700251 public boolean isHeadsUp() {
252 return mIsHeadsUp;
253 }
254
Selim Cinek1a521f32014-11-03 17:39:29 +0100255 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700256 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100257 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700258 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekc80fdb12015-04-13 15:09:08 -0700259 if (intrinsicBefore != getIntrinsicHeight()) {
260 notifyHeightChanged(false /* needsAnimation */);
261 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100262 }
263
Selim Cinekb5605e52015-02-20 18:21:41 +0100264 public void setGroupManager(NotificationGroupManager groupManager) {
265 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700266 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100267 }
268
Adrian Roosb88b1a12015-12-09 18:51:05 -0800269 public void setRemoteInputController(RemoteInputController r) {
270 mPrivateLayout.setRemoteInputController(r);
271 }
272
Selim Cinekb5605e52015-02-20 18:21:41 +0100273 public void addChildNotification(ExpandableNotificationRow row) {
274 addChildNotification(row, -1);
275 }
276
277 /**
278 * Add a child notification to this view.
279 *
280 * @param row the row to add
281 * @param childIndex the index to add it at, if -1 it will be added at the end
282 */
283 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
284 if (mChildrenContainer == null) {
285 mChildrenContainerStub.inflate();
286 }
287 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700288 onChildrenCountChanged();
289 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100290 }
291
292 public void removeChildNotification(ExpandableNotificationRow row) {
293 if (mChildrenContainer != null) {
294 mChildrenContainer.removeNotification(row);
295 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800296 mHeaderUtil.restoreNotificationHeader(row);
Selim Cinek263398f2015-10-21 17:40:23 -0700297 onChildrenCountChanged();
298 row.setIsChildInGroup(false, null);
299 }
300
301 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700302 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700303 }
304
Selim Cinek388df6d2015-10-22 13:25:11 -0700305 public ExpandableNotificationRow getNotificationParent() {
306 return mNotificationParent;
307 }
308
Selim Cinek263398f2015-10-21 17:40:23 -0700309 /**
310 * @param isChildInGroup Is this notification now in a group
311 * @param parent the new parent notification
312 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700313 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
314 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
315 mNotificationParent = childInGroup ? parent : null;
316 mPrivateLayout.setIsChildInGroup(childInGroup);
317 updateNoBackgroundState();
Selim Cinek34d93b02015-10-22 12:30:38 -0700318 }
319
320 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800321 public boolean onTouchEvent(MotionEvent event) {
322 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
323 || !isChildInGroup() || isGroupExpanded()) {
324 return super.onTouchEvent(event);
325 } else {
326 return false;
327 }
328 }
329
330 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700331 protected boolean shouldHideBackground() {
332 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700333 }
334
335 @Override
336 public boolean isSummaryWithChildren() {
337 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100338 }
339
340 @Override
341 public boolean areChildrenExpanded() {
342 return mChildrenExpanded;
343 }
344
345 public List<ExpandableNotificationRow> getNotificationChildren() {
346 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
347 }
348
Selim Cinekeef84282015-10-30 16:28:00 -0700349 public int getNumberOfNotificationChildren() {
350 if (mChildrenContainer == null) {
351 return 0;
352 }
353 return mChildrenContainer.getNotificationChildren().size();
354 }
355
Selim Cinekb5605e52015-02-20 18:21:41 +0100356 /**
357 * Apply the order given in the list to the children.
358 *
359 * @param childOrder the new list order
360 * @return whether the list order has changed
361 */
362 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
363 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
364 }
365
366 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700367 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100368 StackViewState parentState = resultState.getViewStateForView(this);
369 mChildrenContainer.getState(resultState, parentState);
370 }
371 }
372
373 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700374 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100375 mChildrenContainer.applyState(state);
376 }
377 }
378
379 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700380 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100381 mChildrenContainer.prepareExpansionChanged(state);
382 }
383 }
384
385 public void startChildAnimation(StackScrollState finalState,
Selim Cinek99695592016-01-12 17:51:35 -0800386 StackStateAnimator stateAnimator, long delay, long duration) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700387 if (mIsSummaryWithChildren) {
Selim Cinek99695592016-01-12 17:51:35 -0800388 mChildrenContainer.startAnimationToState(finalState, stateAnimator, delay,
Selim Cinekb5605e52015-02-20 18:21:41 +0100389 duration);
390 }
391 }
392
393 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700394 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100395 return this;
396 } else {
397 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
398 return view == null ? this : view;
399 }
400 }
401
Selim Cinekab29aeb2015-02-20 18:18:32 +0100402 public NotificationGuts getGuts() {
403 return mGuts;
404 }
405
Selim Cinek684a4422015-04-15 16:18:39 -0700406 /**
407 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
408 * the notification will be rendered on top of the screen.
409 *
410 * @param pinned whether it is pinned
411 */
412 public void setPinned(boolean pinned) {
413 mIsPinned = pinned;
Selim Cinek31aada42015-12-18 17:51:15 -0800414 if (pinned) {
415 setIconAnimationRunning(true);
416 mExpandedWhenPinned = false;
417 } else if (mExpandedWhenPinned) {
418 setUserExpanded(true);
419 }
Selim Cinek98713a42015-09-21 15:47:20 +0200420 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700421 }
422
Selim Cinek684a4422015-04-15 16:18:39 -0700423 public boolean isPinned() {
424 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700425 }
426
Selim Cinek31aada42015-12-18 17:51:15 -0800427 /**
428 * @param atLeastMinHeight should the value returned be at least the minimum height.
429 * Used to avoid cyclic calls
430 * @return the height of the heads up notification when pinned
431 */
432 public int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800433 if (mIsSummaryWithChildren) {
434 return mChildrenContainer.getIntrinsicHeight();
435 }
Selim Cinek31aada42015-12-18 17:51:15 -0800436 if(mExpandedWhenPinned) {
437 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
438 } else if (atLeastMinHeight) {
439 return Math.max(getMinHeight(), mHeadsUpHeight);
440 } else {
441 return mHeadsUpHeight;
442 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700443 }
444
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700445 /**
446 * Mark whether this notification was just clicked, i.e. the user has just clicked this
447 * notification in this frame.
448 */
449 public void setJustClicked(boolean justClicked) {
450 mJustClicked = justClicked;
451 }
452
453 /**
454 * @return true if this notification has been clicked in this frame, false otherwise
455 */
456 public boolean wasJustClicked() {
457 return mJustClicked;
458 }
459
Selim Cinek98713a42015-09-21 15:47:20 +0200460 public void setChronometerRunning(boolean running) {
461 mLastChronometerRunning = running;
462 setChronometerRunning(running, mPrivateLayout);
463 setChronometerRunning(running, mPublicLayout);
464 if (mChildrenContainer != null) {
465 List<ExpandableNotificationRow> notificationChildren =
466 mChildrenContainer.getNotificationChildren();
467 for (int i = 0; i < notificationChildren.size(); i++) {
468 ExpandableNotificationRow child = notificationChildren.get(i);
469 child.setChronometerRunning(running);
470 }
471 }
472 }
473
474 private void setChronometerRunning(boolean running, NotificationContentView layout) {
475 if (layout != null) {
476 running = running || isPinned();
477 View contractedChild = layout.getContractedChild();
478 View expandedChild = layout.getExpandedChild();
479 View headsUpChild = layout.getHeadsUpChild();
480 setChronometerRunningForChild(running, contractedChild);
481 setChronometerRunningForChild(running, expandedChild);
482 setChronometerRunningForChild(running, headsUpChild);
483 }
484 }
485
486 private void setChronometerRunningForChild(boolean running, View child) {
487 if (child != null) {
488 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
489 if (chronometer instanceof Chronometer) {
490 ((Chronometer) chronometer).setStarted(running);
491 }
492 }
493 }
494
Selim Cinekea4bef72015-12-02 15:51:10 -0800495 public NotificationHeaderView getNotificationHeader() {
496 if (mNotificationHeader != null) {
497 return mNotificationHeader;
Selim Cinek8d6440d2015-10-22 13:00:05 -0700498 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800499 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700500 }
501
Selim Cinek570981d2015-12-01 11:37:01 -0800502 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
503 mOnExpandClickListener = onExpandClickListener;
504 }
505
Selim Cinek31aada42015-12-18 17:51:15 -0800506 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
507 mHeadsUpManager = headsUpManager;
508 }
509
Chris Wren78403d72014-07-28 10:23:24 +0100510 public interface ExpansionLogger {
511 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
512 }
Selim Cinek1685e632014-04-08 02:27:49 +0200513
Chris Wren51c75102013-07-16 20:49:17 -0400514 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
515 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700516 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinekda42d652015-12-04 15:51:16 -0800517 mNotificationMinHeightLegacy = getResources().getDimensionPixelSize(
518 R.dimen.notification_min_height_legacy);
519 mNotificationMinHeight = getResources().getDimensionPixelSize(
520 R.dimen.notification_min_height);
521 mNotificationMaxHeight = getResources().getDimensionPixelSize(
522 R.dimen.notification_max_height);
Selim Cinek77019c72015-12-09 10:18:02 -0800523 mMaxHeadsUpHeightLegacy = getResources().getDimensionPixelSize(
524 R.dimen.notification_max_heads_up_height_legacy);
525 mMaxHeadsUpHeight = getResources().getDimensionPixelSize(
526 R.dimen.notification_max_heads_up_height);
Chris Wren51c75102013-07-16 20:49:17 -0400527 }
528
Christoph Studera7fe6312014-06-27 19:32:44 +0200529 /**
530 * Resets this view so it can be re-used for an updated notification.
531 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200532 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200533 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200534 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +0100535 final boolean wasExpanded = isExpanded();
Selim Cinek379ff8f2015-02-20 17:03:16 +0100536 mMaxViewHeight = 0;
Christoph Studera7fe6312014-06-27 19:32:44 +0200537 mExpandable = false;
538 mHasUserChangedExpansion = false;
539 mUserLocked = false;
540 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200541 mSensitive = false;
542 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200543 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700544 mOnKeyguard = false;
Selim Cinek1a521f32014-11-03 17:39:29 +0100545 mPublicLayout.reset(mIsHeadsUp);
546 mPrivateLayout.reset(mIsHeadsUp);
Selim Cinek31094df2014-08-14 19:28:15 +0200547 resetHeight();
548 logExpansionEvent(false, wasExpanded);
549 }
550
551 public void resetHeight() {
Selim Cinek1a521f32014-11-03 17:39:29 +0100552 if (mIsHeadsUp) {
553 resetActualHeight();
554 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200555 mMaxExpandHeight = 0;
Selim Cinek8d490d42015-04-10 00:05:50 -0700556 mHeadsUpHeight = 0;
Selim Cineka5e211b2014-08-11 17:35:48 +0200557 mWasReset = true;
Selim Cinek31094df2014-08-14 19:28:15 +0200558 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200559 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200560 }
561
Jorim Jaggi251957d2014-04-09 04:24:09 +0200562 @Override
563 protected void onFinishInflate() {
564 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200565 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800566 mPublicLayout.setContainingNotification(this);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200567 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800568 mPrivateLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800569 mPrivateLayout.setContainingNotification(this);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800570 mPublicLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekab29aeb2015-02-20 18:18:32 +0100571 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
572 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200573 @Override
574 public void onInflate(ViewStub stub, View inflated) {
575 mGuts = (NotificationGuts) inflated;
576 mGuts.setClipTopAmount(getClipTopAmount());
577 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100578 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200579 }
580 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100581 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
582 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
583
584 @Override
585 public void onInflate(ViewStub stub, View inflated) {
586 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -0700587 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100588 }
589 });
Selim Cinek863834b2014-05-20 04:20:25 +0200590 mVetoButton = findViewById(R.id.veto);
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200591 }
592
Selim Cinekab29aeb2015-02-20 18:18:32 +0100593 public void inflateGuts() {
594 if (mGuts == null) {
595 mGutsStub.inflate();
596 }
597 }
598
Selim Cinekda42d652015-12-04 15:51:16 -0800599 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -0800600 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
601 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -0800602 if (mChildrenContainer != null) {
603 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
604 : INVISIBLE);
Selim Cinekb5605e52015-02-20 18:21:41 +0100605 }
Selim Cinekef5127e2015-12-21 16:55:58 -0800606 if (mNotificationHeader != null) {
607 mNotificationHeader.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
608 : INVISIBLE);
609 }
Selim Cinekda42d652015-12-04 15:51:16 -0800610 // The limits might have changed if the view suddenly became a group or vice versa
611 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +0100612 }
613
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200614 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800615 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
616 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200617 // Add a record for the entire layout since its content is somehow small.
618 // The event comes from a leaf view that is interacted with.
619 AccessibilityEvent record = AccessibilityEvent.obtain();
620 onInitializeAccessibilityEvent(record);
621 dispatchPopulateAccessibilityEvent(record);
622 event.appendRecord(record);
623 return true;
624 }
625 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200626 }
Chris Wren51c75102013-07-16 20:49:17 -0400627
John Spurlocke15452b2014-08-21 09:44:39 -0400628 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100629 public void setDark(boolean dark, boolean fade, long delay) {
630 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400631 final NotificationContentView showing = getShowingLayout();
632 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100633 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400634 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800635 if (mIsSummaryWithChildren) {
636 mChildrenContainer.setDark(dark, fade, delay);
637 mNotificationHeaderWrapper.setDark(dark, fade, delay);
638 }
John Spurlocke15452b2014-08-21 09:44:39 -0400639 }
640
Chris Wren51c75102013-07-16 20:49:17 -0400641 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -0700642 if (mIsSummaryWithChildren && !mShowingPublic) {
643 return !mChildrenExpanded;
644 }
Chris Wren51c75102013-07-16 20:49:17 -0400645 return mExpandable;
646 }
647
648 public void setExpandable(boolean expandable) {
649 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800650 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -0400651 }
652
Selim Cinek4ffd6362015-12-29 15:12:23 +0100653 @Override
654 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -0800655 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
656 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +0100657 }
658
Selim Cinek1685e632014-04-08 02:27:49 +0200659 /**
660 * @return whether the user has changed the expansion state
661 */
662 public boolean hasUserChangedExpansion() {
663 return mHasUserChangedExpansion;
664 }
665
Chris Wren51c75102013-07-16 20:49:17 -0400666 public boolean isUserExpanded() {
667 return mUserExpanded;
668 }
669
Selim Cinek1685e632014-04-08 02:27:49 +0200670 /**
671 * Set this notification to be expanded by the user
672 *
673 * @param userExpanded whether the user wants this notification to be expanded
674 */
Chris Wren51c75102013-07-16 20:49:17 -0400675 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -0700676 setUserExpanded(userExpanded, false /* allowChildExpansion */);
677 }
678
679 /**
680 * Set this notification to be expanded by the user
681 *
682 * @param userExpanded whether the user wants this notification to be expanded
683 * @param allowChildExpansion whether a call to this method allows expanding children
684 */
685 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700686 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -0700687 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
688 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
689 return;
690 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200691 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +0100692 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +0200693 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -0400694 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +0100695 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -0400696 }
697
Selim Cinekccd14fb2014-08-12 18:53:24 +0200698 public void resetUserExpansion() {
699 mHasUserChangedExpansion = false;
700 mUserExpanded = false;
701 }
702
Chris Wren51c75102013-07-16 20:49:17 -0400703 public boolean isUserLocked() {
704 return mUserLocked;
705 }
706
707 public void setUserLocked(boolean userLocked) {
708 mUserLocked = userLocked;
709 }
710
Selim Cinek1685e632014-04-08 02:27:49 +0200711 /**
712 * @return has the system set this notification to be expanded
713 */
714 public boolean isSystemExpanded() {
715 return mIsSystemExpanded;
716 }
717
718 /**
719 * Set this notification to be expanded by the system.
720 *
721 * @param expand whether the system wants this notification to be expanded.
722 */
723 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +0200724 if (expand != mIsSystemExpanded) {
725 final boolean wasExpanded = isExpanded();
726 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +0100727 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +0200728 logExpansionEvent(false, wasExpanded);
Selim Cinek83bc7832015-10-22 13:26:54 -0700729 if (mChildrenContainer != null) {
730 mChildrenContainer.updateGroupOverflow();
731 }
Selim Cinek31094df2014-08-14 19:28:15 +0200732 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200733 }
734
735 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700736 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200737 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700738 public void setOnKeyguard(boolean onKeyguard) {
739 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +0200740 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -0700741 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +0200742 logExpansionEvent(false, wasExpanded);
743 if (wasExpanded != isExpanded()) {
Selim Cinek2108fe02015-12-10 12:56:13 -0800744 if (mIsSummaryWithChildren) {
745 mChildrenContainer.updateGroupOverflow();
746 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100747 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +0200748 }
749 }
Selim Cinek1685e632014-04-08 02:27:49 +0200750 }
751
752 /**
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400753 * @return Can the underlying notification be cleared?
754 */
755 public boolean isClearable() {
Selim Cineka37774f2014-11-11 19:16:18 +0100756 return mStatusBarNotification != null && mStatusBarNotification.isClearable();
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400757 }
758
759 /**
Selim Cinek1685e632014-04-08 02:27:49 +0200760 * Apply an expansion state to the layout.
Selim Cinek1685e632014-04-08 02:27:49 +0200761 */
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200762 public void applyExpansionToLayout() {
763 boolean expand = isExpanded();
Chris Wren51c75102013-07-16 20:49:17 -0400764 if (expand && mExpandable) {
Selim Cinekeef84282015-10-30 16:28:00 -0700765 setActualHeight(mMaxExpandHeight);
Chris Wren51c75102013-07-16 20:49:17 -0400766 } else {
Selim Cinek860b6da2015-12-16 19:02:19 -0800767 setActualHeight(getMinHeight());
Chris Wren51c75102013-07-16 20:49:17 -0400768 }
Chris Wren51c75102013-07-16 20:49:17 -0400769 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500770
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200771 @Override
772 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +0200773 if (isUserLocked()) {
774 return getActualHeight();
775 }
Selim Cinekd84a5932015-12-15 11:45:36 -0800776 if (mGuts != null && mGuts.areGutsExposed()) {
777 return mGuts.getHeight();
778 } else if ((isChildInGroup() && !isGroupExpanded())) {
779 return mPrivateLayout.getMinHeight();
780 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
781 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700782 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800783 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek60122be2015-04-15 18:16:50 -0700784 } else if (mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -0800785 if (isPinned()) {
786 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
787 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -0800788 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -0700789 } else {
Selim Cinekd84a5932015-12-15 11:45:36 -0800790 return Math.max(getMinHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -0700791 }
Selim Cinek31aada42015-12-18 17:51:15 -0800792 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700793 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -0800794 } else {
795 return getMinHeight();
Selim Cinek1685e632014-04-08 02:27:49 +0200796 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100797 }
Selim Cinek1685e632014-04-08 02:27:49 +0200798
Selim Cinekeef84282015-10-30 16:28:00 -0700799 private boolean isGroupExpanded() {
800 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +0100801 }
802
Selim Cinekeef84282015-10-30 16:28:00 -0700803 /**
804 * @return whether this view has a header on the top of the content
805 */
806 private boolean hasNotificationHeader() {
807 return mIsSummaryWithChildren;
Selim Cinek1685e632014-04-08 02:27:49 +0200808 }
809
Selim Cinek263398f2015-10-21 17:40:23 -0700810 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -0800811 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Selim Cinek263398f2015-10-21 17:40:23 -0700812 && mGroupManager.hasGroupChildren(mStatusBarNotification);
Selim Cinek8fc93c92015-11-23 17:48:07 -0800813 if (mIsSummaryWithChildren) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800814 if (mChildrenContainer == null) {
815 mChildrenContainerStub.inflate();
816 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800817 if (mNotificationHeader == null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800818 recreateNotificationHeader();
819 }
Selim Cinek263398f2015-10-21 17:40:23 -0700820 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800821 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -0800822 updateChildrenHeaderAppearance();
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800823 updateHeaderChildCount();
Selim Cinekda42d652015-12-04 15:51:16 -0800824 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -0700825 }
826
Selim Cinek1685e632014-04-08 02:27:49 +0200827 /**
828 * Check whether the view state is currently expanded. This is given by the system in {@link
829 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
830 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
831 * view can differ from this state, if layout params are modified from outside.
832 *
833 * @return whether the view state is currently expanded.
834 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700835 public boolean isExpanded() {
836 return !mOnKeyguard
Selim Cinekb5605e52015-02-20 18:21:41 +0100837 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
838 || isUserExpanded());
839 }
840
841 private boolean isSystemChildExpanded() {
842 return mIsSystemChildExpanded;
843 }
844
845 public void setSystemChildExpanded(boolean expanded) {
846 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +0200847 }
848
849 @Override
850 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
851 super.onLayout(changed, left, top, right, bottom);
Selim Cineka5e211b2014-08-11 17:35:48 +0200852 boolean updateExpandHeight = mMaxExpandHeight == 0 && !mWasReset;
Selim Cinek8d490d42015-04-10 00:05:50 -0700853 updateMaxHeights();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200854 if (updateExpandHeight) {
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200855 applyExpansionToLayout();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200856 }
Selim Cineka5e211b2014-08-11 17:35:48 +0200857 mWasReset = false;
Selim Cinek1685e632014-04-08 02:27:49 +0200858 }
859
Selim Cinek8d490d42015-04-10 00:05:50 -0700860 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +0200861 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -0700862 View expandedChild = mPrivateLayout.getExpandedChild();
863 if (expandedChild == null) {
864 expandedChild = mPrivateLayout.getContractedChild();
865 }
866 mMaxExpandHeight = expandedChild.getHeight();
867 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -0700868 if (headsUpChild == null) {
869 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700870 }
Selim Cinek1f3f5442015-04-10 17:54:46 -0700871 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +0200872 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100873 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +0200874 }
875 }
876
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800877 @Override
878 public void notifyHeightChanged(boolean needsAnimation) {
879 super.notifyHeightChanged(needsAnimation);
880 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
881 }
882
Jorim Jaggiae441282014-08-01 02:45:18 +0200883 public void setSensitive(boolean sensitive) {
884 mSensitive = sensitive;
885 }
886
887 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -0700888 mHideSensitiveForIntrinsicHeight = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +0200889 }
890
891 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
892 long duration) {
893 boolean oldShowingPublic = mShowingPublic;
894 mShowingPublic = mSensitive && hideSensitive;
895 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
896 return;
897 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500898
899 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +0200900 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500901
Jorim Jaggiae441282014-08-01 02:45:18 +0200902 if (!animated) {
903 mPublicLayout.animate().cancel();
904 mPrivateLayout.animate().cancel();
905 mPublicLayout.setAlpha(1f);
906 mPrivateLayout.setAlpha(1f);
907 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -0800908 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +0200909 } else {
910 animateShowingPublic(delay, duration);
911 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400912
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800913 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinek757d8792016-01-28 16:21:08 -0800914 updateClearability();
Jorim Jaggiae441282014-08-01 02:45:18 +0200915 mShowingPublicInitialized = true;
916 }
917
918 private void animateShowingPublic(long delay, long duration) {
Selim Cinekd84a5932015-12-15 11:45:36 -0800919 View[] privateViews = mIsSummaryWithChildren ?
920 new View[] {mChildrenContainer, mNotificationHeader}
921 : new View[] {mPrivateLayout};
922 View[] publicViews = new View[] {mPublicLayout};
923 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
924 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
925 for (final View hiddenView : hiddenChildren) {
926 hiddenView.setVisibility(View.VISIBLE);
927 hiddenView.animate().cancel();
928 hiddenView.animate()
929 .alpha(0f)
930 .setStartDelay(delay)
931 .setDuration(duration)
932 .withEndAction(new Runnable() {
933 @Override
934 public void run() {
935 hiddenView.setVisibility(View.INVISIBLE);
936 }
937 });
938 }
939 for (View showView : shownChildren) {
940 showView.setVisibility(View.VISIBLE);
941 showView.setAlpha(0f);
942 showView.animate().cancel();
943 showView.animate()
944 .alpha(1f)
945 .setStartDelay(delay)
946 .setDuration(duration);
947 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400948 }
949
Selim Cinek3776fe02016-02-04 13:32:43 -0800950 public boolean mustStayOnScreen() {
951 return mIsHeadsUp;
952 }
953
Selim Cinek757d8792016-01-28 16:21:08 -0800954 private void updateClearability() {
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400955 // public versions cannot be dismissed
956 mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE);
Dan Sandlera5e0f412014-01-23 15:11:54 -0500957 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200958
Selim Cinekb5605e52015-02-20 18:21:41 +0100959 public void setChildrenExpanded(boolean expanded, boolean animate) {
960 mChildrenExpanded = expanded;
Selim Cinek7b836392015-12-04 20:02:59 -0800961 if (mNotificationHeader != null) {
962 mNotificationHeader.setExpanded(expanded);
963 }
Selim Cinek83bc7832015-10-22 13:26:54 -0700964 if (mChildrenContainer != null) {
965 mChildrenContainer.setChildrenExpanded(expanded);
966 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100967 }
968
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800969 public void updateHeaderChildCount() {
970 if (mIsSummaryWithChildren) {
971 mNotificationHeader.setChildCount(
972 mChildrenContainer.getNotificationChildren().size());
Selim Cinekb5605e52015-02-20 18:21:41 +0100973 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100974 }
975
976 public static void applyTint(View v, int color) {
977 int alpha;
978 if (color != 0) {
979 alpha = COLORED_DIVIDER_ALPHA;
980 } else {
981 color = 0xff000000;
982 alpha = DEFAULT_DIVIDER_ALPHA;
983 }
984 if (v.getBackground() instanceof ColorDrawable) {
985 ColorDrawable background = (ColorDrawable) v.getBackground();
986 background.mutate();
987 background.setColor(color);
988 background.setAlpha(alpha);
989 }
990 }
991
Selim Cinek1685e632014-04-08 02:27:49 +0200992 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +0100993 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400994 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +0200995
Jorim Jaggibe565df2014-04-28 17:51:23 +0200996 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200997 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200998 NotificationContentView showingLayout = getShowingLayout();
999 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001000 }
1001
1002 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001003 protected View getContentView() {
1004 return getShowingLayout();
1005 }
1006
1007 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001008 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001009 super.setActualHeight(height, notifyListeners);
Selim Cinekeef84282015-10-30 16:28:00 -07001010 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +01001011 mPrivateLayout.setContentHeight(contentHeight);
1012 mPublicLayout.setContentHeight(contentHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001013 if (mGuts != null) {
1014 mGuts.setActualHeight(height);
1015 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001016 invalidate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001017 }
1018
1019 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001020 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001021 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001022 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001023 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001024 NotificationContentView showingLayout = getShowingLayout();
1025 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001026 }
1027
1028 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001029 public int getMinHeight() {
Selim Cinek31aada42015-12-18 17:51:15 -08001030 if (mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
1031 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1032 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001033 return mChildrenContainer.getMinHeight();
Selim Cinek31aada42015-12-18 17:51:15 -08001034 } else if (mIsHeadsUp) {
1035 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001036 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001037 NotificationContentView showingLayout = getShowingLayout();
1038 return showingLayout.getMinHeight();
1039 }
1040
1041 @Override
1042 public int getMinExpandHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001043 if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001044 return mChildrenContainer.getMinExpandHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001045 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001046 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001047 }
1048
1049 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001050 public void setClipTopAmount(int clipTopAmount) {
1051 super.setClipTopAmount(clipTopAmount);
1052 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001053 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001054 if (mGuts != null) {
1055 mGuts.setClipTopAmount(clipTopAmount);
1056 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001057 }
1058
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001059 private void recreateNotificationHeader() {
1060 final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
1061 getStatusBarNotification().getNotification());
1062 final RemoteViews header = builder.makeNotificationHeader();
1063 if (mNotificationHeader == null) {
1064 mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
1065 final View expandButton = mNotificationHeader.findViewById(
1066 com.android.internal.R.id.expand_button);
1067 expandButton.setVisibility(VISIBLE);
1068 mNotificationHeader.setOnClickListener(mExpandClickListener);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001069 mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
1070 mNotificationHeader);
Selim Cinekb5a83612015-12-11 14:14:39 -08001071 addView(mNotificationHeader, indexOfChild(mChildrenContainer) + 1);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001072 } else {
1073 header.reapply(getContext(), mNotificationHeader);
Selim Cinek4ffd6362015-12-29 15:12:23 +01001074 mNotificationHeaderWrapper.notifyContentUpdated(mEntry.notification);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001075 }
Selim Cinek7b836392015-12-04 20:02:59 -08001076 updateHeaderExpandButton();
Selim Cinekea4bef72015-12-02 15:51:10 -08001077 updateChildrenHeaderAppearance();
Selim Cinek8fc93c92015-11-23 17:48:07 -08001078 updateHeaderChildCount();
Selim Cinek343e6e22014-04-11 21:23:30 +02001079 }
Selim Cinek7d447722014-06-10 15:51:59 +02001080
Selim Cinek7b836392015-12-04 20:02:59 -08001081 private void updateHeaderExpandButton() {
1082 if (mIsSummaryWithChildren) {
1083 mNotificationHeader.setIsGroupHeader(true /* isGroupHeader*/);
1084 }
1085 }
1086
Selim Cinekea4bef72015-12-02 15:51:10 -08001087 public void updateChildrenHeaderAppearance() {
1088 if (mIsSummaryWithChildren) {
1089 mHeaderUtil.updateChildrenHeaderAppearance();
1090 }
1091 }
1092
Selim Cinek31094df2014-08-14 19:28:15 +02001093 public boolean isMaxExpandHeightInitialized() {
1094 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001095 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001096
1097 private NotificationContentView getShowingLayout() {
1098 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1099 }
Chris Wren78403d72014-07-28 10:23:24 +01001100
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001101 @Override
1102 public void setShowingLegacyBackground(boolean showing) {
1103 super.setShowingLegacyBackground(showing);
1104 mPrivateLayout.setShowingLegacyBackground(showing);
1105 mPublicLayout.setShowingLegacyBackground(showing);
1106 }
1107
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001108 @Override
1109 protected void updateBackgroundTint() {
1110 super.updateBackgroundTint();
1111 updateNoBackgroundState();
1112 if (mIsSummaryWithChildren) {
1113 List<ExpandableNotificationRow> notificationChildren =
1114 mChildrenContainer.getNotificationChildren();
1115 for (int i = 0; i < notificationChildren.size(); i++) {
1116 ExpandableNotificationRow child = notificationChildren.get(i);
1117 child.updateNoBackgroundState();
1118 }
1119 }
1120 }
1121
1122 private void updateNoBackgroundState() {
1123 mShowNoBackground = isChildInGroup() && hasSameBgColor(mNotificationParent);
1124 updateBackground();
1125 }
1126
Chris Wren78403d72014-07-28 10:23:24 +01001127 public void setExpansionLogger(ExpansionLogger logger, String key) {
1128 mLogger = logger;
1129 mLoggingKey = key;
1130 }
1131
Selim Cinek6183d122016-01-14 18:48:41 -08001132 @Override
Selim Cinek61633a82016-01-25 15:54:10 -08001133 public boolean needsIncreasedPadding() {
1134 return mIsSummaryWithChildren && isGroupExpanded();
1135 }
1136
1137 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001138 protected boolean disallowSingleClick(MotionEvent event) {
1139 float x = event.getX();
1140 float y = event.getY();
1141 NotificationHeaderView header = getNotificationHeader();
1142 if (header != null) {
1143 return header.isInTouchRect(x, y);
1144 }
1145 return super.disallowSingleClick(event);
1146 }
1147
Chris Wren78403d72014-07-28 10:23:24 +01001148 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
1149 final boolean nowExpanded = isExpanded();
1150 if (wasExpanded != nowExpanded && mLogger != null) {
1151 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1152 }
1153 }
Selim Cinek570981d2015-12-01 11:37:01 -08001154
1155 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001156 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001157 }
Chris Wren51c75102013-07-16 20:49:17 -04001158}