blob: b4c1af7f9f0f9e84c4480ddf3476596365bbee9b [file] [log] [blame]
Chris Wren51c75102013-07-16 20:49:17 -04001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar;
18
Selim Cinekc478f902017-02-22 20:55:44 -080019import static com.android.systemui.statusbar.notification.NotificationInflater.InflationExceptionHandler;
20
Mady Mellor4b80b102016-01-22 08:03:58 -080021import android.animation.Animator;
22import android.animation.AnimatorListenerAdapter;
Mady Mellor4b80b102016-01-22 08:03:58 -080023import android.animation.ObjectAnimator;
Mady Mellor4b80b102016-01-22 08:03:58 -080024import android.animation.ValueAnimator.AnimatorUpdateListener;
Selim Cinekddf1b392016-05-27 16:33:10 -070025import android.annotation.Nullable;
Chris Wren51c75102013-07-16 20:49:17 -040026import android.content.Context;
Selim Cinekcab4a602014-09-03 14:47:57 +020027import android.graphics.drawable.AnimatedVectorDrawable;
28import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010029import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020030import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080031import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070032import android.os.Bundle;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020033import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040034import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070035import android.util.FloatProperty;
36import android.util.Property;
Selim Cinek01af3342016-02-09 19:25:31 -080037import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080038import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080039import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050040import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080041import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020042import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020043import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070044import android.view.accessibility.AccessibilityNodeInfo;
Selim Cinek98713a42015-09-21 15:47:20 +020045import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020046import android.widget.ImageView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080047import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010048
Chris Wren698b1702016-05-23 11:16:32 -040049import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010050import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070051import com.android.internal.util.NotificationColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080052import com.android.internal.widget.CachingIconView;
Selim Cinek0242fbb2016-10-19 13:38:32 -070053import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050054import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070055import com.android.systemui.classifier.FalsingManager;
Mady Mellor87d79452017-01-10 11:52:52 -080056import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
Selim Cinekc897bd32016-03-18 17:32:31 -070057import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080058import com.android.systemui.statusbar.notification.InflationException;
59import com.android.systemui.statusbar.notification.NotificationInflater;
Selim Cinek6743c0b2017-01-18 18:24:01 -080060import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cineka7d4f822016-12-06 14:34:47 -080061import com.android.systemui.statusbar.notification.VisualStabilityManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010062import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050063import com.android.systemui.statusbar.phone.StatusBar;
Selim Cinek31aada42015-12-18 17:51:15 -080064import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek0cfbef42016-11-09 19:06:36 -080065import com.android.systemui.statusbar.stack.AnimationProperties;
66import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010067import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070068import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010069import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010070
Mady Mellor4b80b102016-01-22 08:03:58 -080071import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010072import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050073
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020074public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010075
76 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
77 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Selim Cinek1a48bab2017-02-17 19:38:40 -080078 private final NotificationInflater mNotificationInflater;
Selim Cinek0242fbb2016-10-19 13:38:32 -070079 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -080080 private int mIconTransformContentShiftNoIcon;
Selim Cinek01af3342016-02-09 19:25:31 -080081 private int mNotificationMinHeightLegacy;
82 private int mMaxHeadsUpHeightLegacy;
83 private int mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -080084 private int mMaxHeadsUpHeightIncreased;
Selim Cinek01af3342016-02-09 19:25:31 -080085 private int mNotificationMinHeight;
Selim Cinek7d1009b2017-01-25 15:28:28 -080086 private int mNotificationMinHeightLarge;
Selim Cinek01af3342016-02-09 19:25:31 -080087 private int mNotificationMaxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -080088 private int mNotificationAmbientHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -070089 private int mIncreasedPaddingBetweenElements;
Chris Wren51c75102013-07-16 20:49:17 -040090
Selim Cinek1685e632014-04-08 02:27:49 +020091 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040092 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020093 /** Has the user actively changed the expansion state of this row */
94 private boolean mHasUserChangedExpansion;
95 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040096 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -080097
98 /**
99 * Has this notification been expanded while it was pinned
100 */
101 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +0200102 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -0400103 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +0200104 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -0500105 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +0200106 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -0800107 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +0200108 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700109 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400110
Selim Cinek1685e632014-04-08 02:27:49 +0200111 /**
112 * Is this notification expanded by the system. The expansion state can be overridden by the
113 * user expansion.
114 */
115 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200116
117 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700118 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200119 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700120 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200121
Mady Mellorb0a82462016-04-30 17:31:02 -0700122 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800123 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200124 private NotificationContentView mPublicLayout;
125 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800126 private NotificationContentView[] mLayouts;
Selim Cinek1685e632014-04-08 02:27:49 +0200127 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700128 private int mHeadsUpHeight;
Selim Cinek4bb59342016-04-08 19:29:35 -0700129 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100130 private ExpansionLogger mLogger;
131 private String mLoggingKey;
Mady Mellor761cde12017-01-10 11:36:39 -0800132 private NotificationMenuRow mMenuRow;
Selim Cinek8d490d42015-04-10 00:05:50 -0700133 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800134 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200135 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700136 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100137 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200138 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100139 private ViewStub mChildrenContainerStub;
140 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100141 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700142 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100143 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor761cde12017-01-10 11:36:39 -0800144 private ViewStub mMenuRowStub;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100145 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100146 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700147 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700148 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800149 private HeadsUpManager mHeadsUpManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200150
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700151 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800152 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700153 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700154 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800155 private OnExpandClickListener mOnExpandClickListener;
Mady Mellorb0a82462016-04-30 17:31:02 -0700156 private boolean mGroupExpansionChanging;
157
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800158 private OnClickListener mExpandClickListener = new OnClickListener() {
159 @Override
160 public void onClick(View v) {
Selim Cinek624c02db2015-12-14 21:00:02 -0800161 if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700162 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400163 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
164 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
165 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400166 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
167 nowExpanded);
168 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800169 } else {
Selim Cineke9bad242016-06-15 11:46:37 -0700170 if (v.isAccessibilityFocused()) {
171 mPrivateLayout.setFocusOnVisibilityChange();
172 }
Selim Cinek31aada42015-12-18 17:51:15 -0800173 boolean nowExpanded;
174 if (isPinned()) {
175 nowExpanded = !mExpandedWhenPinned;
176 mExpandedWhenPinned = nowExpanded;
177 } else {
178 nowExpanded = !isExpanded();
179 setUserExpanded(nowExpanded);
180 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800181 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800182 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400183 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
184 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800185 }
186 }
187 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700188 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700189 private boolean mDismissed;
190 private boolean mKeepInParent;
191 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700192 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
193 new FloatProperty<ExpandableNotificationRow>("translate") {
194 @Override
195 public void setValue(ExpandableNotificationRow object, float value) {
196 object.setTranslation(value);
197 }
198
199 @Override
200 public Float get(ExpandableNotificationRow object) {
201 return object.getTranslation();
202 }
203 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700204 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700205 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700206 private View mChildAfterViewWhenDismissed;
207 private View mGroupParentWhenDismissed;
208 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800209 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700210 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700211 private boolean mAboveShelf;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800212 private boolean mShowAmbient;
Selim Cinek875a3a12016-11-18 17:52:16 -0800213 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800214 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800215 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800216 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800217 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800218 private boolean mUseIncreasedHeadsUpHeight;
Selim Cinekef8c2252017-02-10 14:52:18 -0800219 private float mTranslationWhenRemoved;
220 private boolean mWasChildInGroupWhenRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700221
Mady Mellor43c2cd12016-12-12 21:05:13 -0800222 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700223 public boolean isGroupExpansionChanging() {
224 if (isChildInGroup()) {
225 return mNotificationParent.isGroupExpansionChanging();
226 }
227 return mGroupExpansionChanging;
228 }
229
230 public void setGroupExpansionChanging(boolean changing) {
231 mGroupExpansionChanging = changing;
232 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700233
Adrian Roos599be342016-06-13 14:54:39 -0700234 @Override
235 public void setActualHeightAnimating(boolean animating) {
236 if (mPrivateLayout != null) {
237 mPrivateLayout.setContentHeightAnimating(animating);
238 }
239 }
240
Selim Cinek8d490d42015-04-10 00:05:50 -0700241 public NotificationContentView getPrivateLayout() {
242 return mPrivateLayout;
243 }
244
245 public NotificationContentView getPublicLayout() {
246 return mPublicLayout;
247 }
248
Selim Cinekcab4a602014-09-03 14:47:57 +0200249 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800250 for (NotificationContentView l : mLayouts) {
251 setIconAnimationRunning(running, l);
252 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800253 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700254 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800255 List<ExpandableNotificationRow> notificationChildren =
256 mChildrenContainer.getNotificationChildren();
257 for (int i = 0; i < notificationChildren.size(); i++) {
258 ExpandableNotificationRow child = notificationChildren.get(i);
259 child.setIconAnimationRunning(running);
260 }
261 }
262 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200263 }
264
265 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
266 if (layout != null) {
267 View contractedChild = layout.getContractedChild();
268 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700269 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200270 setIconAnimationRunningForChild(running, contractedChild);
271 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700272 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200273 }
274 }
275
276 private void setIconAnimationRunningForChild(boolean running, View child) {
277 if (child != null) {
278 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
279 setIconRunning(icon, running);
280 ImageView rightIcon = (ImageView) child.findViewById(
281 com.android.internal.R.id.right_icon);
282 setIconRunning(rightIcon, running);
283 }
284 }
285
286 private void setIconRunning(ImageView imageView, boolean running) {
287 if (imageView != null) {
288 Drawable drawable = imageView.getDrawable();
289 if (drawable instanceof AnimationDrawable) {
290 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
291 if (running) {
292 animationDrawable.start();
293 } else {
294 animationDrawable.stop();
295 }
296 } else if (drawable instanceof AnimatedVectorDrawable) {
297 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
298 if (running) {
299 animationDrawable.start();
300 } else {
301 animationDrawable.stop();
302 }
303 }
304 }
305 }
306
Selim Cinek1a48bab2017-02-17 19:38:40 -0800307 public void updateNotification(NotificationData.Entry entry) throws InflationException {
Selim Cinekda42d652015-12-04 15:51:16 -0800308 mEntry = entry;
309 mStatusBarNotification = entry.notification;
Selim Cinek1a48bab2017-02-17 19:38:40 -0800310 mNotificationInflater.inflateNotificationViews();
Selim Cinekc478f902017-02-22 20:55:44 -0800311 onNotificationUpdated();
312 }
313
314 private void onNotificationUpdated() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800315 for (NotificationContentView l : mLayouts) {
Selim Cinekc478f902017-02-22 20:55:44 -0800316 l.onNotificationUpdated(mEntry);
Adrian Rooseb434ff2017-01-11 11:18:48 -0800317 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800318 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800319 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700320 updateNotificationColor();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800321 if (mIsSummaryWithChildren) {
Selim Cinekc478f902017-02-22 20:55:44 -0800322 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
323 mEntry.notification);
Selim Cinekc897bd32016-03-18 17:32:31 -0700324 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800325 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800326 if (mIconAnimationRunning) {
327 setIconAnimationRunning(true);
328 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800329 if (mNotificationParent != null) {
330 mNotificationParent.updateChildrenHeaderAppearance();
331 }
Selim Cinek263398f2015-10-21 17:40:23 -0700332 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800333 // The public layouts expand button is always visible
334 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800335 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700336 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800337 updateShelfIconColor();
338 }
339
340 private void updateShelfIconColor() {
341 StatusBarIconView expandedIcon = mEntry.expandedIcon;
342 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
343 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
344 NotificationColorUtil.getInstance(mContext));
Selim Cinek875ba9b2017-02-13 16:20:17 -0800345 int color = StatusBarIconView.NO_COLOR;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800346 if (colorize) {
Selim Cinek875ba9b2017-02-13 16:20:17 -0800347 color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded());
Selim Cinek6743c0b2017-01-18 18:24:01 -0800348 }
Selim Cinek875ba9b2017-02-13 16:20:17 -0800349 expandedIcon.setStaticDrawableColor(color);
Selim Cinekda42d652015-12-04 15:51:16 -0800350 }
351
352 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800353 for (NotificationContentView l : mLayouts) {
354 updateLimitsForView(l);
355 }
Selim Cineka1744872016-03-11 15:36:06 -0800356 }
357
358 private void updateLimitsForView(NotificationContentView layout) {
359 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800360 != com.android.internal.R.id.status_bar_latest_event_content;
361 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800362 int minHeight;
363 if (customView && beforeN && !mIsSummaryWithChildren) {
364 minHeight = mNotificationMinHeightLegacy;
365 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
366 minHeight = mNotificationMinHeightLarge;
367 } else {
368 minHeight = mNotificationMinHeight;
369 }
Selim Cineka1744872016-03-11 15:36:06 -0800370 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
371 layout.getHeadsUpChild().getId()
372 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800373 int headsUpheight;
374 if (headsUpCustom && beforeN) {
375 headsUpheight = mMaxHeadsUpHeightLegacy;
376 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
377 headsUpheight = mMaxHeadsUpHeightIncreased;
378 } else {
379 headsUpheight = mMaxHeadsUpHeight;
380 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800381 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
382 mNotificationAmbientHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200383 }
384
385 public StatusBarNotification getStatusBarNotification() {
386 return mStatusBarNotification;
387 }
388
Selim Cinek281c2022016-10-13 19:14:43 -0700389 public NotificationData.Entry getEntry() {
390 return mEntry;
391 }
392
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700393 public boolean isHeadsUp() {
394 return mIsHeadsUp;
395 }
396
Selim Cinek1a521f32014-11-03 17:39:29 +0100397 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700398 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100399 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700400 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700401 if (mIsSummaryWithChildren) {
402 // The overflow might change since we allow more lines as HUN.
403 mChildrenContainer.updateGroupOverflow();
404 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700405 if (intrinsicBefore != getIntrinsicHeight()) {
406 notifyHeightChanged(false /* needsAnimation */);
407 }
Selim Cinekd127d792016-11-01 19:11:41 -0700408 if (isHeadsUp) {
409 setAboveShelf(true);
410 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100411 }
412
Selim Cinekb5605e52015-02-20 18:21:41 +0100413 public void setGroupManager(NotificationGroupManager groupManager) {
414 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700415 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100416 }
417
Adrian Roosb88b1a12015-12-09 18:51:05 -0800418 public void setRemoteInputController(RemoteInputController r) {
419 mPrivateLayout.setRemoteInputController(r);
420 }
421
Mady Mellor3fd273e2016-03-15 21:08:14 -0700422 public void setAppName(String appName) {
423 mAppName = appName;
Mady Mellor761cde12017-01-10 11:36:39 -0800424 if (mMenuRow != null) {
425 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700426 }
427 }
428
Selim Cinekb5605e52015-02-20 18:21:41 +0100429 public void addChildNotification(ExpandableNotificationRow row) {
430 addChildNotification(row, -1);
431 }
432
433 /**
434 * Add a child notification to this view.
435 *
436 * @param row the row to add
437 * @param childIndex the index to add it at, if -1 it will be added at the end
438 */
439 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
440 if (mChildrenContainer == null) {
441 mChildrenContainerStub.inflate();
442 }
443 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700444 onChildrenCountChanged();
445 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100446 }
447
448 public void removeChildNotification(ExpandableNotificationRow row) {
449 if (mChildrenContainer != null) {
450 mChildrenContainer.removeNotification(row);
451 }
Selim Cinek263398f2015-10-21 17:40:23 -0700452 onChildrenCountChanged();
453 row.setIsChildInGroup(false, null);
454 }
455
Mady Mellor43c2cd12016-12-12 21:05:13 -0800456 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700457 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700458 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700459 }
460
Selim Cinek388df6d2015-10-22 13:25:11 -0700461 public ExpandableNotificationRow getNotificationParent() {
462 return mNotificationParent;
463 }
464
Selim Cinek263398f2015-10-21 17:40:23 -0700465 /**
466 * @param isChildInGroup Is this notification now in a group
467 * @param parent the new parent notification
468 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700469 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500470 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700471 mNotificationParent = childInGroup ? parent : null;
472 mPrivateLayout.setIsChildInGroup(childInGroup);
Selim Cinekc478f902017-02-22 20:55:44 -0800473 if (mNotificationInflater.setIsChildInGroup(childInGroup)) {
474 onNotificationUpdated();
475 }
Mady Mellorc7d65b42016-05-04 11:44:57 -0400476 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700477 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700478 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700479 if (mNotificationParent != null) {
Selim Cinek9ce32852017-02-15 16:21:10 -0800480 setOverrideTintColor(NO_COLOR, 0.0f);
Mady Mellorb0a82462016-04-30 17:31:02 -0700481 mNotificationParent.updateBackgroundForGroupState();
482 }
Selim Cinekdb167372016-11-17 15:41:17 -0800483 updateIconVisibilities();
Selim Cinek34d93b02015-10-22 12:30:38 -0700484 }
485
486 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800487 public boolean onTouchEvent(MotionEvent event) {
488 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
489 || !isChildInGroup() || isGroupExpanded()) {
490 return super.onTouchEvent(event);
491 } else {
492 return false;
493 }
494 }
495
496 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800497 protected boolean handleSlideBack() {
Mady Mellor761cde12017-01-10 11:36:39 -0800498 if (mMenuRow != null && mMenuRow.isVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800499 animateTranslateNotification(0 /* targetLeft */);
500 return true;
501 }
502 return false;
503 }
504
505 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700506 protected boolean shouldHideBackground() {
507 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700508 }
509
510 @Override
511 public boolean isSummaryWithChildren() {
512 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100513 }
514
515 @Override
516 public boolean areChildrenExpanded() {
517 return mChildrenExpanded;
518 }
519
520 public List<ExpandableNotificationRow> getNotificationChildren() {
521 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
522 }
523
Selim Cinekeef84282015-10-30 16:28:00 -0700524 public int getNumberOfNotificationChildren() {
525 if (mChildrenContainer == null) {
526 return 0;
527 }
528 return mChildrenContainer.getNotificationChildren().size();
529 }
530
Selim Cinekb5605e52015-02-20 18:21:41 +0100531 /**
532 * Apply the order given in the list to the children.
533 *
534 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800535 * @param visualStabilityManager
536 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100537 * @return whether the list order has changed
538 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800539 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
540 VisualStabilityManager visualStabilityManager,
541 VisualStabilityManager.Callback callback) {
542 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
543 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100544 }
545
546 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700547 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800548 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100549 mChildrenContainer.getState(resultState, parentState);
550 }
551 }
552
553 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700554 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100555 mChildrenContainer.applyState(state);
556 }
557 }
558
559 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700560 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100561 mChildrenContainer.prepareExpansionChanged(state);
562 }
563 }
564
Selim Cinek0cfbef42016-11-09 19:06:36 -0800565 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700566 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800567 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100568 }
569 }
570
571 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800572 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100573 return this;
574 } else {
575 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
576 return view == null ? this : view;
577 }
578 }
579
Selim Cinekab29aeb2015-02-20 18:18:32 +0100580 public NotificationGuts getGuts() {
581 return mGuts;
582 }
583
Selim Cinek684a4422015-04-15 16:18:39 -0700584 /**
585 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
586 * the notification will be rendered on top of the screen.
587 *
588 * @param pinned whether it is pinned
589 */
590 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700591 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700592 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700593 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700594 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700595 }
Selim Cinek31aada42015-12-18 17:51:15 -0800596 if (pinned) {
597 setIconAnimationRunning(true);
598 mExpandedWhenPinned = false;
599 } else if (mExpandedWhenPinned) {
600 setUserExpanded(true);
601 }
Selim Cinek98713a42015-09-21 15:47:20 +0200602 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700603 }
604
Selim Cinek684a4422015-04-15 16:18:39 -0700605 public boolean isPinned() {
606 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700607 }
608
Selim Cinekd127d792016-11-01 19:11:41 -0700609 @Override
610 public int getPinnedHeadsUpHeight() {
611 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
612 }
613
Selim Cinek31aada42015-12-18 17:51:15 -0800614 /**
615 * @param atLeastMinHeight should the value returned be at least the minimum height.
616 * Used to avoid cyclic calls
617 * @return the height of the heads up notification when pinned
618 */
Selim Cinekd127d792016-11-01 19:11:41 -0700619 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800620 if (mIsSummaryWithChildren) {
621 return mChildrenContainer.getIntrinsicHeight();
622 }
Selim Cinek31aada42015-12-18 17:51:15 -0800623 if(mExpandedWhenPinned) {
624 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
625 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700626 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800627 } else {
628 return mHeadsUpHeight;
629 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700630 }
631
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700632 /**
633 * Mark whether this notification was just clicked, i.e. the user has just clicked this
634 * notification in this frame.
635 */
636 public void setJustClicked(boolean justClicked) {
637 mJustClicked = justClicked;
638 }
639
640 /**
641 * @return true if this notification has been clicked in this frame, false otherwise
642 */
643 public boolean wasJustClicked() {
644 return mJustClicked;
645 }
646
Selim Cinek98713a42015-09-21 15:47:20 +0200647 public void setChronometerRunning(boolean running) {
648 mLastChronometerRunning = running;
649 setChronometerRunning(running, mPrivateLayout);
650 setChronometerRunning(running, mPublicLayout);
651 if (mChildrenContainer != null) {
652 List<ExpandableNotificationRow> notificationChildren =
653 mChildrenContainer.getNotificationChildren();
654 for (int i = 0; i < notificationChildren.size(); i++) {
655 ExpandableNotificationRow child = notificationChildren.get(i);
656 child.setChronometerRunning(running);
657 }
658 }
659 }
660
661 private void setChronometerRunning(boolean running, NotificationContentView layout) {
662 if (layout != null) {
663 running = running || isPinned();
664 View contractedChild = layout.getContractedChild();
665 View expandedChild = layout.getExpandedChild();
666 View headsUpChild = layout.getHeadsUpChild();
667 setChronometerRunningForChild(running, contractedChild);
668 setChronometerRunningForChild(running, expandedChild);
669 setChronometerRunningForChild(running, headsUpChild);
670 }
671 }
672
673 private void setChronometerRunningForChild(boolean running, View child) {
674 if (child != null) {
675 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
676 if (chronometer instanceof Chronometer) {
677 ((Chronometer) chronometer).setStarted(running);
678 }
679 }
680 }
681
Selim Cinekea4bef72015-12-02 15:51:10 -0800682 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700683 if (mIsSummaryWithChildren) {
684 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700685 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800686 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700687 }
688
Selim Cinek34eda5e2016-02-18 17:10:43 -0800689 private NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700690 if (mIsSummaryWithChildren && !mShowingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700691 return mChildrenContainer.getHeaderView();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800692 }
693 return getShowingLayout().getVisibleNotificationHeader();
694 }
695
Selim Cinek570981d2015-12-01 11:37:01 -0800696 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
697 mOnExpandClickListener = onExpandClickListener;
698 }
699
Selim Cinekddf1b392016-05-27 16:33:10 -0700700 @Override
701 public void setOnClickListener(@Nullable OnClickListener l) {
702 super.setOnClickListener(l);
703 mOnClickListener = l;
704 updateClickAndFocus();
705 }
706
707 private void updateClickAndFocus() {
708 boolean normalChild = !isChildInGroup() || isGroupExpanded();
709 boolean clickable = mOnClickListener != null && normalChild;
710 if (isFocusable() != normalChild) {
711 setFocusable(normalChild);
712 }
713 if (isClickable() != clickable) {
714 setClickable(clickable);
715 }
716 }
717
Selim Cinek31aada42015-12-18 17:51:15 -0800718 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
719 mHeadsUpManager = headsUpManager;
720 }
721
Mady Mellor87d79452017-01-10 11:52:52 -0800722 public void setGutsView(MenuItem item) {
723 if (mGuts != null) {
724 item.gutsContent.setInteractionListener(mGuts);
725 mGuts.setGutsContent(item.gutsContent);
726 }
727 }
728
Selim Cinek1a48bab2017-02-17 19:38:40 -0800729 public void onDensityOrFontScaleChanged() {
Selim Cinek01af3342016-02-09 19:25:31 -0800730 initDimens();
731 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800732 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700733 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800734 }
735 }
736 if (mGuts != null) {
737 View oldGuts = mGuts;
738 int index = indexOfChild(oldGuts);
739 removeView(oldGuts);
740 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
741 R.layout.notification_guts, this, false);
742 mGuts.setVisibility(oldGuts.getVisibility());
743 addView(mGuts, index);
744 }
Mady Mellor761cde12017-01-10 11:36:39 -0800745 if (mMenuRow != null) {
746 View oldMenu = mMenuRow;
747 int menuIndex = indexOfChild(oldMenu);
748 removeView(oldMenu);
749 mMenuRow = (NotificationMenuRow) LayoutInflater.from(mContext).inflate(
750 R.layout.notification_menu_row, this, false);
751 mMenuRow.setNotificationRowParent(ExpandableNotificationRow.this);
752 mMenuRow.setAppName(mAppName);
753 mMenuRow.setVisibility(oldMenu.getVisibility());
754 addView(mMenuRow, menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -0800755
756 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800757 for (NotificationContentView l : mLayouts) {
758 l.reInflateViews();
759 }
Selim Cinek1a48bab2017-02-17 19:38:40 -0800760 mNotificationInflater.onDensityOrFontScaleChanged();
761 onNotificationUpdated();
Selim Cinek01af3342016-02-09 19:25:31 -0800762 }
763
Selim Cinekc3179332016-03-04 14:44:56 -0800764 public void setContentBackground(int customBackgroundColor, boolean animate,
765 NotificationContentView notificationContentView) {
766 if (getShowingLayout() == notificationContentView) {
767 setTintColor(customBackgroundColor, animate);
768 }
769 }
770
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700771 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800772 for (NotificationContentView l : mLayouts) {
773 l.closeRemoteInput();
774 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700775 }
776
Selim Cinekc897bd32016-03-18 17:32:31 -0700777 /**
778 * Set by how much the single line view should be indented.
779 */
780 public void setSingleLineWidthIndention(int indention) {
781 mPrivateLayout.setSingleLineWidthIndention(indention);
782 }
783
784 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700785 return mNotificationColor;
786 }
787
788 private void updateNotificationColor() {
789 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
790 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700791 }
792
793 public HybridNotificationView getSingleLineView() {
794 return mPrivateLayout.getSingleLineView();
795 }
796
Selim Cinekf07d0622016-03-21 19:52:52 -0700797 public boolean isOnKeyguard() {
798 return mOnKeyguard;
799 }
800
Selim Cinekc1e389d2016-04-07 11:02:57 -0700801 public void removeAllChildren() {
802 List<ExpandableNotificationRow> notificationChildren
803 = mChildrenContainer.getNotificationChildren();
804 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
805 for (int i = 0; i < clonedList.size(); i++) {
806 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700807 if (row.keepInParent()) {
808 continue;
809 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700810 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700811 row.setIsChildInGroup(false, null);
812 }
813 onChildrenCountChanged();
814 }
815
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700816 public void setForceUnlocked(boolean forceUnlocked) {
817 mForceUnlocked = forceUnlocked;
818 if (mIsSummaryWithChildren) {
819 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
820 for (ExpandableNotificationRow child : notificationChildren) {
821 child.setForceUnlocked(forceUnlocked);
822 }
823 }
824 }
825
Selim Cineke9bad242016-06-15 11:46:37 -0700826 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700827 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700828 mGroupParentWhenDismissed = mNotificationParent;
829 mRefocusOnDismiss = fromAccessibility;
830 mChildAfterViewWhenDismissed = null;
831 if (isChildInGroup()) {
832 List<ExpandableNotificationRow> notificationChildren =
833 mNotificationParent.getNotificationChildren();
834 int i = notificationChildren.indexOf(this);
835 if (i != -1 && i < notificationChildren.size() - 1) {
836 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
837 }
838 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700839 }
840
841 public boolean isDismissed() {
842 return mDismissed;
843 }
844
845 public boolean keepInParent() {
846 return mKeepInParent;
847 }
848
849 public void setKeepInParent(boolean keepInParent) {
850 mKeepInParent = keepInParent;
851 }
852
853 public boolean isRemoved() {
854 return mRemoved;
855 }
856
Adrian Roosd009ab12016-05-20 17:58:53 -0700857 public void setRemoved() {
858 mRemoved = true;
Selim Cinekef8c2252017-02-10 14:52:18 -0800859 mTranslationWhenRemoved = getTranslationY();
860 mWasChildInGroupWhenRemoved = isChildInGroup();
861 if (isChildInGroup()) {
862 mTranslationWhenRemoved += getNotificationParent().getTranslationY();
863 }
Adrian Roosd009ab12016-05-20 17:58:53 -0700864 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700865 }
866
Selim Cinekef8c2252017-02-10 14:52:18 -0800867 public boolean wasChildInGroupWhenRemoved() {
868 return mWasChildInGroupWhenRemoved;
869 }
870
871 public float getTranslationWhenRemoved() {
872 return mTranslationWhenRemoved;
873 }
874
Selim Cinekd1395642016-04-28 12:22:42 -0700875 public NotificationChildrenContainer getChildrenContainer() {
876 return mChildrenContainer;
877 }
878
Selim Cinekcafa87f2016-10-26 17:00:17 -0700879 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
880 mHeadsupDisappearRunning = headsUpAnimatingAway;
881 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
882 }
883
884 /**
885 * @return if the view was just heads upped and is now animating away. During such a time the
886 * layout needs to be kept consistent
887 */
888 public boolean isHeadsUpAnimatingAway() {
889 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700890 }
891
Selim Cineke9bad242016-06-15 11:46:37 -0700892 public View getChildAfterViewWhenDismissed() {
893 return mChildAfterViewWhenDismissed;
894 }
895
896 public View getGroupParentWhenDismissed() {
897 return mGroupParentWhenDismissed;
898 }
899
Selim Cinek9e624e72016-07-20 13:46:49 -0700900 public void performDismiss() {
Selim Cineke9079112016-12-14 14:41:01 -0800901 if (mOnDismissRunnable != null) {
902 mOnDismissRunnable.run();
903 }
Selim Cinek9e624e72016-07-20 13:46:49 -0700904 }
905
Selim Cineke9079112016-12-14 14:41:01 -0800906 public void setOnDismissRunnable(Runnable onDismissRunnable) {
907 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -0700908 }
909
Selim Cinek281c2022016-10-13 19:14:43 -0700910 public View getNotificationIcon() {
911 NotificationHeaderView notificationHeader = getNotificationHeader();
912 if (notificationHeader != null) {
913 return notificationHeader.getIcon();
914 }
915 return null;
916 }
917
918 /**
919 * @return whether the notification is currently showing a view with an icon.
920 */
921 public boolean isShowingIcon() {
Mady Mellor434180c2017-02-13 11:29:42 -0800922 if (areGutsExposed()) {
923 return false;
924 }
Selim Cinek281c2022016-10-13 19:14:43 -0700925 if (mIsSummaryWithChildren) {
926 return true;
927 }
928 NotificationContentView showingLayout = getShowingLayout();
929 NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
930 return notificationHeader != null;
931 }
932
Selim Cinek0242fbb2016-10-19 13:38:32 -0700933 /**
934 * Set how much this notification is transformed into an icon.
935 *
Selim Cinek2b549f42016-11-22 16:38:51 -0800936 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
937 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -0800938 * @param isLastChild is this the last child in the list. If true, then the transformation is
939 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -0700940 */
Selim Cinek2b549f42016-11-22 16:38:51 -0800941 public void setContentTransformationAmount(float contentTransformationAmount,
942 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -0800943 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800944 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800945 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800946 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800947 if (changeTransformation) {
948 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -0800949 }
950 }
951
952 /**
953 * Set the icons to be visible of this notification.
954 */
955 public void setIconsVisible(boolean iconsVisible) {
956 if (iconsVisible != mIconsVisible) {
957 mIconsVisible = iconsVisible;
958 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700959 }
960 }
961
Selim Cinekdb167372016-11-17 15:41:17 -0800962 @Override
963 protected void onBelowSpeedBumpChanged() {
964 updateIconVisibilities();
965 }
966
Selim Cinek875a3a12016-11-18 17:52:16 -0800967 private void updateContentTransformation() {
968 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -0800969 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800970 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -0800971 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800972 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700973 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -0800974 translationY *= 0.4f;
975 } else {
976 contentAlpha = 1.0f;
977 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800978 for (NotificationContentView l : mLayouts) {
979 l.setAlpha(contentAlpha);
980 l.setTranslationY(translationY);
981 }
Selim Cinek875a3a12016-11-18 17:52:16 -0800982 if (mChildrenContainer != null) {
983 mChildrenContainer.setAlpha(contentAlpha);
984 mChildrenContainer.setTranslationY(translationY);
985 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -0700986 }
987 }
988
989 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -0800990 boolean visible = isChildInGroup()
991 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
992 || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800993 for (NotificationContentView l : mLayouts) {
994 l.setIconsVisible(visible);
995 }
Selim Cinekdb167372016-11-17 15:41:17 -0800996 if (mChildrenContainer != null) {
997 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700998 }
999 }
1000
Selim Cinek875a3a12016-11-18 17:52:16 -08001001 /**
1002 * Get the relative top padding of a view relative to this view. This recursively walks up the
1003 * hierarchy and does the corresponding measuring.
1004 *
1005 * @param view the view to the the padding for. The requested view has to be a child of this
1006 * notification.
1007 * @return the toppadding
1008 */
1009 public int getRelativeTopPadding(View view) {
1010 int topPadding = 0;
1011 while (view.getParent() instanceof ViewGroup) {
1012 topPadding += view.getTop();
1013 view = (View) view.getParent();
1014 if (view instanceof ExpandableNotificationRow) {
1015 return topPadding;
1016 }
1017 }
1018 return topPadding;
1019 }
1020
Selim Cineka1d97902016-12-14 16:31:40 -08001021 public float getContentTranslation() {
1022 return mPrivateLayout.getTranslationY();
1023 }
1024
Selim Cinek6743c0b2017-01-18 18:24:01 -08001025 public void setIsLowPriority(boolean isLowPriority) {
1026 mIsLowPriority = isLowPriority;
1027 mPrivateLayout.setIsLowPriority(isLowPriority);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001028 mNotificationInflater.setIsLowPriority(mIsLowPriority);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001029 if (mChildrenContainer != null) {
1030 mChildrenContainer.setIsLowPriority(isLowPriority);
1031 }
1032 }
1033
Selim Cinek7d1009b2017-01-25 15:28:28 -08001034 public void setUseIncreasedCollapsedHeight(boolean use) {
1035 mUseIncreasedCollapsedHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001036 mNotificationInflater.setUsesIncreasedHeight(use);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001037 }
1038
Selim Cinek87ed69b2017-02-09 15:59:43 -08001039 public void setUseIncreasedHeadsUpHeight(boolean use) {
1040 mUseIncreasedHeadsUpHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001041 mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
1042 }
1043
1044 public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
1045 mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001046 }
1047
Selim Cinekc478f902017-02-22 20:55:44 -08001048 public void setInflateExceptionHandler(InflationExceptionHandler inflateExceptionHandler) {
1049 mNotificationInflater.setInflateExceptionHandler(inflateExceptionHandler);
1050 }
1051
Chris Wren78403d72014-07-28 10:23:24 +01001052 public interface ExpansionLogger {
1053 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
1054 }
Selim Cinek1685e632014-04-08 02:27:49 +02001055
Chris Wren51c75102013-07-16 20:49:17 -04001056 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1057 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001058 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001059 mNotificationInflater = new NotificationInflater(this);
Selim Cinek01af3342016-02-09 19:25:31 -08001060 initDimens();
1061 }
1062
1063 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -08001064 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
1065 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001066 mNotificationMinHeightLarge = getFontScaledHeight(
Selim Cinek87ed69b2017-02-09 15:59:43 -08001067 R.dimen.notification_min_height_increased);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001068 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
Adrian Roos0aac04f2016-12-08 15:59:29 -08001069 mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001070 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -08001071 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001072 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001073 mMaxHeadsUpHeightIncreased = getFontScaledHeight(
1074 R.dimen.notification_max_heads_up_height_increased);
Mady Mellorb0a82462016-04-30 17:31:02 -07001075 mIncreasedPaddingBetweenElements = getResources()
1076 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinek875a3a12016-11-18 17:52:16 -08001077 mIconTransformContentShiftNoIcon = getResources().getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001078 R.dimen.notification_icon_transform_content_shift);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001079 }
1080
1081 /**
1082 * @param dimenId the dimen to look up
1083 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
1084 */
1085 private int getFontScaledHeight(int dimenId) {
1086 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
1087 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
1088 getResources().getDisplayMetrics().density);
1089 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -04001090 }
1091
Christoph Studera7fe6312014-06-27 19:32:44 +02001092 /**
1093 * Resets this view so it can be re-used for an updated notification.
1094 */
1095 public void reset() {
Jorim Jaggiae441282014-08-01 02:45:18 +02001096 mShowingPublicInitialized = false;
Selim Cinek31094df2014-08-14 19:28:15 +02001097 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001098 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001099 }
1100
Jorim Jaggi251957d2014-04-09 04:24:09 +02001101 @Override
1102 protected void onFinishInflate() {
1103 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001104 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1105 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001106 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1107
1108 for (NotificationContentView l : mLayouts) {
1109 l.setExpandClickListener(mExpandClickListener);
1110 l.setContainingNotification(this);
1111 }
Mady Mellor761cde12017-01-10 11:36:39 -08001112 mMenuRowStub = (ViewStub) findViewById(R.id.menu_row_stub);
1113 mMenuRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Mady Mellor4b80b102016-01-22 08:03:58 -08001114 @Override
1115 public void onInflate(ViewStub stub, View inflated) {
Mady Mellor761cde12017-01-10 11:36:39 -08001116 mMenuRow = (NotificationMenuRow) inflated;
1117 mMenuRow.setNotificationRowParent(ExpandableNotificationRow.this);
1118 mMenuRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -08001119 }
1120 });
Selim Cinekab29aeb2015-02-20 18:18:32 +01001121 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1122 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001123 @Override
1124 public void onInflate(ViewStub stub, View inflated) {
1125 mGuts = (NotificationGuts) inflated;
1126 mGuts.setClipTopAmount(getClipTopAmount());
1127 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001128 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001129 }
1130 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001131 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1132 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1133
1134 @Override
1135 public void onInflate(ViewStub stub, View inflated) {
1136 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001137 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek388df6d2015-10-22 13:25:11 -07001138 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001139 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -08001140 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +01001141 }
1142 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001143
1144 // Add the views that we translate to reveal the gear
1145 mTranslateableViews = new ArrayList<View>();
1146 for (int i = 0; i < getChildCount(); i++) {
1147 mTranslateableViews.add(getChildAt(i));
1148 }
1149 // Remove views that don't translate
Mady Mellor761cde12017-01-10 11:36:39 -08001150 mTranslateableViews.remove(mMenuRowStub);
Mady Mellor4b80b102016-01-22 08:03:58 -08001151 mTranslateableViews.remove(mChildrenContainerStub);
1152 mTranslateableViews.remove(mGutsStub);
1153 }
1154
Mady Mellor4b80b102016-01-22 08:03:58 -08001155 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001156 if (mTranslateAnim != null) {
1157 mTranslateAnim.cancel();
1158 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001159 if (mTranslateableViews != null) {
1160 for (int i = 0; i < mTranslateableViews.size(); i++) {
1161 mTranslateableViews.get(i).setTranslationX(0);
1162 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001163 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001164 invalidateOutline();
Mady Mellor761cde12017-01-10 11:36:39 -08001165 if (mMenuRow != null) {
1166 mMenuRow.resetState(true /* notify */);
Mady Mellor4b80b102016-01-22 08:03:58 -08001167 }
1168 }
1169
1170 public void animateTranslateNotification(final float leftTarget) {
1171 if (mTranslateAnim != null) {
1172 mTranslateAnim.cancel();
1173 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001174 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001175 if (mTranslateAnim != null) {
1176 mTranslateAnim.start();
1177 }
1178 }
1179
1180 @Override
1181 public void setTranslation(float translationX) {
1182 if (areGutsExposed()) {
1183 // Don't translate if guts are showing.
1184 return;
1185 }
1186 // Translate the group of views
1187 for (int i = 0; i < mTranslateableViews.size(); i++) {
1188 if (mTranslateableViews.get(i) != null) {
1189 mTranslateableViews.get(i).setTranslationX(translationX);
1190 }
1191 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001192 invalidateOutline();
Mady Mellor761cde12017-01-10 11:36:39 -08001193 if (mMenuRow != null) {
1194 mMenuRow.updateMenuAlpha(translationX, getMeasuredWidth());
Mady Mellor34958fa2016-02-23 09:52:17 -08001195 }
1196 }
1197
1198 @Override
1199 public float getTranslation() {
1200 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1201 // All of the views in the list should have same translation, just use first one.
1202 return mTranslateableViews.get(0).getTranslationX();
1203 }
1204 return 0;
1205 }
1206
1207 public Animator getTranslateViewAnimator(final float leftTarget,
1208 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001209 if (mTranslateAnim != null) {
1210 mTranslateAnim.cancel();
1211 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001212 if (areGutsExposed()) {
1213 // No translation if guts are exposed.
1214 return null;
1215 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001216 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1217 leftTarget);
1218 if (listener != null) {
1219 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001220 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001221 translateAnim.addListener(new AnimatorListenerAdapter() {
1222 boolean cancelled = false;
1223
1224 @Override
1225 public void onAnimationCancel(Animator anim) {
1226 cancelled = true;
1227 }
1228
1229 @Override
1230 public void onAnimationEnd(Animator anim) {
Mady Mellor761cde12017-01-10 11:36:39 -08001231 if (!cancelled && mMenuRow != null && leftTarget == 0) {
1232 mMenuRow.resetState(true /* notify */);
Mady Mellorb0a82462016-04-30 17:31:02 -07001233 mTranslateAnim = null;
1234 }
1235 }
1236 });
1237 mTranslateAnim = translateAnim;
1238 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001239 }
1240
1241 public float getSpaceForGear() {
Mady Mellor761cde12017-01-10 11:36:39 -08001242 if (mMenuRow != null) {
1243 return mMenuRow.getSpaceForMenu();
Mady Mellor4b80b102016-01-22 08:03:58 -08001244 }
1245 return 0;
1246 }
1247
Mady Mellor761cde12017-01-10 11:36:39 -08001248 public NotificationMenuRow getSettingsRow() {
1249 if (mMenuRow == null) {
1250 mMenuRowStub.inflate();
Mady Mellor4b80b102016-01-22 08:03:58 -08001251 }
Mady Mellor761cde12017-01-10 11:36:39 -08001252 return mMenuRow;
Mady Mellor4b80b102016-01-22 08:03:58 -08001253 }
1254
Selim Cinekab29aeb2015-02-20 18:18:32 +01001255 public void inflateGuts() {
1256 if (mGuts == null) {
1257 mGutsStub.inflate();
1258 }
1259 }
1260
Selim Cinekda42d652015-12-04 15:51:16 -08001261 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001262 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1263 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001264 if (mChildrenContainer != null) {
1265 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1266 : INVISIBLE);
Mady Mellorb0a82462016-04-30 17:31:02 -07001267 mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
1268 ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001269 : INVISIBLE);
1270 }
Selim Cinekda42d652015-12-04 15:51:16 -08001271 // The limits might have changed if the view suddenly became a group or vice versa
1272 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001273 }
1274
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001275 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001276 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1277 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001278 // Add a record for the entire layout since its content is somehow small.
1279 // The event comes from a leaf view that is interacted with.
1280 AccessibilityEvent record = AccessibilityEvent.obtain();
1281 onInitializeAccessibilityEvent(record);
1282 dispatchPopulateAccessibilityEvent(record);
1283 event.appendRecord(record);
1284 return true;
1285 }
1286 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001287 }
Chris Wren51c75102013-07-16 20:49:17 -04001288
John Spurlocke15452b2014-08-21 09:44:39 -04001289 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001290 public void setDark(boolean dark, boolean fade, long delay) {
1291 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001292 final NotificationContentView showing = getShowingLayout();
1293 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001294 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001295 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001296 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001297 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001298 }
John Spurlocke15452b2014-08-21 09:44:39 -04001299 }
1300
Chris Wren51c75102013-07-16 20:49:17 -04001301 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001302 if (mIsSummaryWithChildren && !mShowingPublic) {
1303 return !mChildrenExpanded;
1304 }
Chris Wren51c75102013-07-16 20:49:17 -04001305 return mExpandable;
1306 }
1307
1308 public void setExpandable(boolean expandable) {
1309 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001310 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001311 }
1312
Selim Cinek4ffd6362015-12-29 15:12:23 +01001313 @Override
1314 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001315 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1316 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001317 }
1318
Selim Cinek1685e632014-04-08 02:27:49 +02001319 /**
1320 * @return whether the user has changed the expansion state
1321 */
1322 public boolean hasUserChangedExpansion() {
1323 return mHasUserChangedExpansion;
1324 }
1325
Chris Wren51c75102013-07-16 20:49:17 -04001326 public boolean isUserExpanded() {
1327 return mUserExpanded;
1328 }
1329
Selim Cinek1685e632014-04-08 02:27:49 +02001330 /**
1331 * Set this notification to be expanded by the user
1332 *
1333 * @param userExpanded whether the user wants this notification to be expanded
1334 */
Chris Wren51c75102013-07-16 20:49:17 -04001335 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001336 setUserExpanded(userExpanded, false /* allowChildExpansion */);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001337 updateShelfIconColor();
Selim Cinek388df6d2015-10-22 13:25:11 -07001338 }
1339
1340 /**
1341 * Set this notification to be expanded by the user
1342 *
1343 * @param userExpanded whether the user wants this notification to be expanded
1344 * @param allowChildExpansion whether a call to this method allows expanding children
1345 */
1346 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001347 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -07001348 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
Chris Wren698b1702016-05-23 11:16:32 -04001349 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001350 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Chris Wren698b1702016-05-23 11:16:32 -04001351 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001352 return;
1353 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001354 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001355 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001356 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001357 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001358 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001359 }
1360
Selim Cinekccd14fb2014-08-12 18:53:24 +02001361 public void resetUserExpansion() {
1362 mHasUserChangedExpansion = false;
1363 mUserExpanded = false;
1364 }
1365
Chris Wren51c75102013-07-16 20:49:17 -04001366 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001367 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001368 }
1369
1370 public void setUserLocked(boolean userLocked) {
1371 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001372 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001373 if (mIsSummaryWithChildren) {
1374 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek7baaa9e2016-07-21 17:21:09 -07001375 if (userLocked || !isGroupExpanded()) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001376 updateBackgroundForGroupState();
1377 }
Selim Cinek42357e02016-02-24 18:48:01 -08001378 }
Chris Wren51c75102013-07-16 20:49:17 -04001379 }
1380
Selim Cinek1685e632014-04-08 02:27:49 +02001381 /**
1382 * @return has the system set this notification to be expanded
1383 */
1384 public boolean isSystemExpanded() {
1385 return mIsSystemExpanded;
1386 }
1387
1388 /**
1389 * Set this notification to be expanded by the system.
1390 *
1391 * @param expand whether the system wants this notification to be expanded.
1392 */
1393 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001394 if (expand != mIsSystemExpanded) {
1395 final boolean wasExpanded = isExpanded();
1396 mIsSystemExpanded = expand;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001397 updateShelfIconColor();
Selim Cinekb5605e52015-02-20 18:21:41 +01001398 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001399 logExpansionEvent(false, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001400 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001401 mChildrenContainer.updateGroupOverflow();
1402 }
Selim Cinek31094df2014-08-14 19:28:15 +02001403 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001404 }
1405
1406 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001407 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001408 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001409 public void setOnKeyguard(boolean onKeyguard) {
1410 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001411 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001412 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001413 logExpansionEvent(false, wasExpanded);
1414 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001415 if (mIsSummaryWithChildren) {
1416 mChildrenContainer.updateGroupOverflow();
1417 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001418 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001419 }
1420 }
Selim Cinek1685e632014-04-08 02:27:49 +02001421 }
1422
1423 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001424 * @return Can the underlying notification be cleared? This can be different from whether the
1425 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1426 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001427 */
1428 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001429 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1430 return false;
1431 }
1432 if (mIsSummaryWithChildren) {
1433 List<ExpandableNotificationRow> notificationChildren =
1434 mChildrenContainer.getNotificationChildren();
1435 for (int i = 0; i < notificationChildren.size(); i++) {
1436 ExpandableNotificationRow child = notificationChildren.get(i);
1437 if (!child.isClearable()) {
1438 return false;
1439 }
1440 }
1441 }
1442 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001443 }
1444
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001445 @Override
1446 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001447 if (isUserLocked()) {
1448 return getActualHeight();
1449 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001450 if (mGuts != null && mGuts.isExposed()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001451 return mGuts.getHeight();
1452 } else if ((isChildInGroup() && !isGroupExpanded())) {
1453 return mPrivateLayout.getMinHeight();
Adrian Roos0aac04f2016-12-08 15:59:29 -08001454 } else if (mShowAmbient) {
1455 return getAmbientHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001456 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1457 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001458 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001459 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001460 } else if (!mOnKeyguard && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07001461 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001462 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1463 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001464 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001465 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001466 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001467 }
Selim Cinek31aada42015-12-18 17:51:15 -08001468 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001469 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001470 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001471 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001472 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001473 }
Selim Cinek1685e632014-04-08 02:27:49 +02001474
Mady Mellor43c2cd12016-12-12 21:05:13 -08001475 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001476 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001477 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001478 }
1479
Selim Cinek263398f2015-10-21 17:40:23 -07001480 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05001481 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001482 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1483 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
1484 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
1485 mEntry.notification);
Selim Cinek263398f2015-10-21 17:40:23 -07001486 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001487 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001488 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001489 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001490 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001491 }
1492
Mady Mellorb0a82462016-04-30 17:31:02 -07001493 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001494 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001495 mChildrenContainer.updateChildrenHeaderAppearance();
1496 }
1497 }
1498
Selim Cinek1685e632014-04-08 02:27:49 +02001499 /**
1500 * Check whether the view state is currently expanded. This is given by the system in {@link
1501 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1502 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1503 * view can differ from this state, if layout params are modified from outside.
1504 *
1505 * @return whether the view state is currently expanded.
1506 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001507 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001508 return isExpanded(false /* allowOnKeyguard */);
1509 }
1510
1511 public boolean isExpanded(boolean allowOnKeyguard) {
1512 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001513 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1514 || isUserExpanded());
1515 }
1516
1517 private boolean isSystemChildExpanded() {
1518 return mIsSystemChildExpanded;
1519 }
1520
1521 public void setSystemChildExpanded(boolean expanded) {
1522 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001523 }
1524
1525 @Override
1526 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1527 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001528 updateMaxHeights();
Mady Mellor761cde12017-01-10 11:36:39 -08001529 if (mMenuRow != null) {
1530 mMenuRow.updateVerticalLocation();
Mady Mellora6edc872016-04-26 11:01:03 -07001531 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001532 updateContentShiftHeight();
1533 }
1534
1535 /**
1536 * Updates the content shift height such that the header is completely hidden when coming from
1537 * the top.
1538 */
1539 private void updateContentShiftHeight() {
1540 NotificationHeaderView notificationHeader = getNotificationHeader();
1541 if (notificationHeader != null) {
1542 CachingIconView icon = notificationHeader.getIcon();
1543 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1544 } else {
1545 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1546 }
Selim Cinek1685e632014-04-08 02:27:49 +02001547 }
1548
Selim Cinek8d490d42015-04-10 00:05:50 -07001549 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001550 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001551 View expandedChild = mPrivateLayout.getExpandedChild();
1552 if (expandedChild == null) {
1553 expandedChild = mPrivateLayout.getContractedChild();
1554 }
1555 mMaxExpandHeight = expandedChild.getHeight();
1556 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001557 if (headsUpChild == null) {
1558 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001559 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001560 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001561 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001562 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001563 }
1564 }
1565
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001566 @Override
1567 public void notifyHeightChanged(boolean needsAnimation) {
1568 super.notifyHeightChanged(needsAnimation);
1569 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1570 }
1571
Selim Cinek3c76d502016-02-19 15:16:33 -08001572 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001573 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001574 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001575 }
1576
Mady Mellor43c2cd12016-12-12 21:05:13 -08001577 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001578 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001579 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001580 if (mIsSummaryWithChildren) {
1581 List<ExpandableNotificationRow> notificationChildren =
1582 mChildrenContainer.getNotificationChildren();
1583 for (int i = 0; i < notificationChildren.size(); i++) {
1584 ExpandableNotificationRow child = notificationChildren.get(i);
1585 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1586 }
1587 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001588 }
1589
Mady Mellor43c2cd12016-12-12 21:05:13 -08001590 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001591 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1592 long duration) {
1593 boolean oldShowingPublic = mShowingPublic;
1594 mShowingPublic = mSensitive && hideSensitive;
1595 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1596 return;
1597 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001598
1599 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001600 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001601
Jorim Jaggiae441282014-08-01 02:45:18 +02001602 if (!animated) {
1603 mPublicLayout.animate().cancel();
1604 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001605 if (mChildrenContainer != null) {
1606 mChildrenContainer.animate().cancel();
1607 mChildrenContainer.setAlpha(1f);
1608 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001609 mPublicLayout.setAlpha(1f);
1610 mPrivateLayout.setAlpha(1f);
1611 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001612 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001613 } else {
1614 animateShowingPublic(delay, duration);
1615 }
Selim Cinekc3179332016-03-04 14:44:56 -08001616 NotificationContentView showingLayout = getShowingLayout();
1617 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001618 mPrivateLayout.updateExpandButtons(isExpandable());
Adrian Roose5726a22016-12-19 14:26:51 -08001619 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02001620 mShowingPublicInitialized = true;
1621 }
1622
1623 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001624 View[] privateViews = mIsSummaryWithChildren
1625 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001626 : new View[] {mPrivateLayout};
1627 View[] publicViews = new View[] {mPublicLayout};
1628 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1629 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1630 for (final View hiddenView : hiddenChildren) {
1631 hiddenView.setVisibility(View.VISIBLE);
1632 hiddenView.animate().cancel();
1633 hiddenView.animate()
1634 .alpha(0f)
1635 .setStartDelay(delay)
1636 .setDuration(duration)
1637 .withEndAction(new Runnable() {
1638 @Override
1639 public void run() {
1640 hiddenView.setVisibility(View.INVISIBLE);
1641 }
1642 });
1643 }
1644 for (View showView : shownChildren) {
1645 showView.setVisibility(View.VISIBLE);
1646 showView.setAlpha(0f);
1647 showView.animate().cancel();
1648 showView.animate()
1649 .alpha(1f)
1650 .setStartDelay(delay)
1651 .setDuration(duration);
1652 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001653 }
1654
Mady Mellor43c2cd12016-12-12 21:05:13 -08001655 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08001656 public boolean mustStayOnScreen() {
1657 return mIsHeadsUp;
1658 }
1659
Selim Cinek9e624e72016-07-20 13:46:49 -07001660 /**
1661 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1662 * otherwise some state might not be updated. To request about the general clearability
1663 * see {@link #isClearable()}.
1664 */
1665 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001666 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001667 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001668
Ricky Waicd35def2016-05-03 11:07:07 +01001669 public void makeActionsVisibile() {
1670 setUserExpanded(true, true);
1671 if (isChildInGroup()) {
1672 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1673 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001674 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001675 }
1676
Selim Cinekb5605e52015-02-20 18:21:41 +01001677 public void setChildrenExpanded(boolean expanded, boolean animate) {
1678 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001679 if (mChildrenContainer != null) {
1680 mChildrenContainer.setChildrenExpanded(expanded);
1681 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001682 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001683 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001684 }
1685
Selim Cinekb5605e52015-02-20 18:21:41 +01001686 public static void applyTint(View v, int color) {
1687 int alpha;
1688 if (color != 0) {
1689 alpha = COLORED_DIVIDER_ALPHA;
1690 } else {
1691 color = 0xff000000;
1692 alpha = DEFAULT_DIVIDER_ALPHA;
1693 }
1694 if (v.getBackground() instanceof ColorDrawable) {
1695 ColorDrawable background = (ColorDrawable) v.getBackground();
1696 background.mutate();
1697 background.setColor(color);
1698 background.setAlpha(alpha);
1699 }
1700 }
1701
Selim Cinek1685e632014-04-08 02:27:49 +02001702 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001703 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001704 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001705
Mady Mellor34958fa2016-02-23 09:52:17 -08001706 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001707 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08001708 }
1709
Jorim Jaggibe565df2014-04-28 17:51:23 +02001710 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001711 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001712 NotificationContentView showingLayout = getShowingLayout();
1713 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001714 }
1715
1716 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001717 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001718 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001719 return mChildrenContainer;
1720 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001721 return getShowingLayout();
1722 }
1723
1724 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001725 protected void onAppearAnimationFinished(boolean wasAppearing) {
1726 super.onAppearAnimationFinished(wasAppearing);
1727 if (wasAppearing) {
1728 // During the animation the visible view might have changed, so let's make sure all
1729 // alphas are reset
1730 if (mChildrenContainer != null) {
1731 mChildrenContainer.setAlpha(1.0f);
1732 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1733 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001734 for (NotificationContentView l : mLayouts) {
1735 l.setAlpha(1.0f);
1736 l.setLayerType(LAYER_TYPE_NONE, null);
1737 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07001738 }
1739 }
1740
1741 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001742 public int getExtraBottomPadding() {
1743 if (mIsSummaryWithChildren && isGroupExpanded()) {
1744 return mIncreasedPaddingBetweenElements;
1745 }
1746 return 0;
1747 }
1748
1749 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001750 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001751 super.setActualHeight(height, notifyListeners);
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001752 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08001753 mGuts.setActualHeight(height);
1754 return;
1755 }
Selim Cinekeef84282015-10-30 16:28:00 -07001756 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001757 for (NotificationContentView l : mLayouts) {
1758 l.setContentHeight(contentHeight);
1759 }
Selim Cinek42357e02016-02-24 18:48:01 -08001760 if (mIsSummaryWithChildren) {
1761 mChildrenContainer.setActualHeight(height);
1762 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001763 if (mGuts != null) {
1764 mGuts.setActualHeight(height);
1765 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001766 }
1767
1768 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001769 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001770 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001771 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001772 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001773 NotificationContentView showingLayout = getShowingLayout();
1774 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001775 }
1776
1777 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001778 public int getMinHeight() {
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001779 if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08001780 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1781 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001782 return mChildrenContainer.getMinHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001783 } else if (!mOnKeyguard && mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001784 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001785 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001786 NotificationContentView showingLayout = getShowingLayout();
1787 return showingLayout.getMinHeight();
1788 }
1789
Adrian Roos0aac04f2016-12-08 15:59:29 -08001790 private int getAmbientHeight() {
1791 NotificationContentView showingLayout = getShowingLayout();
1792 return showingLayout.getAmbientChild() != null
1793 ? showingLayout.getAmbientChild().getHeight()
1794 : getCollapsedHeight();
1795 }
1796
Selim Cinek816c8e42015-11-19 12:00:45 -08001797 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001798 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001799 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001800 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001801 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001802 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001803 }
1804
1805 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001806 public void setClipTopAmount(int clipTopAmount) {
1807 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001808 for (NotificationContentView l : mLayouts) {
1809 l.setClipTopAmount(clipTopAmount);
1810 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001811 if (mGuts != null) {
1812 mGuts.setClipTopAmount(clipTopAmount);
1813 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001814 }
1815
Selim Cineka686b2c2016-10-26 13:58:27 -07001816 @Override
1817 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001818 if (clipBottomAmount != mClipBottomAmount) {
1819 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001820 for (NotificationContentView l : mLayouts) {
1821 l.setClipBottomAmount(clipBottomAmount);
1822 }
Selim Cinek65d418e2016-11-29 15:42:34 -08001823 if (mGuts != null) {
1824 mGuts.setClipBottomAmount(clipBottomAmount);
1825 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001826 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001827 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001828 // We have to update this even if it hasn't changed, since the children locations can
1829 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001830 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
1831 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001832 }
1833
Selim Cinek31094df2014-08-14 19:28:15 +02001834 public boolean isMaxExpandHeightInitialized() {
1835 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001836 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001837
Selim Cinek42357e02016-02-24 18:48:01 -08001838 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001839 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1840 }
Chris Wren78403d72014-07-28 10:23:24 +01001841
Selim Cinek1a48bab2017-02-17 19:38:40 -08001842 public void setLegacy(boolean legacy) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08001843 for (NotificationContentView l : mLayouts) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08001844 l.setLegacy(legacy);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001845 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001846 }
1847
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001848 @Override
1849 protected void updateBackgroundTint() {
1850 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001851 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001852 if (mIsSummaryWithChildren) {
1853 List<ExpandableNotificationRow> notificationChildren =
1854 mChildrenContainer.getNotificationChildren();
1855 for (int i = 0; i < notificationChildren.size(); i++) {
1856 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001857 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001858 }
1859 }
1860 }
1861
Mady Mellorb0a82462016-04-30 17:31:02 -07001862 /**
1863 * Called when a group has finished animating from collapsed or expanded state.
1864 */
1865 public void onFinishedExpansionChange() {
1866 mGroupExpansionChanging = false;
1867 updateBackgroundForGroupState();
1868 }
1869
1870 /**
1871 * Updates the parent and children backgrounds in a group based on the expansion state.
1872 */
1873 public void updateBackgroundForGroupState() {
1874 if (mIsSummaryWithChildren) {
1875 // Only when the group has finished expanding do we hide its background.
1876 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1877 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1878 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1879 for (int i = 0; i < children.size(); i++) {
1880 children.get(i).updateBackgroundForGroupState();
1881 }
1882 } else if (isChildInGroup()) {
1883 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
1884 // Only show a background if the group is expanded OR if it is expanding / collapsing
1885 // and has a custom background color
1886 final boolean showBackground = isGroupExpanded()
1887 || ((mNotificationParent.isGroupExpansionChanging()
1888 || mNotificationParent.isUserLocked()) && childColor != 0);
1889 mShowNoBackground = !showBackground;
1890 } else {
1891 // Only children or parents ever need no background.
1892 mShowNoBackground = false;
1893 }
1894 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001895 updateBackground();
1896 }
1897
Adrian Roos4a579672016-05-24 16:54:37 -07001898 public int getPositionOfChild(ExpandableNotificationRow childRow) {
1899 if (mIsSummaryWithChildren) {
1900 return mChildrenContainer.getPositionInLinearLayout(childRow);
1901 }
1902 return 0;
1903 }
1904
Chris Wren78403d72014-07-28 10:23:24 +01001905 public void setExpansionLogger(ExpansionLogger logger, String key) {
1906 mLogger = logger;
1907 mLoggingKey = key;
1908 }
1909
Chris Wren6abeeb92016-05-26 14:44:38 -04001910 public void onExpandedByGesture(boolean userExpanded) {
1911 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
1912 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
1913 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
1914 }
1915 MetricsLogger.action(mContext, event, userExpanded);
1916 }
1917
Selim Cinek6183d122016-01-14 18:48:41 -08001918 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001919 public float getIncreasedPaddingAmount() {
1920 if (mIsSummaryWithChildren) {
1921 if (isGroupExpanded()) {
1922 return 1.0f;
1923 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001924 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001925 }
Selim Cinek99104832017-01-25 14:47:33 -08001926 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08001927 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08001928 }
1929 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001930 }
1931
Selim Cineka7ed2c12017-01-23 20:47:24 -08001932 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08001933 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08001934 }
1935
Selim Cinek61633a82016-01-25 15:54:10 -08001936 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001937 protected boolean disallowSingleClick(MotionEvent event) {
1938 float x = event.getX();
1939 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001940 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001941 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001942 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001943 }
1944 return super.disallowSingleClick(event);
1945 }
1946
Chris Wren78403d72014-07-28 10:23:24 +01001947 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04001948 boolean nowExpanded = isExpanded();
1949 if (mIsSummaryWithChildren) {
1950 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
1951 }
Chris Wren78403d72014-07-28 10:23:24 +01001952 if (wasExpanded != nowExpanded && mLogger != null) {
1953 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1954 }
1955 }
Selim Cinek570981d2015-12-01 11:37:01 -08001956
Selim Cineke9bad242016-06-15 11:46:37 -07001957 @Override
1958 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1959 super.onInitializeAccessibilityNodeInfoInternal(info);
1960 if (canViewBeDismissed()) {
1961 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
1962 }
1963 }
1964
1965 @Override
1966 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
1967 if (super.performAccessibilityActionInternal(action, arguments)) {
1968 return true;
1969 }
1970 switch (action) {
1971 case AccessibilityNodeInfo.ACTION_DISMISS:
1972 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
1973 true /* fromAccessibility */);
1974 return true;
1975 }
1976 return false;
1977 }
1978
1979 public boolean shouldRefocusOnDismiss() {
1980 return mRefocusOnDismiss || isAccessibilityFocused();
1981 }
1982
Selim Cinek570981d2015-12-01 11:37:01 -08001983 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001984 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001985 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001986
1987 @Override
1988 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
1989 return new NotificationViewState(stackScrollState);
1990 }
1991
Selim Cinekd127d792016-11-01 19:11:41 -07001992 @Override
1993 public boolean isAboveShelf() {
1994 return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
1995 }
1996
Adrian Roos0aac04f2016-12-08 15:59:29 -08001997 public void setShowAmbient(boolean showAmbient) {
1998 if (showAmbient != mShowAmbient) {
1999 mShowAmbient = showAmbient;
2000 notifyHeightChanged(false /* needsAnimation */);
2001 }
2002 }
2003
Selim Cinekd127d792016-11-01 19:11:41 -07002004 public void setAboveShelf(boolean aboveShelf) {
2005 mAboveShelf = aboveShelf;
2006 }
2007
Selim Cinekd4776a52017-02-14 18:50:16 -08002008 public static class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08002009
2010 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07002011
Selim Cinekbbcebde2016-11-09 18:28:20 -08002012
2013 private NotificationViewState(StackScrollState stackScrollState) {
2014 mOverallState = stackScrollState;
2015 }
2016
2017 @Override
2018 public void applyToView(View view) {
2019 super.applyToView(view);
2020 if (view instanceof ExpandableNotificationRow) {
2021 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinekbbcebde2016-11-09 18:28:20 -08002022 row.applyChildrenState(mOverallState);
2023 }
2024 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002025
2026 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08002027 protected void onYTranslationAnimationFinished(View view) {
2028 super.onYTranslationAnimationFinished(view);
Selim Cinekd4776a52017-02-14 18:50:16 -08002029 if (view instanceof ExpandableNotificationRow) {
2030 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
2031 if (row.isHeadsUpAnimatingAway()) {
2032 row.setHeadsUpAnimatingAway(false);
2033 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002034 }
2035 }
2036
2037 @Override
2038 public void animateTo(View child, AnimationProperties properties) {
2039 super.animateTo(child, properties);
2040 if (child instanceof ExpandableNotificationRow) {
2041 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
2042 row.startChildAnimation(mOverallState, properties);
2043 }
2044 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002045 }
Chris Wren51c75102013-07-16 20:49:17 -04002046}