blob: 0a28b8016ae6849fb728ca7fe6dbf8a26580ad01 [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
Mady Mellor4b80b102016-01-22 08:03:58 -080019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.AnimatorSet;
22import android.animation.ObjectAnimator;
23import android.animation.ValueAnimator;
24import android.animation.ValueAnimator.AnimatorUpdateListener;
Selim Cineka6c6bfb2015-10-29 16:27:08 -070025import android.app.Notification;
Chris Wren51c75102013-07-16 20:49:17 -040026import android.content.Context;
Selim Cinekcab4a602014-09-03 14:47:57 +020027import android.graphics.drawable.AnimatedVectorDrawable;
28import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010029import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020030import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080031import android.os.Build;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020032import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040033import android.util.AttributeSet;
Selim Cinek01af3342016-02-09 19:25:31 -080034import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080035import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080036import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050037import android.view.View;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020038import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020039import android.view.accessibility.AccessibilityEvent;
Selim Cinek98713a42015-09-21 15:47:20 +020040import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020041import android.widget.ImageView;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080042import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010043
Selim Cinek4bb59342016-04-08 19:29:35 -070044import com.android.internal.util.NotificationColorUtil;
Dan Sandlera5e0f412014-01-23 15:11:54 -050045import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070046import com.android.systemui.classifier.FalsingManager;
Selim Cinekc897bd32016-03-18 17:32:31 -070047import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinek0ffbda62016-01-01 20:29:12 +010048import com.android.systemui.statusbar.notification.NotificationViewWrapper;
Selim Cinekb5605e52015-02-20 18:21:41 +010049import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinek31aada42015-12-18 17:51:15 -080050import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010051import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
52import com.android.systemui.statusbar.stack.StackScrollState;
53import com.android.systemui.statusbar.stack.StackStateAnimator;
54import com.android.systemui.statusbar.stack.StackViewState;
55
Mady Mellor4b80b102016-01-22 08:03:58 -080056import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010057import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050058
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020059public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010060
61 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
62 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Selim Cinek01af3342016-02-09 19:25:31 -080063 private int mNotificationMinHeightLegacy;
64 private int mMaxHeadsUpHeightLegacy;
65 private int mMaxHeadsUpHeight;
66 private int mNotificationMinHeight;
67 private int mNotificationMaxHeight;
Chris Wren51c75102013-07-16 20:49:17 -040068
Selim Cinek1685e632014-04-08 02:27:49 +020069 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040070 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020071 /** Has the user actively changed the expansion state of this row */
72 private boolean mHasUserChangedExpansion;
73 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040074 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -080075
76 /**
77 * Has this notification been expanded while it was pinned
78 */
79 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +020080 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040081 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020082 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050083 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020084 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -080085 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +020086 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -070087 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -040088
Selim Cinek1685e632014-04-08 02:27:49 +020089 /**
90 * Is this notification expanded by the system. The expansion state can be overridden by the
91 * user expansion.
92 */
93 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020094
95 /**
Selim Cinek83bc7832015-10-22 13:26:54 -070096 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020097 */
Selim Cinek83bc7832015-10-22 13:26:54 -070098 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020099
Mady Mellor4b80b102016-01-22 08:03:58 -0800100 private AnimatorSet mTranslateAnim;
101 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200102 private NotificationContentView mPublicLayout;
103 private NotificationContentView mPrivateLayout;
Selim Cinek1685e632014-04-08 02:27:49 +0200104 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700105 private int mHeadsUpHeight;
Selim Cinek863834b2014-05-20 04:20:25 +0200106 private View mVetoButton;
Selim Cinek4bb59342016-04-08 19:29:35 -0700107 private int mNotificationColor;
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400108 private boolean mClearable;
Chris Wren78403d72014-07-28 10:23:24 +0100109 private ExpansionLogger mLogger;
110 private String mLoggingKey;
Mady Mellor4b80b102016-01-22 08:03:58 -0800111 private NotificationSettingsIconRow mSettingsIconRow;
Selim Cinek8d490d42015-04-10 00:05:50 -0700112 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800113 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200114 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700115 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100116 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200117 private boolean mLastChronometerRunning = true;
Selim Cinekeef84282015-10-30 16:28:00 -0700118 private NotificationHeaderView mNotificationHeader;
Selim Cinek9c7712d2015-12-08 19:19:48 -0800119 private NotificationViewWrapper mNotificationHeaderWrapper;
Selim Cinekb5605e52015-02-20 18:21:41 +0100120 private ViewStub mChildrenContainerStub;
121 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100122 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700123 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100124 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor4b80b102016-01-22 08:03:58 -0800125 private ViewStub mSettingsIconRowStub;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100126 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100127 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700128 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700129 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800130 private HeadsUpManager mHeadsUpManager;
Selim Cinekea4bef72015-12-02 15:51:10 -0800131 private NotificationHeaderUtil mHeaderUtil = new NotificationHeaderUtil(this);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200132
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700133 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800134 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700135 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700136 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800137 private OnExpandClickListener mOnExpandClickListener;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800138 private OnClickListener mExpandClickListener = new OnClickListener() {
139 @Override
140 public void onClick(View v) {
Selim Cinek624c02db2015-12-14 21:00:02 -0800141 if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800142 mGroupManager.toggleGroupExpansion(mStatusBarNotification);
Selim Cinek31aada42015-12-18 17:51:15 -0800143 mOnExpandClickListener.onExpandClicked(mEntry,
Selim Cinek570981d2015-12-01 11:37:01 -0800144 mGroupManager.isGroupExpanded(mStatusBarNotification));
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800145 } else {
Selim Cinek31aada42015-12-18 17:51:15 -0800146 boolean nowExpanded;
147 if (isPinned()) {
148 nowExpanded = !mExpandedWhenPinned;
149 mExpandedWhenPinned = nowExpanded;
150 } else {
151 nowExpanded = !isExpanded();
152 setUserExpanded(nowExpanded);
153 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800154 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800155 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800156 }
157 }
158 };
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700159
Selim Cinek8d490d42015-04-10 00:05:50 -0700160 public NotificationContentView getPrivateLayout() {
161 return mPrivateLayout;
162 }
163
164 public NotificationContentView getPublicLayout() {
165 return mPublicLayout;
166 }
167
Selim Cinekcab4a602014-09-03 14:47:57 +0200168 public void setIconAnimationRunning(boolean running) {
169 setIconAnimationRunning(running, mPublicLayout);
170 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800171 setIconAnimationRunningForChild(running, mNotificationHeader);
172 if (mIsSummaryWithChildren) {
173 List<ExpandableNotificationRow> notificationChildren =
174 mChildrenContainer.getNotificationChildren();
175 for (int i = 0; i < notificationChildren.size(); i++) {
176 ExpandableNotificationRow child = notificationChildren.get(i);
177 child.setIconAnimationRunning(running);
178 }
179 }
180 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200181 }
182
183 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
184 if (layout != null) {
185 View contractedChild = layout.getContractedChild();
186 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700187 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200188 setIconAnimationRunningForChild(running, contractedChild);
189 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700190 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200191 }
192 }
193
194 private void setIconAnimationRunningForChild(boolean running, View child) {
195 if (child != null) {
196 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
197 setIconRunning(icon, running);
198 ImageView rightIcon = (ImageView) child.findViewById(
199 com.android.internal.R.id.right_icon);
200 setIconRunning(rightIcon, running);
201 }
202 }
203
204 private void setIconRunning(ImageView imageView, boolean running) {
205 if (imageView != null) {
206 Drawable drawable = imageView.getDrawable();
207 if (drawable instanceof AnimationDrawable) {
208 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
209 if (running) {
210 animationDrawable.start();
211 } else {
212 animationDrawable.stop();
213 }
214 } else if (drawable instanceof AnimatedVectorDrawable) {
215 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
216 if (running) {
217 animationDrawable.start();
218 } else {
219 animationDrawable.stop();
220 }
221 }
222 }
223 }
224
Selim Cinekda42d652015-12-04 15:51:16 -0800225 public void onNotificationUpdated(NotificationData.Entry entry) {
226 mEntry = entry;
227 mStatusBarNotification = entry.notification;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800228 mPrivateLayout.onNotificationUpdated(entry);
229 mPublicLayout.onNotificationUpdated(entry);
Selim Cinek757d8792016-01-28 16:21:08 -0800230 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700231 updateNotificationColor();
Selim Cinek757d8792016-01-28 16:21:08 -0800232 updateClearability();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800233 if (mIsSummaryWithChildren) {
234 recreateNotificationHeader();
Selim Cinekc897bd32016-03-18 17:32:31 -0700235 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800236 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800237 if (mIconAnimationRunning) {
238 setIconAnimationRunning(true);
239 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800240 if (mNotificationParent != null) {
241 mNotificationParent.updateChildrenHeaderAppearance();
242 }
Selim Cinek263398f2015-10-21 17:40:23 -0700243 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800244 // The public layouts expand button is always visible
245 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800246 updateLimits();
247 }
248
249 private void updateLimits() {
Selim Cineka1744872016-03-11 15:36:06 -0800250 updateLimitsForView(mPrivateLayout);
251 updateLimitsForView(mPublicLayout);
252 }
253
254 private void updateLimitsForView(NotificationContentView layout) {
255 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800256 != com.android.internal.R.id.status_bar_latest_event_content;
257 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
258 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
259 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800260 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
261 layout.getHeadsUpChild().getId()
262 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek77019c72015-12-09 10:18:02 -0800263 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
264 : mMaxHeadsUpHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800265 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200266 }
267
268 public StatusBarNotification getStatusBarNotification() {
269 return mStatusBarNotification;
270 }
271
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700272 public boolean isHeadsUp() {
273 return mIsHeadsUp;
274 }
275
Selim Cinek1a521f32014-11-03 17:39:29 +0100276 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700277 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100278 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700279 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700280 if (mIsSummaryWithChildren) {
281 // The overflow might change since we allow more lines as HUN.
282 mChildrenContainer.updateGroupOverflow();
283 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700284 if (intrinsicBefore != getIntrinsicHeight()) {
285 notifyHeightChanged(false /* needsAnimation */);
286 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100287 }
288
Selim Cinekb5605e52015-02-20 18:21:41 +0100289 public void setGroupManager(NotificationGroupManager groupManager) {
290 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700291 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100292 }
293
Adrian Roosb88b1a12015-12-09 18:51:05 -0800294 public void setRemoteInputController(RemoteInputController r) {
295 mPrivateLayout.setRemoteInputController(r);
296 }
297
Mady Mellor3fd273e2016-03-15 21:08:14 -0700298 public void setAppName(String appName) {
299 mAppName = appName;
300 if (mSettingsIconRow != null) {
301 mSettingsIconRow.setAppName(mAppName);
302 }
303 }
304
Selim Cinekb5605e52015-02-20 18:21:41 +0100305 public void addChildNotification(ExpandableNotificationRow row) {
306 addChildNotification(row, -1);
307 }
308
309 /**
310 * Add a child notification to this view.
311 *
312 * @param row the row to add
313 * @param childIndex the index to add it at, if -1 it will be added at the end
314 */
315 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
316 if (mChildrenContainer == null) {
317 mChildrenContainerStub.inflate();
318 }
319 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700320 onChildrenCountChanged();
321 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100322 }
323
324 public void removeChildNotification(ExpandableNotificationRow row) {
325 if (mChildrenContainer != null) {
326 mChildrenContainer.removeNotification(row);
327 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800328 mHeaderUtil.restoreNotificationHeader(row);
Selim Cinek263398f2015-10-21 17:40:23 -0700329 onChildrenCountChanged();
330 row.setIsChildInGroup(false, null);
331 }
332
333 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700334 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700335 }
336
Selim Cinek388df6d2015-10-22 13:25:11 -0700337 public ExpandableNotificationRow getNotificationParent() {
338 return mNotificationParent;
339 }
340
Selim Cinek263398f2015-10-21 17:40:23 -0700341 /**
342 * @param isChildInGroup Is this notification now in a group
343 * @param parent the new parent notification
344 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700345 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
346 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
347 mNotificationParent = childInGroup ? parent : null;
348 mPrivateLayout.setIsChildInGroup(childInGroup);
349 updateNoBackgroundState();
Selim Cinek34d93b02015-10-22 12:30:38 -0700350 }
351
352 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800353 public boolean onTouchEvent(MotionEvent event) {
354 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
355 || !isChildInGroup() || isGroupExpanded()) {
356 return super.onTouchEvent(event);
357 } else {
358 return false;
359 }
360 }
361
362 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800363 protected boolean handleSlideBack() {
364 if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
365 animateTranslateNotification(0 /* targetLeft */);
366 return true;
367 }
368 return false;
369 }
370
371 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700372 protected boolean shouldHideBackground() {
373 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700374 }
375
376 @Override
377 public boolean isSummaryWithChildren() {
378 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100379 }
380
381 @Override
382 public boolean areChildrenExpanded() {
383 return mChildrenExpanded;
384 }
385
386 public List<ExpandableNotificationRow> getNotificationChildren() {
387 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
388 }
389
Selim Cinekeef84282015-10-30 16:28:00 -0700390 public int getNumberOfNotificationChildren() {
391 if (mChildrenContainer == null) {
392 return 0;
393 }
394 return mChildrenContainer.getNotificationChildren().size();
395 }
396
Selim Cinekb5605e52015-02-20 18:21:41 +0100397 /**
398 * Apply the order given in the list to the children.
399 *
400 * @param childOrder the new list order
401 * @return whether the list order has changed
402 */
403 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
404 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
405 }
406
407 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700408 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100409 StackViewState parentState = resultState.getViewStateForView(this);
410 mChildrenContainer.getState(resultState, parentState);
411 }
412 }
413
414 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700415 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100416 mChildrenContainer.applyState(state);
417 }
418 }
419
420 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700421 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100422 mChildrenContainer.prepareExpansionChanged(state);
423 }
424 }
425
426 public void startChildAnimation(StackScrollState finalState,
Selim Cinek99695592016-01-12 17:51:35 -0800427 StackStateAnimator stateAnimator, long delay, long duration) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700428 if (mIsSummaryWithChildren) {
Selim Cinek99695592016-01-12 17:51:35 -0800429 mChildrenContainer.startAnimationToState(finalState, stateAnimator, delay,
Selim Cinekb5605e52015-02-20 18:21:41 +0100430 duration);
431 }
432 }
433
434 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800435 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100436 return this;
437 } else {
438 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
439 return view == null ? this : view;
440 }
441 }
442
Selim Cinekab29aeb2015-02-20 18:18:32 +0100443 public NotificationGuts getGuts() {
444 return mGuts;
445 }
446
Selim Cinek684a4422015-04-15 16:18:39 -0700447 /**
448 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
449 * the notification will be rendered on top of the screen.
450 *
451 * @param pinned whether it is pinned
452 */
453 public void setPinned(boolean pinned) {
454 mIsPinned = pinned;
Selim Cinek31aada42015-12-18 17:51:15 -0800455 if (pinned) {
456 setIconAnimationRunning(true);
457 mExpandedWhenPinned = false;
458 } else if (mExpandedWhenPinned) {
459 setUserExpanded(true);
460 }
Selim Cinek98713a42015-09-21 15:47:20 +0200461 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700462 }
463
Selim Cinek684a4422015-04-15 16:18:39 -0700464 public boolean isPinned() {
465 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700466 }
467
Selim Cinek31aada42015-12-18 17:51:15 -0800468 /**
469 * @param atLeastMinHeight should the value returned be at least the minimum height.
470 * Used to avoid cyclic calls
471 * @return the height of the heads up notification when pinned
472 */
473 public int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800474 if (mIsSummaryWithChildren) {
475 return mChildrenContainer.getIntrinsicHeight();
476 }
Selim Cinek31aada42015-12-18 17:51:15 -0800477 if(mExpandedWhenPinned) {
478 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
479 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700480 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800481 } else {
482 return mHeadsUpHeight;
483 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700484 }
485
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700486 /**
487 * Mark whether this notification was just clicked, i.e. the user has just clicked this
488 * notification in this frame.
489 */
490 public void setJustClicked(boolean justClicked) {
491 mJustClicked = justClicked;
492 }
493
494 /**
495 * @return true if this notification has been clicked in this frame, false otherwise
496 */
497 public boolean wasJustClicked() {
498 return mJustClicked;
499 }
500
Selim Cinek98713a42015-09-21 15:47:20 +0200501 public void setChronometerRunning(boolean running) {
502 mLastChronometerRunning = running;
503 setChronometerRunning(running, mPrivateLayout);
504 setChronometerRunning(running, mPublicLayout);
505 if (mChildrenContainer != null) {
506 List<ExpandableNotificationRow> notificationChildren =
507 mChildrenContainer.getNotificationChildren();
508 for (int i = 0; i < notificationChildren.size(); i++) {
509 ExpandableNotificationRow child = notificationChildren.get(i);
510 child.setChronometerRunning(running);
511 }
512 }
513 }
514
515 private void setChronometerRunning(boolean running, NotificationContentView layout) {
516 if (layout != null) {
517 running = running || isPinned();
518 View contractedChild = layout.getContractedChild();
519 View expandedChild = layout.getExpandedChild();
520 View headsUpChild = layout.getHeadsUpChild();
521 setChronometerRunningForChild(running, contractedChild);
522 setChronometerRunningForChild(running, expandedChild);
523 setChronometerRunningForChild(running, headsUpChild);
524 }
525 }
526
527 private void setChronometerRunningForChild(boolean running, View child) {
528 if (child != null) {
529 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
530 if (chronometer instanceof Chronometer) {
531 ((Chronometer) chronometer).setStarted(running);
532 }
533 }
534 }
535
Selim Cinekea4bef72015-12-02 15:51:10 -0800536 public NotificationHeaderView getNotificationHeader() {
537 if (mNotificationHeader != null) {
538 return mNotificationHeader;
Selim Cinek8d6440d2015-10-22 13:00:05 -0700539 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800540 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700541 }
542
Selim Cinek34eda5e2016-02-18 17:10:43 -0800543 private NotificationHeaderView getVisibleNotificationHeader() {
544 if (mNotificationHeader != null) {
545 return mNotificationHeader;
546 }
547 return getShowingLayout().getVisibleNotificationHeader();
548 }
549
Selim Cinek570981d2015-12-01 11:37:01 -0800550 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
551 mOnExpandClickListener = onExpandClickListener;
552 }
553
Selim Cinek31aada42015-12-18 17:51:15 -0800554 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
555 mHeadsUpManager = headsUpManager;
556 }
557
Selim Cinek01af3342016-02-09 19:25:31 -0800558 public void reInflateViews() {
559 initDimens();
560 if (mIsSummaryWithChildren) {
561 removeView(mNotificationHeader);
562 mNotificationHeader = null;
563 recreateNotificationHeader();
564 if (mChildrenContainer != null) {
565 mChildrenContainer.reInflateViews();
566 }
567 }
568 if (mGuts != null) {
569 View oldGuts = mGuts;
570 int index = indexOfChild(oldGuts);
571 removeView(oldGuts);
572 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
573 R.layout.notification_guts, this, false);
574 mGuts.setVisibility(oldGuts.getVisibility());
575 addView(mGuts, index);
576 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800577 if (mSettingsIconRow != null) {
578 View oldSettings = mSettingsIconRow;
579 int settingsIndex = indexOfChild(oldSettings);
580 removeView(oldSettings);
581 mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
582 R.layout.notification_settings_icon_row, this, false);
583 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700584 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800585 mSettingsIconRow.setVisibility(oldSettings.getVisibility());
586 addView(mSettingsIconRow, settingsIndex);
587
588 }
Selim Cinekde33a4a2016-02-11 16:43:41 -0800589 mPrivateLayout.reInflateViews();
590 mPublicLayout.reInflateViews();
Selim Cinek01af3342016-02-09 19:25:31 -0800591 }
592
Selim Cinekc3179332016-03-04 14:44:56 -0800593 public void setContentBackground(int customBackgroundColor, boolean animate,
594 NotificationContentView notificationContentView) {
595 if (getShowingLayout() == notificationContentView) {
596 setTintColor(customBackgroundColor, animate);
597 }
598 }
599
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700600 public void closeRemoteInput() {
601 mPrivateLayout.closeRemoteInput();
602 mPublicLayout.closeRemoteInput();
603 }
604
Selim Cinekc897bd32016-03-18 17:32:31 -0700605 /**
606 * Set by how much the single line view should be indented.
607 */
608 public void setSingleLineWidthIndention(int indention) {
609 mPrivateLayout.setSingleLineWidthIndention(indention);
610 }
611
612 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700613 return mNotificationColor;
614 }
615
616 private void updateNotificationColor() {
617 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
618 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700619 }
620
621 public HybridNotificationView getSingleLineView() {
622 return mPrivateLayout.getSingleLineView();
623 }
624
Selim Cinekf07d0622016-03-21 19:52:52 -0700625 public boolean isOnKeyguard() {
626 return mOnKeyguard;
627 }
628
Selim Cinekc1e389d2016-04-07 11:02:57 -0700629 public void removeAllChildren() {
630 List<ExpandableNotificationRow> notificationChildren
631 = mChildrenContainer.getNotificationChildren();
632 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
633 for (int i = 0; i < clonedList.size(); i++) {
634 ExpandableNotificationRow row = clonedList.get(i);
635 mChildrenContainer.removeNotification(row);
636 mHeaderUtil.restoreNotificationHeader(row);
637 row.setIsChildInGroup(false, null);
638 }
639 onChildrenCountChanged();
640 }
641
Chris Wren78403d72014-07-28 10:23:24 +0100642 public interface ExpansionLogger {
643 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
644 }
Selim Cinek1685e632014-04-08 02:27:49 +0200645
Chris Wren51c75102013-07-16 20:49:17 -0400646 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
647 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700648 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -0800649 initDimens();
650 }
651
652 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800653 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
654 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
655 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
656 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -0800657 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800658 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
659 }
660
661 /**
662 * @param dimenId the dimen to look up
663 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
664 */
665 private int getFontScaledHeight(int dimenId) {
666 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
667 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
668 getResources().getDisplayMetrics().density);
669 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -0400670 }
671
Christoph Studera7fe6312014-06-27 19:32:44 +0200672 /**
673 * Resets this view so it can be re-used for an updated notification.
674 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200675 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200676 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200677 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +0100678 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +0200679 mExpandable = false;
680 mHasUserChangedExpansion = false;
681 mUserLocked = false;
682 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200683 mSensitive = false;
684 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200685 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700686 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -0800687 mPublicLayout.reset();
688 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +0200689 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -0800690 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +0200691 logExpansionEvent(false, wasExpanded);
692 }
693
694 public void resetHeight() {
Christoph Studera7fe6312014-06-27 19:32:44 +0200695 mMaxExpandHeight = 0;
Selim Cinek8d490d42015-04-10 00:05:50 -0700696 mHeadsUpHeight = 0;
Selim Cinek31094df2014-08-14 19:28:15 +0200697 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200698 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200699 }
700
Jorim Jaggi251957d2014-04-09 04:24:09 +0200701 @Override
702 protected void onFinishInflate() {
703 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200704 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800705 mPublicLayout.setContainingNotification(this);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200706 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800707 mPrivateLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800708 mPrivateLayout.setContainingNotification(this);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800709 mPublicLayout.setExpandClickListener(mExpandClickListener);
Mady Mellor4b80b102016-01-22 08:03:58 -0800710 mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
711 mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
712 @Override
713 public void onInflate(ViewStub stub, View inflated) {
714 mSettingsIconRow = (NotificationSettingsIconRow) inflated;
715 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700716 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800717 }
718 });
Selim Cinekab29aeb2015-02-20 18:18:32 +0100719 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
720 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200721 @Override
722 public void onInflate(ViewStub stub, View inflated) {
723 mGuts = (NotificationGuts) inflated;
724 mGuts.setClipTopAmount(getClipTopAmount());
725 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100726 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200727 }
728 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100729 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
730 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
731
732 @Override
733 public void onInflate(ViewStub stub, View inflated) {
734 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -0700735 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -0700736 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -0800737 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +0100738 }
739 });
Selim Cinek863834b2014-05-20 04:20:25 +0200740 mVetoButton = findViewById(R.id.veto);
Mady Mellor4b80b102016-01-22 08:03:58 -0800741
742 // Add the views that we translate to reveal the gear
743 mTranslateableViews = new ArrayList<View>();
744 for (int i = 0; i < getChildCount(); i++) {
745 mTranslateableViews.add(getChildAt(i));
746 }
747 // Remove views that don't translate
748 mTranslateableViews.remove(mVetoButton);
749 mTranslateableViews.remove(mSettingsIconRowStub);
750 mTranslateableViews.remove(mChildrenContainerStub);
751 mTranslateableViews.remove(mGutsStub);
752 }
753
Mady Mellor34958fa2016-02-23 09:52:17 -0800754 private void setTranslationForOutline(float translationX) {
Mady Mellor4b80b102016-01-22 08:03:58 -0800755 setOutlineRect(false, translationX, getTop(), getRight() + translationX, getBottom());
756 }
757
758 public void resetTranslation() {
759 if (mTranslateableViews != null) {
760 for (int i = 0; i < mTranslateableViews.size(); i++) {
761 mTranslateableViews.get(i).setTranslationX(0);
762 }
763 setTranslationForOutline(0);
764 }
765 if (mSettingsIconRow != null) {
766 mSettingsIconRow.resetState();
767 }
768 }
769
770 public void animateTranslateNotification(final float leftTarget) {
771 if (mTranslateAnim != null) {
772 mTranslateAnim.cancel();
773 }
Mady Mellor34958fa2016-02-23 09:52:17 -0800774 mTranslateAnim = (AnimatorSet) getTranslateViewAnimator(leftTarget,
775 null /* updateListener */);
776 if (mTranslateAnim != null) {
777 mTranslateAnim.start();
778 }
779 }
780
781 @Override
782 public void setTranslation(float translationX) {
783 if (areGutsExposed()) {
784 // Don't translate if guts are showing.
785 return;
786 }
787 // Translate the group of views
788 for (int i = 0; i < mTranslateableViews.size(); i++) {
789 if (mTranslateableViews.get(i) != null) {
790 mTranslateableViews.get(i).setTranslationX(translationX);
791 }
792 }
793 setTranslationForOutline(translationX);
794 if (mSettingsIconRow != null) {
795 mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
796 }
797 }
798
799 @Override
800 public float getTranslation() {
801 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
802 // All of the views in the list should have same translation, just use first one.
803 return mTranslateableViews.get(0).getTranslationX();
804 }
805 return 0;
806 }
807
808 public Animator getTranslateViewAnimator(final float leftTarget,
809 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -0700810 if (mTranslateAnim != null) {
811 mTranslateAnim.cancel();
812 }
Mady Mellor34958fa2016-02-23 09:52:17 -0800813 if (areGutsExposed()) {
814 // No translation if guts are exposed.
815 return null;
816 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800817 AnimatorSet set = new AnimatorSet();
818 if (mTranslateableViews != null) {
819 for (int i = 0; i < mTranslateableViews.size(); i++) {
820 final View animView = mTranslateableViews.get(i);
821 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(
822 animView, "translationX", leftTarget);
823 if (i == 0) {
824 translateAnim.addUpdateListener(new AnimatorUpdateListener() {
825 @Override
826 public void onAnimationUpdate(ValueAnimator animation) {
827 setTranslationForOutline((float) animation.getAnimatedValue());
Mady Mellor34958fa2016-02-23 09:52:17 -0800828 if (mSettingsIconRow != null) {
829 mSettingsIconRow.updateSettingsIcons(
830 (float) animation.getAnimatedValue(), getMeasuredWidth());
831 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800832 }
833 });
Mady Mellor34958fa2016-02-23 09:52:17 -0800834 if (listener != null) {
835 translateAnim.addUpdateListener(listener);
836 }
Mady Mellor723f1f92016-03-13 15:54:06 -0700837 translateAnim.addListener(new AnimatorListenerAdapter() {
838 boolean cancelled = false;
839
840 @Override
841 public void onAnimationCancel(Animator anim) {
842 cancelled = true;
Mady Mellor4b80b102016-01-22 08:03:58 -0800843 }
Mady Mellor723f1f92016-03-13 15:54:06 -0700844
845 @Override
846 public void onAnimationEnd(Animator anim) {
847 if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
848 mSettingsIconRow.resetState();
849 mTranslateAnim = null;
850 }
851 }
852 });
853 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800854 set.play(translateAnim);
855 }
856 }
Mady Mellor723f1f92016-03-13 15:54:06 -0700857 mTranslateAnim = set;
Mady Mellor34958fa2016-02-23 09:52:17 -0800858 return set;
Mady Mellor4b80b102016-01-22 08:03:58 -0800859 }
860
861 public float getSpaceForGear() {
862 if (mSettingsIconRow != null) {
863 return mSettingsIconRow.getSpaceForGear();
864 }
865 return 0;
866 }
867
868 public NotificationSettingsIconRow getSettingsRow() {
869 if (mSettingsIconRow == null) {
870 mSettingsIconRowStub.inflate();
871 }
872 return mSettingsIconRow;
873 }
874
Selim Cinekab29aeb2015-02-20 18:18:32 +0100875 public void inflateGuts() {
876 if (mGuts == null) {
877 mGutsStub.inflate();
878 }
879 }
880
Selim Cinekda42d652015-12-04 15:51:16 -0800881 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -0800882 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
883 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -0800884 if (mChildrenContainer != null) {
885 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
886 : INVISIBLE);
Selim Cinekb5605e52015-02-20 18:21:41 +0100887 }
Selim Cinekef5127e2015-12-21 16:55:58 -0800888 if (mNotificationHeader != null) {
889 mNotificationHeader.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
890 : INVISIBLE);
891 }
Selim Cinekda42d652015-12-04 15:51:16 -0800892 // The limits might have changed if the view suddenly became a group or vice versa
893 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +0100894 }
895
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200896 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800897 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
898 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200899 // Add a record for the entire layout since its content is somehow small.
900 // The event comes from a leaf view that is interacted with.
901 AccessibilityEvent record = AccessibilityEvent.obtain();
902 onInitializeAccessibilityEvent(record);
903 dispatchPopulateAccessibilityEvent(record);
904 event.appendRecord(record);
905 return true;
906 }
907 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200908 }
Chris Wren51c75102013-07-16 20:49:17 -0400909
John Spurlocke15452b2014-08-21 09:44:39 -0400910 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100911 public void setDark(boolean dark, boolean fade, long delay) {
912 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400913 final NotificationContentView showing = getShowingLayout();
914 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100915 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400916 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800917 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -0700918 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -0800919 mNotificationHeaderWrapper.setDark(dark, fade, delay);
920 }
John Spurlocke15452b2014-08-21 09:44:39 -0400921 }
922
Chris Wren51c75102013-07-16 20:49:17 -0400923 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -0700924 if (mIsSummaryWithChildren && !mShowingPublic) {
925 return !mChildrenExpanded;
926 }
Chris Wren51c75102013-07-16 20:49:17 -0400927 return mExpandable;
928 }
929
930 public void setExpandable(boolean expandable) {
931 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800932 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -0400933 }
934
Selim Cinek4ffd6362015-12-29 15:12:23 +0100935 @Override
936 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -0800937 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
938 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +0100939 }
940
Selim Cinek1685e632014-04-08 02:27:49 +0200941 /**
942 * @return whether the user has changed the expansion state
943 */
944 public boolean hasUserChangedExpansion() {
945 return mHasUserChangedExpansion;
946 }
947
Chris Wren51c75102013-07-16 20:49:17 -0400948 public boolean isUserExpanded() {
949 return mUserExpanded;
950 }
951
Selim Cinek1685e632014-04-08 02:27:49 +0200952 /**
953 * Set this notification to be expanded by the user
954 *
955 * @param userExpanded whether the user wants this notification to be expanded
956 */
Chris Wren51c75102013-07-16 20:49:17 -0400957 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -0700958 setUserExpanded(userExpanded, false /* allowChildExpansion */);
959 }
960
961 /**
962 * Set this notification to be expanded by the user
963 *
964 * @param userExpanded whether the user wants this notification to be expanded
965 * @param allowChildExpansion whether a call to this method allows expanding children
966 */
967 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700968 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -0700969 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
970 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
971 return;
972 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200973 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +0100974 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +0200975 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -0400976 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +0100977 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -0400978 }
979
Selim Cinekccd14fb2014-08-12 18:53:24 +0200980 public void resetUserExpansion() {
981 mHasUserChangedExpansion = false;
982 mUserExpanded = false;
983 }
984
Chris Wren51c75102013-07-16 20:49:17 -0400985 public boolean isUserLocked() {
986 return mUserLocked;
987 }
988
989 public void setUserLocked(boolean userLocked) {
990 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800991 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -0800992 if (mIsSummaryWithChildren) {
993 mChildrenContainer.setUserLocked(userLocked);
994 }
Chris Wren51c75102013-07-16 20:49:17 -0400995 }
996
Selim Cinek1685e632014-04-08 02:27:49 +0200997 /**
998 * @return has the system set this notification to be expanded
999 */
1000 public boolean isSystemExpanded() {
1001 return mIsSystemExpanded;
1002 }
1003
1004 /**
1005 * Set this notification to be expanded by the system.
1006 *
1007 * @param expand whether the system wants this notification to be expanded.
1008 */
1009 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001010 if (expand != mIsSystemExpanded) {
1011 final boolean wasExpanded = isExpanded();
1012 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001013 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001014 logExpansionEvent(false, wasExpanded);
Selim Cinekc897bd32016-03-18 17:32:31 -07001015 if (mChildrenContainer != null) {
1016 mChildrenContainer.updateGroupOverflow();
1017 }
Selim Cinek31094df2014-08-14 19:28:15 +02001018 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001019 }
1020
1021 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001022 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001023 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001024 public void setOnKeyguard(boolean onKeyguard) {
1025 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001026 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001027 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001028 logExpansionEvent(false, wasExpanded);
1029 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001030 if (mIsSummaryWithChildren) {
1031 mChildrenContainer.updateGroupOverflow();
1032 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001033 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001034 }
1035 }
Selim Cinek1685e632014-04-08 02:27:49 +02001036 }
1037
1038 /**
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001039 * @return Can the underlying notification be cleared?
1040 */
1041 public boolean isClearable() {
Selim Cineka37774f2014-11-11 19:16:18 +01001042 return mStatusBarNotification != null && mStatusBarNotification.isClearable();
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001043 }
1044
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001045 @Override
1046 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001047 if (isUserLocked()) {
1048 return getActualHeight();
1049 }
Selim Cinekd84a5932015-12-15 11:45:36 -08001050 if (mGuts != null && mGuts.areGutsExposed()) {
1051 return mGuts.getHeight();
1052 } else if ((isChildInGroup() && !isGroupExpanded())) {
1053 return mPrivateLayout.getMinHeight();
1054 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1055 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001056 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001057 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek60122be2015-04-15 18:16:50 -07001058 } else if (mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001059 if (isPinned()) {
1060 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1061 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001062 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001063 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001064 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001065 }
Selim Cinek31aada42015-12-18 17:51:15 -08001066 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001067 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001068 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001069 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001070 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001071 }
Selim Cinek1685e632014-04-08 02:27:49 +02001072
Selim Cinekeef84282015-10-30 16:28:00 -07001073 private boolean isGroupExpanded() {
1074 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001075 }
1076
Selim Cinekeef84282015-10-30 16:28:00 -07001077 /**
1078 * @return whether this view has a header on the top of the content
1079 */
1080 private boolean hasNotificationHeader() {
1081 return mIsSummaryWithChildren;
Selim Cinek1685e632014-04-08 02:27:49 +02001082 }
1083
Selim Cinek263398f2015-10-21 17:40:23 -07001084 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001085 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Selim Cinek2a739342016-03-17 10:28:55 -07001086 && mChildrenContainer != null && mChildrenContainer.getChildCount() > 0;
Selim Cinek8fc93c92015-11-23 17:48:07 -08001087 if (mIsSummaryWithChildren) {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001088 if (mNotificationHeader == null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001089 recreateNotificationHeader();
1090 }
Selim Cinek263398f2015-10-21 17:40:23 -07001091 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001092 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001093 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001094 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001095 }
1096
Selim Cinek1685e632014-04-08 02:27:49 +02001097 /**
1098 * Check whether the view state is currently expanded. This is given by the system in {@link
1099 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1100 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1101 * view can differ from this state, if layout params are modified from outside.
1102 *
1103 * @return whether the view state is currently expanded.
1104 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001105 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001106 return isExpanded(false /* allowOnKeyguard */);
1107 }
1108
1109 public boolean isExpanded(boolean allowOnKeyguard) {
1110 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001111 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1112 || isUserExpanded());
1113 }
1114
1115 private boolean isSystemChildExpanded() {
1116 return mIsSystemChildExpanded;
1117 }
1118
1119 public void setSystemChildExpanded(boolean expanded) {
1120 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001121 }
1122
1123 @Override
1124 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1125 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001126 updateMaxHeights();
Mady Mellora6edc872016-04-26 11:01:03 -07001127 if (mSettingsIconRow != null) {
1128 mSettingsIconRow.updateVerticalLocation();
1129 }
Selim Cinek1685e632014-04-08 02:27:49 +02001130 }
1131
Selim Cinek8d490d42015-04-10 00:05:50 -07001132 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001133 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001134 View expandedChild = mPrivateLayout.getExpandedChild();
1135 if (expandedChild == null) {
1136 expandedChild = mPrivateLayout.getContractedChild();
1137 }
1138 mMaxExpandHeight = expandedChild.getHeight();
1139 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001140 if (headsUpChild == null) {
1141 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001142 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001143 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001144 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001145 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001146 }
1147 }
1148
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001149 @Override
1150 public void notifyHeightChanged(boolean needsAnimation) {
1151 super.notifyHeightChanged(needsAnimation);
1152 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1153 }
1154
Selim Cinek3c76d502016-02-19 15:16:33 -08001155 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001156 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001157 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001158 }
1159
1160 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001161 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001162 if (mIsSummaryWithChildren) {
1163 List<ExpandableNotificationRow> notificationChildren =
1164 mChildrenContainer.getNotificationChildren();
1165 for (int i = 0; i < notificationChildren.size(); i++) {
1166 ExpandableNotificationRow child = notificationChildren.get(i);
1167 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1168 }
1169 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001170 }
1171
1172 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1173 long duration) {
1174 boolean oldShowingPublic = mShowingPublic;
1175 mShowingPublic = mSensitive && hideSensitive;
1176 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1177 return;
1178 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001179
1180 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001181 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001182
Jorim Jaggiae441282014-08-01 02:45:18 +02001183 if (!animated) {
1184 mPublicLayout.animate().cancel();
1185 mPrivateLayout.animate().cancel();
1186 mPublicLayout.setAlpha(1f);
1187 mPrivateLayout.setAlpha(1f);
1188 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001189 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001190 } else {
1191 animateShowingPublic(delay, duration);
1192 }
Selim Cinekc3179332016-03-04 14:44:56 -08001193 NotificationContentView showingLayout = getShowingLayout();
1194 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001195 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinek757d8792016-01-28 16:21:08 -08001196 updateClearability();
Jorim Jaggiae441282014-08-01 02:45:18 +02001197 mShowingPublicInitialized = true;
1198 }
1199
1200 private void animateShowingPublic(long delay, long duration) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001201 View[] privateViews = mIsSummaryWithChildren ?
1202 new View[] {mChildrenContainer, mNotificationHeader}
1203 : new View[] {mPrivateLayout};
1204 View[] publicViews = new View[] {mPublicLayout};
1205 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1206 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1207 for (final View hiddenView : hiddenChildren) {
1208 hiddenView.setVisibility(View.VISIBLE);
1209 hiddenView.animate().cancel();
1210 hiddenView.animate()
1211 .alpha(0f)
1212 .setStartDelay(delay)
1213 .setDuration(duration)
1214 .withEndAction(new Runnable() {
1215 @Override
1216 public void run() {
1217 hiddenView.setVisibility(View.INVISIBLE);
1218 }
1219 });
1220 }
1221 for (View showView : shownChildren) {
1222 showView.setVisibility(View.VISIBLE);
1223 showView.setAlpha(0f);
1224 showView.animate().cancel();
1225 showView.animate()
1226 .alpha(1f)
1227 .setStartDelay(delay)
1228 .setDuration(duration);
1229 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001230 }
1231
Selim Cinek3776fe02016-02-04 13:32:43 -08001232 public boolean mustStayOnScreen() {
1233 return mIsHeadsUp;
1234 }
1235
Selim Cinek757d8792016-01-28 16:21:08 -08001236 private void updateClearability() {
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001237 // public versions cannot be dismissed
Selim Cinek3c76d502016-02-19 15:16:33 -08001238 mVetoButton.setVisibility(isClearable() && (!mShowingPublic
1239 || !mSensitiveHiddenInGeneral) ? View.VISIBLE : View.GONE);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001240 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001241
Ricky Waicd35def2016-05-03 11:07:07 +01001242 public void makeActionsVisibile() {
1243 setUserExpanded(true, true);
1244 if (isChildInGroup()) {
1245 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1246 }
1247 notifyHeightChanged(false);
1248 }
1249
Selim Cinekb5605e52015-02-20 18:21:41 +01001250 public void setChildrenExpanded(boolean expanded, boolean animate) {
1251 mChildrenExpanded = expanded;
Selim Cinek7b836392015-12-04 20:02:59 -08001252 if (mNotificationHeader != null) {
1253 mNotificationHeader.setExpanded(expanded);
1254 }
Selim Cinek83bc7832015-10-22 13:26:54 -07001255 if (mChildrenContainer != null) {
1256 mChildrenContainer.setChildrenExpanded(expanded);
1257 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001258 }
1259
Selim Cinekb5605e52015-02-20 18:21:41 +01001260 public static void applyTint(View v, int color) {
1261 int alpha;
1262 if (color != 0) {
1263 alpha = COLORED_DIVIDER_ALPHA;
1264 } else {
1265 color = 0xff000000;
1266 alpha = DEFAULT_DIVIDER_ALPHA;
1267 }
1268 if (v.getBackground() instanceof ColorDrawable) {
1269 ColorDrawable background = (ColorDrawable) v.getBackground();
1270 background.mutate();
1271 background.setColor(color);
1272 background.setAlpha(alpha);
1273 }
1274 }
1275
Selim Cinek1685e632014-04-08 02:27:49 +02001276 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001277 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001278 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001279
Mady Mellor34958fa2016-02-23 09:52:17 -08001280 public boolean areGutsExposed() {
1281 return (mGuts != null && mGuts.areGutsExposed());
1282 }
1283
Jorim Jaggibe565df2014-04-28 17:51:23 +02001284 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001285 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001286 NotificationContentView showingLayout = getShowingLayout();
1287 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001288 }
1289
1290 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001291 protected View getContentView() {
1292 return getShowingLayout();
1293 }
1294
1295 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001296 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001297 super.setActualHeight(height, notifyListeners);
Mady Mellorb53bc272016-02-11 18:28:23 -08001298 if (mGuts != null && mGuts.areGutsExposed()) {
1299 mGuts.setActualHeight(height);
1300 return;
1301 }
Selim Cinekeef84282015-10-30 16:28:00 -07001302 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +01001303 mPrivateLayout.setContentHeight(contentHeight);
1304 mPublicLayout.setContentHeight(contentHeight);
Selim Cinek42357e02016-02-24 18:48:01 -08001305 if (mIsSummaryWithChildren) {
1306 mChildrenContainer.setActualHeight(height);
1307 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001308 if (mGuts != null) {
1309 mGuts.setActualHeight(height);
1310 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001311 }
1312
1313 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001314 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001315 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001316 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001317 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001318 NotificationContentView showingLayout = getShowingLayout();
1319 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001320 }
1321
1322 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001323 public int getMinHeight() {
Selim Cinek31aada42015-12-18 17:51:15 -08001324 if (mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
1325 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1326 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001327 return mChildrenContainer.getMinHeight();
Selim Cinek31aada42015-12-18 17:51:15 -08001328 } else if (mIsHeadsUp) {
1329 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001330 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001331 NotificationContentView showingLayout = getShowingLayout();
1332 return showingLayout.getMinHeight();
1333 }
1334
1335 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001336 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001337 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001338 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001339 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001340 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001341 }
1342
1343 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001344 public void setClipTopAmount(int clipTopAmount) {
1345 super.setClipTopAmount(clipTopAmount);
1346 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001347 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001348 if (mGuts != null) {
1349 mGuts.setClipTopAmount(clipTopAmount);
1350 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001351 }
1352
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001353 private void recreateNotificationHeader() {
1354 final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
1355 getStatusBarNotification().getNotification());
1356 final RemoteViews header = builder.makeNotificationHeader();
1357 if (mNotificationHeader == null) {
1358 mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
1359 final View expandButton = mNotificationHeader.findViewById(
1360 com.android.internal.R.id.expand_button);
1361 expandButton.setVisibility(VISIBLE);
1362 mNotificationHeader.setOnClickListener(mExpandClickListener);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001363 mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
Selim Cinek7d1c63e2016-04-21 15:26:10 -07001364 mNotificationHeader, this);
Selim Cinekb5a83612015-12-11 14:14:39 -08001365 addView(mNotificationHeader, indexOfChild(mChildrenContainer) + 1);
Mady Mellor4b80b102016-01-22 08:03:58 -08001366 mTranslateableViews.add(mNotificationHeader);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001367 } else {
1368 header.reapply(getContext(), mNotificationHeader);
Selim Cinek4ffd6362015-12-29 15:12:23 +01001369 mNotificationHeaderWrapper.notifyContentUpdated(mEntry.notification);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001370 }
Selim Cinekea4bef72015-12-02 15:51:10 -08001371 updateChildrenHeaderAppearance();
Selim Cinek343e6e22014-04-11 21:23:30 +02001372 }
Selim Cinek7d447722014-06-10 15:51:59 +02001373
Selim Cinekea4bef72015-12-02 15:51:10 -08001374 public void updateChildrenHeaderAppearance() {
1375 if (mIsSummaryWithChildren) {
1376 mHeaderUtil.updateChildrenHeaderAppearance();
1377 }
1378 }
1379
Selim Cinek31094df2014-08-14 19:28:15 +02001380 public boolean isMaxExpandHeightInitialized() {
1381 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001382 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001383
Selim Cinek42357e02016-02-24 18:48:01 -08001384 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001385 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1386 }
Chris Wren78403d72014-07-28 10:23:24 +01001387
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001388 @Override
1389 public void setShowingLegacyBackground(boolean showing) {
1390 super.setShowingLegacyBackground(showing);
1391 mPrivateLayout.setShowingLegacyBackground(showing);
1392 mPublicLayout.setShowingLegacyBackground(showing);
1393 }
1394
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001395 @Override
1396 protected void updateBackgroundTint() {
1397 super.updateBackgroundTint();
1398 updateNoBackgroundState();
1399 if (mIsSummaryWithChildren) {
1400 List<ExpandableNotificationRow> notificationChildren =
1401 mChildrenContainer.getNotificationChildren();
1402 for (int i = 0; i < notificationChildren.size(); i++) {
1403 ExpandableNotificationRow child = notificationChildren.get(i);
1404 child.updateNoBackgroundState();
1405 }
1406 }
1407 }
1408
1409 private void updateNoBackgroundState() {
1410 mShowNoBackground = isChildInGroup() && hasSameBgColor(mNotificationParent);
1411 updateBackground();
1412 }
1413
Chris Wren78403d72014-07-28 10:23:24 +01001414 public void setExpansionLogger(ExpansionLogger logger, String key) {
1415 mLogger = logger;
1416 mLoggingKey = key;
1417 }
1418
Selim Cinek6183d122016-01-14 18:48:41 -08001419 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001420 public float getIncreasedPaddingAmount() {
1421 if (mIsSummaryWithChildren) {
1422 if (isGroupExpanded()) {
1423 return 1.0f;
1424 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001425 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001426 }
1427 }
1428 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001429 }
1430
1431 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001432 protected boolean disallowSingleClick(MotionEvent event) {
1433 float x = event.getX();
1434 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001435 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001436 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001437 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001438 }
1439 return super.disallowSingleClick(event);
1440 }
1441
Chris Wren78403d72014-07-28 10:23:24 +01001442 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
1443 final boolean nowExpanded = isExpanded();
1444 if (wasExpanded != nowExpanded && mLogger != null) {
1445 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1446 }
1447 }
Selim Cinek570981d2015-12-01 11:37:01 -08001448
1449 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001450 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001451 }
Chris Wren51c75102013-07-16 20:49:17 -04001452}