blob: 6a5f79fdcd9ba35375cace4252485dd63d00517f [file] [log] [blame]
Chris Wren51c75102013-07-16 20:49:17 -04001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar;
18
Mady Mellor4b80b102016-01-22 08:03:58 -080019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
Mady Mellor4b80b102016-01-22 08:03:58 -080021import android.animation.ObjectAnimator;
Mady Mellor4b80b102016-01-22 08:03:58 -080022import android.animation.ValueAnimator.AnimatorUpdateListener;
Selim Cinekddf1b392016-05-27 16:33:10 -070023import android.annotation.Nullable;
Chris Wren51c75102013-07-16 20:49:17 -040024import android.content.Context;
Selim Cinek6743c0b2017-01-18 18:24:01 -080025import android.content.res.ColorStateList;
Selim Cinekcab4a602014-09-03 14:47:57 +020026import android.graphics.drawable.AnimatedVectorDrawable;
27import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010028import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020029import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080030import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070031import android.os.Bundle;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020032import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040033import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070034import android.util.FloatProperty;
35import android.util.Property;
Selim Cinek01af3342016-02-09 19:25:31 -080036import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080037import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080038import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050039import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080040import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020041import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020042import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070043import android.view.accessibility.AccessibilityNodeInfo;
Selim Cinek98713a42015-09-21 15:47:20 +020044import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020045import android.widget.ImageView;
Selim Cinekb5605e52015-02-20 18:21:41 +010046
Chris Wren698b1702016-05-23 11:16:32 -040047import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010048import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070049import com.android.internal.util.NotificationColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080050import com.android.internal.widget.CachingIconView;
Selim Cinek0242fbb2016-10-19 13:38:32 -070051import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050052import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070053import com.android.systemui.classifier.FalsingManager;
Mady Mellor87d79452017-01-10 11:52:52 -080054import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
Selim Cinekc897bd32016-03-18 17:32:31 -070055import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinek6743c0b2017-01-18 18:24:01 -080056import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cineka7d4f822016-12-06 14:34:47 -080057import com.android.systemui.statusbar.notification.VisualStabilityManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010058import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050059import com.android.systemui.statusbar.phone.StatusBar;
Selim Cinek31aada42015-12-18 17:51:15 -080060import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek0cfbef42016-11-09 19:06:36 -080061import com.android.systemui.statusbar.stack.AnimationProperties;
62import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010063import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070064import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010065import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010066
Mady Mellor4b80b102016-01-22 08:03:58 -080067import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010068import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050069
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020070public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010071
72 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
73 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Selim Cinek0242fbb2016-10-19 13:38:32 -070074 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -080075 private int mIconTransformContentShiftNoIcon;
Selim Cinek01af3342016-02-09 19:25:31 -080076 private int mNotificationMinHeightLegacy;
77 private int mMaxHeadsUpHeightLegacy;
78 private int mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -080079 private int mMaxHeadsUpHeightIncreased;
Selim Cinek01af3342016-02-09 19:25:31 -080080 private int mNotificationMinHeight;
Selim Cinek7d1009b2017-01-25 15:28:28 -080081 private int mNotificationMinHeightLarge;
Selim Cinek01af3342016-02-09 19:25:31 -080082 private int mNotificationMaxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -080083 private int mNotificationAmbientHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -070084 private int mIncreasedPaddingBetweenElements;
Chris Wren51c75102013-07-16 20:49:17 -040085
Selim Cinek1685e632014-04-08 02:27:49 +020086 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040087 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020088 /** Has the user actively changed the expansion state of this row */
89 private boolean mHasUserChangedExpansion;
90 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040091 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -080092
93 /**
94 * Has this notification been expanded while it was pinned
95 */
96 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +020097 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040098 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020099 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -0500100 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +0200101 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -0800102 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +0200103 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700104 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400105
Selim Cinek1685e632014-04-08 02:27:49 +0200106 /**
107 * Is this notification expanded by the system. The expansion state can be overridden by the
108 * user expansion.
109 */
110 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200111
112 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700113 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200114 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700115 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200116
Mady Mellorb0a82462016-04-30 17:31:02 -0700117 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800118 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200119 private NotificationContentView mPublicLayout;
120 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800121 private NotificationContentView[] mLayouts;
Selim Cinek1685e632014-04-08 02:27:49 +0200122 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700123 private int mHeadsUpHeight;
Selim Cinek4bb59342016-04-08 19:29:35 -0700124 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100125 private ExpansionLogger mLogger;
126 private String mLoggingKey;
Mady Mellor761cde12017-01-10 11:36:39 -0800127 private NotificationMenuRow mMenuRow;
Selim Cinek8d490d42015-04-10 00:05:50 -0700128 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800129 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200130 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700131 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100132 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200133 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100134 private ViewStub mChildrenContainerStub;
135 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100136 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700137 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100138 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor761cde12017-01-10 11:36:39 -0800139 private ViewStub mMenuRowStub;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100140 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100141 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700142 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700143 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800144 private HeadsUpManager mHeadsUpManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200145
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700146 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800147 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700148 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700149 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800150 private OnExpandClickListener mOnExpandClickListener;
Mady Mellorb0a82462016-04-30 17:31:02 -0700151 private boolean mGroupExpansionChanging;
152
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800153 private OnClickListener mExpandClickListener = new OnClickListener() {
154 @Override
155 public void onClick(View v) {
Selim Cinek624c02db2015-12-14 21:00:02 -0800156 if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700157 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400158 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
159 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
160 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400161 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
162 nowExpanded);
163 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800164 } else {
Selim Cineke9bad242016-06-15 11:46:37 -0700165 if (v.isAccessibilityFocused()) {
166 mPrivateLayout.setFocusOnVisibilityChange();
167 }
Selim Cinek31aada42015-12-18 17:51:15 -0800168 boolean nowExpanded;
169 if (isPinned()) {
170 nowExpanded = !mExpandedWhenPinned;
171 mExpandedWhenPinned = nowExpanded;
172 } else {
173 nowExpanded = !isExpanded();
174 setUserExpanded(nowExpanded);
175 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800176 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800177 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400178 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
179 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800180 }
181 }
182 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700183 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700184 private boolean mDismissed;
185 private boolean mKeepInParent;
186 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700187 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
188 new FloatProperty<ExpandableNotificationRow>("translate") {
189 @Override
190 public void setValue(ExpandableNotificationRow object, float value) {
191 object.setTranslation(value);
192 }
193
194 @Override
195 public Float get(ExpandableNotificationRow object) {
196 return object.getTranslation();
197 }
198 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700199 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700200 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700201 private View mChildAfterViewWhenDismissed;
202 private View mGroupParentWhenDismissed;
203 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800204 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700205 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700206 private boolean mAboveShelf;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800207 private boolean mShowAmbient;
Selim Cinek875a3a12016-11-18 17:52:16 -0800208 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800209 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800210 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800211 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800212 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800213 private boolean mUseIncreasedHeadsUpHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -0700214
Mady Mellor43c2cd12016-12-12 21:05:13 -0800215 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700216 public boolean isGroupExpansionChanging() {
217 if (isChildInGroup()) {
218 return mNotificationParent.isGroupExpansionChanging();
219 }
220 return mGroupExpansionChanging;
221 }
222
223 public void setGroupExpansionChanging(boolean changing) {
224 mGroupExpansionChanging = changing;
225 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700226
Adrian Roos599be342016-06-13 14:54:39 -0700227 @Override
228 public void setActualHeightAnimating(boolean animating) {
229 if (mPrivateLayout != null) {
230 mPrivateLayout.setContentHeightAnimating(animating);
231 }
232 }
233
Selim Cinek8d490d42015-04-10 00:05:50 -0700234 public NotificationContentView getPrivateLayout() {
235 return mPrivateLayout;
236 }
237
238 public NotificationContentView getPublicLayout() {
239 return mPublicLayout;
240 }
241
Selim Cinekcab4a602014-09-03 14:47:57 +0200242 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800243 for (NotificationContentView l : mLayouts) {
244 setIconAnimationRunning(running, l);
245 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800246 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700247 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800248 List<ExpandableNotificationRow> notificationChildren =
249 mChildrenContainer.getNotificationChildren();
250 for (int i = 0; i < notificationChildren.size(); i++) {
251 ExpandableNotificationRow child = notificationChildren.get(i);
252 child.setIconAnimationRunning(running);
253 }
254 }
255 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200256 }
257
258 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
259 if (layout != null) {
260 View contractedChild = layout.getContractedChild();
261 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700262 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200263 setIconAnimationRunningForChild(running, contractedChild);
264 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700265 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200266 }
267 }
268
269 private void setIconAnimationRunningForChild(boolean running, View child) {
270 if (child != null) {
271 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
272 setIconRunning(icon, running);
273 ImageView rightIcon = (ImageView) child.findViewById(
274 com.android.internal.R.id.right_icon);
275 setIconRunning(rightIcon, running);
276 }
277 }
278
279 private void setIconRunning(ImageView imageView, boolean running) {
280 if (imageView != null) {
281 Drawable drawable = imageView.getDrawable();
282 if (drawable instanceof AnimationDrawable) {
283 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
284 if (running) {
285 animationDrawable.start();
286 } else {
287 animationDrawable.stop();
288 }
289 } else if (drawable instanceof AnimatedVectorDrawable) {
290 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
291 if (running) {
292 animationDrawable.start();
293 } else {
294 animationDrawable.stop();
295 }
296 }
297 }
298 }
299
Selim Cinekda42d652015-12-04 15:51:16 -0800300 public void onNotificationUpdated(NotificationData.Entry entry) {
301 mEntry = entry;
302 mStatusBarNotification = entry.notification;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800303 for (NotificationContentView l : mLayouts) {
304 l.onNotificationUpdated(entry);
305 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800306 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800307 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700308 updateNotificationColor();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800309 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700310 mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
Selim Cinekc897bd32016-03-18 17:32:31 -0700311 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800312 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800313 if (mIconAnimationRunning) {
314 setIconAnimationRunning(true);
315 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800316 if (mNotificationParent != null) {
317 mNotificationParent.updateChildrenHeaderAppearance();
318 }
Selim Cinek263398f2015-10-21 17:40:23 -0700319 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800320 // The public layouts expand button is always visible
321 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800322 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700323 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800324 updateShelfIconColor();
325 }
326
327 private void updateShelfIconColor() {
328 StatusBarIconView expandedIcon = mEntry.expandedIcon;
329 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
330 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
331 NotificationColorUtil.getInstance(mContext));
332 if (colorize) {
333 int color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded());
334 expandedIcon.setImageTintList(ColorStateList.valueOf(color));
335 }
Selim Cinekda42d652015-12-04 15:51:16 -0800336 }
337
338 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800339 for (NotificationContentView l : mLayouts) {
340 updateLimitsForView(l);
341 }
Selim Cineka1744872016-03-11 15:36:06 -0800342 }
343
344 private void updateLimitsForView(NotificationContentView layout) {
345 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800346 != com.android.internal.R.id.status_bar_latest_event_content;
347 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800348 int minHeight;
349 if (customView && beforeN && !mIsSummaryWithChildren) {
350 minHeight = mNotificationMinHeightLegacy;
351 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
352 minHeight = mNotificationMinHeightLarge;
353 } else {
354 minHeight = mNotificationMinHeight;
355 }
Selim Cineka1744872016-03-11 15:36:06 -0800356 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
357 layout.getHeadsUpChild().getId()
358 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800359 int headsUpheight;
360 if (headsUpCustom && beforeN) {
361 headsUpheight = mMaxHeadsUpHeightLegacy;
362 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
363 headsUpheight = mMaxHeadsUpHeightIncreased;
364 } else {
365 headsUpheight = mMaxHeadsUpHeight;
366 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800367 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
368 mNotificationAmbientHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200369 }
370
371 public StatusBarNotification getStatusBarNotification() {
372 return mStatusBarNotification;
373 }
374
Selim Cinek281c2022016-10-13 19:14:43 -0700375 public NotificationData.Entry getEntry() {
376 return mEntry;
377 }
378
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700379 public boolean isHeadsUp() {
380 return mIsHeadsUp;
381 }
382
Selim Cinek1a521f32014-11-03 17:39:29 +0100383 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700384 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100385 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700386 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700387 if (mIsSummaryWithChildren) {
388 // The overflow might change since we allow more lines as HUN.
389 mChildrenContainer.updateGroupOverflow();
390 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700391 if (intrinsicBefore != getIntrinsicHeight()) {
392 notifyHeightChanged(false /* needsAnimation */);
393 }
Selim Cinekd127d792016-11-01 19:11:41 -0700394 if (isHeadsUp) {
395 setAboveShelf(true);
396 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100397 }
398
Selim Cinekb5605e52015-02-20 18:21:41 +0100399 public void setGroupManager(NotificationGroupManager groupManager) {
400 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700401 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100402 }
403
Adrian Roosb88b1a12015-12-09 18:51:05 -0800404 public void setRemoteInputController(RemoteInputController r) {
405 mPrivateLayout.setRemoteInputController(r);
406 }
407
Mady Mellor3fd273e2016-03-15 21:08:14 -0700408 public void setAppName(String appName) {
409 mAppName = appName;
Mady Mellor761cde12017-01-10 11:36:39 -0800410 if (mMenuRow != null) {
411 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700412 }
413 }
414
Selim Cinekb5605e52015-02-20 18:21:41 +0100415 public void addChildNotification(ExpandableNotificationRow row) {
416 addChildNotification(row, -1);
417 }
418
419 /**
420 * Add a child notification to this view.
421 *
422 * @param row the row to add
423 * @param childIndex the index to add it at, if -1 it will be added at the end
424 */
425 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
426 if (mChildrenContainer == null) {
427 mChildrenContainerStub.inflate();
428 }
429 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700430 onChildrenCountChanged();
431 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100432 }
433
434 public void removeChildNotification(ExpandableNotificationRow row) {
435 if (mChildrenContainer != null) {
436 mChildrenContainer.removeNotification(row);
437 }
Selim Cinek263398f2015-10-21 17:40:23 -0700438 onChildrenCountChanged();
439 row.setIsChildInGroup(false, null);
440 }
441
Mady Mellor43c2cd12016-12-12 21:05:13 -0800442 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700443 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700444 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700445 }
446
Selim Cinek388df6d2015-10-22 13:25:11 -0700447 public ExpandableNotificationRow getNotificationParent() {
448 return mNotificationParent;
449 }
450
Selim Cinek263398f2015-10-21 17:40:23 -0700451 /**
452 * @param isChildInGroup Is this notification now in a group
453 * @param parent the new parent notification
454 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700455 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500456 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700457 mNotificationParent = childInGroup ? parent : null;
458 mPrivateLayout.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400459 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700460 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700461 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700462 if (mNotificationParent != null) {
463 mNotificationParent.updateBackgroundForGroupState();
464 }
Selim Cinekdb167372016-11-17 15:41:17 -0800465 updateIconVisibilities();
Selim Cinek34d93b02015-10-22 12:30:38 -0700466 }
467
468 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800469 public boolean onTouchEvent(MotionEvent event) {
470 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
471 || !isChildInGroup() || isGroupExpanded()) {
472 return super.onTouchEvent(event);
473 } else {
474 return false;
475 }
476 }
477
478 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800479 protected boolean handleSlideBack() {
Mady Mellor761cde12017-01-10 11:36:39 -0800480 if (mMenuRow != null && mMenuRow.isVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800481 animateTranslateNotification(0 /* targetLeft */);
482 return true;
483 }
484 return false;
485 }
486
487 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700488 protected boolean shouldHideBackground() {
489 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700490 }
491
492 @Override
493 public boolean isSummaryWithChildren() {
494 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100495 }
496
497 @Override
498 public boolean areChildrenExpanded() {
499 return mChildrenExpanded;
500 }
501
502 public List<ExpandableNotificationRow> getNotificationChildren() {
503 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
504 }
505
Selim Cinekeef84282015-10-30 16:28:00 -0700506 public int getNumberOfNotificationChildren() {
507 if (mChildrenContainer == null) {
508 return 0;
509 }
510 return mChildrenContainer.getNotificationChildren().size();
511 }
512
Selim Cinekb5605e52015-02-20 18:21:41 +0100513 /**
514 * Apply the order given in the list to the children.
515 *
516 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800517 * @param visualStabilityManager
518 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100519 * @return whether the list order has changed
520 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800521 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
522 VisualStabilityManager visualStabilityManager,
523 VisualStabilityManager.Callback callback) {
524 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
525 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100526 }
527
528 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700529 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800530 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100531 mChildrenContainer.getState(resultState, parentState);
532 }
533 }
534
535 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700536 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100537 mChildrenContainer.applyState(state);
538 }
539 }
540
541 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700542 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100543 mChildrenContainer.prepareExpansionChanged(state);
544 }
545 }
546
Selim Cinek0cfbef42016-11-09 19:06:36 -0800547 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700548 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800549 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100550 }
551 }
552
553 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800554 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100555 return this;
556 } else {
557 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
558 return view == null ? this : view;
559 }
560 }
561
Selim Cinekab29aeb2015-02-20 18:18:32 +0100562 public NotificationGuts getGuts() {
563 return mGuts;
564 }
565
Selim Cinek684a4422015-04-15 16:18:39 -0700566 /**
567 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
568 * the notification will be rendered on top of the screen.
569 *
570 * @param pinned whether it is pinned
571 */
572 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700573 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700574 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700575 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700576 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700577 }
Selim Cinek31aada42015-12-18 17:51:15 -0800578 if (pinned) {
579 setIconAnimationRunning(true);
580 mExpandedWhenPinned = false;
581 } else if (mExpandedWhenPinned) {
582 setUserExpanded(true);
583 }
Selim Cinek98713a42015-09-21 15:47:20 +0200584 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700585 }
586
Selim Cinek684a4422015-04-15 16:18:39 -0700587 public boolean isPinned() {
588 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700589 }
590
Selim Cinekd127d792016-11-01 19:11:41 -0700591 @Override
592 public int getPinnedHeadsUpHeight() {
593 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
594 }
595
Selim Cinek31aada42015-12-18 17:51:15 -0800596 /**
597 * @param atLeastMinHeight should the value returned be at least the minimum height.
598 * Used to avoid cyclic calls
599 * @return the height of the heads up notification when pinned
600 */
Selim Cinekd127d792016-11-01 19:11:41 -0700601 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800602 if (mIsSummaryWithChildren) {
603 return mChildrenContainer.getIntrinsicHeight();
604 }
Selim Cinek31aada42015-12-18 17:51:15 -0800605 if(mExpandedWhenPinned) {
606 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
607 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700608 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800609 } else {
610 return mHeadsUpHeight;
611 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700612 }
613
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700614 /**
615 * Mark whether this notification was just clicked, i.e. the user has just clicked this
616 * notification in this frame.
617 */
618 public void setJustClicked(boolean justClicked) {
619 mJustClicked = justClicked;
620 }
621
622 /**
623 * @return true if this notification has been clicked in this frame, false otherwise
624 */
625 public boolean wasJustClicked() {
626 return mJustClicked;
627 }
628
Selim Cinek98713a42015-09-21 15:47:20 +0200629 public void setChronometerRunning(boolean running) {
630 mLastChronometerRunning = running;
631 setChronometerRunning(running, mPrivateLayout);
632 setChronometerRunning(running, mPublicLayout);
633 if (mChildrenContainer != null) {
634 List<ExpandableNotificationRow> notificationChildren =
635 mChildrenContainer.getNotificationChildren();
636 for (int i = 0; i < notificationChildren.size(); i++) {
637 ExpandableNotificationRow child = notificationChildren.get(i);
638 child.setChronometerRunning(running);
639 }
640 }
641 }
642
643 private void setChronometerRunning(boolean running, NotificationContentView layout) {
644 if (layout != null) {
645 running = running || isPinned();
646 View contractedChild = layout.getContractedChild();
647 View expandedChild = layout.getExpandedChild();
648 View headsUpChild = layout.getHeadsUpChild();
649 setChronometerRunningForChild(running, contractedChild);
650 setChronometerRunningForChild(running, expandedChild);
651 setChronometerRunningForChild(running, headsUpChild);
652 }
653 }
654
655 private void setChronometerRunningForChild(boolean running, View child) {
656 if (child != null) {
657 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
658 if (chronometer instanceof Chronometer) {
659 ((Chronometer) chronometer).setStarted(running);
660 }
661 }
662 }
663
Selim Cinekea4bef72015-12-02 15:51:10 -0800664 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700665 if (mIsSummaryWithChildren) {
666 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700667 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800668 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700669 }
670
Selim Cinek34eda5e2016-02-18 17:10:43 -0800671 private NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700672 if (mIsSummaryWithChildren && !mShowingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700673 return mChildrenContainer.getHeaderView();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800674 }
675 return getShowingLayout().getVisibleNotificationHeader();
676 }
677
Selim Cinek570981d2015-12-01 11:37:01 -0800678 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
679 mOnExpandClickListener = onExpandClickListener;
680 }
681
Selim Cinekddf1b392016-05-27 16:33:10 -0700682 @Override
683 public void setOnClickListener(@Nullable OnClickListener l) {
684 super.setOnClickListener(l);
685 mOnClickListener = l;
686 updateClickAndFocus();
687 }
688
689 private void updateClickAndFocus() {
690 boolean normalChild = !isChildInGroup() || isGroupExpanded();
691 boolean clickable = mOnClickListener != null && normalChild;
692 if (isFocusable() != normalChild) {
693 setFocusable(normalChild);
694 }
695 if (isClickable() != clickable) {
696 setClickable(clickable);
697 }
698 }
699
Selim Cinek31aada42015-12-18 17:51:15 -0800700 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
701 mHeadsUpManager = headsUpManager;
702 }
703
Mady Mellor87d79452017-01-10 11:52:52 -0800704 public void setGutsView(MenuItem item) {
705 if (mGuts != null) {
706 item.gutsContent.setInteractionListener(mGuts);
707 mGuts.setGutsContent(item.gutsContent);
708 }
709 }
710
Selim Cinek01af3342016-02-09 19:25:31 -0800711 public void reInflateViews() {
712 initDimens();
713 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800714 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700715 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800716 }
717 }
718 if (mGuts != null) {
719 View oldGuts = mGuts;
720 int index = indexOfChild(oldGuts);
721 removeView(oldGuts);
722 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
723 R.layout.notification_guts, this, false);
724 mGuts.setVisibility(oldGuts.getVisibility());
725 addView(mGuts, index);
726 }
Mady Mellor761cde12017-01-10 11:36:39 -0800727 if (mMenuRow != null) {
728 View oldMenu = mMenuRow;
729 int menuIndex = indexOfChild(oldMenu);
730 removeView(oldMenu);
731 mMenuRow = (NotificationMenuRow) LayoutInflater.from(mContext).inflate(
732 R.layout.notification_menu_row, this, false);
733 mMenuRow.setNotificationRowParent(ExpandableNotificationRow.this);
734 mMenuRow.setAppName(mAppName);
735 mMenuRow.setVisibility(oldMenu.getVisibility());
736 addView(mMenuRow, menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -0800737
738 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800739 for (NotificationContentView l : mLayouts) {
740 l.reInflateViews();
741 }
Selim Cinek01af3342016-02-09 19:25:31 -0800742 }
743
Selim Cinekc3179332016-03-04 14:44:56 -0800744 public void setContentBackground(int customBackgroundColor, boolean animate,
745 NotificationContentView notificationContentView) {
746 if (getShowingLayout() == notificationContentView) {
747 setTintColor(customBackgroundColor, animate);
748 }
749 }
750
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700751 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800752 for (NotificationContentView l : mLayouts) {
753 l.closeRemoteInput();
754 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700755 }
756
Selim Cinekc897bd32016-03-18 17:32:31 -0700757 /**
758 * Set by how much the single line view should be indented.
759 */
760 public void setSingleLineWidthIndention(int indention) {
761 mPrivateLayout.setSingleLineWidthIndention(indention);
762 }
763
764 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700765 return mNotificationColor;
766 }
767
768 private void updateNotificationColor() {
769 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
770 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700771 }
772
773 public HybridNotificationView getSingleLineView() {
774 return mPrivateLayout.getSingleLineView();
775 }
776
Selim Cinekf07d0622016-03-21 19:52:52 -0700777 public boolean isOnKeyguard() {
778 return mOnKeyguard;
779 }
780
Selim Cinekc1e389d2016-04-07 11:02:57 -0700781 public void removeAllChildren() {
782 List<ExpandableNotificationRow> notificationChildren
783 = mChildrenContainer.getNotificationChildren();
784 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
785 for (int i = 0; i < clonedList.size(); i++) {
786 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700787 if (row.keepInParent()) {
788 continue;
789 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700790 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700791 row.setIsChildInGroup(false, null);
792 }
793 onChildrenCountChanged();
794 }
795
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700796 public void setForceUnlocked(boolean forceUnlocked) {
797 mForceUnlocked = forceUnlocked;
798 if (mIsSummaryWithChildren) {
799 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
800 for (ExpandableNotificationRow child : notificationChildren) {
801 child.setForceUnlocked(forceUnlocked);
802 }
803 }
804 }
805
Selim Cineke9bad242016-06-15 11:46:37 -0700806 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700807 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700808 mGroupParentWhenDismissed = mNotificationParent;
809 mRefocusOnDismiss = fromAccessibility;
810 mChildAfterViewWhenDismissed = null;
811 if (isChildInGroup()) {
812 List<ExpandableNotificationRow> notificationChildren =
813 mNotificationParent.getNotificationChildren();
814 int i = notificationChildren.indexOf(this);
815 if (i != -1 && i < notificationChildren.size() - 1) {
816 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
817 }
818 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700819 }
820
821 public boolean isDismissed() {
822 return mDismissed;
823 }
824
825 public boolean keepInParent() {
826 return mKeepInParent;
827 }
828
829 public void setKeepInParent(boolean keepInParent) {
830 mKeepInParent = keepInParent;
831 }
832
833 public boolean isRemoved() {
834 return mRemoved;
835 }
836
Adrian Roosd009ab12016-05-20 17:58:53 -0700837 public void setRemoved() {
838 mRemoved = true;
839
840 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700841 }
842
Selim Cinekd1395642016-04-28 12:22:42 -0700843 public NotificationChildrenContainer getChildrenContainer() {
844 return mChildrenContainer;
845 }
846
Selim Cinekcafa87f2016-10-26 17:00:17 -0700847 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
848 mHeadsupDisappearRunning = headsUpAnimatingAway;
849 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
850 }
851
852 /**
853 * @return if the view was just heads upped and is now animating away. During such a time the
854 * layout needs to be kept consistent
855 */
856 public boolean isHeadsUpAnimatingAway() {
857 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700858 }
859
Selim Cineke9bad242016-06-15 11:46:37 -0700860 public View getChildAfterViewWhenDismissed() {
861 return mChildAfterViewWhenDismissed;
862 }
863
864 public View getGroupParentWhenDismissed() {
865 return mGroupParentWhenDismissed;
866 }
867
Selim Cinek9e624e72016-07-20 13:46:49 -0700868 public void performDismiss() {
Selim Cineke9079112016-12-14 14:41:01 -0800869 if (mOnDismissRunnable != null) {
870 mOnDismissRunnable.run();
871 }
Selim Cinek9e624e72016-07-20 13:46:49 -0700872 }
873
Selim Cineke9079112016-12-14 14:41:01 -0800874 public void setOnDismissRunnable(Runnable onDismissRunnable) {
875 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -0700876 }
877
Selim Cinek281c2022016-10-13 19:14:43 -0700878 public View getNotificationIcon() {
879 NotificationHeaderView notificationHeader = getNotificationHeader();
880 if (notificationHeader != null) {
881 return notificationHeader.getIcon();
882 }
883 return null;
884 }
885
886 /**
887 * @return whether the notification is currently showing a view with an icon.
888 */
889 public boolean isShowingIcon() {
890 if (mIsSummaryWithChildren) {
891 return true;
892 }
893 NotificationContentView showingLayout = getShowingLayout();
894 NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
895 return notificationHeader != null;
896 }
897
Selim Cinek0242fbb2016-10-19 13:38:32 -0700898 /**
899 * Set how much this notification is transformed into an icon.
900 *
Selim Cinek2b549f42016-11-22 16:38:51 -0800901 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
902 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -0800903 * @param isLastChild is this the last child in the list. If true, then the transformation is
904 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -0700905 */
Selim Cinek2b549f42016-11-22 16:38:51 -0800906 public void setContentTransformationAmount(float contentTransformationAmount,
907 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -0800908 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800909 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800910 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800911 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800912 if (changeTransformation) {
913 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -0800914 }
915 }
916
917 /**
918 * Set the icons to be visible of this notification.
919 */
920 public void setIconsVisible(boolean iconsVisible) {
921 if (iconsVisible != mIconsVisible) {
922 mIconsVisible = iconsVisible;
923 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700924 }
925 }
926
Selim Cinekdb167372016-11-17 15:41:17 -0800927 @Override
928 protected void onBelowSpeedBumpChanged() {
929 updateIconVisibilities();
930 }
931
Selim Cinek875a3a12016-11-18 17:52:16 -0800932 private void updateContentTransformation() {
933 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -0800934 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800935 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -0800936 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800937 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700938 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -0800939 translationY *= 0.4f;
940 } else {
941 contentAlpha = 1.0f;
942 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800943 for (NotificationContentView l : mLayouts) {
944 l.setAlpha(contentAlpha);
945 l.setTranslationY(translationY);
946 }
Selim Cinek875a3a12016-11-18 17:52:16 -0800947 if (mChildrenContainer != null) {
948 mChildrenContainer.setAlpha(contentAlpha);
949 mChildrenContainer.setTranslationY(translationY);
950 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -0700951 }
952 }
953
954 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -0800955 boolean visible = isChildInGroup()
956 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
957 || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800958 for (NotificationContentView l : mLayouts) {
959 l.setIconsVisible(visible);
960 }
Selim Cinekdb167372016-11-17 15:41:17 -0800961 if (mChildrenContainer != null) {
962 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700963 }
964 }
965
Selim Cinek875a3a12016-11-18 17:52:16 -0800966 /**
967 * Get the relative top padding of a view relative to this view. This recursively walks up the
968 * hierarchy and does the corresponding measuring.
969 *
970 * @param view the view to the the padding for. The requested view has to be a child of this
971 * notification.
972 * @return the toppadding
973 */
974 public int getRelativeTopPadding(View view) {
975 int topPadding = 0;
976 while (view.getParent() instanceof ViewGroup) {
977 topPadding += view.getTop();
978 view = (View) view.getParent();
979 if (view instanceof ExpandableNotificationRow) {
980 return topPadding;
981 }
982 }
983 return topPadding;
984 }
985
Selim Cineka1d97902016-12-14 16:31:40 -0800986 public float getContentTranslation() {
987 return mPrivateLayout.getTranslationY();
988 }
989
Selim Cinek6743c0b2017-01-18 18:24:01 -0800990 public void setIsLowPriority(boolean isLowPriority) {
991 mIsLowPriority = isLowPriority;
992 mPrivateLayout.setIsLowPriority(isLowPriority);
993 if (mChildrenContainer != null) {
994 mChildrenContainer.setIsLowPriority(isLowPriority);
995 }
996 }
997
Selim Cinek7d1009b2017-01-25 15:28:28 -0800998 public void setUseIncreasedCollapsedHeight(boolean use) {
999 mUseIncreasedCollapsedHeight = use;
1000 }
1001
Selim Cinek87ed69b2017-02-09 15:59:43 -08001002 public void setUseIncreasedHeadsUpHeight(boolean use) {
1003 mUseIncreasedHeadsUpHeight = use;
1004 }
1005
Chris Wren78403d72014-07-28 10:23:24 +01001006 public interface ExpansionLogger {
1007 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
1008 }
Selim Cinek1685e632014-04-08 02:27:49 +02001009
Chris Wren51c75102013-07-16 20:49:17 -04001010 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1011 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001012 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -08001013 initDimens();
1014 }
1015
1016 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -08001017 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
1018 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001019 mNotificationMinHeightLarge = getFontScaledHeight(
Selim Cinek87ed69b2017-02-09 15:59:43 -08001020 R.dimen.notification_min_height_increased);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001021 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
Adrian Roos0aac04f2016-12-08 15:59:29 -08001022 mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001023 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -08001024 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001025 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001026 mMaxHeadsUpHeightIncreased = getFontScaledHeight(
1027 R.dimen.notification_max_heads_up_height_increased);
Mady Mellorb0a82462016-04-30 17:31:02 -07001028 mIncreasedPaddingBetweenElements = getResources()
1029 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinek875a3a12016-11-18 17:52:16 -08001030 mIconTransformContentShiftNoIcon = getResources().getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001031 R.dimen.notification_icon_transform_content_shift);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001032 }
1033
1034 /**
1035 * @param dimenId the dimen to look up
1036 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
1037 */
1038 private int getFontScaledHeight(int dimenId) {
1039 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
1040 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
1041 getResources().getDisplayMetrics().density);
1042 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -04001043 }
1044
Christoph Studera7fe6312014-06-27 19:32:44 +02001045 /**
1046 * Resets this view so it can be re-used for an updated notification.
1047 */
Christoph Studer22f2ee52014-07-29 22:57:21 +02001048 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +02001049 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +02001050 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +01001051 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +02001052 mExpandable = false;
1053 mHasUserChangedExpansion = false;
1054 mUserLocked = false;
1055 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +02001056 mSensitive = false;
1057 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +02001058 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -07001059 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -08001060 mPublicLayout.reset();
1061 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +02001062 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -08001063 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +02001064 logExpansionEvent(false, wasExpanded);
1065 }
1066
1067 public void resetHeight() {
Selim Cinek31094df2014-08-14 19:28:15 +02001068 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001069 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001070 }
1071
Jorim Jaggi251957d2014-04-09 04:24:09 +02001072 @Override
1073 protected void onFinishInflate() {
1074 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001075 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1076 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001077 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1078
1079 for (NotificationContentView l : mLayouts) {
1080 l.setExpandClickListener(mExpandClickListener);
1081 l.setContainingNotification(this);
1082 }
Mady Mellor761cde12017-01-10 11:36:39 -08001083 mMenuRowStub = (ViewStub) findViewById(R.id.menu_row_stub);
1084 mMenuRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Mady Mellor4b80b102016-01-22 08:03:58 -08001085 @Override
1086 public void onInflate(ViewStub stub, View inflated) {
Mady Mellor761cde12017-01-10 11:36:39 -08001087 mMenuRow = (NotificationMenuRow) inflated;
1088 mMenuRow.setNotificationRowParent(ExpandableNotificationRow.this);
1089 mMenuRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -08001090 }
1091 });
Selim Cinekab29aeb2015-02-20 18:18:32 +01001092 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1093 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001094 @Override
1095 public void onInflate(ViewStub stub, View inflated) {
1096 mGuts = (NotificationGuts) inflated;
1097 mGuts.setClipTopAmount(getClipTopAmount());
1098 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001099 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001100 }
1101 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001102 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1103 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1104
1105 @Override
1106 public void onInflate(ViewStub stub, View inflated) {
1107 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001108 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek388df6d2015-10-22 13:25:11 -07001109 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001110 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -08001111 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +01001112 }
1113 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001114
1115 // Add the views that we translate to reveal the gear
1116 mTranslateableViews = new ArrayList<View>();
1117 for (int i = 0; i < getChildCount(); i++) {
1118 mTranslateableViews.add(getChildAt(i));
1119 }
1120 // Remove views that don't translate
Mady Mellor761cde12017-01-10 11:36:39 -08001121 mTranslateableViews.remove(mMenuRowStub);
Mady Mellor4b80b102016-01-22 08:03:58 -08001122 mTranslateableViews.remove(mChildrenContainerStub);
1123 mTranslateableViews.remove(mGutsStub);
1124 }
1125
Mady Mellor4b80b102016-01-22 08:03:58 -08001126 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001127 if (mTranslateAnim != null) {
1128 mTranslateAnim.cancel();
1129 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001130 if (mTranslateableViews != null) {
1131 for (int i = 0; i < mTranslateableViews.size(); i++) {
1132 mTranslateableViews.get(i).setTranslationX(0);
1133 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001134 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001135 invalidateOutline();
Mady Mellor761cde12017-01-10 11:36:39 -08001136 if (mMenuRow != null) {
1137 mMenuRow.resetState(true /* notify */);
Mady Mellor4b80b102016-01-22 08:03:58 -08001138 }
1139 }
1140
1141 public void animateTranslateNotification(final float leftTarget) {
1142 if (mTranslateAnim != null) {
1143 mTranslateAnim.cancel();
1144 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001145 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001146 if (mTranslateAnim != null) {
1147 mTranslateAnim.start();
1148 }
1149 }
1150
1151 @Override
1152 public void setTranslation(float translationX) {
1153 if (areGutsExposed()) {
1154 // Don't translate if guts are showing.
1155 return;
1156 }
1157 // Translate the group of views
1158 for (int i = 0; i < mTranslateableViews.size(); i++) {
1159 if (mTranslateableViews.get(i) != null) {
1160 mTranslateableViews.get(i).setTranslationX(translationX);
1161 }
1162 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001163 invalidateOutline();
Mady Mellor761cde12017-01-10 11:36:39 -08001164 if (mMenuRow != null) {
1165 mMenuRow.updateMenuAlpha(translationX, getMeasuredWidth());
Mady Mellor34958fa2016-02-23 09:52:17 -08001166 }
1167 }
1168
1169 @Override
1170 public float getTranslation() {
1171 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1172 // All of the views in the list should have same translation, just use first one.
1173 return mTranslateableViews.get(0).getTranslationX();
1174 }
1175 return 0;
1176 }
1177
1178 public Animator getTranslateViewAnimator(final float leftTarget,
1179 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001180 if (mTranslateAnim != null) {
1181 mTranslateAnim.cancel();
1182 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001183 if (areGutsExposed()) {
1184 // No translation if guts are exposed.
1185 return null;
1186 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001187 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1188 leftTarget);
1189 if (listener != null) {
1190 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001191 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001192 translateAnim.addListener(new AnimatorListenerAdapter() {
1193 boolean cancelled = false;
1194
1195 @Override
1196 public void onAnimationCancel(Animator anim) {
1197 cancelled = true;
1198 }
1199
1200 @Override
1201 public void onAnimationEnd(Animator anim) {
Mady Mellor761cde12017-01-10 11:36:39 -08001202 if (!cancelled && mMenuRow != null && leftTarget == 0) {
1203 mMenuRow.resetState(true /* notify */);
Mady Mellorb0a82462016-04-30 17:31:02 -07001204 mTranslateAnim = null;
1205 }
1206 }
1207 });
1208 mTranslateAnim = translateAnim;
1209 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001210 }
1211
1212 public float getSpaceForGear() {
Mady Mellor761cde12017-01-10 11:36:39 -08001213 if (mMenuRow != null) {
1214 return mMenuRow.getSpaceForMenu();
Mady Mellor4b80b102016-01-22 08:03:58 -08001215 }
1216 return 0;
1217 }
1218
Mady Mellor761cde12017-01-10 11:36:39 -08001219 public NotificationMenuRow getSettingsRow() {
1220 if (mMenuRow == null) {
1221 mMenuRowStub.inflate();
Mady Mellor4b80b102016-01-22 08:03:58 -08001222 }
Mady Mellor761cde12017-01-10 11:36:39 -08001223 return mMenuRow;
Mady Mellor4b80b102016-01-22 08:03:58 -08001224 }
1225
Selim Cinekab29aeb2015-02-20 18:18:32 +01001226 public void inflateGuts() {
1227 if (mGuts == null) {
1228 mGutsStub.inflate();
1229 }
1230 }
1231
Selim Cinekda42d652015-12-04 15:51:16 -08001232 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001233 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1234 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001235 if (mChildrenContainer != null) {
1236 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1237 : INVISIBLE);
Mady Mellorb0a82462016-04-30 17:31:02 -07001238 mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
1239 ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001240 : INVISIBLE);
1241 }
Selim Cinekda42d652015-12-04 15:51:16 -08001242 // The limits might have changed if the view suddenly became a group or vice versa
1243 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001244 }
1245
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001246 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001247 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1248 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001249 // Add a record for the entire layout since its content is somehow small.
1250 // The event comes from a leaf view that is interacted with.
1251 AccessibilityEvent record = AccessibilityEvent.obtain();
1252 onInitializeAccessibilityEvent(record);
1253 dispatchPopulateAccessibilityEvent(record);
1254 event.appendRecord(record);
1255 return true;
1256 }
1257 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001258 }
Chris Wren51c75102013-07-16 20:49:17 -04001259
John Spurlocke15452b2014-08-21 09:44:39 -04001260 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001261 public void setDark(boolean dark, boolean fade, long delay) {
1262 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001263 final NotificationContentView showing = getShowingLayout();
1264 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001265 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001266 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001267 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001268 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001269 }
John Spurlocke15452b2014-08-21 09:44:39 -04001270 }
1271
Chris Wren51c75102013-07-16 20:49:17 -04001272 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001273 if (mIsSummaryWithChildren && !mShowingPublic) {
1274 return !mChildrenExpanded;
1275 }
Chris Wren51c75102013-07-16 20:49:17 -04001276 return mExpandable;
1277 }
1278
1279 public void setExpandable(boolean expandable) {
1280 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001281 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001282 }
1283
Selim Cinek4ffd6362015-12-29 15:12:23 +01001284 @Override
1285 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001286 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1287 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001288 }
1289
Selim Cinek1685e632014-04-08 02:27:49 +02001290 /**
1291 * @return whether the user has changed the expansion state
1292 */
1293 public boolean hasUserChangedExpansion() {
1294 return mHasUserChangedExpansion;
1295 }
1296
Chris Wren51c75102013-07-16 20:49:17 -04001297 public boolean isUserExpanded() {
1298 return mUserExpanded;
1299 }
1300
Selim Cinek1685e632014-04-08 02:27:49 +02001301 /**
1302 * Set this notification to be expanded by the user
1303 *
1304 * @param userExpanded whether the user wants this notification to be expanded
1305 */
Chris Wren51c75102013-07-16 20:49:17 -04001306 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001307 setUserExpanded(userExpanded, false /* allowChildExpansion */);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001308 updateShelfIconColor();
Selim Cinek388df6d2015-10-22 13:25:11 -07001309 }
1310
1311 /**
1312 * Set this notification to be expanded by the user
1313 *
1314 * @param userExpanded whether the user wants this notification to be expanded
1315 * @param allowChildExpansion whether a call to this method allows expanding children
1316 */
1317 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001318 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -07001319 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
Chris Wren698b1702016-05-23 11:16:32 -04001320 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001321 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Chris Wren698b1702016-05-23 11:16:32 -04001322 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001323 return;
1324 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001325 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001326 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001327 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001328 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001329 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001330 }
1331
Selim Cinekccd14fb2014-08-12 18:53:24 +02001332 public void resetUserExpansion() {
1333 mHasUserChangedExpansion = false;
1334 mUserExpanded = false;
1335 }
1336
Chris Wren51c75102013-07-16 20:49:17 -04001337 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001338 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001339 }
1340
1341 public void setUserLocked(boolean userLocked) {
1342 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001343 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001344 if (mIsSummaryWithChildren) {
1345 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek7baaa9e2016-07-21 17:21:09 -07001346 if (userLocked || !isGroupExpanded()) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001347 updateBackgroundForGroupState();
1348 }
Selim Cinek42357e02016-02-24 18:48:01 -08001349 }
Chris Wren51c75102013-07-16 20:49:17 -04001350 }
1351
Selim Cinek1685e632014-04-08 02:27:49 +02001352 /**
1353 * @return has the system set this notification to be expanded
1354 */
1355 public boolean isSystemExpanded() {
1356 return mIsSystemExpanded;
1357 }
1358
1359 /**
1360 * Set this notification to be expanded by the system.
1361 *
1362 * @param expand whether the system wants this notification to be expanded.
1363 */
1364 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001365 if (expand != mIsSystemExpanded) {
1366 final boolean wasExpanded = isExpanded();
1367 mIsSystemExpanded = expand;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001368 updateShelfIconColor();
Selim Cinekb5605e52015-02-20 18:21:41 +01001369 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001370 logExpansionEvent(false, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001371 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001372 mChildrenContainer.updateGroupOverflow();
1373 }
Selim Cinek31094df2014-08-14 19:28:15 +02001374 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001375 }
1376
1377 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001378 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001379 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001380 public void setOnKeyguard(boolean onKeyguard) {
1381 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001382 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001383 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001384 logExpansionEvent(false, wasExpanded);
1385 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001386 if (mIsSummaryWithChildren) {
1387 mChildrenContainer.updateGroupOverflow();
1388 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001389 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001390 }
1391 }
Selim Cinek1685e632014-04-08 02:27:49 +02001392 }
1393
1394 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001395 * @return Can the underlying notification be cleared? This can be different from whether the
1396 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1397 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001398 */
1399 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001400 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1401 return false;
1402 }
1403 if (mIsSummaryWithChildren) {
1404 List<ExpandableNotificationRow> notificationChildren =
1405 mChildrenContainer.getNotificationChildren();
1406 for (int i = 0; i < notificationChildren.size(); i++) {
1407 ExpandableNotificationRow child = notificationChildren.get(i);
1408 if (!child.isClearable()) {
1409 return false;
1410 }
1411 }
1412 }
1413 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001414 }
1415
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001416 @Override
1417 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001418 if (isUserLocked()) {
1419 return getActualHeight();
1420 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001421 if (mGuts != null && mGuts.isExposed()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001422 return mGuts.getHeight();
1423 } else if ((isChildInGroup() && !isGroupExpanded())) {
1424 return mPrivateLayout.getMinHeight();
Adrian Roos0aac04f2016-12-08 15:59:29 -08001425 } else if (mShowAmbient) {
1426 return getAmbientHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001427 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1428 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001429 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001430 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001431 } else if (!mOnKeyguard && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07001432 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001433 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1434 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001435 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001436 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001437 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001438 }
Selim Cinek31aada42015-12-18 17:51:15 -08001439 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001440 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001441 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001442 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001443 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001444 }
Selim Cinek1685e632014-04-08 02:27:49 +02001445
Mady Mellor43c2cd12016-12-12 21:05:13 -08001446 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001447 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001448 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001449 }
1450
Selim Cinek263398f2015-10-21 17:40:23 -07001451 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05001452 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001453 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1454 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
1455 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
1456 mEntry.notification);
Selim Cinek263398f2015-10-21 17:40:23 -07001457 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001458 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001459 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001460 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001461 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001462 }
1463
Mady Mellorb0a82462016-04-30 17:31:02 -07001464 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001465 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001466 mChildrenContainer.updateChildrenHeaderAppearance();
1467 }
1468 }
1469
Selim Cinek1685e632014-04-08 02:27:49 +02001470 /**
1471 * Check whether the view state is currently expanded. This is given by the system in {@link
1472 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1473 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1474 * view can differ from this state, if layout params are modified from outside.
1475 *
1476 * @return whether the view state is currently expanded.
1477 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001478 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001479 return isExpanded(false /* allowOnKeyguard */);
1480 }
1481
1482 public boolean isExpanded(boolean allowOnKeyguard) {
1483 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001484 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1485 || isUserExpanded());
1486 }
1487
1488 private boolean isSystemChildExpanded() {
1489 return mIsSystemChildExpanded;
1490 }
1491
1492 public void setSystemChildExpanded(boolean expanded) {
1493 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001494 }
1495
1496 @Override
1497 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1498 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001499 updateMaxHeights();
Mady Mellor761cde12017-01-10 11:36:39 -08001500 if (mMenuRow != null) {
1501 mMenuRow.updateVerticalLocation();
Mady Mellora6edc872016-04-26 11:01:03 -07001502 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001503 updateContentShiftHeight();
1504 }
1505
1506 /**
1507 * Updates the content shift height such that the header is completely hidden when coming from
1508 * the top.
1509 */
1510 private void updateContentShiftHeight() {
1511 NotificationHeaderView notificationHeader = getNotificationHeader();
1512 if (notificationHeader != null) {
1513 CachingIconView icon = notificationHeader.getIcon();
1514 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1515 } else {
1516 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1517 }
Selim Cinek1685e632014-04-08 02:27:49 +02001518 }
1519
Selim Cinek8d490d42015-04-10 00:05:50 -07001520 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001521 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001522 View expandedChild = mPrivateLayout.getExpandedChild();
1523 if (expandedChild == null) {
1524 expandedChild = mPrivateLayout.getContractedChild();
1525 }
1526 mMaxExpandHeight = expandedChild.getHeight();
1527 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001528 if (headsUpChild == null) {
1529 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001530 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001531 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001532 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001533 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001534 }
1535 }
1536
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001537 @Override
1538 public void notifyHeightChanged(boolean needsAnimation) {
1539 super.notifyHeightChanged(needsAnimation);
1540 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1541 }
1542
Selim Cinek3c76d502016-02-19 15:16:33 -08001543 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001544 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001545 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001546 }
1547
Mady Mellor43c2cd12016-12-12 21:05:13 -08001548 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001549 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001550 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001551 if (mIsSummaryWithChildren) {
1552 List<ExpandableNotificationRow> notificationChildren =
1553 mChildrenContainer.getNotificationChildren();
1554 for (int i = 0; i < notificationChildren.size(); i++) {
1555 ExpandableNotificationRow child = notificationChildren.get(i);
1556 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1557 }
1558 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001559 }
1560
Mady Mellor43c2cd12016-12-12 21:05:13 -08001561 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001562 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1563 long duration) {
1564 boolean oldShowingPublic = mShowingPublic;
1565 mShowingPublic = mSensitive && hideSensitive;
1566 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1567 return;
1568 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001569
1570 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001571 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001572
Jorim Jaggiae441282014-08-01 02:45:18 +02001573 if (!animated) {
1574 mPublicLayout.animate().cancel();
1575 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001576 if (mChildrenContainer != null) {
1577 mChildrenContainer.animate().cancel();
1578 mChildrenContainer.setAlpha(1f);
1579 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001580 mPublicLayout.setAlpha(1f);
1581 mPrivateLayout.setAlpha(1f);
1582 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001583 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001584 } else {
1585 animateShowingPublic(delay, duration);
1586 }
Selim Cinekc3179332016-03-04 14:44:56 -08001587 NotificationContentView showingLayout = getShowingLayout();
1588 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001589 mPrivateLayout.updateExpandButtons(isExpandable());
Adrian Roose5726a22016-12-19 14:26:51 -08001590 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02001591 mShowingPublicInitialized = true;
1592 }
1593
1594 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001595 View[] privateViews = mIsSummaryWithChildren
1596 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001597 : new View[] {mPrivateLayout};
1598 View[] publicViews = new View[] {mPublicLayout};
1599 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1600 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1601 for (final View hiddenView : hiddenChildren) {
1602 hiddenView.setVisibility(View.VISIBLE);
1603 hiddenView.animate().cancel();
1604 hiddenView.animate()
1605 .alpha(0f)
1606 .setStartDelay(delay)
1607 .setDuration(duration)
1608 .withEndAction(new Runnable() {
1609 @Override
1610 public void run() {
1611 hiddenView.setVisibility(View.INVISIBLE);
1612 }
1613 });
1614 }
1615 for (View showView : shownChildren) {
1616 showView.setVisibility(View.VISIBLE);
1617 showView.setAlpha(0f);
1618 showView.animate().cancel();
1619 showView.animate()
1620 .alpha(1f)
1621 .setStartDelay(delay)
1622 .setDuration(duration);
1623 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001624 }
1625
Mady Mellor43c2cd12016-12-12 21:05:13 -08001626 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08001627 public boolean mustStayOnScreen() {
1628 return mIsHeadsUp;
1629 }
1630
Selim Cinek9e624e72016-07-20 13:46:49 -07001631 /**
1632 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1633 * otherwise some state might not be updated. To request about the general clearability
1634 * see {@link #isClearable()}.
1635 */
1636 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001637 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001638 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001639
Ricky Waicd35def2016-05-03 11:07:07 +01001640 public void makeActionsVisibile() {
1641 setUserExpanded(true, true);
1642 if (isChildInGroup()) {
1643 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1644 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001645 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001646 }
1647
Selim Cinekb5605e52015-02-20 18:21:41 +01001648 public void setChildrenExpanded(boolean expanded, boolean animate) {
1649 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001650 if (mChildrenContainer != null) {
1651 mChildrenContainer.setChildrenExpanded(expanded);
1652 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001653 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001654 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001655 }
1656
Selim Cinekb5605e52015-02-20 18:21:41 +01001657 public static void applyTint(View v, int color) {
1658 int alpha;
1659 if (color != 0) {
1660 alpha = COLORED_DIVIDER_ALPHA;
1661 } else {
1662 color = 0xff000000;
1663 alpha = DEFAULT_DIVIDER_ALPHA;
1664 }
1665 if (v.getBackground() instanceof ColorDrawable) {
1666 ColorDrawable background = (ColorDrawable) v.getBackground();
1667 background.mutate();
1668 background.setColor(color);
1669 background.setAlpha(alpha);
1670 }
1671 }
1672
Selim Cinek1685e632014-04-08 02:27:49 +02001673 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001674 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001675 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001676
Mady Mellor34958fa2016-02-23 09:52:17 -08001677 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001678 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08001679 }
1680
Jorim Jaggibe565df2014-04-28 17:51:23 +02001681 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001682 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001683 NotificationContentView showingLayout = getShowingLayout();
1684 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001685 }
1686
1687 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001688 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001689 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001690 return mChildrenContainer;
1691 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001692 return getShowingLayout();
1693 }
1694
1695 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001696 protected void onAppearAnimationFinished(boolean wasAppearing) {
1697 super.onAppearAnimationFinished(wasAppearing);
1698 if (wasAppearing) {
1699 // During the animation the visible view might have changed, so let's make sure all
1700 // alphas are reset
1701 if (mChildrenContainer != null) {
1702 mChildrenContainer.setAlpha(1.0f);
1703 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1704 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001705 for (NotificationContentView l : mLayouts) {
1706 l.setAlpha(1.0f);
1707 l.setLayerType(LAYER_TYPE_NONE, null);
1708 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07001709 }
1710 }
1711
1712 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001713 public int getExtraBottomPadding() {
1714 if (mIsSummaryWithChildren && isGroupExpanded()) {
1715 return mIncreasedPaddingBetweenElements;
1716 }
1717 return 0;
1718 }
1719
1720 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001721 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001722 super.setActualHeight(height, notifyListeners);
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001723 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08001724 mGuts.setActualHeight(height);
1725 return;
1726 }
Selim Cinekeef84282015-10-30 16:28:00 -07001727 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001728 for (NotificationContentView l : mLayouts) {
1729 l.setContentHeight(contentHeight);
1730 }
Selim Cinek42357e02016-02-24 18:48:01 -08001731 if (mIsSummaryWithChildren) {
1732 mChildrenContainer.setActualHeight(height);
1733 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001734 if (mGuts != null) {
1735 mGuts.setActualHeight(height);
1736 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001737 }
1738
1739 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001740 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001741 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001742 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001743 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001744 NotificationContentView showingLayout = getShowingLayout();
1745 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001746 }
1747
1748 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001749 public int getMinHeight() {
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001750 if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08001751 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1752 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001753 return mChildrenContainer.getMinHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001754 } else if (!mOnKeyguard && mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001755 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001756 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001757 NotificationContentView showingLayout = getShowingLayout();
1758 return showingLayout.getMinHeight();
1759 }
1760
Adrian Roos0aac04f2016-12-08 15:59:29 -08001761 private int getAmbientHeight() {
1762 NotificationContentView showingLayout = getShowingLayout();
1763 return showingLayout.getAmbientChild() != null
1764 ? showingLayout.getAmbientChild().getHeight()
1765 : getCollapsedHeight();
1766 }
1767
Selim Cinek816c8e42015-11-19 12:00:45 -08001768 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001769 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001770 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001771 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001772 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001773 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001774 }
1775
1776 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001777 public void setClipTopAmount(int clipTopAmount) {
1778 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001779 for (NotificationContentView l : mLayouts) {
1780 l.setClipTopAmount(clipTopAmount);
1781 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001782 if (mGuts != null) {
1783 mGuts.setClipTopAmount(clipTopAmount);
1784 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001785 }
1786
Selim Cineka686b2c2016-10-26 13:58:27 -07001787 @Override
1788 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001789 if (clipBottomAmount != mClipBottomAmount) {
1790 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001791 for (NotificationContentView l : mLayouts) {
1792 l.setClipBottomAmount(clipBottomAmount);
1793 }
Selim Cinek65d418e2016-11-29 15:42:34 -08001794 if (mGuts != null) {
1795 mGuts.setClipBottomAmount(clipBottomAmount);
1796 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001797 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001798 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001799 // We have to update this even if it hasn't changed, since the children locations can
1800 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001801 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
1802 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001803 }
1804
Selim Cinek31094df2014-08-14 19:28:15 +02001805 public boolean isMaxExpandHeightInitialized() {
1806 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001807 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001808
Selim Cinek42357e02016-02-24 18:48:01 -08001809 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001810 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1811 }
Chris Wren78403d72014-07-28 10:23:24 +01001812
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001813 public void setShowingLegacyBackground(boolean showing) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08001814 for (NotificationContentView l : mLayouts) {
1815 l.setShowingLegacyBackground(showing);
1816 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001817 }
1818
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001819 @Override
1820 protected void updateBackgroundTint() {
1821 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001822 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001823 if (mIsSummaryWithChildren) {
1824 List<ExpandableNotificationRow> notificationChildren =
1825 mChildrenContainer.getNotificationChildren();
1826 for (int i = 0; i < notificationChildren.size(); i++) {
1827 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001828 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001829 }
1830 }
1831 }
1832
Mady Mellorb0a82462016-04-30 17:31:02 -07001833 /**
1834 * Called when a group has finished animating from collapsed or expanded state.
1835 */
1836 public void onFinishedExpansionChange() {
1837 mGroupExpansionChanging = false;
1838 updateBackgroundForGroupState();
1839 }
1840
1841 /**
1842 * Updates the parent and children backgrounds in a group based on the expansion state.
1843 */
1844 public void updateBackgroundForGroupState() {
1845 if (mIsSummaryWithChildren) {
1846 // Only when the group has finished expanding do we hide its background.
1847 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1848 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1849 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1850 for (int i = 0; i < children.size(); i++) {
1851 children.get(i).updateBackgroundForGroupState();
1852 }
1853 } else if (isChildInGroup()) {
1854 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
1855 // Only show a background if the group is expanded OR if it is expanding / collapsing
1856 // and has a custom background color
1857 final boolean showBackground = isGroupExpanded()
1858 || ((mNotificationParent.isGroupExpansionChanging()
1859 || mNotificationParent.isUserLocked()) && childColor != 0);
1860 mShowNoBackground = !showBackground;
1861 } else {
1862 // Only children or parents ever need no background.
1863 mShowNoBackground = false;
1864 }
1865 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001866 updateBackground();
1867 }
1868
Adrian Roos4a579672016-05-24 16:54:37 -07001869 public int getPositionOfChild(ExpandableNotificationRow childRow) {
1870 if (mIsSummaryWithChildren) {
1871 return mChildrenContainer.getPositionInLinearLayout(childRow);
1872 }
1873 return 0;
1874 }
1875
Chris Wren78403d72014-07-28 10:23:24 +01001876 public void setExpansionLogger(ExpansionLogger logger, String key) {
1877 mLogger = logger;
1878 mLoggingKey = key;
1879 }
1880
Chris Wren6abeeb92016-05-26 14:44:38 -04001881 public void onExpandedByGesture(boolean userExpanded) {
1882 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
1883 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
1884 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
1885 }
1886 MetricsLogger.action(mContext, event, userExpanded);
1887 }
1888
Selim Cinek6183d122016-01-14 18:48:41 -08001889 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001890 public float getIncreasedPaddingAmount() {
1891 if (mIsSummaryWithChildren) {
1892 if (isGroupExpanded()) {
1893 return 1.0f;
1894 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001895 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001896 }
Selim Cinek99104832017-01-25 14:47:33 -08001897 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08001898 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08001899 }
1900 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001901 }
1902
Selim Cineka7ed2c12017-01-23 20:47:24 -08001903 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08001904 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08001905 }
1906
Selim Cinek61633a82016-01-25 15:54:10 -08001907 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001908 protected boolean disallowSingleClick(MotionEvent event) {
1909 float x = event.getX();
1910 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001911 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001912 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001913 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001914 }
1915 return super.disallowSingleClick(event);
1916 }
1917
Chris Wren78403d72014-07-28 10:23:24 +01001918 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04001919 boolean nowExpanded = isExpanded();
1920 if (mIsSummaryWithChildren) {
1921 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
1922 }
Chris Wren78403d72014-07-28 10:23:24 +01001923 if (wasExpanded != nowExpanded && mLogger != null) {
1924 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1925 }
1926 }
Selim Cinek570981d2015-12-01 11:37:01 -08001927
Selim Cineke9bad242016-06-15 11:46:37 -07001928 @Override
1929 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1930 super.onInitializeAccessibilityNodeInfoInternal(info);
1931 if (canViewBeDismissed()) {
1932 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
1933 }
1934 }
1935
1936 @Override
1937 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
1938 if (super.performAccessibilityActionInternal(action, arguments)) {
1939 return true;
1940 }
1941 switch (action) {
1942 case AccessibilityNodeInfo.ACTION_DISMISS:
1943 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
1944 true /* fromAccessibility */);
1945 return true;
1946 }
1947 return false;
1948 }
1949
1950 public boolean shouldRefocusOnDismiss() {
1951 return mRefocusOnDismiss || isAccessibilityFocused();
1952 }
1953
Selim Cinek570981d2015-12-01 11:37:01 -08001954 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001955 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001956 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001957
1958 @Override
1959 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
1960 return new NotificationViewState(stackScrollState);
1961 }
1962
Selim Cinekd127d792016-11-01 19:11:41 -07001963 @Override
1964 public boolean isAboveShelf() {
1965 return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
1966 }
1967
Adrian Roos0aac04f2016-12-08 15:59:29 -08001968 public void setShowAmbient(boolean showAmbient) {
1969 if (showAmbient != mShowAmbient) {
1970 mShowAmbient = showAmbient;
1971 notifyHeightChanged(false /* needsAnimation */);
1972 }
1973 }
1974
Selim Cinekd127d792016-11-01 19:11:41 -07001975 public void setAboveShelf(boolean aboveShelf) {
1976 mAboveShelf = aboveShelf;
1977 }
1978
Selim Cinek0cfbef42016-11-09 19:06:36 -08001979 public class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08001980
1981 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07001982
Selim Cinekbbcebde2016-11-09 18:28:20 -08001983
1984 private NotificationViewState(StackScrollState stackScrollState) {
1985 mOverallState = stackScrollState;
1986 }
1987
1988 @Override
1989 public void applyToView(View view) {
1990 super.applyToView(view);
1991 if (view instanceof ExpandableNotificationRow) {
1992 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinekbbcebde2016-11-09 18:28:20 -08001993 row.applyChildrenState(mOverallState);
1994 }
1995 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08001996
1997 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08001998 protected void onYTranslationAnimationFinished(View view) {
1999 super.onYTranslationAnimationFinished(view);
Selim Cinek0cfbef42016-11-09 19:06:36 -08002000 if (mHeadsupDisappearRunning) {
Selim Cinekcafa87f2016-10-26 17:00:17 -07002001 setHeadsUpAnimatingAway(false);
Selim Cinek0cfbef42016-11-09 19:06:36 -08002002 }
2003 }
2004
2005 @Override
2006 public void animateTo(View child, AnimationProperties properties) {
2007 super.animateTo(child, properties);
2008 if (child instanceof ExpandableNotificationRow) {
2009 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
2010 row.startChildAnimation(mOverallState, properties);
2011 }
2012 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002013 }
Chris Wren51c75102013-07-16 20:49:17 -04002014}