blob: 93c48f86cec94d676d56c9dd6fe7516266ce2286 [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;
Mady Mellor4b80b102016-01-22 08:03:58 -080021import android.animation.ObjectAnimator;
Mady Mellor4b80b102016-01-22 08:03:58 -080022import android.animation.ValueAnimator.AnimatorUpdateListener;
Selim Cinekddf1b392016-05-27 16:33:10 -070023import android.annotation.Nullable;
Chris Wren51c75102013-07-16 20:49:17 -040024import android.content.Context;
Selim Cinekcab4a602014-09-03 14:47:57 +020025import android.graphics.drawable.AnimatedVectorDrawable;
26import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010027import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020028import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080029import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070030import android.os.Bundle;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020031import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040032import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070033import android.util.FloatProperty;
34import android.util.Property;
Selim Cinek01af3342016-02-09 19:25:31 -080035import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080036import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080037import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050038import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080039import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020040import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020041import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070042import android.view.accessibility.AccessibilityNodeInfo;
Selim Cinek98713a42015-09-21 15:47:20 +020043import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020044import android.widget.ImageView;
Selim Cinekb5605e52015-02-20 18:21:41 +010045
Chris Wren698b1702016-05-23 11:16:32 -040046import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010047import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070048import com.android.internal.util.NotificationColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080049import com.android.internal.widget.CachingIconView;
Selim Cinek0242fbb2016-10-19 13:38:32 -070050import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050051import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070052import com.android.systemui.classifier.FalsingManager;
Selim Cinekc897bd32016-03-18 17:32:31 -070053import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cineka7d4f822016-12-06 14:34:47 -080054import com.android.systemui.statusbar.notification.VisualStabilityManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010055import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinek31aada42015-12-18 17:51:15 -080056import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek0cfbef42016-11-09 19:06:36 -080057import com.android.systemui.statusbar.stack.AnimationProperties;
58import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010059import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070060import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010061import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010062
Mady Mellor4b80b102016-01-22 08:03:58 -080063import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010064import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050065
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020066public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010067
68 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
69 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Selim Cinek0242fbb2016-10-19 13:38:32 -070070 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -080071 private int mIconTransformContentShiftNoIcon;
Selim Cinek01af3342016-02-09 19:25:31 -080072 private int mNotificationMinHeightLegacy;
73 private int mMaxHeadsUpHeightLegacy;
74 private int mMaxHeadsUpHeight;
75 private int mNotificationMinHeight;
76 private int mNotificationMaxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -080077 private int mNotificationAmbientHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -070078 private int mIncreasedPaddingBetweenElements;
Chris Wren51c75102013-07-16 20:49:17 -040079
Selim Cinek1685e632014-04-08 02:27:49 +020080 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040081 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020082 /** Has the user actively changed the expansion state of this row */
83 private boolean mHasUserChangedExpansion;
84 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040085 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -080086
87 /**
88 * Has this notification been expanded while it was pinned
89 */
90 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +020091 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040092 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020093 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050094 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020095 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -080096 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +020097 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -070098 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -040099
Selim Cinek1685e632014-04-08 02:27:49 +0200100 /**
101 * Is this notification expanded by the system. The expansion state can be overridden by the
102 * user expansion.
103 */
104 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200105
106 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700107 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200108 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700109 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200110
Mady Mellorb0a82462016-04-30 17:31:02 -0700111 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800112 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200113 private NotificationContentView mPublicLayout;
114 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800115 private NotificationContentView[] mLayouts;
Selim Cinek1685e632014-04-08 02:27:49 +0200116 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700117 private int mHeadsUpHeight;
Selim Cinek4bb59342016-04-08 19:29:35 -0700118 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100119 private ExpansionLogger mLogger;
120 private String mLoggingKey;
Mady Mellor4b80b102016-01-22 08:03:58 -0800121 private NotificationSettingsIconRow mSettingsIconRow;
Selim Cinek8d490d42015-04-10 00:05:50 -0700122 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800123 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200124 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700125 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100126 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200127 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100128 private ViewStub mChildrenContainerStub;
129 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100130 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700131 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100132 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor4b80b102016-01-22 08:03:58 -0800133 private ViewStub mSettingsIconRowStub;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100134 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100135 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700136 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700137 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800138 private HeadsUpManager mHeadsUpManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200139
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700140 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800141 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700142 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700143 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800144 private OnExpandClickListener mOnExpandClickListener;
Mady Mellorb0a82462016-04-30 17:31:02 -0700145 private boolean mGroupExpansionChanging;
146
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800147 private OnClickListener mExpandClickListener = new OnClickListener() {
148 @Override
149 public void onClick(View v) {
Selim Cinek624c02db2015-12-14 21:00:02 -0800150 if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700151 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400152 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
153 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
154 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400155 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
156 nowExpanded);
157 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800158 } else {
Selim Cineke9bad242016-06-15 11:46:37 -0700159 if (v.isAccessibilityFocused()) {
160 mPrivateLayout.setFocusOnVisibilityChange();
161 }
Selim Cinek31aada42015-12-18 17:51:15 -0800162 boolean nowExpanded;
163 if (isPinned()) {
164 nowExpanded = !mExpandedWhenPinned;
165 mExpandedWhenPinned = nowExpanded;
166 } else {
167 nowExpanded = !isExpanded();
168 setUserExpanded(nowExpanded);
169 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800170 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800171 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400172 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
173 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800174 }
175 }
176 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700177 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700178 private boolean mDismissed;
179 private boolean mKeepInParent;
180 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700181 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
182 new FloatProperty<ExpandableNotificationRow>("translate") {
183 @Override
184 public void setValue(ExpandableNotificationRow object, float value) {
185 object.setTranslation(value);
186 }
187
188 @Override
189 public Float get(ExpandableNotificationRow object) {
190 return object.getTranslation();
191 }
192 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700193 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700194 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700195 private View mChildAfterViewWhenDismissed;
196 private View mGroupParentWhenDismissed;
197 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800198 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700199 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700200 private boolean mAboveShelf;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800201 private boolean mShowAmbient;
Selim Cinek875a3a12016-11-18 17:52:16 -0800202 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800203 private Runnable mOnDismissRunnable;
Mady Mellorb0a82462016-04-30 17:31:02 -0700204
205 public boolean isGroupExpansionChanging() {
206 if (isChildInGroup()) {
207 return mNotificationParent.isGroupExpansionChanging();
208 }
209 return mGroupExpansionChanging;
210 }
211
212 public void setGroupExpansionChanging(boolean changing) {
213 mGroupExpansionChanging = changing;
214 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700215
Adrian Roos599be342016-06-13 14:54:39 -0700216 @Override
217 public void setActualHeightAnimating(boolean animating) {
218 if (mPrivateLayout != null) {
219 mPrivateLayout.setContentHeightAnimating(animating);
220 }
221 }
222
Selim Cinek8d490d42015-04-10 00:05:50 -0700223 public NotificationContentView getPrivateLayout() {
224 return mPrivateLayout;
225 }
226
227 public NotificationContentView getPublicLayout() {
228 return mPublicLayout;
229 }
230
Selim Cinekcab4a602014-09-03 14:47:57 +0200231 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800232 for (NotificationContentView l : mLayouts) {
233 setIconAnimationRunning(running, l);
234 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800235 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700236 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800237 List<ExpandableNotificationRow> notificationChildren =
238 mChildrenContainer.getNotificationChildren();
239 for (int i = 0; i < notificationChildren.size(); i++) {
240 ExpandableNotificationRow child = notificationChildren.get(i);
241 child.setIconAnimationRunning(running);
242 }
243 }
244 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200245 }
246
247 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
248 if (layout != null) {
249 View contractedChild = layout.getContractedChild();
250 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700251 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200252 setIconAnimationRunningForChild(running, contractedChild);
253 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700254 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200255 }
256 }
257
258 private void setIconAnimationRunningForChild(boolean running, View child) {
259 if (child != null) {
260 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
261 setIconRunning(icon, running);
262 ImageView rightIcon = (ImageView) child.findViewById(
263 com.android.internal.R.id.right_icon);
264 setIconRunning(rightIcon, running);
265 }
266 }
267
268 private void setIconRunning(ImageView imageView, boolean running) {
269 if (imageView != null) {
270 Drawable drawable = imageView.getDrawable();
271 if (drawable instanceof AnimationDrawable) {
272 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
273 if (running) {
274 animationDrawable.start();
275 } else {
276 animationDrawable.stop();
277 }
278 } else if (drawable instanceof AnimatedVectorDrawable) {
279 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
280 if (running) {
281 animationDrawable.start();
282 } else {
283 animationDrawable.stop();
284 }
285 }
286 }
287 }
288
Selim Cinekda42d652015-12-04 15:51:16 -0800289 public void onNotificationUpdated(NotificationData.Entry entry) {
290 mEntry = entry;
291 mStatusBarNotification = entry.notification;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800292 for (NotificationContentView l : mLayouts) {
293 l.onNotificationUpdated(entry);
294 }
Selim Cinek757d8792016-01-28 16:21:08 -0800295 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700296 updateNotificationColor();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800297 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700298 mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
Selim Cinekc897bd32016-03-18 17:32:31 -0700299 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800300 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800301 if (mIconAnimationRunning) {
302 setIconAnimationRunning(true);
303 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800304 if (mNotificationParent != null) {
305 mNotificationParent.updateChildrenHeaderAppearance();
306 }
Selim Cinek263398f2015-10-21 17:40:23 -0700307 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800308 // The public layouts expand button is always visible
309 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800310 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700311 updateIconVisibilities();
Selim Cinekda42d652015-12-04 15:51:16 -0800312 }
313
314 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800315 for (NotificationContentView l : mLayouts) {
316 updateLimitsForView(l);
317 }
Selim Cineka1744872016-03-11 15:36:06 -0800318 }
319
320 private void updateLimitsForView(NotificationContentView layout) {
321 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800322 != com.android.internal.R.id.status_bar_latest_event_content;
323 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
324 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
325 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800326 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
327 layout.getHeadsUpChild().getId()
328 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek77019c72015-12-09 10:18:02 -0800329 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
330 : mMaxHeadsUpHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800331 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
332 mNotificationAmbientHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200333 }
334
335 public StatusBarNotification getStatusBarNotification() {
336 return mStatusBarNotification;
337 }
338
Selim Cinek281c2022016-10-13 19:14:43 -0700339 public NotificationData.Entry getEntry() {
340 return mEntry;
341 }
342
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700343 public boolean isHeadsUp() {
344 return mIsHeadsUp;
345 }
346
Selim Cinek1a521f32014-11-03 17:39:29 +0100347 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700348 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100349 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700350 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700351 if (mIsSummaryWithChildren) {
352 // The overflow might change since we allow more lines as HUN.
353 mChildrenContainer.updateGroupOverflow();
354 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700355 if (intrinsicBefore != getIntrinsicHeight()) {
356 notifyHeightChanged(false /* needsAnimation */);
357 }
Selim Cinekd127d792016-11-01 19:11:41 -0700358 if (isHeadsUp) {
359 setAboveShelf(true);
360 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100361 }
362
Selim Cinekb5605e52015-02-20 18:21:41 +0100363 public void setGroupManager(NotificationGroupManager groupManager) {
364 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700365 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100366 }
367
Adrian Roosb88b1a12015-12-09 18:51:05 -0800368 public void setRemoteInputController(RemoteInputController r) {
369 mPrivateLayout.setRemoteInputController(r);
370 }
371
Mady Mellor3fd273e2016-03-15 21:08:14 -0700372 public void setAppName(String appName) {
373 mAppName = appName;
374 if (mSettingsIconRow != null) {
375 mSettingsIconRow.setAppName(mAppName);
376 }
377 }
378
Selim Cinekb5605e52015-02-20 18:21:41 +0100379 public void addChildNotification(ExpandableNotificationRow row) {
380 addChildNotification(row, -1);
381 }
382
383 /**
384 * Add a child notification to this view.
385 *
386 * @param row the row to add
387 * @param childIndex the index to add it at, if -1 it will be added at the end
388 */
389 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
390 if (mChildrenContainer == null) {
391 mChildrenContainerStub.inflate();
392 }
393 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700394 onChildrenCountChanged();
395 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100396 }
397
398 public void removeChildNotification(ExpandableNotificationRow row) {
399 if (mChildrenContainer != null) {
400 mChildrenContainer.removeNotification(row);
401 }
Selim Cinek263398f2015-10-21 17:40:23 -0700402 onChildrenCountChanged();
403 row.setIsChildInGroup(false, null);
404 }
405
406 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700407 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700408 }
409
Selim Cinek388df6d2015-10-22 13:25:11 -0700410 public ExpandableNotificationRow getNotificationParent() {
411 return mNotificationParent;
412 }
413
Selim Cinek263398f2015-10-21 17:40:23 -0700414 /**
415 * @param isChildInGroup Is this notification now in a group
416 * @param parent the new parent notification
417 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700418 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
419 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
420 mNotificationParent = childInGroup ? parent : null;
421 mPrivateLayout.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400422 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700423 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700424 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700425 if (mNotificationParent != null) {
426 mNotificationParent.updateBackgroundForGroupState();
427 }
Selim Cinekdb167372016-11-17 15:41:17 -0800428 updateIconVisibilities();
Selim Cinek34d93b02015-10-22 12:30:38 -0700429 }
430
431 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800432 public boolean onTouchEvent(MotionEvent event) {
433 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
434 || !isChildInGroup() || isGroupExpanded()) {
435 return super.onTouchEvent(event);
436 } else {
437 return false;
438 }
439 }
440
441 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800442 protected boolean handleSlideBack() {
443 if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
444 animateTranslateNotification(0 /* targetLeft */);
445 return true;
446 }
447 return false;
448 }
449
450 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700451 protected boolean shouldHideBackground() {
452 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700453 }
454
455 @Override
456 public boolean isSummaryWithChildren() {
457 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100458 }
459
460 @Override
461 public boolean areChildrenExpanded() {
462 return mChildrenExpanded;
463 }
464
465 public List<ExpandableNotificationRow> getNotificationChildren() {
466 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
467 }
468
Selim Cinekeef84282015-10-30 16:28:00 -0700469 public int getNumberOfNotificationChildren() {
470 if (mChildrenContainer == null) {
471 return 0;
472 }
473 return mChildrenContainer.getNotificationChildren().size();
474 }
475
Selim Cinekb5605e52015-02-20 18:21:41 +0100476 /**
477 * Apply the order given in the list to the children.
478 *
479 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800480 * @param visualStabilityManager
481 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100482 * @return whether the list order has changed
483 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800484 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
485 VisualStabilityManager visualStabilityManager,
486 VisualStabilityManager.Callback callback) {
487 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
488 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100489 }
490
491 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700492 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800493 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100494 mChildrenContainer.getState(resultState, parentState);
495 }
496 }
497
498 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700499 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100500 mChildrenContainer.applyState(state);
501 }
502 }
503
504 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700505 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100506 mChildrenContainer.prepareExpansionChanged(state);
507 }
508 }
509
Selim Cinek0cfbef42016-11-09 19:06:36 -0800510 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700511 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800512 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100513 }
514 }
515
516 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800517 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100518 return this;
519 } else {
520 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
521 return view == null ? this : view;
522 }
523 }
524
Selim Cinekab29aeb2015-02-20 18:18:32 +0100525 public NotificationGuts getGuts() {
526 return mGuts;
527 }
528
Selim Cinek684a4422015-04-15 16:18:39 -0700529 /**
530 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
531 * the notification will be rendered on top of the screen.
532 *
533 * @param pinned whether it is pinned
534 */
535 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700536 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700537 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700538 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700539 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700540 }
Selim Cinek31aada42015-12-18 17:51:15 -0800541 if (pinned) {
542 setIconAnimationRunning(true);
543 mExpandedWhenPinned = false;
544 } else if (mExpandedWhenPinned) {
545 setUserExpanded(true);
546 }
Selim Cinek98713a42015-09-21 15:47:20 +0200547 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700548 }
549
Selim Cinek684a4422015-04-15 16:18:39 -0700550 public boolean isPinned() {
551 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700552 }
553
Selim Cinekd127d792016-11-01 19:11:41 -0700554 @Override
555 public int getPinnedHeadsUpHeight() {
556 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
557 }
558
Selim Cinek31aada42015-12-18 17:51:15 -0800559 /**
560 * @param atLeastMinHeight should the value returned be at least the minimum height.
561 * Used to avoid cyclic calls
562 * @return the height of the heads up notification when pinned
563 */
Selim Cinekd127d792016-11-01 19:11:41 -0700564 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800565 if (mIsSummaryWithChildren) {
566 return mChildrenContainer.getIntrinsicHeight();
567 }
Selim Cinek31aada42015-12-18 17:51:15 -0800568 if(mExpandedWhenPinned) {
569 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
570 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700571 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800572 } else {
573 return mHeadsUpHeight;
574 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700575 }
576
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700577 /**
578 * Mark whether this notification was just clicked, i.e. the user has just clicked this
579 * notification in this frame.
580 */
581 public void setJustClicked(boolean justClicked) {
582 mJustClicked = justClicked;
583 }
584
585 /**
586 * @return true if this notification has been clicked in this frame, false otherwise
587 */
588 public boolean wasJustClicked() {
589 return mJustClicked;
590 }
591
Selim Cinek98713a42015-09-21 15:47:20 +0200592 public void setChronometerRunning(boolean running) {
593 mLastChronometerRunning = running;
594 setChronometerRunning(running, mPrivateLayout);
595 setChronometerRunning(running, mPublicLayout);
596 if (mChildrenContainer != null) {
597 List<ExpandableNotificationRow> notificationChildren =
598 mChildrenContainer.getNotificationChildren();
599 for (int i = 0; i < notificationChildren.size(); i++) {
600 ExpandableNotificationRow child = notificationChildren.get(i);
601 child.setChronometerRunning(running);
602 }
603 }
604 }
605
606 private void setChronometerRunning(boolean running, NotificationContentView layout) {
607 if (layout != null) {
608 running = running || isPinned();
609 View contractedChild = layout.getContractedChild();
610 View expandedChild = layout.getExpandedChild();
611 View headsUpChild = layout.getHeadsUpChild();
612 setChronometerRunningForChild(running, contractedChild);
613 setChronometerRunningForChild(running, expandedChild);
614 setChronometerRunningForChild(running, headsUpChild);
615 }
616 }
617
618 private void setChronometerRunningForChild(boolean running, View child) {
619 if (child != null) {
620 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
621 if (chronometer instanceof Chronometer) {
622 ((Chronometer) chronometer).setStarted(running);
623 }
624 }
625 }
626
Selim Cinekea4bef72015-12-02 15:51:10 -0800627 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700628 if (mIsSummaryWithChildren) {
629 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700630 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800631 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700632 }
633
Selim Cinek34eda5e2016-02-18 17:10:43 -0800634 private NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700635 if (mIsSummaryWithChildren && !mShowingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700636 return mChildrenContainer.getHeaderView();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800637 }
638 return getShowingLayout().getVisibleNotificationHeader();
639 }
640
Selim Cinek570981d2015-12-01 11:37:01 -0800641 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
642 mOnExpandClickListener = onExpandClickListener;
643 }
644
Selim Cinekddf1b392016-05-27 16:33:10 -0700645 @Override
646 public void setOnClickListener(@Nullable OnClickListener l) {
647 super.setOnClickListener(l);
648 mOnClickListener = l;
649 updateClickAndFocus();
650 }
651
652 private void updateClickAndFocus() {
653 boolean normalChild = !isChildInGroup() || isGroupExpanded();
654 boolean clickable = mOnClickListener != null && normalChild;
655 if (isFocusable() != normalChild) {
656 setFocusable(normalChild);
657 }
658 if (isClickable() != clickable) {
659 setClickable(clickable);
660 }
661 }
662
Selim Cinek31aada42015-12-18 17:51:15 -0800663 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
664 mHeadsUpManager = headsUpManager;
665 }
666
Selim Cinek01af3342016-02-09 19:25:31 -0800667 public void reInflateViews() {
668 initDimens();
669 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800670 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700671 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800672 }
673 }
674 if (mGuts != null) {
675 View oldGuts = mGuts;
676 int index = indexOfChild(oldGuts);
677 removeView(oldGuts);
678 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
679 R.layout.notification_guts, this, false);
680 mGuts.setVisibility(oldGuts.getVisibility());
681 addView(mGuts, index);
682 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800683 if (mSettingsIconRow != null) {
684 View oldSettings = mSettingsIconRow;
685 int settingsIndex = indexOfChild(oldSettings);
686 removeView(oldSettings);
687 mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
688 R.layout.notification_settings_icon_row, this, false);
689 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700690 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800691 mSettingsIconRow.setVisibility(oldSettings.getVisibility());
692 addView(mSettingsIconRow, settingsIndex);
693
694 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800695 for (NotificationContentView l : mLayouts) {
696 l.reInflateViews();
697 }
Selim Cinek01af3342016-02-09 19:25:31 -0800698 }
699
Selim Cinekc3179332016-03-04 14:44:56 -0800700 public void setContentBackground(int customBackgroundColor, boolean animate,
701 NotificationContentView notificationContentView) {
702 if (getShowingLayout() == notificationContentView) {
703 setTintColor(customBackgroundColor, animate);
704 }
705 }
706
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700707 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800708 for (NotificationContentView l : mLayouts) {
709 l.closeRemoteInput();
710 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700711 }
712
Selim Cinekc897bd32016-03-18 17:32:31 -0700713 /**
714 * Set by how much the single line view should be indented.
715 */
716 public void setSingleLineWidthIndention(int indention) {
717 mPrivateLayout.setSingleLineWidthIndention(indention);
718 }
719
720 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700721 return mNotificationColor;
722 }
723
724 private void updateNotificationColor() {
725 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
726 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700727 }
728
729 public HybridNotificationView getSingleLineView() {
730 return mPrivateLayout.getSingleLineView();
731 }
732
Selim Cinekf07d0622016-03-21 19:52:52 -0700733 public boolean isOnKeyguard() {
734 return mOnKeyguard;
735 }
736
Selim Cinekc1e389d2016-04-07 11:02:57 -0700737 public void removeAllChildren() {
738 List<ExpandableNotificationRow> notificationChildren
739 = mChildrenContainer.getNotificationChildren();
740 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
741 for (int i = 0; i < clonedList.size(); i++) {
742 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700743 if (row.keepInParent()) {
744 continue;
745 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700746 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700747 row.setIsChildInGroup(false, null);
748 }
749 onChildrenCountChanged();
750 }
751
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700752 public void setForceUnlocked(boolean forceUnlocked) {
753 mForceUnlocked = forceUnlocked;
754 if (mIsSummaryWithChildren) {
755 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
756 for (ExpandableNotificationRow child : notificationChildren) {
757 child.setForceUnlocked(forceUnlocked);
758 }
759 }
760 }
761
Selim Cineke9bad242016-06-15 11:46:37 -0700762 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700763 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700764 mGroupParentWhenDismissed = mNotificationParent;
765 mRefocusOnDismiss = fromAccessibility;
766 mChildAfterViewWhenDismissed = null;
767 if (isChildInGroup()) {
768 List<ExpandableNotificationRow> notificationChildren =
769 mNotificationParent.getNotificationChildren();
770 int i = notificationChildren.indexOf(this);
771 if (i != -1 && i < notificationChildren.size() - 1) {
772 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
773 }
774 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700775 }
776
777 public boolean isDismissed() {
778 return mDismissed;
779 }
780
781 public boolean keepInParent() {
782 return mKeepInParent;
783 }
784
785 public void setKeepInParent(boolean keepInParent) {
786 mKeepInParent = keepInParent;
787 }
788
789 public boolean isRemoved() {
790 return mRemoved;
791 }
792
Adrian Roosd009ab12016-05-20 17:58:53 -0700793 public void setRemoved() {
794 mRemoved = true;
795
796 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700797 }
798
Selim Cinekd1395642016-04-28 12:22:42 -0700799 public NotificationChildrenContainer getChildrenContainer() {
800 return mChildrenContainer;
801 }
802
Selim Cinekcafa87f2016-10-26 17:00:17 -0700803 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
804 mHeadsupDisappearRunning = headsUpAnimatingAway;
805 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
806 }
807
808 /**
809 * @return if the view was just heads upped and is now animating away. During such a time the
810 * layout needs to be kept consistent
811 */
812 public boolean isHeadsUpAnimatingAway() {
813 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700814 }
815
Selim Cineke9bad242016-06-15 11:46:37 -0700816 public View getChildAfterViewWhenDismissed() {
817 return mChildAfterViewWhenDismissed;
818 }
819
820 public View getGroupParentWhenDismissed() {
821 return mGroupParentWhenDismissed;
822 }
823
Selim Cinek9e624e72016-07-20 13:46:49 -0700824 public void performDismiss() {
Selim Cineke9079112016-12-14 14:41:01 -0800825 if (mOnDismissRunnable != null) {
826 mOnDismissRunnable.run();
827 }
Selim Cinek9e624e72016-07-20 13:46:49 -0700828 }
829
Selim Cineke9079112016-12-14 14:41:01 -0800830 public void setOnDismissRunnable(Runnable onDismissRunnable) {
831 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -0700832 }
833
Selim Cinek281c2022016-10-13 19:14:43 -0700834 public View getNotificationIcon() {
835 NotificationHeaderView notificationHeader = getNotificationHeader();
836 if (notificationHeader != null) {
837 return notificationHeader.getIcon();
838 }
839 return null;
840 }
841
842 /**
843 * @return whether the notification is currently showing a view with an icon.
844 */
845 public boolean isShowingIcon() {
846 if (mIsSummaryWithChildren) {
847 return true;
848 }
849 NotificationContentView showingLayout = getShowingLayout();
850 NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
851 return notificationHeader != null;
852 }
853
Selim Cinek0242fbb2016-10-19 13:38:32 -0700854 /**
855 * Set how much this notification is transformed into an icon.
856 *
Selim Cinek2b549f42016-11-22 16:38:51 -0800857 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
858 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -0800859 * @param isLastChild is this the last child in the list. If true, then the transformation is
860 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -0700861 */
Selim Cinek2b549f42016-11-22 16:38:51 -0800862 public void setContentTransformationAmount(float contentTransformationAmount,
863 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -0800864 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800865 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800866 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800867 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800868 if (changeTransformation) {
869 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -0800870 }
871 }
872
873 /**
874 * Set the icons to be visible of this notification.
875 */
876 public void setIconsVisible(boolean iconsVisible) {
877 if (iconsVisible != mIconsVisible) {
878 mIconsVisible = iconsVisible;
879 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700880 }
881 }
882
Selim Cinekdb167372016-11-17 15:41:17 -0800883 @Override
884 protected void onBelowSpeedBumpChanged() {
885 updateIconVisibilities();
886 }
887
Selim Cinek875a3a12016-11-18 17:52:16 -0800888 private void updateContentTransformation() {
889 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -0800890 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800891 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -0800892 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800893 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700894 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -0800895 translationY *= 0.4f;
896 } else {
897 contentAlpha = 1.0f;
898 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800899 for (NotificationContentView l : mLayouts) {
900 l.setAlpha(contentAlpha);
901 l.setTranslationY(translationY);
902 }
Selim Cinek875a3a12016-11-18 17:52:16 -0800903 if (mChildrenContainer != null) {
904 mChildrenContainer.setAlpha(contentAlpha);
905 mChildrenContainer.setTranslationY(translationY);
906 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -0700907 }
908 }
909
910 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -0800911 boolean visible = isChildInGroup()
912 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
913 || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800914 for (NotificationContentView l : mLayouts) {
915 l.setIconsVisible(visible);
916 }
Selim Cinekdb167372016-11-17 15:41:17 -0800917 if (mChildrenContainer != null) {
918 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700919 }
920 }
921
Selim Cinek875a3a12016-11-18 17:52:16 -0800922 /**
923 * Get the relative top padding of a view relative to this view. This recursively walks up the
924 * hierarchy and does the corresponding measuring.
925 *
926 * @param view the view to the the padding for. The requested view has to be a child of this
927 * notification.
928 * @return the toppadding
929 */
930 public int getRelativeTopPadding(View view) {
931 int topPadding = 0;
932 while (view.getParent() instanceof ViewGroup) {
933 topPadding += view.getTop();
934 view = (View) view.getParent();
935 if (view instanceof ExpandableNotificationRow) {
936 return topPadding;
937 }
938 }
939 return topPadding;
940 }
941
Selim Cineka1d97902016-12-14 16:31:40 -0800942 public float getContentTranslation() {
943 return mPrivateLayout.getTranslationY();
944 }
945
Chris Wren78403d72014-07-28 10:23:24 +0100946 public interface ExpansionLogger {
947 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
948 }
Selim Cinek1685e632014-04-08 02:27:49 +0200949
Chris Wren51c75102013-07-16 20:49:17 -0400950 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
951 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700952 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -0800953 initDimens();
954 }
955
956 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800957 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
958 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
959 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
Adrian Roos0aac04f2016-12-08 15:59:29 -0800960 mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800961 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -0800962 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800963 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Mady Mellorb0a82462016-04-30 17:31:02 -0700964 mIncreasedPaddingBetweenElements = getResources()
965 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinek875a3a12016-11-18 17:52:16 -0800966 mIconTransformContentShiftNoIcon = getResources().getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -0700967 R.dimen.notification_icon_transform_content_shift);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800968 }
969
970 /**
971 * @param dimenId the dimen to look up
972 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
973 */
974 private int getFontScaledHeight(int dimenId) {
975 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
976 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
977 getResources().getDisplayMetrics().density);
978 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -0400979 }
980
Christoph Studera7fe6312014-06-27 19:32:44 +0200981 /**
982 * Resets this view so it can be re-used for an updated notification.
983 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200984 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200985 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200986 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +0100987 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +0200988 mExpandable = false;
989 mHasUserChangedExpansion = false;
990 mUserLocked = false;
991 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200992 mSensitive = false;
993 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200994 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700995 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -0800996 mPublicLayout.reset();
997 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +0200998 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -0800999 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +02001000 logExpansionEvent(false, wasExpanded);
1001 }
1002
1003 public void resetHeight() {
Selim Cinek31094df2014-08-14 19:28:15 +02001004 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001005 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001006 }
1007
Jorim Jaggi251957d2014-04-09 04:24:09 +02001008 @Override
1009 protected void onFinishInflate() {
1010 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001011 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1012 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001013
1014 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1015
1016 for (NotificationContentView l : mLayouts) {
1017 l.setExpandClickListener(mExpandClickListener);
1018 l.setContainingNotification(this);
1019 }
1020
Mady Mellor4b80b102016-01-22 08:03:58 -08001021 mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
1022 mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1023 @Override
1024 public void onInflate(ViewStub stub, View inflated) {
1025 mSettingsIconRow = (NotificationSettingsIconRow) inflated;
1026 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -07001027 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -08001028 }
1029 });
Selim Cinekab29aeb2015-02-20 18:18:32 +01001030 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1031 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001032 @Override
1033 public void onInflate(ViewStub stub, View inflated) {
1034 mGuts = (NotificationGuts) inflated;
1035 mGuts.setClipTopAmount(getClipTopAmount());
1036 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001037 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001038 }
1039 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001040 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1041 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1042
1043 @Override
1044 public void onInflate(ViewStub stub, View inflated) {
1045 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -07001046 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001047 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -08001048 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +01001049 }
1050 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001051
1052 // Add the views that we translate to reveal the gear
1053 mTranslateableViews = new ArrayList<View>();
1054 for (int i = 0; i < getChildCount(); i++) {
1055 mTranslateableViews.add(getChildAt(i));
1056 }
1057 // Remove views that don't translate
Mady Mellor4b80b102016-01-22 08:03:58 -08001058 mTranslateableViews.remove(mSettingsIconRowStub);
1059 mTranslateableViews.remove(mChildrenContainerStub);
1060 mTranslateableViews.remove(mGutsStub);
1061 }
1062
Mady Mellor4b80b102016-01-22 08:03:58 -08001063 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001064 if (mTranslateAnim != null) {
1065 mTranslateAnim.cancel();
1066 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001067 if (mTranslateableViews != null) {
1068 for (int i = 0; i < mTranslateableViews.size(); i++) {
1069 mTranslateableViews.get(i).setTranslationX(0);
1070 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001071 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001072 invalidateOutline();
Mady Mellor4b80b102016-01-22 08:03:58 -08001073 if (mSettingsIconRow != null) {
1074 mSettingsIconRow.resetState();
1075 }
1076 }
1077
1078 public void animateTranslateNotification(final float leftTarget) {
1079 if (mTranslateAnim != null) {
1080 mTranslateAnim.cancel();
1081 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001082 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001083 if (mTranslateAnim != null) {
1084 mTranslateAnim.start();
1085 }
1086 }
1087
1088 @Override
1089 public void setTranslation(float translationX) {
1090 if (areGutsExposed()) {
1091 // Don't translate if guts are showing.
1092 return;
1093 }
1094 // Translate the group of views
1095 for (int i = 0; i < mTranslateableViews.size(); i++) {
1096 if (mTranslateableViews.get(i) != null) {
1097 mTranslateableViews.get(i).setTranslationX(translationX);
1098 }
1099 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001100 invalidateOutline();
Mady Mellor34958fa2016-02-23 09:52:17 -08001101 if (mSettingsIconRow != null) {
1102 mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
1103 }
1104 }
1105
1106 @Override
1107 public float getTranslation() {
1108 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1109 // All of the views in the list should have same translation, just use first one.
1110 return mTranslateableViews.get(0).getTranslationX();
1111 }
1112 return 0;
1113 }
1114
1115 public Animator getTranslateViewAnimator(final float leftTarget,
1116 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001117 if (mTranslateAnim != null) {
1118 mTranslateAnim.cancel();
1119 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001120 if (areGutsExposed()) {
1121 // No translation if guts are exposed.
1122 return null;
1123 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001124 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1125 leftTarget);
1126 if (listener != null) {
1127 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001128 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001129 translateAnim.addListener(new AnimatorListenerAdapter() {
1130 boolean cancelled = false;
1131
1132 @Override
1133 public void onAnimationCancel(Animator anim) {
1134 cancelled = true;
1135 }
1136
1137 @Override
1138 public void onAnimationEnd(Animator anim) {
1139 if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
1140 mSettingsIconRow.resetState();
1141 mTranslateAnim = null;
1142 }
1143 }
1144 });
1145 mTranslateAnim = translateAnim;
1146 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001147 }
1148
1149 public float getSpaceForGear() {
1150 if (mSettingsIconRow != null) {
1151 return mSettingsIconRow.getSpaceForGear();
1152 }
1153 return 0;
1154 }
1155
1156 public NotificationSettingsIconRow getSettingsRow() {
1157 if (mSettingsIconRow == null) {
1158 mSettingsIconRowStub.inflate();
1159 }
1160 return mSettingsIconRow;
1161 }
1162
Selim Cinekab29aeb2015-02-20 18:18:32 +01001163 public void inflateGuts() {
1164 if (mGuts == null) {
1165 mGutsStub.inflate();
1166 }
1167 }
1168
Selim Cinekda42d652015-12-04 15:51:16 -08001169 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001170 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1171 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001172 if (mChildrenContainer != null) {
1173 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1174 : INVISIBLE);
Mady Mellorb0a82462016-04-30 17:31:02 -07001175 mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
1176 ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001177 : INVISIBLE);
1178 }
Selim Cinekda42d652015-12-04 15:51:16 -08001179 // The limits might have changed if the view suddenly became a group or vice versa
1180 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001181 }
1182
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001183 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001184 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1185 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001186 // Add a record for the entire layout since its content is somehow small.
1187 // The event comes from a leaf view that is interacted with.
1188 AccessibilityEvent record = AccessibilityEvent.obtain();
1189 onInitializeAccessibilityEvent(record);
1190 dispatchPopulateAccessibilityEvent(record);
1191 event.appendRecord(record);
1192 return true;
1193 }
1194 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001195 }
Chris Wren51c75102013-07-16 20:49:17 -04001196
John Spurlocke15452b2014-08-21 09:44:39 -04001197 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001198 public void setDark(boolean dark, boolean fade, long delay) {
1199 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001200 final NotificationContentView showing = getShowingLayout();
1201 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001202 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001203 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001204 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001205 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001206 }
John Spurlocke15452b2014-08-21 09:44:39 -04001207 }
1208
Chris Wren51c75102013-07-16 20:49:17 -04001209 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001210 if (mIsSummaryWithChildren && !mShowingPublic) {
1211 return !mChildrenExpanded;
1212 }
Chris Wren51c75102013-07-16 20:49:17 -04001213 return mExpandable;
1214 }
1215
1216 public void setExpandable(boolean expandable) {
1217 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001218 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001219 }
1220
Selim Cinek4ffd6362015-12-29 15:12:23 +01001221 @Override
1222 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001223 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1224 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001225 }
1226
Selim Cinek1685e632014-04-08 02:27:49 +02001227 /**
1228 * @return whether the user has changed the expansion state
1229 */
1230 public boolean hasUserChangedExpansion() {
1231 return mHasUserChangedExpansion;
1232 }
1233
Chris Wren51c75102013-07-16 20:49:17 -04001234 public boolean isUserExpanded() {
1235 return mUserExpanded;
1236 }
1237
Selim Cinek1685e632014-04-08 02:27:49 +02001238 /**
1239 * Set this notification to be expanded by the user
1240 *
1241 * @param userExpanded whether the user wants this notification to be expanded
1242 */
Chris Wren51c75102013-07-16 20:49:17 -04001243 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001244 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1245 }
1246
1247 /**
1248 * Set this notification to be expanded by the user
1249 *
1250 * @param userExpanded whether the user wants this notification to be expanded
1251 * @param allowChildExpansion whether a call to this method allows expanding children
1252 */
1253 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001254 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -07001255 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
Chris Wren698b1702016-05-23 11:16:32 -04001256 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001257 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Chris Wren698b1702016-05-23 11:16:32 -04001258 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001259 return;
1260 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001261 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001262 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001263 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001264 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001265 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001266 }
1267
Selim Cinekccd14fb2014-08-12 18:53:24 +02001268 public void resetUserExpansion() {
1269 mHasUserChangedExpansion = false;
1270 mUserExpanded = false;
1271 }
1272
Chris Wren51c75102013-07-16 20:49:17 -04001273 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001274 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001275 }
1276
1277 public void setUserLocked(boolean userLocked) {
1278 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001279 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001280 if (mIsSummaryWithChildren) {
1281 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek7baaa9e2016-07-21 17:21:09 -07001282 if (userLocked || !isGroupExpanded()) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001283 updateBackgroundForGroupState();
1284 }
Selim Cinek42357e02016-02-24 18:48:01 -08001285 }
Chris Wren51c75102013-07-16 20:49:17 -04001286 }
1287
Selim Cinek1685e632014-04-08 02:27:49 +02001288 /**
1289 * @return has the system set this notification to be expanded
1290 */
1291 public boolean isSystemExpanded() {
1292 return mIsSystemExpanded;
1293 }
1294
1295 /**
1296 * Set this notification to be expanded by the system.
1297 *
1298 * @param expand whether the system wants this notification to be expanded.
1299 */
1300 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001301 if (expand != mIsSystemExpanded) {
1302 final boolean wasExpanded = isExpanded();
1303 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001304 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001305 logExpansionEvent(false, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001306 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001307 mChildrenContainer.updateGroupOverflow();
1308 }
Selim Cinek31094df2014-08-14 19:28:15 +02001309 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001310 }
1311
1312 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001313 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001314 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001315 public void setOnKeyguard(boolean onKeyguard) {
1316 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001317 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001318 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001319 logExpansionEvent(false, wasExpanded);
1320 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001321 if (mIsSummaryWithChildren) {
1322 mChildrenContainer.updateGroupOverflow();
1323 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001324 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001325 }
1326 }
Selim Cinek1685e632014-04-08 02:27:49 +02001327 }
1328
1329 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001330 * @return Can the underlying notification be cleared? This can be different from whether the
1331 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1332 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001333 */
1334 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001335 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1336 return false;
1337 }
1338 if (mIsSummaryWithChildren) {
1339 List<ExpandableNotificationRow> notificationChildren =
1340 mChildrenContainer.getNotificationChildren();
1341 for (int i = 0; i < notificationChildren.size(); i++) {
1342 ExpandableNotificationRow child = notificationChildren.get(i);
1343 if (!child.isClearable()) {
1344 return false;
1345 }
1346 }
1347 }
1348 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001349 }
1350
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001351 @Override
1352 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001353 if (isUserLocked()) {
1354 return getActualHeight();
1355 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001356 if (mGuts != null && mGuts.isExposed()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001357 return mGuts.getHeight();
1358 } else if ((isChildInGroup() && !isGroupExpanded())) {
1359 return mPrivateLayout.getMinHeight();
Adrian Roos0aac04f2016-12-08 15:59:29 -08001360 } else if (mShowAmbient) {
1361 return getAmbientHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001362 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1363 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001364 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001365 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001366 } else if (!mOnKeyguard && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07001367 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001368 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1369 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001370 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001371 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001372 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001373 }
Selim Cinek31aada42015-12-18 17:51:15 -08001374 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001375 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001376 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001377 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001378 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001379 }
Selim Cinek1685e632014-04-08 02:27:49 +02001380
Mady Mellorb0a82462016-04-30 17:31:02 -07001381 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001382 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001383 }
1384
Selim Cinek263398f2015-10-21 17:40:23 -07001385 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001386 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001387 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1388 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
1389 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
1390 mEntry.notification);
Selim Cinek263398f2015-10-21 17:40:23 -07001391 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001392 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001393 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001394 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001395 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001396 }
1397
Mady Mellorb0a82462016-04-30 17:31:02 -07001398 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001399 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001400 mChildrenContainer.updateChildrenHeaderAppearance();
1401 }
1402 }
1403
Selim Cinek1685e632014-04-08 02:27:49 +02001404 /**
1405 * Check whether the view state is currently expanded. This is given by the system in {@link
1406 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1407 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1408 * view can differ from this state, if layout params are modified from outside.
1409 *
1410 * @return whether the view state is currently expanded.
1411 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001412 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001413 return isExpanded(false /* allowOnKeyguard */);
1414 }
1415
1416 public boolean isExpanded(boolean allowOnKeyguard) {
1417 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001418 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1419 || isUserExpanded());
1420 }
1421
1422 private boolean isSystemChildExpanded() {
1423 return mIsSystemChildExpanded;
1424 }
1425
1426 public void setSystemChildExpanded(boolean expanded) {
1427 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001428 }
1429
1430 @Override
1431 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1432 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001433 updateMaxHeights();
Mady Mellora6edc872016-04-26 11:01:03 -07001434 if (mSettingsIconRow != null) {
1435 mSettingsIconRow.updateVerticalLocation();
1436 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001437 updateContentShiftHeight();
1438 }
1439
1440 /**
1441 * Updates the content shift height such that the header is completely hidden when coming from
1442 * the top.
1443 */
1444 private void updateContentShiftHeight() {
1445 NotificationHeaderView notificationHeader = getNotificationHeader();
1446 if (notificationHeader != null) {
1447 CachingIconView icon = notificationHeader.getIcon();
1448 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1449 } else {
1450 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1451 }
Selim Cinek1685e632014-04-08 02:27:49 +02001452 }
1453
Selim Cinek8d490d42015-04-10 00:05:50 -07001454 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001455 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001456 View expandedChild = mPrivateLayout.getExpandedChild();
1457 if (expandedChild == null) {
1458 expandedChild = mPrivateLayout.getContractedChild();
1459 }
1460 mMaxExpandHeight = expandedChild.getHeight();
1461 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001462 if (headsUpChild == null) {
1463 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001464 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001465 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001466 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001467 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001468 }
1469 }
1470
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001471 @Override
1472 public void notifyHeightChanged(boolean needsAnimation) {
1473 super.notifyHeightChanged(needsAnimation);
1474 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1475 }
1476
Selim Cinek3c76d502016-02-19 15:16:33 -08001477 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001478 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001479 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001480 }
1481
1482 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001483 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001484 if (mIsSummaryWithChildren) {
1485 List<ExpandableNotificationRow> notificationChildren =
1486 mChildrenContainer.getNotificationChildren();
1487 for (int i = 0; i < notificationChildren.size(); i++) {
1488 ExpandableNotificationRow child = notificationChildren.get(i);
1489 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1490 }
1491 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001492 }
1493
1494 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1495 long duration) {
1496 boolean oldShowingPublic = mShowingPublic;
1497 mShowingPublic = mSensitive && hideSensitive;
1498 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1499 return;
1500 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001501
1502 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001503 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001504
Jorim Jaggiae441282014-08-01 02:45:18 +02001505 if (!animated) {
1506 mPublicLayout.animate().cancel();
1507 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001508 if (mChildrenContainer != null) {
1509 mChildrenContainer.animate().cancel();
1510 mChildrenContainer.setAlpha(1f);
1511 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001512 mPublicLayout.setAlpha(1f);
1513 mPrivateLayout.setAlpha(1f);
1514 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001515 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001516 } else {
1517 animateShowingPublic(delay, duration);
1518 }
Selim Cinekc3179332016-03-04 14:44:56 -08001519 NotificationContentView showingLayout = getShowingLayout();
1520 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001521 mPrivateLayout.updateExpandButtons(isExpandable());
Adrian Roose5726a22016-12-19 14:26:51 -08001522 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02001523 mShowingPublicInitialized = true;
1524 }
1525
1526 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001527 View[] privateViews = mIsSummaryWithChildren
1528 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001529 : new View[] {mPrivateLayout};
1530 View[] publicViews = new View[] {mPublicLayout};
1531 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1532 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1533 for (final View hiddenView : hiddenChildren) {
1534 hiddenView.setVisibility(View.VISIBLE);
1535 hiddenView.animate().cancel();
1536 hiddenView.animate()
1537 .alpha(0f)
1538 .setStartDelay(delay)
1539 .setDuration(duration)
1540 .withEndAction(new Runnable() {
1541 @Override
1542 public void run() {
1543 hiddenView.setVisibility(View.INVISIBLE);
1544 }
1545 });
1546 }
1547 for (View showView : shownChildren) {
1548 showView.setVisibility(View.VISIBLE);
1549 showView.setAlpha(0f);
1550 showView.animate().cancel();
1551 showView.animate()
1552 .alpha(1f)
1553 .setStartDelay(delay)
1554 .setDuration(duration);
1555 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001556 }
1557
Selim Cinek3776fe02016-02-04 13:32:43 -08001558 public boolean mustStayOnScreen() {
1559 return mIsHeadsUp;
1560 }
1561
Selim Cinek9e624e72016-07-20 13:46:49 -07001562 /**
1563 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1564 * otherwise some state might not be updated. To request about the general clearability
1565 * see {@link #isClearable()}.
1566 */
1567 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001568 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001569 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001570
Ricky Waicd35def2016-05-03 11:07:07 +01001571 public void makeActionsVisibile() {
1572 setUserExpanded(true, true);
1573 if (isChildInGroup()) {
1574 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1575 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001576 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001577 }
1578
Selim Cinekb5605e52015-02-20 18:21:41 +01001579 public void setChildrenExpanded(boolean expanded, boolean animate) {
1580 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001581 if (mChildrenContainer != null) {
1582 mChildrenContainer.setChildrenExpanded(expanded);
1583 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001584 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001585 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001586 }
1587
Selim Cinekb5605e52015-02-20 18:21:41 +01001588 public static void applyTint(View v, int color) {
1589 int alpha;
1590 if (color != 0) {
1591 alpha = COLORED_DIVIDER_ALPHA;
1592 } else {
1593 color = 0xff000000;
1594 alpha = DEFAULT_DIVIDER_ALPHA;
1595 }
1596 if (v.getBackground() instanceof ColorDrawable) {
1597 ColorDrawable background = (ColorDrawable) v.getBackground();
1598 background.mutate();
1599 background.setColor(color);
1600 background.setAlpha(alpha);
1601 }
1602 }
1603
Selim Cinek1685e632014-04-08 02:27:49 +02001604 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001605 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001606 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001607
Mady Mellor34958fa2016-02-23 09:52:17 -08001608 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001609 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08001610 }
1611
Jorim Jaggibe565df2014-04-28 17:51:23 +02001612 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001613 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001614 NotificationContentView showingLayout = getShowingLayout();
1615 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001616 }
1617
1618 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001619 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001620 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001621 return mChildrenContainer;
1622 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001623 return getShowingLayout();
1624 }
1625
1626 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001627 protected void onAppearAnimationFinished(boolean wasAppearing) {
1628 super.onAppearAnimationFinished(wasAppearing);
1629 if (wasAppearing) {
1630 // During the animation the visible view might have changed, so let's make sure all
1631 // alphas are reset
1632 if (mChildrenContainer != null) {
1633 mChildrenContainer.setAlpha(1.0f);
1634 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1635 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001636 for (NotificationContentView l : mLayouts) {
1637 l.setAlpha(1.0f);
1638 l.setLayerType(LAYER_TYPE_NONE, null);
1639 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07001640 }
1641 }
1642
1643 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001644 public int getExtraBottomPadding() {
1645 if (mIsSummaryWithChildren && isGroupExpanded()) {
1646 return mIncreasedPaddingBetweenElements;
1647 }
1648 return 0;
1649 }
1650
1651 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001652 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001653 super.setActualHeight(height, notifyListeners);
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001654 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08001655 mGuts.setActualHeight(height);
1656 return;
1657 }
Selim Cinekeef84282015-10-30 16:28:00 -07001658 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001659 for (NotificationContentView l : mLayouts) {
1660 l.setContentHeight(contentHeight);
1661 }
Selim Cinek42357e02016-02-24 18:48:01 -08001662 if (mIsSummaryWithChildren) {
1663 mChildrenContainer.setActualHeight(height);
1664 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001665 if (mGuts != null) {
1666 mGuts.setActualHeight(height);
1667 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001668 }
1669
1670 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001671 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001672 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001673 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001674 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001675 NotificationContentView showingLayout = getShowingLayout();
1676 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001677 }
1678
1679 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001680 public int getMinHeight() {
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001681 if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08001682 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1683 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001684 return mChildrenContainer.getMinHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001685 } else if (!mOnKeyguard && mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001686 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001687 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001688 NotificationContentView showingLayout = getShowingLayout();
1689 return showingLayout.getMinHeight();
1690 }
1691
Adrian Roos0aac04f2016-12-08 15:59:29 -08001692 private int getAmbientHeight() {
1693 NotificationContentView showingLayout = getShowingLayout();
1694 return showingLayout.getAmbientChild() != null
1695 ? showingLayout.getAmbientChild().getHeight()
1696 : getCollapsedHeight();
1697 }
1698
Selim Cinek816c8e42015-11-19 12:00:45 -08001699 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001700 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001701 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001702 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001703 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001704 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001705 }
1706
1707 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001708 public void setClipTopAmount(int clipTopAmount) {
1709 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001710 for (NotificationContentView l : mLayouts) {
1711 l.setClipTopAmount(clipTopAmount);
1712 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001713 if (mGuts != null) {
1714 mGuts.setClipTopAmount(clipTopAmount);
1715 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001716 }
1717
Selim Cineka686b2c2016-10-26 13:58:27 -07001718 @Override
1719 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001720 if (clipBottomAmount != mClipBottomAmount) {
1721 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001722 for (NotificationContentView l : mLayouts) {
1723 l.setClipBottomAmount(clipBottomAmount);
1724 }
Selim Cinek65d418e2016-11-29 15:42:34 -08001725 if (mGuts != null) {
1726 mGuts.setClipBottomAmount(clipBottomAmount);
1727 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001728 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001729 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001730 // We have to update this even if it hasn't changed, since the children locations can
1731 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001732 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
1733 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001734 }
1735
Selim Cinek31094df2014-08-14 19:28:15 +02001736 public boolean isMaxExpandHeightInitialized() {
1737 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001738 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001739
Selim Cinek42357e02016-02-24 18:48:01 -08001740 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001741 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1742 }
Chris Wren78403d72014-07-28 10:23:24 +01001743
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001744 @Override
1745 public void setShowingLegacyBackground(boolean showing) {
1746 super.setShowingLegacyBackground(showing);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001747 for (NotificationContentView l : mLayouts) {
1748 l.setShowingLegacyBackground(showing);
1749 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001750 }
1751
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001752 @Override
1753 protected void updateBackgroundTint() {
1754 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001755 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001756 if (mIsSummaryWithChildren) {
1757 List<ExpandableNotificationRow> notificationChildren =
1758 mChildrenContainer.getNotificationChildren();
1759 for (int i = 0; i < notificationChildren.size(); i++) {
1760 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001761 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001762 }
1763 }
1764 }
1765
Mady Mellorb0a82462016-04-30 17:31:02 -07001766 /**
1767 * Called when a group has finished animating from collapsed or expanded state.
1768 */
1769 public void onFinishedExpansionChange() {
1770 mGroupExpansionChanging = false;
1771 updateBackgroundForGroupState();
1772 }
1773
1774 /**
1775 * Updates the parent and children backgrounds in a group based on the expansion state.
1776 */
1777 public void updateBackgroundForGroupState() {
1778 if (mIsSummaryWithChildren) {
1779 // Only when the group has finished expanding do we hide its background.
1780 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1781 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1782 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1783 for (int i = 0; i < children.size(); i++) {
1784 children.get(i).updateBackgroundForGroupState();
1785 }
1786 } else if (isChildInGroup()) {
1787 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
1788 // Only show a background if the group is expanded OR if it is expanding / collapsing
1789 // and has a custom background color
1790 final boolean showBackground = isGroupExpanded()
1791 || ((mNotificationParent.isGroupExpansionChanging()
1792 || mNotificationParent.isUserLocked()) && childColor != 0);
1793 mShowNoBackground = !showBackground;
1794 } else {
1795 // Only children or parents ever need no background.
1796 mShowNoBackground = false;
1797 }
1798 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001799 updateBackground();
1800 }
1801
Adrian Roos4a579672016-05-24 16:54:37 -07001802 public int getPositionOfChild(ExpandableNotificationRow childRow) {
1803 if (mIsSummaryWithChildren) {
1804 return mChildrenContainer.getPositionInLinearLayout(childRow);
1805 }
1806 return 0;
1807 }
1808
Chris Wren78403d72014-07-28 10:23:24 +01001809 public void setExpansionLogger(ExpansionLogger logger, String key) {
1810 mLogger = logger;
1811 mLoggingKey = key;
1812 }
1813
Chris Wren6abeeb92016-05-26 14:44:38 -04001814 public void onExpandedByGesture(boolean userExpanded) {
1815 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
1816 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
1817 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
1818 }
1819 MetricsLogger.action(mContext, event, userExpanded);
1820 }
1821
Selim Cinek6183d122016-01-14 18:48:41 -08001822 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001823 public float getIncreasedPaddingAmount() {
1824 if (mIsSummaryWithChildren) {
1825 if (isGroupExpanded()) {
1826 return 1.0f;
1827 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001828 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001829 }
1830 }
1831 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001832 }
1833
1834 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001835 protected boolean disallowSingleClick(MotionEvent event) {
1836 float x = event.getX();
1837 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001838 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001839 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001840 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001841 }
1842 return super.disallowSingleClick(event);
1843 }
1844
Chris Wren78403d72014-07-28 10:23:24 +01001845 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04001846 boolean nowExpanded = isExpanded();
1847 if (mIsSummaryWithChildren) {
1848 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
1849 }
Chris Wren78403d72014-07-28 10:23:24 +01001850 if (wasExpanded != nowExpanded && mLogger != null) {
1851 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1852 }
1853 }
Selim Cinek570981d2015-12-01 11:37:01 -08001854
Selim Cineke9bad242016-06-15 11:46:37 -07001855 @Override
1856 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1857 super.onInitializeAccessibilityNodeInfoInternal(info);
1858 if (canViewBeDismissed()) {
1859 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
1860 }
1861 }
1862
1863 @Override
1864 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
1865 if (super.performAccessibilityActionInternal(action, arguments)) {
1866 return true;
1867 }
1868 switch (action) {
1869 case AccessibilityNodeInfo.ACTION_DISMISS:
1870 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
1871 true /* fromAccessibility */);
1872 return true;
1873 }
1874 return false;
1875 }
1876
1877 public boolean shouldRefocusOnDismiss() {
1878 return mRefocusOnDismiss || isAccessibilityFocused();
1879 }
1880
Selim Cinek570981d2015-12-01 11:37:01 -08001881 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001882 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001883 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001884
1885 @Override
1886 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
1887 return new NotificationViewState(stackScrollState);
1888 }
1889
Selim Cinekd127d792016-11-01 19:11:41 -07001890 @Override
1891 public boolean isAboveShelf() {
1892 return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
1893 }
1894
Adrian Roos0aac04f2016-12-08 15:59:29 -08001895 public void setShowAmbient(boolean showAmbient) {
1896 if (showAmbient != mShowAmbient) {
1897 mShowAmbient = showAmbient;
1898 notifyHeightChanged(false /* needsAnimation */);
1899 }
1900 }
1901
Selim Cinekd127d792016-11-01 19:11:41 -07001902 public void setAboveShelf(boolean aboveShelf) {
1903 mAboveShelf = aboveShelf;
1904 }
1905
Selim Cinek0cfbef42016-11-09 19:06:36 -08001906 public class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08001907
1908 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07001909
Selim Cinekbbcebde2016-11-09 18:28:20 -08001910
1911 private NotificationViewState(StackScrollState stackScrollState) {
1912 mOverallState = stackScrollState;
1913 }
1914
1915 @Override
1916 public void applyToView(View view) {
1917 super.applyToView(view);
1918 if (view instanceof ExpandableNotificationRow) {
1919 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinekbbcebde2016-11-09 18:28:20 -08001920 row.applyChildrenState(mOverallState);
1921 }
1922 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08001923
1924 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08001925 protected void onYTranslationAnimationFinished(View view) {
1926 super.onYTranslationAnimationFinished(view);
Selim Cinek0cfbef42016-11-09 19:06:36 -08001927 if (mHeadsupDisappearRunning) {
Selim Cinekcafa87f2016-10-26 17:00:17 -07001928 setHeadsUpAnimatingAway(false);
Selim Cinek0cfbef42016-11-09 19:06:36 -08001929 }
1930 }
1931
1932 @Override
1933 public void animateTo(View child, AnimationProperties properties) {
1934 super.animateTo(child, properties);
1935 if (child instanceof ExpandableNotificationRow) {
1936 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
1937 row.startChildAnimation(mOverallState, properties);
1938 }
1939 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001940 }
Chris Wren51c75102013-07-16 20:49:17 -04001941}