blob: 3bbaf998cc9af9ac06c7b05b3f4a973f15bd2dc7 [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 Cinek6743c0b2017-01-18 18:24:01 -080025import android.content.res.ColorStateList;
Selim Cinekcab4a602014-09-03 14:47:57 +020026import android.graphics.drawable.AnimatedVectorDrawable;
27import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010028import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020029import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080030import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070031import android.os.Bundle;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020032import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040033import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070034import android.util.FloatProperty;
35import android.util.Property;
Selim Cinek01af3342016-02-09 19:25:31 -080036import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080037import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080038import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050039import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080040import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020041import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020042import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070043import android.view.accessibility.AccessibilityNodeInfo;
Selim Cinek98713a42015-09-21 15:47:20 +020044import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020045import android.widget.ImageView;
Selim Cinekb5605e52015-02-20 18:21:41 +010046
Chris Wren698b1702016-05-23 11:16:32 -040047import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010048import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070049import com.android.internal.util.NotificationColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080050import com.android.internal.widget.CachingIconView;
Selim Cinek0242fbb2016-10-19 13:38:32 -070051import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050052import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070053import com.android.systemui.classifier.FalsingManager;
Mady Mellor87d79452017-01-10 11:52:52 -080054import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
Selim Cinekc897bd32016-03-18 17:32:31 -070055import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinek6743c0b2017-01-18 18:24:01 -080056import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cineka7d4f822016-12-06 14:34:47 -080057import com.android.systemui.statusbar.notification.VisualStabilityManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010058import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050059import com.android.systemui.statusbar.phone.StatusBar;
Selim Cinek31aada42015-12-18 17:51:15 -080060import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek0cfbef42016-11-09 19:06:36 -080061import com.android.systemui.statusbar.stack.AnimationProperties;
62import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010063import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070064import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010065import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010066
Mady Mellor4b80b102016-01-22 08:03:58 -080067import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010068import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050069
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020070public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010071
72 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
73 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Selim Cinek0242fbb2016-10-19 13:38:32 -070074 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -080075 private int mIconTransformContentShiftNoIcon;
Selim Cinek01af3342016-02-09 19:25:31 -080076 private int mNotificationMinHeightLegacy;
77 private int mMaxHeadsUpHeightLegacy;
78 private int mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -080079 private int mMaxHeadsUpHeightIncreased;
Selim Cinek01af3342016-02-09 19:25:31 -080080 private int mNotificationMinHeight;
Selim Cinek7d1009b2017-01-25 15:28:28 -080081 private int mNotificationMinHeightLarge;
Selim Cinek01af3342016-02-09 19:25:31 -080082 private int mNotificationMaxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -080083 private int mNotificationAmbientHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -070084 private int mIncreasedPaddingBetweenElements;
Chris Wren51c75102013-07-16 20:49:17 -040085
Selim Cinek1685e632014-04-08 02:27:49 +020086 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040087 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020088 /** Has the user actively changed the expansion state of this row */
89 private boolean mHasUserChangedExpansion;
90 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040091 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -080092
93 /**
94 * Has this notification been expanded while it was pinned
95 */
96 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +020097 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040098 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020099 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -0500100 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +0200101 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -0800102 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +0200103 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700104 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400105
Selim Cinek1685e632014-04-08 02:27:49 +0200106 /**
107 * Is this notification expanded by the system. The expansion state can be overridden by the
108 * user expansion.
109 */
110 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200111
112 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700113 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200114 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700115 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200116
Mady Mellorb0a82462016-04-30 17:31:02 -0700117 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800118 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200119 private NotificationContentView mPublicLayout;
120 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800121 private NotificationContentView[] mLayouts;
Selim Cinek1685e632014-04-08 02:27:49 +0200122 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700123 private int mHeadsUpHeight;
Selim Cinek4bb59342016-04-08 19:29:35 -0700124 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100125 private ExpansionLogger mLogger;
126 private String mLoggingKey;
Mady Mellor761cde12017-01-10 11:36:39 -0800127 private NotificationMenuRow mMenuRow;
Selim Cinek8d490d42015-04-10 00:05:50 -0700128 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800129 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200130 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700131 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100132 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200133 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100134 private ViewStub mChildrenContainerStub;
135 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100136 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700137 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100138 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor761cde12017-01-10 11:36:39 -0800139 private ViewStub mMenuRowStub;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100140 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100141 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700142 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700143 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800144 private HeadsUpManager mHeadsUpManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200145
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700146 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800147 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700148 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700149 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800150 private OnExpandClickListener mOnExpandClickListener;
Mady Mellorb0a82462016-04-30 17:31:02 -0700151 private boolean mGroupExpansionChanging;
152
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800153 private OnClickListener mExpandClickListener = new OnClickListener() {
154 @Override
155 public void onClick(View v) {
Selim Cinek624c02db2015-12-14 21:00:02 -0800156 if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700157 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400158 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
159 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
160 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400161 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
162 nowExpanded);
163 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800164 } else {
Selim Cineke9bad242016-06-15 11:46:37 -0700165 if (v.isAccessibilityFocused()) {
166 mPrivateLayout.setFocusOnVisibilityChange();
167 }
Selim Cinek31aada42015-12-18 17:51:15 -0800168 boolean nowExpanded;
169 if (isPinned()) {
170 nowExpanded = !mExpandedWhenPinned;
171 mExpandedWhenPinned = nowExpanded;
172 } else {
173 nowExpanded = !isExpanded();
174 setUserExpanded(nowExpanded);
175 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800176 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800177 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400178 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
179 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800180 }
181 }
182 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700183 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700184 private boolean mDismissed;
185 private boolean mKeepInParent;
186 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700187 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
188 new FloatProperty<ExpandableNotificationRow>("translate") {
189 @Override
190 public void setValue(ExpandableNotificationRow object, float value) {
191 object.setTranslation(value);
192 }
193
194 @Override
195 public Float get(ExpandableNotificationRow object) {
196 return object.getTranslation();
197 }
198 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700199 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700200 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700201 private View mChildAfterViewWhenDismissed;
202 private View mGroupParentWhenDismissed;
203 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800204 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700205 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700206 private boolean mAboveShelf;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800207 private boolean mShowAmbient;
Selim Cinek875a3a12016-11-18 17:52:16 -0800208 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800209 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800210 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800211 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800212 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800213 private boolean mUseIncreasedHeadsUpHeight;
Selim Cinekef8c2252017-02-10 14:52:18 -0800214 private float mTranslationWhenRemoved;
215 private boolean mWasChildInGroupWhenRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700216
Mady Mellor43c2cd12016-12-12 21:05:13 -0800217 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700218 public boolean isGroupExpansionChanging() {
219 if (isChildInGroup()) {
220 return mNotificationParent.isGroupExpansionChanging();
221 }
222 return mGroupExpansionChanging;
223 }
224
225 public void setGroupExpansionChanging(boolean changing) {
226 mGroupExpansionChanging = changing;
227 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700228
Adrian Roos599be342016-06-13 14:54:39 -0700229 @Override
230 public void setActualHeightAnimating(boolean animating) {
231 if (mPrivateLayout != null) {
232 mPrivateLayout.setContentHeightAnimating(animating);
233 }
234 }
235
Selim Cinek8d490d42015-04-10 00:05:50 -0700236 public NotificationContentView getPrivateLayout() {
237 return mPrivateLayout;
238 }
239
240 public NotificationContentView getPublicLayout() {
241 return mPublicLayout;
242 }
243
Selim Cinekcab4a602014-09-03 14:47:57 +0200244 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800245 for (NotificationContentView l : mLayouts) {
246 setIconAnimationRunning(running, l);
247 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800248 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700249 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800250 List<ExpandableNotificationRow> notificationChildren =
251 mChildrenContainer.getNotificationChildren();
252 for (int i = 0; i < notificationChildren.size(); i++) {
253 ExpandableNotificationRow child = notificationChildren.get(i);
254 child.setIconAnimationRunning(running);
255 }
256 }
257 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200258 }
259
260 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
261 if (layout != null) {
262 View contractedChild = layout.getContractedChild();
263 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700264 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200265 setIconAnimationRunningForChild(running, contractedChild);
266 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700267 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200268 }
269 }
270
271 private void setIconAnimationRunningForChild(boolean running, View child) {
272 if (child != null) {
273 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
274 setIconRunning(icon, running);
275 ImageView rightIcon = (ImageView) child.findViewById(
276 com.android.internal.R.id.right_icon);
277 setIconRunning(rightIcon, running);
278 }
279 }
280
281 private void setIconRunning(ImageView imageView, boolean running) {
282 if (imageView != null) {
283 Drawable drawable = imageView.getDrawable();
284 if (drawable instanceof AnimationDrawable) {
285 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
286 if (running) {
287 animationDrawable.start();
288 } else {
289 animationDrawable.stop();
290 }
291 } else if (drawable instanceof AnimatedVectorDrawable) {
292 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
293 if (running) {
294 animationDrawable.start();
295 } else {
296 animationDrawable.stop();
297 }
298 }
299 }
300 }
301
Selim Cinekda42d652015-12-04 15:51:16 -0800302 public void onNotificationUpdated(NotificationData.Entry entry) {
303 mEntry = entry;
304 mStatusBarNotification = entry.notification;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800305 for (NotificationContentView l : mLayouts) {
306 l.onNotificationUpdated(entry);
307 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800308 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800309 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700310 updateNotificationColor();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800311 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700312 mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
Selim Cinekc897bd32016-03-18 17:32:31 -0700313 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800314 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800315 if (mIconAnimationRunning) {
316 setIconAnimationRunning(true);
317 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800318 if (mNotificationParent != null) {
319 mNotificationParent.updateChildrenHeaderAppearance();
320 }
Selim Cinek263398f2015-10-21 17:40:23 -0700321 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800322 // The public layouts expand button is always visible
323 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800324 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700325 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800326 updateShelfIconColor();
327 }
328
329 private void updateShelfIconColor() {
330 StatusBarIconView expandedIcon = mEntry.expandedIcon;
331 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
332 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
333 NotificationColorUtil.getInstance(mContext));
334 if (colorize) {
335 int color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded());
336 expandedIcon.setImageTintList(ColorStateList.valueOf(color));
337 }
Selim Cinekda42d652015-12-04 15:51:16 -0800338 }
339
340 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800341 for (NotificationContentView l : mLayouts) {
342 updateLimitsForView(l);
343 }
Selim Cineka1744872016-03-11 15:36:06 -0800344 }
345
346 private void updateLimitsForView(NotificationContentView layout) {
347 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800348 != com.android.internal.R.id.status_bar_latest_event_content;
349 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800350 int minHeight;
351 if (customView && beforeN && !mIsSummaryWithChildren) {
352 minHeight = mNotificationMinHeightLegacy;
353 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
354 minHeight = mNotificationMinHeightLarge;
355 } else {
356 minHeight = mNotificationMinHeight;
357 }
Selim Cineka1744872016-03-11 15:36:06 -0800358 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
359 layout.getHeadsUpChild().getId()
360 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800361 int headsUpheight;
362 if (headsUpCustom && beforeN) {
363 headsUpheight = mMaxHeadsUpHeightLegacy;
364 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
365 headsUpheight = mMaxHeadsUpHeightIncreased;
366 } else {
367 headsUpheight = mMaxHeadsUpHeight;
368 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800369 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
370 mNotificationAmbientHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200371 }
372
373 public StatusBarNotification getStatusBarNotification() {
374 return mStatusBarNotification;
375 }
376
Selim Cinek281c2022016-10-13 19:14:43 -0700377 public NotificationData.Entry getEntry() {
378 return mEntry;
379 }
380
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700381 public boolean isHeadsUp() {
382 return mIsHeadsUp;
383 }
384
Selim Cinek1a521f32014-11-03 17:39:29 +0100385 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700386 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100387 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700388 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700389 if (mIsSummaryWithChildren) {
390 // The overflow might change since we allow more lines as HUN.
391 mChildrenContainer.updateGroupOverflow();
392 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700393 if (intrinsicBefore != getIntrinsicHeight()) {
394 notifyHeightChanged(false /* needsAnimation */);
395 }
Selim Cinekd127d792016-11-01 19:11:41 -0700396 if (isHeadsUp) {
397 setAboveShelf(true);
398 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100399 }
400
Selim Cinekb5605e52015-02-20 18:21:41 +0100401 public void setGroupManager(NotificationGroupManager groupManager) {
402 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700403 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100404 }
405
Adrian Roosb88b1a12015-12-09 18:51:05 -0800406 public void setRemoteInputController(RemoteInputController r) {
407 mPrivateLayout.setRemoteInputController(r);
408 }
409
Mady Mellor3fd273e2016-03-15 21:08:14 -0700410 public void setAppName(String appName) {
411 mAppName = appName;
Mady Mellor761cde12017-01-10 11:36:39 -0800412 if (mMenuRow != null) {
413 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700414 }
415 }
416
Selim Cinekb5605e52015-02-20 18:21:41 +0100417 public void addChildNotification(ExpandableNotificationRow row) {
418 addChildNotification(row, -1);
419 }
420
421 /**
422 * Add a child notification to this view.
423 *
424 * @param row the row to add
425 * @param childIndex the index to add it at, if -1 it will be added at the end
426 */
427 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
428 if (mChildrenContainer == null) {
429 mChildrenContainerStub.inflate();
430 }
431 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700432 onChildrenCountChanged();
433 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100434 }
435
436 public void removeChildNotification(ExpandableNotificationRow row) {
437 if (mChildrenContainer != null) {
438 mChildrenContainer.removeNotification(row);
439 }
Selim Cinek263398f2015-10-21 17:40:23 -0700440 onChildrenCountChanged();
441 row.setIsChildInGroup(false, null);
442 }
443
Mady Mellor43c2cd12016-12-12 21:05:13 -0800444 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700445 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700446 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700447 }
448
Selim Cinek388df6d2015-10-22 13:25:11 -0700449 public ExpandableNotificationRow getNotificationParent() {
450 return mNotificationParent;
451 }
452
Selim Cinek263398f2015-10-21 17:40:23 -0700453 /**
454 * @param isChildInGroup Is this notification now in a group
455 * @param parent the new parent notification
456 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700457 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500458 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700459 mNotificationParent = childInGroup ? parent : null;
460 mPrivateLayout.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400461 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700462 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700463 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700464 if (mNotificationParent != null) {
465 mNotificationParent.updateBackgroundForGroupState();
466 }
Selim Cinekdb167372016-11-17 15:41:17 -0800467 updateIconVisibilities();
Selim Cinek34d93b02015-10-22 12:30:38 -0700468 }
469
470 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800471 public boolean onTouchEvent(MotionEvent event) {
472 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
473 || !isChildInGroup() || isGroupExpanded()) {
474 return super.onTouchEvent(event);
475 } else {
476 return false;
477 }
478 }
479
480 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800481 protected boolean handleSlideBack() {
Mady Mellor761cde12017-01-10 11:36:39 -0800482 if (mMenuRow != null && mMenuRow.isVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800483 animateTranslateNotification(0 /* targetLeft */);
484 return true;
485 }
486 return false;
487 }
488
489 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700490 protected boolean shouldHideBackground() {
491 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700492 }
493
494 @Override
495 public boolean isSummaryWithChildren() {
496 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100497 }
498
499 @Override
500 public boolean areChildrenExpanded() {
501 return mChildrenExpanded;
502 }
503
504 public List<ExpandableNotificationRow> getNotificationChildren() {
505 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
506 }
507
Selim Cinekeef84282015-10-30 16:28:00 -0700508 public int getNumberOfNotificationChildren() {
509 if (mChildrenContainer == null) {
510 return 0;
511 }
512 return mChildrenContainer.getNotificationChildren().size();
513 }
514
Selim Cinekb5605e52015-02-20 18:21:41 +0100515 /**
516 * Apply the order given in the list to the children.
517 *
518 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800519 * @param visualStabilityManager
520 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100521 * @return whether the list order has changed
522 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800523 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
524 VisualStabilityManager visualStabilityManager,
525 VisualStabilityManager.Callback callback) {
526 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
527 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100528 }
529
530 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700531 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800532 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100533 mChildrenContainer.getState(resultState, parentState);
534 }
535 }
536
537 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700538 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100539 mChildrenContainer.applyState(state);
540 }
541 }
542
543 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700544 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100545 mChildrenContainer.prepareExpansionChanged(state);
546 }
547 }
548
Selim Cinek0cfbef42016-11-09 19:06:36 -0800549 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700550 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800551 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100552 }
553 }
554
555 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800556 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100557 return this;
558 } else {
559 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
560 return view == null ? this : view;
561 }
562 }
563
Selim Cinekab29aeb2015-02-20 18:18:32 +0100564 public NotificationGuts getGuts() {
565 return mGuts;
566 }
567
Selim Cinek684a4422015-04-15 16:18:39 -0700568 /**
569 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
570 * the notification will be rendered on top of the screen.
571 *
572 * @param pinned whether it is pinned
573 */
574 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700575 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700576 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700577 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700578 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700579 }
Selim Cinek31aada42015-12-18 17:51:15 -0800580 if (pinned) {
581 setIconAnimationRunning(true);
582 mExpandedWhenPinned = false;
583 } else if (mExpandedWhenPinned) {
584 setUserExpanded(true);
585 }
Selim Cinek98713a42015-09-21 15:47:20 +0200586 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700587 }
588
Selim Cinek684a4422015-04-15 16:18:39 -0700589 public boolean isPinned() {
590 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700591 }
592
Selim Cinekd127d792016-11-01 19:11:41 -0700593 @Override
594 public int getPinnedHeadsUpHeight() {
595 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
596 }
597
Selim Cinek31aada42015-12-18 17:51:15 -0800598 /**
599 * @param atLeastMinHeight should the value returned be at least the minimum height.
600 * Used to avoid cyclic calls
601 * @return the height of the heads up notification when pinned
602 */
Selim Cinekd127d792016-11-01 19:11:41 -0700603 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800604 if (mIsSummaryWithChildren) {
605 return mChildrenContainer.getIntrinsicHeight();
606 }
Selim Cinek31aada42015-12-18 17:51:15 -0800607 if(mExpandedWhenPinned) {
608 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
609 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700610 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800611 } else {
612 return mHeadsUpHeight;
613 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700614 }
615
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700616 /**
617 * Mark whether this notification was just clicked, i.e. the user has just clicked this
618 * notification in this frame.
619 */
620 public void setJustClicked(boolean justClicked) {
621 mJustClicked = justClicked;
622 }
623
624 /**
625 * @return true if this notification has been clicked in this frame, false otherwise
626 */
627 public boolean wasJustClicked() {
628 return mJustClicked;
629 }
630
Selim Cinek98713a42015-09-21 15:47:20 +0200631 public void setChronometerRunning(boolean running) {
632 mLastChronometerRunning = running;
633 setChronometerRunning(running, mPrivateLayout);
634 setChronometerRunning(running, mPublicLayout);
635 if (mChildrenContainer != null) {
636 List<ExpandableNotificationRow> notificationChildren =
637 mChildrenContainer.getNotificationChildren();
638 for (int i = 0; i < notificationChildren.size(); i++) {
639 ExpandableNotificationRow child = notificationChildren.get(i);
640 child.setChronometerRunning(running);
641 }
642 }
643 }
644
645 private void setChronometerRunning(boolean running, NotificationContentView layout) {
646 if (layout != null) {
647 running = running || isPinned();
648 View contractedChild = layout.getContractedChild();
649 View expandedChild = layout.getExpandedChild();
650 View headsUpChild = layout.getHeadsUpChild();
651 setChronometerRunningForChild(running, contractedChild);
652 setChronometerRunningForChild(running, expandedChild);
653 setChronometerRunningForChild(running, headsUpChild);
654 }
655 }
656
657 private void setChronometerRunningForChild(boolean running, View child) {
658 if (child != null) {
659 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
660 if (chronometer instanceof Chronometer) {
661 ((Chronometer) chronometer).setStarted(running);
662 }
663 }
664 }
665
Selim Cinekea4bef72015-12-02 15:51:10 -0800666 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700667 if (mIsSummaryWithChildren) {
668 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700669 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800670 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700671 }
672
Selim Cinek34eda5e2016-02-18 17:10:43 -0800673 private NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700674 if (mIsSummaryWithChildren && !mShowingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700675 return mChildrenContainer.getHeaderView();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800676 }
677 return getShowingLayout().getVisibleNotificationHeader();
678 }
679
Selim Cinek570981d2015-12-01 11:37:01 -0800680 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
681 mOnExpandClickListener = onExpandClickListener;
682 }
683
Selim Cinekddf1b392016-05-27 16:33:10 -0700684 @Override
685 public void setOnClickListener(@Nullable OnClickListener l) {
686 super.setOnClickListener(l);
687 mOnClickListener = l;
688 updateClickAndFocus();
689 }
690
691 private void updateClickAndFocus() {
692 boolean normalChild = !isChildInGroup() || isGroupExpanded();
693 boolean clickable = mOnClickListener != null && normalChild;
694 if (isFocusable() != normalChild) {
695 setFocusable(normalChild);
696 }
697 if (isClickable() != clickable) {
698 setClickable(clickable);
699 }
700 }
701
Selim Cinek31aada42015-12-18 17:51:15 -0800702 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
703 mHeadsUpManager = headsUpManager;
704 }
705
Mady Mellor87d79452017-01-10 11:52:52 -0800706 public void setGutsView(MenuItem item) {
707 if (mGuts != null) {
708 item.gutsContent.setInteractionListener(mGuts);
709 mGuts.setGutsContent(item.gutsContent);
710 }
711 }
712
Selim Cinek01af3342016-02-09 19:25:31 -0800713 public void reInflateViews() {
714 initDimens();
715 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800716 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700717 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800718 }
719 }
720 if (mGuts != null) {
721 View oldGuts = mGuts;
722 int index = indexOfChild(oldGuts);
723 removeView(oldGuts);
724 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
725 R.layout.notification_guts, this, false);
726 mGuts.setVisibility(oldGuts.getVisibility());
727 addView(mGuts, index);
728 }
Mady Mellor761cde12017-01-10 11:36:39 -0800729 if (mMenuRow != null) {
730 View oldMenu = mMenuRow;
731 int menuIndex = indexOfChild(oldMenu);
732 removeView(oldMenu);
733 mMenuRow = (NotificationMenuRow) LayoutInflater.from(mContext).inflate(
734 R.layout.notification_menu_row, this, false);
735 mMenuRow.setNotificationRowParent(ExpandableNotificationRow.this);
736 mMenuRow.setAppName(mAppName);
737 mMenuRow.setVisibility(oldMenu.getVisibility());
738 addView(mMenuRow, menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -0800739
740 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800741 for (NotificationContentView l : mLayouts) {
742 l.reInflateViews();
743 }
Selim Cinek01af3342016-02-09 19:25:31 -0800744 }
745
Selim Cinekc3179332016-03-04 14:44:56 -0800746 public void setContentBackground(int customBackgroundColor, boolean animate,
747 NotificationContentView notificationContentView) {
748 if (getShowingLayout() == notificationContentView) {
749 setTintColor(customBackgroundColor, animate);
750 }
751 }
752
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700753 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800754 for (NotificationContentView l : mLayouts) {
755 l.closeRemoteInput();
756 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700757 }
758
Selim Cinekc897bd32016-03-18 17:32:31 -0700759 /**
760 * Set by how much the single line view should be indented.
761 */
762 public void setSingleLineWidthIndention(int indention) {
763 mPrivateLayout.setSingleLineWidthIndention(indention);
764 }
765
766 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700767 return mNotificationColor;
768 }
769
770 private void updateNotificationColor() {
771 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
772 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700773 }
774
775 public HybridNotificationView getSingleLineView() {
776 return mPrivateLayout.getSingleLineView();
777 }
778
Selim Cinekf07d0622016-03-21 19:52:52 -0700779 public boolean isOnKeyguard() {
780 return mOnKeyguard;
781 }
782
Selim Cinekc1e389d2016-04-07 11:02:57 -0700783 public void removeAllChildren() {
784 List<ExpandableNotificationRow> notificationChildren
785 = mChildrenContainer.getNotificationChildren();
786 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
787 for (int i = 0; i < clonedList.size(); i++) {
788 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700789 if (row.keepInParent()) {
790 continue;
791 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700792 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700793 row.setIsChildInGroup(false, null);
794 }
795 onChildrenCountChanged();
796 }
797
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700798 public void setForceUnlocked(boolean forceUnlocked) {
799 mForceUnlocked = forceUnlocked;
800 if (mIsSummaryWithChildren) {
801 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
802 for (ExpandableNotificationRow child : notificationChildren) {
803 child.setForceUnlocked(forceUnlocked);
804 }
805 }
806 }
807
Selim Cineke9bad242016-06-15 11:46:37 -0700808 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700809 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700810 mGroupParentWhenDismissed = mNotificationParent;
811 mRefocusOnDismiss = fromAccessibility;
812 mChildAfterViewWhenDismissed = null;
813 if (isChildInGroup()) {
814 List<ExpandableNotificationRow> notificationChildren =
815 mNotificationParent.getNotificationChildren();
816 int i = notificationChildren.indexOf(this);
817 if (i != -1 && i < notificationChildren.size() - 1) {
818 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
819 }
820 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700821 }
822
823 public boolean isDismissed() {
824 return mDismissed;
825 }
826
827 public boolean keepInParent() {
828 return mKeepInParent;
829 }
830
831 public void setKeepInParent(boolean keepInParent) {
832 mKeepInParent = keepInParent;
833 }
834
835 public boolean isRemoved() {
836 return mRemoved;
837 }
838
Adrian Roosd009ab12016-05-20 17:58:53 -0700839 public void setRemoved() {
840 mRemoved = true;
Selim Cinekef8c2252017-02-10 14:52:18 -0800841 mTranslationWhenRemoved = getTranslationY();
842 mWasChildInGroupWhenRemoved = isChildInGroup();
843 if (isChildInGroup()) {
844 mTranslationWhenRemoved += getNotificationParent().getTranslationY();
845 }
Adrian Roosd009ab12016-05-20 17:58:53 -0700846 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700847 }
848
Selim Cinekef8c2252017-02-10 14:52:18 -0800849 public boolean wasChildInGroupWhenRemoved() {
850 return mWasChildInGroupWhenRemoved;
851 }
852
853 public float getTranslationWhenRemoved() {
854 return mTranslationWhenRemoved;
855 }
856
Selim Cinekd1395642016-04-28 12:22:42 -0700857 public NotificationChildrenContainer getChildrenContainer() {
858 return mChildrenContainer;
859 }
860
Selim Cinekcafa87f2016-10-26 17:00:17 -0700861 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
862 mHeadsupDisappearRunning = headsUpAnimatingAway;
863 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
864 }
865
866 /**
867 * @return if the view was just heads upped and is now animating away. During such a time the
868 * layout needs to be kept consistent
869 */
870 public boolean isHeadsUpAnimatingAway() {
871 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700872 }
873
Selim Cineke9bad242016-06-15 11:46:37 -0700874 public View getChildAfterViewWhenDismissed() {
875 return mChildAfterViewWhenDismissed;
876 }
877
878 public View getGroupParentWhenDismissed() {
879 return mGroupParentWhenDismissed;
880 }
881
Selim Cinek9e624e72016-07-20 13:46:49 -0700882 public void performDismiss() {
Selim Cineke9079112016-12-14 14:41:01 -0800883 if (mOnDismissRunnable != null) {
884 mOnDismissRunnable.run();
885 }
Selim Cinek9e624e72016-07-20 13:46:49 -0700886 }
887
Selim Cineke9079112016-12-14 14:41:01 -0800888 public void setOnDismissRunnable(Runnable onDismissRunnable) {
889 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -0700890 }
891
Selim Cinek281c2022016-10-13 19:14:43 -0700892 public View getNotificationIcon() {
893 NotificationHeaderView notificationHeader = getNotificationHeader();
894 if (notificationHeader != null) {
895 return notificationHeader.getIcon();
896 }
897 return null;
898 }
899
900 /**
901 * @return whether the notification is currently showing a view with an icon.
902 */
903 public boolean isShowingIcon() {
904 if (mIsSummaryWithChildren) {
905 return true;
906 }
907 NotificationContentView showingLayout = getShowingLayout();
908 NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
909 return notificationHeader != null;
910 }
911
Selim Cinek0242fbb2016-10-19 13:38:32 -0700912 /**
913 * Set how much this notification is transformed into an icon.
914 *
Selim Cinek2b549f42016-11-22 16:38:51 -0800915 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
916 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -0800917 * @param isLastChild is this the last child in the list. If true, then the transformation is
918 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -0700919 */
Selim Cinek2b549f42016-11-22 16:38:51 -0800920 public void setContentTransformationAmount(float contentTransformationAmount,
921 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -0800922 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800923 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800924 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800925 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800926 if (changeTransformation) {
927 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -0800928 }
929 }
930
931 /**
932 * Set the icons to be visible of this notification.
933 */
934 public void setIconsVisible(boolean iconsVisible) {
935 if (iconsVisible != mIconsVisible) {
936 mIconsVisible = iconsVisible;
937 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700938 }
939 }
940
Selim Cinekdb167372016-11-17 15:41:17 -0800941 @Override
942 protected void onBelowSpeedBumpChanged() {
943 updateIconVisibilities();
944 }
945
Selim Cinek875a3a12016-11-18 17:52:16 -0800946 private void updateContentTransformation() {
947 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -0800948 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800949 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -0800950 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800951 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700952 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -0800953 translationY *= 0.4f;
954 } else {
955 contentAlpha = 1.0f;
956 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800957 for (NotificationContentView l : mLayouts) {
958 l.setAlpha(contentAlpha);
959 l.setTranslationY(translationY);
960 }
Selim Cinek875a3a12016-11-18 17:52:16 -0800961 if (mChildrenContainer != null) {
962 mChildrenContainer.setAlpha(contentAlpha);
963 mChildrenContainer.setTranslationY(translationY);
964 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -0700965 }
966 }
967
968 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -0800969 boolean visible = isChildInGroup()
970 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
971 || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800972 for (NotificationContentView l : mLayouts) {
973 l.setIconsVisible(visible);
974 }
Selim Cinekdb167372016-11-17 15:41:17 -0800975 if (mChildrenContainer != null) {
976 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700977 }
978 }
979
Selim Cinek875a3a12016-11-18 17:52:16 -0800980 /**
981 * Get the relative top padding of a view relative to this view. This recursively walks up the
982 * hierarchy and does the corresponding measuring.
983 *
984 * @param view the view to the the padding for. The requested view has to be a child of this
985 * notification.
986 * @return the toppadding
987 */
988 public int getRelativeTopPadding(View view) {
989 int topPadding = 0;
990 while (view.getParent() instanceof ViewGroup) {
991 topPadding += view.getTop();
992 view = (View) view.getParent();
993 if (view instanceof ExpandableNotificationRow) {
994 return topPadding;
995 }
996 }
997 return topPadding;
998 }
999
Selim Cineka1d97902016-12-14 16:31:40 -08001000 public float getContentTranslation() {
1001 return mPrivateLayout.getTranslationY();
1002 }
1003
Selim Cinek6743c0b2017-01-18 18:24:01 -08001004 public void setIsLowPriority(boolean isLowPriority) {
1005 mIsLowPriority = isLowPriority;
1006 mPrivateLayout.setIsLowPriority(isLowPriority);
1007 if (mChildrenContainer != null) {
1008 mChildrenContainer.setIsLowPriority(isLowPriority);
1009 }
1010 }
1011
Selim Cinek7d1009b2017-01-25 15:28:28 -08001012 public void setUseIncreasedCollapsedHeight(boolean use) {
1013 mUseIncreasedCollapsedHeight = use;
1014 }
1015
Selim Cinek87ed69b2017-02-09 15:59:43 -08001016 public void setUseIncreasedHeadsUpHeight(boolean use) {
1017 mUseIncreasedHeadsUpHeight = use;
1018 }
1019
Chris Wren78403d72014-07-28 10:23:24 +01001020 public interface ExpansionLogger {
1021 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
1022 }
Selim Cinek1685e632014-04-08 02:27:49 +02001023
Chris Wren51c75102013-07-16 20:49:17 -04001024 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1025 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001026 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -08001027 initDimens();
1028 }
1029
1030 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -08001031 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
1032 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001033 mNotificationMinHeightLarge = getFontScaledHeight(
Selim Cinek87ed69b2017-02-09 15:59:43 -08001034 R.dimen.notification_min_height_increased);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001035 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
Adrian Roos0aac04f2016-12-08 15:59:29 -08001036 mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001037 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -08001038 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001039 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001040 mMaxHeadsUpHeightIncreased = getFontScaledHeight(
1041 R.dimen.notification_max_heads_up_height_increased);
Mady Mellorb0a82462016-04-30 17:31:02 -07001042 mIncreasedPaddingBetweenElements = getResources()
1043 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinek875a3a12016-11-18 17:52:16 -08001044 mIconTransformContentShiftNoIcon = getResources().getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001045 R.dimen.notification_icon_transform_content_shift);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001046 }
1047
1048 /**
1049 * @param dimenId the dimen to look up
1050 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
1051 */
1052 private int getFontScaledHeight(int dimenId) {
1053 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
1054 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
1055 getResources().getDisplayMetrics().density);
1056 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -04001057 }
1058
Christoph Studera7fe6312014-06-27 19:32:44 +02001059 /**
1060 * Resets this view so it can be re-used for an updated notification.
1061 */
Christoph Studer22f2ee52014-07-29 22:57:21 +02001062 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +02001063 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +02001064 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +01001065 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +02001066 mExpandable = false;
1067 mHasUserChangedExpansion = false;
1068 mUserLocked = false;
1069 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +02001070 mSensitive = false;
1071 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +02001072 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -07001073 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -08001074 mPublicLayout.reset();
1075 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +02001076 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -08001077 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +02001078 logExpansionEvent(false, wasExpanded);
1079 }
1080
1081 public void resetHeight() {
Selim Cinek31094df2014-08-14 19:28:15 +02001082 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001083 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001084 }
1085
Jorim Jaggi251957d2014-04-09 04:24:09 +02001086 @Override
1087 protected void onFinishInflate() {
1088 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001089 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1090 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001091 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1092
1093 for (NotificationContentView l : mLayouts) {
1094 l.setExpandClickListener(mExpandClickListener);
1095 l.setContainingNotification(this);
1096 }
Mady Mellor761cde12017-01-10 11:36:39 -08001097 mMenuRowStub = (ViewStub) findViewById(R.id.menu_row_stub);
1098 mMenuRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Mady Mellor4b80b102016-01-22 08:03:58 -08001099 @Override
1100 public void onInflate(ViewStub stub, View inflated) {
Mady Mellor761cde12017-01-10 11:36:39 -08001101 mMenuRow = (NotificationMenuRow) inflated;
1102 mMenuRow.setNotificationRowParent(ExpandableNotificationRow.this);
1103 mMenuRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -08001104 }
1105 });
Selim Cinekab29aeb2015-02-20 18:18:32 +01001106 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1107 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001108 @Override
1109 public void onInflate(ViewStub stub, View inflated) {
1110 mGuts = (NotificationGuts) inflated;
1111 mGuts.setClipTopAmount(getClipTopAmount());
1112 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001113 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001114 }
1115 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001116 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1117 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1118
1119 @Override
1120 public void onInflate(ViewStub stub, View inflated) {
1121 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001122 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek388df6d2015-10-22 13:25:11 -07001123 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001124 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -08001125 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +01001126 }
1127 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001128
1129 // Add the views that we translate to reveal the gear
1130 mTranslateableViews = new ArrayList<View>();
1131 for (int i = 0; i < getChildCount(); i++) {
1132 mTranslateableViews.add(getChildAt(i));
1133 }
1134 // Remove views that don't translate
Mady Mellor761cde12017-01-10 11:36:39 -08001135 mTranslateableViews.remove(mMenuRowStub);
Mady Mellor4b80b102016-01-22 08:03:58 -08001136 mTranslateableViews.remove(mChildrenContainerStub);
1137 mTranslateableViews.remove(mGutsStub);
1138 }
1139
Mady Mellor4b80b102016-01-22 08:03:58 -08001140 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001141 if (mTranslateAnim != null) {
1142 mTranslateAnim.cancel();
1143 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001144 if (mTranslateableViews != null) {
1145 for (int i = 0; i < mTranslateableViews.size(); i++) {
1146 mTranslateableViews.get(i).setTranslationX(0);
1147 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001148 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001149 invalidateOutline();
Mady Mellor761cde12017-01-10 11:36:39 -08001150 if (mMenuRow != null) {
1151 mMenuRow.resetState(true /* notify */);
Mady Mellor4b80b102016-01-22 08:03:58 -08001152 }
1153 }
1154
1155 public void animateTranslateNotification(final float leftTarget) {
1156 if (mTranslateAnim != null) {
1157 mTranslateAnim.cancel();
1158 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001159 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001160 if (mTranslateAnim != null) {
1161 mTranslateAnim.start();
1162 }
1163 }
1164
1165 @Override
1166 public void setTranslation(float translationX) {
1167 if (areGutsExposed()) {
1168 // Don't translate if guts are showing.
1169 return;
1170 }
1171 // Translate the group of views
1172 for (int i = 0; i < mTranslateableViews.size(); i++) {
1173 if (mTranslateableViews.get(i) != null) {
1174 mTranslateableViews.get(i).setTranslationX(translationX);
1175 }
1176 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001177 invalidateOutline();
Mady Mellor761cde12017-01-10 11:36:39 -08001178 if (mMenuRow != null) {
1179 mMenuRow.updateMenuAlpha(translationX, getMeasuredWidth());
Mady Mellor34958fa2016-02-23 09:52:17 -08001180 }
1181 }
1182
1183 @Override
1184 public float getTranslation() {
1185 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1186 // All of the views in the list should have same translation, just use first one.
1187 return mTranslateableViews.get(0).getTranslationX();
1188 }
1189 return 0;
1190 }
1191
1192 public Animator getTranslateViewAnimator(final float leftTarget,
1193 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001194 if (mTranslateAnim != null) {
1195 mTranslateAnim.cancel();
1196 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001197 if (areGutsExposed()) {
1198 // No translation if guts are exposed.
1199 return null;
1200 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001201 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1202 leftTarget);
1203 if (listener != null) {
1204 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001205 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001206 translateAnim.addListener(new AnimatorListenerAdapter() {
1207 boolean cancelled = false;
1208
1209 @Override
1210 public void onAnimationCancel(Animator anim) {
1211 cancelled = true;
1212 }
1213
1214 @Override
1215 public void onAnimationEnd(Animator anim) {
Mady Mellor761cde12017-01-10 11:36:39 -08001216 if (!cancelled && mMenuRow != null && leftTarget == 0) {
1217 mMenuRow.resetState(true /* notify */);
Mady Mellorb0a82462016-04-30 17:31:02 -07001218 mTranslateAnim = null;
1219 }
1220 }
1221 });
1222 mTranslateAnim = translateAnim;
1223 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001224 }
1225
1226 public float getSpaceForGear() {
Mady Mellor761cde12017-01-10 11:36:39 -08001227 if (mMenuRow != null) {
1228 return mMenuRow.getSpaceForMenu();
Mady Mellor4b80b102016-01-22 08:03:58 -08001229 }
1230 return 0;
1231 }
1232
Mady Mellor761cde12017-01-10 11:36:39 -08001233 public NotificationMenuRow getSettingsRow() {
1234 if (mMenuRow == null) {
1235 mMenuRowStub.inflate();
Mady Mellor4b80b102016-01-22 08:03:58 -08001236 }
Mady Mellor761cde12017-01-10 11:36:39 -08001237 return mMenuRow;
Mady Mellor4b80b102016-01-22 08:03:58 -08001238 }
1239
Selim Cinekab29aeb2015-02-20 18:18:32 +01001240 public void inflateGuts() {
1241 if (mGuts == null) {
1242 mGutsStub.inflate();
1243 }
1244 }
1245
Selim Cinekda42d652015-12-04 15:51:16 -08001246 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001247 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1248 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001249 if (mChildrenContainer != null) {
1250 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1251 : INVISIBLE);
Mady Mellorb0a82462016-04-30 17:31:02 -07001252 mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
1253 ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001254 : INVISIBLE);
1255 }
Selim Cinekda42d652015-12-04 15:51:16 -08001256 // The limits might have changed if the view suddenly became a group or vice versa
1257 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001258 }
1259
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001260 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001261 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1262 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001263 // Add a record for the entire layout since its content is somehow small.
1264 // The event comes from a leaf view that is interacted with.
1265 AccessibilityEvent record = AccessibilityEvent.obtain();
1266 onInitializeAccessibilityEvent(record);
1267 dispatchPopulateAccessibilityEvent(record);
1268 event.appendRecord(record);
1269 return true;
1270 }
1271 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001272 }
Chris Wren51c75102013-07-16 20:49:17 -04001273
John Spurlocke15452b2014-08-21 09:44:39 -04001274 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001275 public void setDark(boolean dark, boolean fade, long delay) {
1276 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001277 final NotificationContentView showing = getShowingLayout();
1278 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001279 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001280 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001281 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001282 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001283 }
John Spurlocke15452b2014-08-21 09:44:39 -04001284 }
1285
Chris Wren51c75102013-07-16 20:49:17 -04001286 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001287 if (mIsSummaryWithChildren && !mShowingPublic) {
1288 return !mChildrenExpanded;
1289 }
Chris Wren51c75102013-07-16 20:49:17 -04001290 return mExpandable;
1291 }
1292
1293 public void setExpandable(boolean expandable) {
1294 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001295 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001296 }
1297
Selim Cinek4ffd6362015-12-29 15:12:23 +01001298 @Override
1299 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001300 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1301 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001302 }
1303
Selim Cinek1685e632014-04-08 02:27:49 +02001304 /**
1305 * @return whether the user has changed the expansion state
1306 */
1307 public boolean hasUserChangedExpansion() {
1308 return mHasUserChangedExpansion;
1309 }
1310
Chris Wren51c75102013-07-16 20:49:17 -04001311 public boolean isUserExpanded() {
1312 return mUserExpanded;
1313 }
1314
Selim Cinek1685e632014-04-08 02:27:49 +02001315 /**
1316 * Set this notification to be expanded by the user
1317 *
1318 * @param userExpanded whether the user wants this notification to be expanded
1319 */
Chris Wren51c75102013-07-16 20:49:17 -04001320 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001321 setUserExpanded(userExpanded, false /* allowChildExpansion */);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001322 updateShelfIconColor();
Selim Cinek388df6d2015-10-22 13:25:11 -07001323 }
1324
1325 /**
1326 * Set this notification to be expanded by the user
1327 *
1328 * @param userExpanded whether the user wants this notification to be expanded
1329 * @param allowChildExpansion whether a call to this method allows expanding children
1330 */
1331 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001332 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -07001333 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
Chris Wren698b1702016-05-23 11:16:32 -04001334 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001335 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Chris Wren698b1702016-05-23 11:16:32 -04001336 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001337 return;
1338 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001339 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001340 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001341 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001342 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001343 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001344 }
1345
Selim Cinekccd14fb2014-08-12 18:53:24 +02001346 public void resetUserExpansion() {
1347 mHasUserChangedExpansion = false;
1348 mUserExpanded = false;
1349 }
1350
Chris Wren51c75102013-07-16 20:49:17 -04001351 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001352 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001353 }
1354
1355 public void setUserLocked(boolean userLocked) {
1356 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001357 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001358 if (mIsSummaryWithChildren) {
1359 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek7baaa9e2016-07-21 17:21:09 -07001360 if (userLocked || !isGroupExpanded()) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001361 updateBackgroundForGroupState();
1362 }
Selim Cinek42357e02016-02-24 18:48:01 -08001363 }
Chris Wren51c75102013-07-16 20:49:17 -04001364 }
1365
Selim Cinek1685e632014-04-08 02:27:49 +02001366 /**
1367 * @return has the system set this notification to be expanded
1368 */
1369 public boolean isSystemExpanded() {
1370 return mIsSystemExpanded;
1371 }
1372
1373 /**
1374 * Set this notification to be expanded by the system.
1375 *
1376 * @param expand whether the system wants this notification to be expanded.
1377 */
1378 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001379 if (expand != mIsSystemExpanded) {
1380 final boolean wasExpanded = isExpanded();
1381 mIsSystemExpanded = expand;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001382 updateShelfIconColor();
Selim Cinekb5605e52015-02-20 18:21:41 +01001383 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001384 logExpansionEvent(false, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001385 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001386 mChildrenContainer.updateGroupOverflow();
1387 }
Selim Cinek31094df2014-08-14 19:28:15 +02001388 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001389 }
1390
1391 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001392 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001393 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001394 public void setOnKeyguard(boolean onKeyguard) {
1395 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001396 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001397 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001398 logExpansionEvent(false, wasExpanded);
1399 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001400 if (mIsSummaryWithChildren) {
1401 mChildrenContainer.updateGroupOverflow();
1402 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001403 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001404 }
1405 }
Selim Cinek1685e632014-04-08 02:27:49 +02001406 }
1407
1408 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001409 * @return Can the underlying notification be cleared? This can be different from whether the
1410 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1411 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001412 */
1413 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001414 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1415 return false;
1416 }
1417 if (mIsSummaryWithChildren) {
1418 List<ExpandableNotificationRow> notificationChildren =
1419 mChildrenContainer.getNotificationChildren();
1420 for (int i = 0; i < notificationChildren.size(); i++) {
1421 ExpandableNotificationRow child = notificationChildren.get(i);
1422 if (!child.isClearable()) {
1423 return false;
1424 }
1425 }
1426 }
1427 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001428 }
1429
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001430 @Override
1431 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001432 if (isUserLocked()) {
1433 return getActualHeight();
1434 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001435 if (mGuts != null && mGuts.isExposed()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001436 return mGuts.getHeight();
1437 } else if ((isChildInGroup() && !isGroupExpanded())) {
1438 return mPrivateLayout.getMinHeight();
Adrian Roos0aac04f2016-12-08 15:59:29 -08001439 } else if (mShowAmbient) {
1440 return getAmbientHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001441 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1442 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001443 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001444 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001445 } else if (!mOnKeyguard && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07001446 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001447 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1448 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001449 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001450 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001451 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001452 }
Selim Cinek31aada42015-12-18 17:51:15 -08001453 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001454 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001455 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001456 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001457 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001458 }
Selim Cinek1685e632014-04-08 02:27:49 +02001459
Mady Mellor43c2cd12016-12-12 21:05:13 -08001460 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001461 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001462 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001463 }
1464
Selim Cinek263398f2015-10-21 17:40:23 -07001465 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05001466 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001467 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1468 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
1469 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
1470 mEntry.notification);
Selim Cinek263398f2015-10-21 17:40:23 -07001471 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001472 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001473 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001474 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001475 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001476 }
1477
Mady Mellorb0a82462016-04-30 17:31:02 -07001478 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001479 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001480 mChildrenContainer.updateChildrenHeaderAppearance();
1481 }
1482 }
1483
Selim Cinek1685e632014-04-08 02:27:49 +02001484 /**
1485 * Check whether the view state is currently expanded. This is given by the system in {@link
1486 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1487 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1488 * view can differ from this state, if layout params are modified from outside.
1489 *
1490 * @return whether the view state is currently expanded.
1491 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001492 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001493 return isExpanded(false /* allowOnKeyguard */);
1494 }
1495
1496 public boolean isExpanded(boolean allowOnKeyguard) {
1497 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001498 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1499 || isUserExpanded());
1500 }
1501
1502 private boolean isSystemChildExpanded() {
1503 return mIsSystemChildExpanded;
1504 }
1505
1506 public void setSystemChildExpanded(boolean expanded) {
1507 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001508 }
1509
1510 @Override
1511 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1512 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001513 updateMaxHeights();
Mady Mellor761cde12017-01-10 11:36:39 -08001514 if (mMenuRow != null) {
1515 mMenuRow.updateVerticalLocation();
Mady Mellora6edc872016-04-26 11:01:03 -07001516 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001517 updateContentShiftHeight();
1518 }
1519
1520 /**
1521 * Updates the content shift height such that the header is completely hidden when coming from
1522 * the top.
1523 */
1524 private void updateContentShiftHeight() {
1525 NotificationHeaderView notificationHeader = getNotificationHeader();
1526 if (notificationHeader != null) {
1527 CachingIconView icon = notificationHeader.getIcon();
1528 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1529 } else {
1530 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1531 }
Selim Cinek1685e632014-04-08 02:27:49 +02001532 }
1533
Selim Cinek8d490d42015-04-10 00:05:50 -07001534 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001535 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001536 View expandedChild = mPrivateLayout.getExpandedChild();
1537 if (expandedChild == null) {
1538 expandedChild = mPrivateLayout.getContractedChild();
1539 }
1540 mMaxExpandHeight = expandedChild.getHeight();
1541 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001542 if (headsUpChild == null) {
1543 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001544 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001545 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001546 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001547 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001548 }
1549 }
1550
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001551 @Override
1552 public void notifyHeightChanged(boolean needsAnimation) {
1553 super.notifyHeightChanged(needsAnimation);
1554 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1555 }
1556
Selim Cinek3c76d502016-02-19 15:16:33 -08001557 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001558 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001559 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001560 }
1561
Mady Mellor43c2cd12016-12-12 21:05:13 -08001562 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001563 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001564 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001565 if (mIsSummaryWithChildren) {
1566 List<ExpandableNotificationRow> notificationChildren =
1567 mChildrenContainer.getNotificationChildren();
1568 for (int i = 0; i < notificationChildren.size(); i++) {
1569 ExpandableNotificationRow child = notificationChildren.get(i);
1570 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1571 }
1572 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001573 }
1574
Mady Mellor43c2cd12016-12-12 21:05:13 -08001575 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001576 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1577 long duration) {
1578 boolean oldShowingPublic = mShowingPublic;
1579 mShowingPublic = mSensitive && hideSensitive;
1580 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1581 return;
1582 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001583
1584 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001585 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001586
Jorim Jaggiae441282014-08-01 02:45:18 +02001587 if (!animated) {
1588 mPublicLayout.animate().cancel();
1589 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001590 if (mChildrenContainer != null) {
1591 mChildrenContainer.animate().cancel();
1592 mChildrenContainer.setAlpha(1f);
1593 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001594 mPublicLayout.setAlpha(1f);
1595 mPrivateLayout.setAlpha(1f);
1596 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001597 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001598 } else {
1599 animateShowingPublic(delay, duration);
1600 }
Selim Cinekc3179332016-03-04 14:44:56 -08001601 NotificationContentView showingLayout = getShowingLayout();
1602 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001603 mPrivateLayout.updateExpandButtons(isExpandable());
Adrian Roose5726a22016-12-19 14:26:51 -08001604 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02001605 mShowingPublicInitialized = true;
1606 }
1607
1608 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001609 View[] privateViews = mIsSummaryWithChildren
1610 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001611 : new View[] {mPrivateLayout};
1612 View[] publicViews = new View[] {mPublicLayout};
1613 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1614 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1615 for (final View hiddenView : hiddenChildren) {
1616 hiddenView.setVisibility(View.VISIBLE);
1617 hiddenView.animate().cancel();
1618 hiddenView.animate()
1619 .alpha(0f)
1620 .setStartDelay(delay)
1621 .setDuration(duration)
1622 .withEndAction(new Runnable() {
1623 @Override
1624 public void run() {
1625 hiddenView.setVisibility(View.INVISIBLE);
1626 }
1627 });
1628 }
1629 for (View showView : shownChildren) {
1630 showView.setVisibility(View.VISIBLE);
1631 showView.setAlpha(0f);
1632 showView.animate().cancel();
1633 showView.animate()
1634 .alpha(1f)
1635 .setStartDelay(delay)
1636 .setDuration(duration);
1637 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001638 }
1639
Mady Mellor43c2cd12016-12-12 21:05:13 -08001640 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08001641 public boolean mustStayOnScreen() {
1642 return mIsHeadsUp;
1643 }
1644
Selim Cinek9e624e72016-07-20 13:46:49 -07001645 /**
1646 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1647 * otherwise some state might not be updated. To request about the general clearability
1648 * see {@link #isClearable()}.
1649 */
1650 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001651 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001652 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001653
Ricky Waicd35def2016-05-03 11:07:07 +01001654 public void makeActionsVisibile() {
1655 setUserExpanded(true, true);
1656 if (isChildInGroup()) {
1657 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1658 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001659 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001660 }
1661
Selim Cinekb5605e52015-02-20 18:21:41 +01001662 public void setChildrenExpanded(boolean expanded, boolean animate) {
1663 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001664 if (mChildrenContainer != null) {
1665 mChildrenContainer.setChildrenExpanded(expanded);
1666 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001667 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001668 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001669 }
1670
Selim Cinekb5605e52015-02-20 18:21:41 +01001671 public static void applyTint(View v, int color) {
1672 int alpha;
1673 if (color != 0) {
1674 alpha = COLORED_DIVIDER_ALPHA;
1675 } else {
1676 color = 0xff000000;
1677 alpha = DEFAULT_DIVIDER_ALPHA;
1678 }
1679 if (v.getBackground() instanceof ColorDrawable) {
1680 ColorDrawable background = (ColorDrawable) v.getBackground();
1681 background.mutate();
1682 background.setColor(color);
1683 background.setAlpha(alpha);
1684 }
1685 }
1686
Selim Cinek1685e632014-04-08 02:27:49 +02001687 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001688 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001689 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001690
Mady Mellor34958fa2016-02-23 09:52:17 -08001691 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001692 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08001693 }
1694
Jorim Jaggibe565df2014-04-28 17:51:23 +02001695 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001696 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001697 NotificationContentView showingLayout = getShowingLayout();
1698 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001699 }
1700
1701 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001702 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001703 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001704 return mChildrenContainer;
1705 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001706 return getShowingLayout();
1707 }
1708
1709 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001710 protected void onAppearAnimationFinished(boolean wasAppearing) {
1711 super.onAppearAnimationFinished(wasAppearing);
1712 if (wasAppearing) {
1713 // During the animation the visible view might have changed, so let's make sure all
1714 // alphas are reset
1715 if (mChildrenContainer != null) {
1716 mChildrenContainer.setAlpha(1.0f);
1717 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1718 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001719 for (NotificationContentView l : mLayouts) {
1720 l.setAlpha(1.0f);
1721 l.setLayerType(LAYER_TYPE_NONE, null);
1722 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07001723 }
1724 }
1725
1726 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001727 public int getExtraBottomPadding() {
1728 if (mIsSummaryWithChildren && isGroupExpanded()) {
1729 return mIncreasedPaddingBetweenElements;
1730 }
1731 return 0;
1732 }
1733
1734 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001735 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001736 super.setActualHeight(height, notifyListeners);
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001737 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08001738 mGuts.setActualHeight(height);
1739 return;
1740 }
Selim Cinekeef84282015-10-30 16:28:00 -07001741 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001742 for (NotificationContentView l : mLayouts) {
1743 l.setContentHeight(contentHeight);
1744 }
Selim Cinek42357e02016-02-24 18:48:01 -08001745 if (mIsSummaryWithChildren) {
1746 mChildrenContainer.setActualHeight(height);
1747 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001748 if (mGuts != null) {
1749 mGuts.setActualHeight(height);
1750 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001751 }
1752
1753 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001754 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001755 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001756 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001757 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001758 NotificationContentView showingLayout = getShowingLayout();
1759 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001760 }
1761
1762 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001763 public int getMinHeight() {
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001764 if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08001765 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1766 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001767 return mChildrenContainer.getMinHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001768 } else if (!mOnKeyguard && mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001769 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001770 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001771 NotificationContentView showingLayout = getShowingLayout();
1772 return showingLayout.getMinHeight();
1773 }
1774
Adrian Roos0aac04f2016-12-08 15:59:29 -08001775 private int getAmbientHeight() {
1776 NotificationContentView showingLayout = getShowingLayout();
1777 return showingLayout.getAmbientChild() != null
1778 ? showingLayout.getAmbientChild().getHeight()
1779 : getCollapsedHeight();
1780 }
1781
Selim Cinek816c8e42015-11-19 12:00:45 -08001782 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001783 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001784 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001785 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001786 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001787 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001788 }
1789
1790 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001791 public void setClipTopAmount(int clipTopAmount) {
1792 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001793 for (NotificationContentView l : mLayouts) {
1794 l.setClipTopAmount(clipTopAmount);
1795 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001796 if (mGuts != null) {
1797 mGuts.setClipTopAmount(clipTopAmount);
1798 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001799 }
1800
Selim Cineka686b2c2016-10-26 13:58:27 -07001801 @Override
1802 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001803 if (clipBottomAmount != mClipBottomAmount) {
1804 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001805 for (NotificationContentView l : mLayouts) {
1806 l.setClipBottomAmount(clipBottomAmount);
1807 }
Selim Cinek65d418e2016-11-29 15:42:34 -08001808 if (mGuts != null) {
1809 mGuts.setClipBottomAmount(clipBottomAmount);
1810 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001811 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001812 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001813 // We have to update this even if it hasn't changed, since the children locations can
1814 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001815 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
1816 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001817 }
1818
Selim Cinek31094df2014-08-14 19:28:15 +02001819 public boolean isMaxExpandHeightInitialized() {
1820 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001821 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001822
Selim Cinek42357e02016-02-24 18:48:01 -08001823 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001824 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1825 }
Chris Wren78403d72014-07-28 10:23:24 +01001826
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001827 public void setShowingLegacyBackground(boolean showing) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08001828 for (NotificationContentView l : mLayouts) {
1829 l.setShowingLegacyBackground(showing);
1830 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001831 }
1832
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001833 @Override
1834 protected void updateBackgroundTint() {
1835 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001836 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001837 if (mIsSummaryWithChildren) {
1838 List<ExpandableNotificationRow> notificationChildren =
1839 mChildrenContainer.getNotificationChildren();
1840 for (int i = 0; i < notificationChildren.size(); i++) {
1841 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001842 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001843 }
1844 }
1845 }
1846
Mady Mellorb0a82462016-04-30 17:31:02 -07001847 /**
1848 * Called when a group has finished animating from collapsed or expanded state.
1849 */
1850 public void onFinishedExpansionChange() {
1851 mGroupExpansionChanging = false;
1852 updateBackgroundForGroupState();
1853 }
1854
1855 /**
1856 * Updates the parent and children backgrounds in a group based on the expansion state.
1857 */
1858 public void updateBackgroundForGroupState() {
1859 if (mIsSummaryWithChildren) {
1860 // Only when the group has finished expanding do we hide its background.
1861 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1862 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1863 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1864 for (int i = 0; i < children.size(); i++) {
1865 children.get(i).updateBackgroundForGroupState();
1866 }
1867 } else if (isChildInGroup()) {
1868 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
1869 // Only show a background if the group is expanded OR if it is expanding / collapsing
1870 // and has a custom background color
1871 final boolean showBackground = isGroupExpanded()
1872 || ((mNotificationParent.isGroupExpansionChanging()
1873 || mNotificationParent.isUserLocked()) && childColor != 0);
1874 mShowNoBackground = !showBackground;
1875 } else {
1876 // Only children or parents ever need no background.
1877 mShowNoBackground = false;
1878 }
1879 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001880 updateBackground();
1881 }
1882
Adrian Roos4a579672016-05-24 16:54:37 -07001883 public int getPositionOfChild(ExpandableNotificationRow childRow) {
1884 if (mIsSummaryWithChildren) {
1885 return mChildrenContainer.getPositionInLinearLayout(childRow);
1886 }
1887 return 0;
1888 }
1889
Chris Wren78403d72014-07-28 10:23:24 +01001890 public void setExpansionLogger(ExpansionLogger logger, String key) {
1891 mLogger = logger;
1892 mLoggingKey = key;
1893 }
1894
Chris Wren6abeeb92016-05-26 14:44:38 -04001895 public void onExpandedByGesture(boolean userExpanded) {
1896 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
1897 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
1898 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
1899 }
1900 MetricsLogger.action(mContext, event, userExpanded);
1901 }
1902
Selim Cinek6183d122016-01-14 18:48:41 -08001903 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001904 public float getIncreasedPaddingAmount() {
1905 if (mIsSummaryWithChildren) {
1906 if (isGroupExpanded()) {
1907 return 1.0f;
1908 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001909 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001910 }
Selim Cinek99104832017-01-25 14:47:33 -08001911 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08001912 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08001913 }
1914 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001915 }
1916
Selim Cineka7ed2c12017-01-23 20:47:24 -08001917 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08001918 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08001919 }
1920
Selim Cinek61633a82016-01-25 15:54:10 -08001921 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001922 protected boolean disallowSingleClick(MotionEvent event) {
1923 float x = event.getX();
1924 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001925 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001926 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001927 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001928 }
1929 return super.disallowSingleClick(event);
1930 }
1931
Chris Wren78403d72014-07-28 10:23:24 +01001932 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04001933 boolean nowExpanded = isExpanded();
1934 if (mIsSummaryWithChildren) {
1935 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
1936 }
Chris Wren78403d72014-07-28 10:23:24 +01001937 if (wasExpanded != nowExpanded && mLogger != null) {
1938 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1939 }
1940 }
Selim Cinek570981d2015-12-01 11:37:01 -08001941
Selim Cineke9bad242016-06-15 11:46:37 -07001942 @Override
1943 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1944 super.onInitializeAccessibilityNodeInfoInternal(info);
1945 if (canViewBeDismissed()) {
1946 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
1947 }
1948 }
1949
1950 @Override
1951 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
1952 if (super.performAccessibilityActionInternal(action, arguments)) {
1953 return true;
1954 }
1955 switch (action) {
1956 case AccessibilityNodeInfo.ACTION_DISMISS:
1957 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
1958 true /* fromAccessibility */);
1959 return true;
1960 }
1961 return false;
1962 }
1963
1964 public boolean shouldRefocusOnDismiss() {
1965 return mRefocusOnDismiss || isAccessibilityFocused();
1966 }
1967
Selim Cinek570981d2015-12-01 11:37:01 -08001968 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001969 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001970 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001971
1972 @Override
1973 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
1974 return new NotificationViewState(stackScrollState);
1975 }
1976
Selim Cinekd127d792016-11-01 19:11:41 -07001977 @Override
1978 public boolean isAboveShelf() {
1979 return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
1980 }
1981
Adrian Roos0aac04f2016-12-08 15:59:29 -08001982 public void setShowAmbient(boolean showAmbient) {
1983 if (showAmbient != mShowAmbient) {
1984 mShowAmbient = showAmbient;
1985 notifyHeightChanged(false /* needsAnimation */);
1986 }
1987 }
1988
Selim Cinekd127d792016-11-01 19:11:41 -07001989 public void setAboveShelf(boolean aboveShelf) {
1990 mAboveShelf = aboveShelf;
1991 }
1992
Selim Cinek0cfbef42016-11-09 19:06:36 -08001993 public class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08001994
1995 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07001996
Selim Cinekbbcebde2016-11-09 18:28:20 -08001997
1998 private NotificationViewState(StackScrollState stackScrollState) {
1999 mOverallState = stackScrollState;
2000 }
2001
2002 @Override
2003 public void applyToView(View view) {
2004 super.applyToView(view);
2005 if (view instanceof ExpandableNotificationRow) {
2006 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinekbbcebde2016-11-09 18:28:20 -08002007 row.applyChildrenState(mOverallState);
2008 }
2009 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002010
2011 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08002012 protected void onYTranslationAnimationFinished(View view) {
2013 super.onYTranslationAnimationFinished(view);
Selim Cinek0cfbef42016-11-09 19:06:36 -08002014 if (mHeadsupDisappearRunning) {
Selim Cinekcafa87f2016-10-26 17:00:17 -07002015 setHeadsUpAnimatingAway(false);
Selim Cinek0cfbef42016-11-09 19:06:36 -08002016 }
2017 }
2018
2019 @Override
2020 public void animateTo(View child, AnimationProperties properties) {
2021 super.animateTo(child, properties);
2022 if (child instanceof ExpandableNotificationRow) {
2023 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
2024 row.startChildAnimation(mOverallState, properties);
2025 }
2026 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002027 }
Chris Wren51c75102013-07-16 20:49:17 -04002028}