blob: 5f4854aeeb7bbc815c625e32ec6c78e21f40a298 [file] [log] [blame]
Chris Wren51c75102013-07-16 20:49:17 -04001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar;
18
Selim Cinek5ba22542017-04-20 15:16:10 -070019import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;
Selim Cinekc478f902017-02-22 20:55:44 -080020
Mady Mellor4b80b102016-01-22 08:03:58 -080021import android.animation.Animator;
22import android.animation.AnimatorListenerAdapter;
Mady Mellor4b80b102016-01-22 08:03:58 -080023import android.animation.ObjectAnimator;
Mady Mellor4b80b102016-01-22 08:03:58 -080024import android.animation.ValueAnimator.AnimatorUpdateListener;
Selim Cinekddf1b392016-05-27 16:33:10 -070025import android.annotation.Nullable;
Chris Wren51c75102013-07-16 20:49:17 -040026import android.content.Context;
Anthony Chen7acbb772017-04-07 16:45:25 -070027import android.content.res.Resources;
Mady Mellor9d03a522017-04-04 18:45:30 -070028import android.content.res.Configuration;
Selim Cinek515b2032017-11-15 10:20:19 -080029import android.graphics.Path;
Selim Cinekcab4a602014-09-03 14:47:57 +020030import android.graphics.drawable.AnimatedVectorDrawable;
31import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010032import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020033import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080034import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070035import android.os.Bundle;
Dan Sandler1d958f82018-01-09 21:10:26 -050036import android.service.notification.NotificationListenerService;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020037import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040038import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070039import android.util.FloatProperty;
40import android.util.Property;
Geoffrey Pitsch409db272017-08-28 14:51:52 +000041import android.view.KeyEvent;
Selim Cinek01af3342016-02-09 19:25:31 -080042import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080043import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080044import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050045import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080046import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020047import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020048import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070049import android.view.accessibility.AccessibilityNodeInfo;
Selim Cinek98713a42015-09-21 15:47:20 +020050import android.widget.Chronometer;
Mady Mellor95d743c2017-01-10 12:05:27 -080051import android.widget.FrameLayout;
Selim Cinekcab4a602014-09-03 14:47:57 +020052import android.widget.ImageView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080053import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010054
Selim Cinek5ba22542017-04-20 15:16:10 -070055import com.android.internal.annotations.VisibleForTesting;
Chris Wren698b1702016-05-23 11:16:32 -040056import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010057import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070058import com.android.internal.util.NotificationColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080059import com.android.internal.widget.CachingIconView;
Mady Mellor95d743c2017-01-10 12:05:27 -080060import com.android.systemui.Dependency;
Selim Cinek0242fbb2016-10-19 13:38:32 -070061import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050062import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070063import com.android.systemui.classifier.FalsingManager;
Mady Mellor95d743c2017-01-10 12:05:27 -080064import com.android.systemui.plugins.PluginListener;
65import com.android.systemui.plugins.PluginManager;
66import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
67import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
68import com.android.systemui.statusbar.NotificationGuts.GutsContent;
Selim Cinek5cf1d052017-06-01 17:36:46 -070069import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
Selim Cinekc897bd32016-03-18 17:32:31 -070070import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080071import com.android.systemui.statusbar.notification.NotificationInflater;
Selim Cinek6743c0b2017-01-18 18:24:01 -080072import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cineke62255c2017-09-28 18:23:23 -070073import com.android.systemui.statusbar.notification.NotificationViewWrapper;
Selim Cineka7d4f822016-12-06 14:34:47 -080074import com.android.systemui.statusbar.notification.VisualStabilityManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010075import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050076import com.android.systemui.statusbar.phone.StatusBar;
Selim Cinek31aada42015-12-18 17:51:15 -080077import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek0cfbef42016-11-09 19:06:36 -080078import com.android.systemui.statusbar.stack.AnimationProperties;
79import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010080import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070081import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010082import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010083
Mady Mellor4b80b102016-01-22 08:03:58 -080084import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010085import java.util.List;
Lucas Dupincecc7c22017-09-12 16:02:45 -070086import java.util.function.BooleanSupplier;
Dan Sandlera5e0f412014-01-23 15:11:54 -050087
Mady Mellor95d743c2017-01-10 12:05:27 -080088public class ExpandableNotificationRow extends ActivatableNotificationView
89 implements PluginListener<NotificationMenuRowPlugin> {
Selim Cinekb5605e52015-02-20 18:21:41 +010090
91 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
92 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Mady Mellor95d743c2017-01-10 12:05:27 -080093 private static final int MENU_VIEW_INDEX = 0;
94
Mady Mellor035badd2017-04-04 18:45:30 -070095 public interface LayoutListener {
96 public void onLayout();
97 }
98
99 private LayoutListener mLayoutListener;
Lucas Dupincecc7c22017-09-12 16:02:45 -0700100 private boolean mDark;
Selim Cinek55a3e732017-05-25 18:30:10 -0700101 private boolean mLowPriorityStateUpdated;
Selim Cinek1a48bab2017-02-17 19:38:40 -0800102 private final NotificationInflater mNotificationInflater;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700103 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800104 private int mIconTransformContentShiftNoIcon;
Selim Cinek01af3342016-02-09 19:25:31 -0800105 private int mNotificationMinHeightLegacy;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800106 private int mNotificationMinHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800107 private int mMaxHeadsUpHeightLegacy;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800108 private int mMaxHeadsUpHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800109 private int mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800110 private int mMaxHeadsUpHeightIncreased;
Selim Cinek01af3342016-02-09 19:25:31 -0800111 private int mNotificationMinHeight;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800112 private int mNotificationMinHeightLarge;
Selim Cinek01af3342016-02-09 19:25:31 -0800113 private int mNotificationMaxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800114 private int mNotificationAmbientHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -0700115 private int mIncreasedPaddingBetweenElements;
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100116 private boolean mMustStayOnScreen;
Chris Wren51c75102013-07-16 20:49:17 -0400117
Selim Cinek1685e632014-04-08 02:27:49 +0200118 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -0400119 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +0200120 /** Has the user actively changed the expansion state of this row */
121 private boolean mHasUserChangedExpansion;
122 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -0400123 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -0800124
125 /**
126 * Has this notification been expanded while it was pinned
127 */
128 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +0200129 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -0400130 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +0200131 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -0500132 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +0200133 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -0800134 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +0200135 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700136 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400137
Selim Cinek1685e632014-04-08 02:27:49 +0200138 /**
139 * Is this notification expanded by the system. The expansion state can be overridden by the
140 * user expansion.
141 */
142 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200143
144 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700145 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200146 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700147 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200148
Mady Mellorb0a82462016-04-30 17:31:02 -0700149 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800150 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200151 private NotificationContentView mPublicLayout;
152 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800153 private NotificationContentView[] mLayouts;
Selim Cinek1685e632014-04-08 02:27:49 +0200154 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700155 private int mHeadsUpHeight;
Selim Cinek4bb59342016-04-08 19:29:35 -0700156 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100157 private ExpansionLogger mLogger;
158 private String mLoggingKey;
Selim Cinek8d490d42015-04-10 00:05:50 -0700159 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800160 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200161 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700162 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100163 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200164 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100165 private ViewStub mChildrenContainerStub;
166 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100167 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700168 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100169 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor95d743c2017-01-10 12:05:27 -0800170 private NotificationMenuRowPlugin mMenuRow;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100171 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100172 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700173 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700174 private FalsingManager mFalsingManager;
Selim Cinek5cf1d052017-06-01 17:36:46 -0700175 private AboveShelfChangedListener mAboveShelfChangedListener;
Selim Cinek31aada42015-12-18 17:51:15 -0800176 private HeadsUpManager mHeadsUpManager;
Dan Sandler1d958f82018-01-09 21:10:26 -0500177 private View mHelperButton;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200178
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700179 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800180 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700181 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700182 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800183 private OnExpandClickListener mOnExpandClickListener;
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000184
185 // Listener will be called when receiving a long click event.
186 // Use #setLongPressPosition to optionally assign positional data with the long press.
187 private LongPressListener mLongPressListener;
188
Mady Mellorb0a82462016-04-30 17:31:02 -0700189 private boolean mGroupExpansionChanging;
190
Anthony Chen6bf88a02017-04-10 14:41:44 -0700191 /**
Lucas Dupincecc7c22017-09-12 16:02:45 -0700192 * A supplier that returns true if keyguard is secure.
193 */
194 private BooleanSupplier mSecureStateProvider;
195
196 /**
Anthony Chen6bf88a02017-04-10 14:41:44 -0700197 * Whether or not a notification that is not part of a group of notifications can be manually
198 * expanded by the user.
199 */
200 private boolean mEnableNonGroupedNotificationExpand;
201
202 /**
203 * Whether or not to update the background of the header of the notification when its expanded.
204 * If {@code true}, the header background will disappear when expanded.
205 */
206 private boolean mShowGroupBackgroundWhenExpanded;
207
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800208 private OnClickListener mExpandClickListener = new OnClickListener() {
209 @Override
210 public void onClick(View v) {
Selim Cinek0b9cf462017-12-07 16:31:03 -0800211 if (!shouldShowPublic() && (!mIsLowPriority || isExpanded())
Selim Cinek414ad332017-02-24 19:06:12 -0800212 && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700213 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400214 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
215 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
216 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400217 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
218 nowExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -0800219 onExpansionChanged(true /* userAction */, wasExpanded);
Anthony Chen6bf88a02017-04-10 14:41:44 -0700220 } else if (mEnableNonGroupedNotificationExpand) {
Selim Cineke9bad242016-06-15 11:46:37 -0700221 if (v.isAccessibilityFocused()) {
222 mPrivateLayout.setFocusOnVisibilityChange();
223 }
Selim Cinek31aada42015-12-18 17:51:15 -0800224 boolean nowExpanded;
225 if (isPinned()) {
226 nowExpanded = !mExpandedWhenPinned;
227 mExpandedWhenPinned = nowExpanded;
228 } else {
229 nowExpanded = !isExpanded();
230 setUserExpanded(nowExpanded);
231 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800232 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800233 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400234 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
235 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800236 }
237 }
238 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700239 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700240 private boolean mDismissed;
241 private boolean mKeepInParent;
242 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700243 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
244 new FloatProperty<ExpandableNotificationRow>("translate") {
245 @Override
246 public void setValue(ExpandableNotificationRow object, float value) {
247 object.setTranslation(value);
248 }
249
250 @Override
251 public Float get(ExpandableNotificationRow object) {
252 return object.getTranslation();
253 }
254 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700255 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700256 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700257 private View mChildAfterViewWhenDismissed;
258 private View mGroupParentWhenDismissed;
259 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800260 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700261 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700262 private boolean mAboveShelf;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800263 private boolean mShowAmbient;
Selim Cinek875a3a12016-11-18 17:52:16 -0800264 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800265 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800266 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800267 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800268 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800269 private boolean mUseIncreasedHeadsUpHeight;
Selim Cinekef8c2252017-02-10 14:52:18 -0800270 private float mTranslationWhenRemoved;
271 private boolean mWasChildInGroupWhenRemoved;
Adrian Roos6f6e1592017-05-02 16:22:53 -0700272 private int mNotificationColorAmbient;
Mady Mellorb0a82462016-04-30 17:31:02 -0700273
Mady Mellor43c2cd12016-12-12 21:05:13 -0800274 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700275 public boolean isGroupExpansionChanging() {
276 if (isChildInGroup()) {
277 return mNotificationParent.isGroupExpansionChanging();
278 }
279 return mGroupExpansionChanging;
280 }
281
282 public void setGroupExpansionChanging(boolean changing) {
283 mGroupExpansionChanging = changing;
284 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700285
Adrian Roos599be342016-06-13 14:54:39 -0700286 @Override
287 public void setActualHeightAnimating(boolean animating) {
288 if (mPrivateLayout != null) {
289 mPrivateLayout.setContentHeightAnimating(animating);
290 }
291 }
292
Selim Cinek8d490d42015-04-10 00:05:50 -0700293 public NotificationContentView getPrivateLayout() {
294 return mPrivateLayout;
295 }
296
297 public NotificationContentView getPublicLayout() {
298 return mPublicLayout;
299 }
300
Selim Cinekcab4a602014-09-03 14:47:57 +0200301 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800302 for (NotificationContentView l : mLayouts) {
303 setIconAnimationRunning(running, l);
304 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800305 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700306 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek414ad332017-02-24 19:06:12 -0800307 setIconAnimationRunningForChild(running, mChildrenContainer.getLowPriorityHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800308 List<ExpandableNotificationRow> notificationChildren =
309 mChildrenContainer.getNotificationChildren();
310 for (int i = 0; i < notificationChildren.size(); i++) {
311 ExpandableNotificationRow child = notificationChildren.get(i);
312 child.setIconAnimationRunning(running);
313 }
314 }
315 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200316 }
317
318 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
319 if (layout != null) {
320 View contractedChild = layout.getContractedChild();
321 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700322 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200323 setIconAnimationRunningForChild(running, contractedChild);
324 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700325 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200326 }
327 }
328
329 private void setIconAnimationRunningForChild(boolean running, View child) {
330 if (child != null) {
331 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
332 setIconRunning(icon, running);
333 ImageView rightIcon = (ImageView) child.findViewById(
334 com.android.internal.R.id.right_icon);
335 setIconRunning(rightIcon, running);
336 }
337 }
338
339 private void setIconRunning(ImageView imageView, boolean running) {
340 if (imageView != null) {
341 Drawable drawable = imageView.getDrawable();
342 if (drawable instanceof AnimationDrawable) {
343 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
344 if (running) {
345 animationDrawable.start();
346 } else {
347 animationDrawable.stop();
348 }
349 } else if (drawable instanceof AnimatedVectorDrawable) {
350 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
351 if (running) {
352 animationDrawable.start();
353 } else {
354 animationDrawable.stop();
355 }
356 }
357 }
358 }
359
Selim Cinek5ba22542017-04-20 15:16:10 -0700360 public void updateNotification(NotificationData.Entry entry) {
Selim Cinekda42d652015-12-04 15:51:16 -0800361 mEntry = entry;
362 mStatusBarNotification = entry.notification;
Selim Cinek1a48bab2017-02-17 19:38:40 -0800363 mNotificationInflater.inflateNotificationViews();
Selim Cinekc478f902017-02-22 20:55:44 -0800364 }
365
Selim Cinek5ba22542017-04-20 15:16:10 -0700366 public void onNotificationUpdated() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800367 for (NotificationContentView l : mLayouts) {
Selim Cinekc478f902017-02-22 20:55:44 -0800368 l.onNotificationUpdated(mEntry);
Adrian Rooseb434ff2017-01-11 11:18:48 -0800369 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800370 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800371 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700372 updateNotificationColor();
Mady Mellor4c197602017-04-10 17:57:52 -0700373 if (mMenuRow != null) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700374 mMenuRow.onNotificationUpdated(mStatusBarNotification);
Mady Mellor4c197602017-04-10 17:57:52 -0700375 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800376 if (mIsSummaryWithChildren) {
Selim Cinek414ad332017-02-24 19:06:12 -0800377 mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
Selim Cinekc897bd32016-03-18 17:32:31 -0700378 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800379 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800380 if (mIconAnimationRunning) {
381 setIconAnimationRunning(true);
382 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800383 if (mNotificationParent != null) {
384 mNotificationParent.updateChildrenHeaderAppearance();
385 }
Selim Cinek263398f2015-10-21 17:40:23 -0700386 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800387 // The public layouts expand button is always visible
388 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800389 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700390 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800391 updateShelfIconColor();
Dan Sandler1d958f82018-01-09 21:10:26 -0500392
393 showBlockingHelper(mEntry.userSentiment ==
394 NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE);
Selim Cinek6743c0b2017-01-18 18:24:01 -0800395 }
396
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700397 @VisibleForTesting
398 void updateShelfIconColor() {
Selim Cinek6743c0b2017-01-18 18:24:01 -0800399 StatusBarIconView expandedIcon = mEntry.expandedIcon;
400 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
401 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
402 NotificationColorUtil.getInstance(mContext));
Selim Cinek875ba9b2017-02-13 16:20:17 -0800403 int color = StatusBarIconView.NO_COLOR;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800404 if (colorize) {
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700405 NotificationHeaderView header = getVisibleNotificationHeader();
406 if (header != null) {
407 color = header.getOriginalIconColor();
408 } else {
409 color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
410 getBackgroundColorWithoutTint());
411 }
Selim Cinek6743c0b2017-01-18 18:24:01 -0800412 }
Selim Cinek875ba9b2017-02-13 16:20:17 -0800413 expandedIcon.setStaticDrawableColor(color);
Selim Cinekda42d652015-12-04 15:51:16 -0800414 }
415
Selim Cinek5cf1d052017-06-01 17:36:46 -0700416 public void setAboveShelfChangedListener(AboveShelfChangedListener aboveShelfChangedListener) {
417 mAboveShelfChangedListener = aboveShelfChangedListener;
418 }
419
Lucas Dupincecc7c22017-09-12 16:02:45 -0700420 /**
421 * Sets a supplier that can determine whether the keyguard is secure or not.
422 * @param secureStateProvider A function that returns true if keyguard is secure.
423 */
424 public void setSecureStateProvider(BooleanSupplier secureStateProvider) {
425 mSecureStateProvider = secureStateProvider;
426 }
427
Selim Cinek4705f292017-04-24 22:18:48 -0700428 @Override
429 public boolean isDimmable() {
430 if (!getShowingLayout().isDimmable()) {
431 return false;
432 }
433 return super.isDimmable();
434 }
435
Selim Cinekda42d652015-12-04 15:51:16 -0800436 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800437 for (NotificationContentView l : mLayouts) {
438 updateLimitsForView(l);
439 }
Selim Cineka1744872016-03-11 15:36:06 -0800440 }
441
442 private void updateLimitsForView(NotificationContentView layout) {
443 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800444 != com.android.internal.R.id.status_bar_latest_event_content;
445 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800446 boolean beforeP = mEntry.targetSdk < Build.VERSION_CODES.P;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800447 int minHeight;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800448 if (customView && beforeP && !mIsSummaryWithChildren) {
449 minHeight = beforeN ? mNotificationMinHeightLegacy : mNotificationMinHeightBeforeP;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800450 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
451 minHeight = mNotificationMinHeightLarge;
452 } else {
453 minHeight = mNotificationMinHeight;
454 }
Selim Cineka1744872016-03-11 15:36:06 -0800455 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
456 layout.getHeadsUpChild().getId()
457 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800458 int headsUpheight;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800459 if (headsUpCustom && beforeP) {
460 headsUpheight = beforeN ? mMaxHeadsUpHeightLegacy : mMaxHeadsUpHeightBeforeP;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800461 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
462 headsUpheight = mMaxHeadsUpHeightIncreased;
463 } else {
464 headsUpheight = mMaxHeadsUpHeight;
465 }
Selim Cineke62255c2017-09-28 18:23:23 -0700466 NotificationViewWrapper headsUpWrapper = layout.getVisibleWrapper(
467 NotificationContentView.VISIBLE_TYPE_HEADSUP);
468 if (headsUpWrapper != null) {
469 headsUpheight = Math.max(headsUpheight, headsUpWrapper.getMinLayoutHeight());
470 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800471 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
472 mNotificationAmbientHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200473 }
474
475 public StatusBarNotification getStatusBarNotification() {
476 return mStatusBarNotification;
477 }
478
Selim Cinek281c2022016-10-13 19:14:43 -0700479 public NotificationData.Entry getEntry() {
480 return mEntry;
481 }
482
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700483 public boolean isHeadsUp() {
484 return mIsHeadsUp;
485 }
486
Selim Cinek1a521f32014-11-03 17:39:29 +0100487 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinek5cf1d052017-06-01 17:36:46 -0700488 boolean wasAboveShelf = isAboveShelf();
Selim Cinekc80fdb12015-04-13 15:09:08 -0700489 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100490 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700491 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700492 if (mIsSummaryWithChildren) {
493 // The overflow might change since we allow more lines as HUN.
494 mChildrenContainer.updateGroupOverflow();
495 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700496 if (intrinsicBefore != getIntrinsicHeight()) {
497 notifyHeightChanged(false /* needsAnimation */);
498 }
Selim Cinekd127d792016-11-01 19:11:41 -0700499 if (isHeadsUp) {
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100500 mMustStayOnScreen = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700501 setAboveShelf(true);
Selim Cinek5cf1d052017-06-01 17:36:46 -0700502 } else if (isAboveShelf() != wasAboveShelf) {
503 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
Selim Cinekd127d792016-11-01 19:11:41 -0700504 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100505 }
506
Selim Cinekb5605e52015-02-20 18:21:41 +0100507 public void setGroupManager(NotificationGroupManager groupManager) {
508 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700509 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100510 }
511
Adrian Roosb88b1a12015-12-09 18:51:05 -0800512 public void setRemoteInputController(RemoteInputController r) {
513 mPrivateLayout.setRemoteInputController(r);
514 }
515
Mady Mellor3fd273e2016-03-15 21:08:14 -0700516 public void setAppName(String appName) {
517 mAppName = appName;
Mady Mellor95d743c2017-01-10 12:05:27 -0800518 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800519 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700520 }
521 }
522
Selim Cinekb5605e52015-02-20 18:21:41 +0100523 public void addChildNotification(ExpandableNotificationRow row) {
524 addChildNotification(row, -1);
525 }
526
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100527 @Override
528 public void setHeadsUpIsVisible() {
529 super.setHeadsUpIsVisible();
530 mMustStayOnScreen = false;
531 }
532
Selim Cinekb5605e52015-02-20 18:21:41 +0100533 /**
534 * Add a child notification to this view.
535 *
536 * @param row the row to add
537 * @param childIndex the index to add it at, if -1 it will be added at the end
538 */
539 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
540 if (mChildrenContainer == null) {
541 mChildrenContainerStub.inflate();
542 }
543 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700544 onChildrenCountChanged();
545 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100546 }
547
548 public void removeChildNotification(ExpandableNotificationRow row) {
549 if (mChildrenContainer != null) {
550 mChildrenContainer.removeNotification(row);
551 }
Selim Cinek263398f2015-10-21 17:40:23 -0700552 onChildrenCountChanged();
553 row.setIsChildInGroup(false, null);
Selim Cinek2871bef2017-11-22 08:40:00 -0800554 row.setBottomRoundness(0.0f, false /* animate */);
Selim Cinek263398f2015-10-21 17:40:23 -0700555 }
556
Mady Mellor43c2cd12016-12-12 21:05:13 -0800557 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700558 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700559 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700560 }
561
Selim Cinek388df6d2015-10-22 13:25:11 -0700562 public ExpandableNotificationRow getNotificationParent() {
563 return mNotificationParent;
564 }
565
Selim Cinek263398f2015-10-21 17:40:23 -0700566 /**
567 * @param isChildInGroup Is this notification now in a group
568 * @param parent the new parent notification
569 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700570 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500571 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700572 mNotificationParent = childInGroup ? parent : null;
573 mPrivateLayout.setIsChildInGroup(childInGroup);
Selim Cinek5ba22542017-04-20 15:16:10 -0700574 mNotificationInflater.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400575 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700576 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700577 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700578 if (mNotificationParent != null) {
Selim Cinek9ce32852017-02-15 16:21:10 -0800579 setOverrideTintColor(NO_COLOR, 0.0f);
Mady Mellorb0a82462016-04-30 17:31:02 -0700580 mNotificationParent.updateBackgroundForGroupState();
581 }
Selim Cinekdb167372016-11-17 15:41:17 -0800582 updateIconVisibilities();
Selim Cinek2871bef2017-11-22 08:40:00 -0800583 updateBackgroundClipping();
Selim Cinek34d93b02015-10-22 12:30:38 -0700584 }
585
586 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800587 public boolean onTouchEvent(MotionEvent event) {
588 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
589 || !isChildInGroup() || isGroupExpanded()) {
590 return super.onTouchEvent(event);
591 } else {
592 return false;
593 }
594 }
595
596 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800597 protected boolean handleSlideBack() {
Mady Mellor95d743c2017-01-10 12:05:27 -0800598 if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800599 animateTranslateNotification(0 /* targetLeft */);
600 return true;
601 }
602 return false;
603 }
604
605 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700606 protected boolean shouldHideBackground() {
607 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700608 }
609
610 @Override
611 public boolean isSummaryWithChildren() {
612 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100613 }
614
615 @Override
616 public boolean areChildrenExpanded() {
617 return mChildrenExpanded;
618 }
619
620 public List<ExpandableNotificationRow> getNotificationChildren() {
621 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
622 }
623
Selim Cinekeef84282015-10-30 16:28:00 -0700624 public int getNumberOfNotificationChildren() {
625 if (mChildrenContainer == null) {
626 return 0;
627 }
628 return mChildrenContainer.getNotificationChildren().size();
629 }
630
Selim Cinekb5605e52015-02-20 18:21:41 +0100631 /**
632 * Apply the order given in the list to the children.
633 *
634 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800635 * @param visualStabilityManager
636 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100637 * @return whether the list order has changed
638 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800639 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
640 VisualStabilityManager visualStabilityManager,
641 VisualStabilityManager.Callback callback) {
642 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
643 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100644 }
645
646 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700647 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800648 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100649 mChildrenContainer.getState(resultState, parentState);
650 }
651 }
652
653 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700654 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100655 mChildrenContainer.applyState(state);
656 }
657 }
658
659 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700660 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100661 mChildrenContainer.prepareExpansionChanged(state);
662 }
663 }
664
Selim Cinek0cfbef42016-11-09 19:06:36 -0800665 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700666 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800667 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100668 }
669 }
670
671 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800672 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100673 return this;
674 } else {
675 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
676 return view == null ? this : view;
677 }
678 }
679
Selim Cinekab29aeb2015-02-20 18:18:32 +0100680 public NotificationGuts getGuts() {
681 return mGuts;
682 }
683
Selim Cinek684a4422015-04-15 16:18:39 -0700684 /**
685 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
686 * the notification will be rendered on top of the screen.
687 *
688 * @param pinned whether it is pinned
689 */
690 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700691 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek5cf1d052017-06-01 17:36:46 -0700692 boolean wasAboveShelf = isAboveShelf();
Selim Cinek684a4422015-04-15 16:18:39 -0700693 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700694 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700695 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700696 }
Selim Cinek31aada42015-12-18 17:51:15 -0800697 if (pinned) {
698 setIconAnimationRunning(true);
699 mExpandedWhenPinned = false;
700 } else if (mExpandedWhenPinned) {
701 setUserExpanded(true);
702 }
Selim Cinek98713a42015-09-21 15:47:20 +0200703 setChronometerRunning(mLastChronometerRunning);
Selim Cinek5cf1d052017-06-01 17:36:46 -0700704 if (isAboveShelf() != wasAboveShelf) {
705 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
706 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700707 }
708
Selim Cinek684a4422015-04-15 16:18:39 -0700709 public boolean isPinned() {
710 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700711 }
712
Selim Cinekd127d792016-11-01 19:11:41 -0700713 @Override
714 public int getPinnedHeadsUpHeight() {
715 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
716 }
717
Selim Cinek31aada42015-12-18 17:51:15 -0800718 /**
719 * @param atLeastMinHeight should the value returned be at least the minimum height.
720 * Used to avoid cyclic calls
721 * @return the height of the heads up notification when pinned
722 */
Selim Cinekd127d792016-11-01 19:11:41 -0700723 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800724 if (mIsSummaryWithChildren) {
725 return mChildrenContainer.getIntrinsicHeight();
726 }
Selim Cinek31aada42015-12-18 17:51:15 -0800727 if(mExpandedWhenPinned) {
728 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
729 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700730 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800731 } else {
732 return mHeadsUpHeight;
733 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700734 }
735
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700736 /**
737 * Mark whether this notification was just clicked, i.e. the user has just clicked this
738 * notification in this frame.
739 */
740 public void setJustClicked(boolean justClicked) {
741 mJustClicked = justClicked;
742 }
743
744 /**
745 * @return true if this notification has been clicked in this frame, false otherwise
746 */
747 public boolean wasJustClicked() {
748 return mJustClicked;
749 }
750
Selim Cinek98713a42015-09-21 15:47:20 +0200751 public void setChronometerRunning(boolean running) {
752 mLastChronometerRunning = running;
753 setChronometerRunning(running, mPrivateLayout);
754 setChronometerRunning(running, mPublicLayout);
755 if (mChildrenContainer != null) {
756 List<ExpandableNotificationRow> notificationChildren =
757 mChildrenContainer.getNotificationChildren();
758 for (int i = 0; i < notificationChildren.size(); i++) {
759 ExpandableNotificationRow child = notificationChildren.get(i);
760 child.setChronometerRunning(running);
761 }
762 }
763 }
764
765 private void setChronometerRunning(boolean running, NotificationContentView layout) {
766 if (layout != null) {
767 running = running || isPinned();
768 View contractedChild = layout.getContractedChild();
769 View expandedChild = layout.getExpandedChild();
770 View headsUpChild = layout.getHeadsUpChild();
771 setChronometerRunningForChild(running, contractedChild);
772 setChronometerRunningForChild(running, expandedChild);
773 setChronometerRunningForChild(running, headsUpChild);
774 }
775 }
776
777 private void setChronometerRunningForChild(boolean running, View child) {
778 if (child != null) {
779 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
780 if (chronometer instanceof Chronometer) {
781 ((Chronometer) chronometer).setStarted(running);
782 }
783 }
784 }
785
Selim Cinekea4bef72015-12-02 15:51:10 -0800786 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700787 if (mIsSummaryWithChildren) {
788 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700789 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800790 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700791 }
792
Selim Cinek414ad332017-02-24 19:06:12 -0800793 /**
794 * @return the currently visible notification header. This can be different from
795 * {@link #getNotificationHeader()} in case it is a low-priority group.
796 */
797 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinek0b9cf462017-12-07 16:31:03 -0800798 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek414ad332017-02-24 19:06:12 -0800799 return mChildrenContainer.getVisibleHeader();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800800 }
801 return getShowingLayout().getVisibleNotificationHeader();
802 }
803
Selim Cinekb26afa32017-06-29 10:28:17 +0200804
805 /**
806 * @return the contracted notification header. This can be different from
807 * {@link #getNotificationHeader()} and also {@link #getVisibleNotificationHeader()} and only
808 * returns the contracted version.
809 */
810 public NotificationHeaderView getContractedNotificationHeader() {
811 if (mIsSummaryWithChildren) {
812 return mChildrenContainer.getHeaderView();
813 }
814 return mPrivateLayout.getContractedNotificationHeader();
815 }
816
Selim Cinek570981d2015-12-01 11:37:01 -0800817 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
818 mOnExpandClickListener = onExpandClickListener;
819 }
820
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000821 public void setLongPressListener(LongPressListener longPressListener) {
822 mLongPressListener = longPressListener;
823 }
824
Selim Cinekddf1b392016-05-27 16:33:10 -0700825 @Override
826 public void setOnClickListener(@Nullable OnClickListener l) {
827 super.setOnClickListener(l);
828 mOnClickListener = l;
829 updateClickAndFocus();
830 }
831
832 private void updateClickAndFocus() {
833 boolean normalChild = !isChildInGroup() || isGroupExpanded();
834 boolean clickable = mOnClickListener != null && normalChild;
835 if (isFocusable() != normalChild) {
836 setFocusable(normalChild);
837 }
838 if (isClickable() != clickable) {
839 setClickable(clickable);
840 }
841 }
842
Selim Cinek31aada42015-12-18 17:51:15 -0800843 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
844 mHeadsUpManager = headsUpManager;
845 }
846
Mady Mellor87d79452017-01-10 11:52:52 -0800847 public void setGutsView(MenuItem item) {
Mady Mellor95d743c2017-01-10 12:05:27 -0800848 if (mGuts != null && item.getGutsView() instanceof GutsContent) {
849 ((GutsContent) item.getGutsView()).setGutsParent(mGuts);
850 mGuts.setGutsContent((GutsContent) item.getGutsView());
Mady Mellor87d79452017-01-10 11:52:52 -0800851 }
852 }
853
Mady Mellor95d743c2017-01-10 12:05:27 -0800854 @Override
855 protected void onAttachedToWindow() {
856 super.onAttachedToWindow();
857 Dependency.get(PluginManager.class).addPluginListener(this,
858 NotificationMenuRowPlugin.class, false /* Allow multiple */);
859 }
860
861 @Override
862 protected void onDetachedFromWindow() {
863 super.onDetachedFromWindow();
864 Dependency.get(PluginManager.class).removePluginListener(this);
865 }
866
867 @Override
868 public void onPluginConnected(NotificationMenuRowPlugin plugin, Context pluginContext) {
869 boolean existed = mMenuRow.getMenuView() != null;
870 if (existed) {
871 removeView(mMenuRow.getMenuView());
872 }
873 mMenuRow = plugin;
874 if (mMenuRow.useDefaultMenuItems()) {
Mady Mellor4c197602017-04-10 17:57:52 -0700875 ArrayList<MenuItem> items = new ArrayList<>();
876 items.add(NotificationMenuRow.createInfoItem(mContext));
877 items.add(NotificationMenuRow.createSnoozeItem(mContext));
878 mMenuRow.setMenuItems(items);
Mady Mellor95d743c2017-01-10 12:05:27 -0800879 }
880 if (existed) {
881 createMenu();
882 }
883 }
884
885 @Override
886 public void onPluginDisconnected(NotificationMenuRowPlugin plugin) {
887 boolean existed = mMenuRow.getMenuView() != null;
888 mMenuRow = new NotificationMenuRow(mContext); // Back to default
889 if (existed) {
890 createMenu();
891 }
892 }
893
894 public NotificationMenuRowPlugin createMenu() {
895 if (mMenuRow.getMenuView() == null) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700896 mMenuRow.createMenu(this, mStatusBarNotification);
Mady Mellor95d743c2017-01-10 12:05:27 -0800897 mMenuRow.setAppName(mAppName);
898 FrameLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
899 LayoutParams.MATCH_PARENT);
900 addView(mMenuRow.getMenuView(), MENU_VIEW_INDEX, lp);
901 }
902 return mMenuRow;
903 }
904
Mady Mellor95d743c2017-01-10 12:05:27 -0800905 public NotificationMenuRowPlugin getProvider() {
906 return mMenuRow;
907 }
908
Anthony Chen9fe1ee72017-04-07 13:53:37 -0700909 @Override
Selim Cinek1a48bab2017-02-17 19:38:40 -0800910 public void onDensityOrFontScaleChanged() {
Anthony Chen9fe1ee72017-04-07 13:53:37 -0700911 super.onDensityOrFontScaleChanged();
Selim Cinek01af3342016-02-09 19:25:31 -0800912 initDimens();
Anthony Chenad4d1582017-04-10 16:07:58 -0700913 initBackground();
Selim Cinek817abe72017-05-24 11:08:55 -0700914 // Let's update our childrencontainer. This is intentionally not guarded with
915 // mIsSummaryWithChildren since we might have had children but not anymore.
916 if (mChildrenContainer != null) {
917 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800918 }
919 if (mGuts != null) {
920 View oldGuts = mGuts;
921 int index = indexOfChild(oldGuts);
922 removeView(oldGuts);
923 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
924 R.layout.notification_guts, this, false);
925 mGuts.setVisibility(oldGuts.getVisibility());
926 addView(mGuts, index);
927 }
Mady Mellor95d743c2017-01-10 12:05:27 -0800928 View oldMenu = mMenuRow.getMenuView();
929 if (oldMenu != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800930 int menuIndex = indexOfChild(oldMenu);
931 removeView(oldMenu);
Mady Mellor4ab28202017-06-06 11:42:50 -0700932 mMenuRow.createMenu(ExpandableNotificationRow.this, mStatusBarNotification);
Mady Mellor761cde12017-01-10 11:36:39 -0800933 mMenuRow.setAppName(mAppName);
Mady Mellor95d743c2017-01-10 12:05:27 -0800934 addView(mMenuRow.getMenuView(), menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -0800935 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800936 for (NotificationContentView l : mLayouts) {
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800937 l.initView();
Adrian Rooseb434ff2017-01-11 11:18:48 -0800938 l.reInflateViews();
939 }
Selim Cinek1a48bab2017-02-17 19:38:40 -0800940 mNotificationInflater.onDensityOrFontScaleChanged();
941 onNotificationUpdated();
Selim Cinek01af3342016-02-09 19:25:31 -0800942 }
943
Mady Mellor9d03a522017-04-04 18:45:30 -0700944 @Override
945 public void onConfigurationChanged(Configuration newConfig) {
946 if (mMenuRow.getMenuView() != null) {
947 mMenuRow.onConfigurationChanged();
948 }
949 }
950
Selim Cinekc3179332016-03-04 14:44:56 -0800951 public void setContentBackground(int customBackgroundColor, boolean animate,
952 NotificationContentView notificationContentView) {
953 if (getShowingLayout() == notificationContentView) {
954 setTintColor(customBackgroundColor, animate);
955 }
956 }
957
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700958 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800959 for (NotificationContentView l : mLayouts) {
960 l.closeRemoteInput();
961 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700962 }
963
Selim Cinekc897bd32016-03-18 17:32:31 -0700964 /**
965 * Set by how much the single line view should be indented.
966 */
967 public void setSingleLineWidthIndention(int indention) {
968 mPrivateLayout.setSingleLineWidthIndention(indention);
969 }
970
971 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700972 return mNotificationColor;
973 }
974
975 private void updateNotificationColor() {
976 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
Selim Cinekac5f0272017-05-02 16:05:41 -0700977 getStatusBarNotification().getNotification().color,
978 getBackgroundColorWithoutTint());
Adrian Roos6f6e1592017-05-02 16:22:53 -0700979 mNotificationColorAmbient = NotificationColorUtil.resolveAmbientColor(mContext,
980 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700981 }
982
983 public HybridNotificationView getSingleLineView() {
984 return mPrivateLayout.getSingleLineView();
985 }
986
Adrian Roos6f6e1592017-05-02 16:22:53 -0700987 public HybridNotificationView getAmbientSingleLineView() {
988 return getShowingLayout().getAmbientSingleLineChild();
989 }
990
Selim Cinekf07d0622016-03-21 19:52:52 -0700991 public boolean isOnKeyguard() {
992 return mOnKeyguard;
993 }
994
Selim Cinekc1e389d2016-04-07 11:02:57 -0700995 public void removeAllChildren() {
996 List<ExpandableNotificationRow> notificationChildren
997 = mChildrenContainer.getNotificationChildren();
998 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
999 for (int i = 0; i < clonedList.size(); i++) {
1000 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -07001001 if (row.keepInParent()) {
1002 continue;
1003 }
Selim Cinekc1e389d2016-04-07 11:02:57 -07001004 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -07001005 row.setIsChildInGroup(false, null);
1006 }
1007 onChildrenCountChanged();
1008 }
1009
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001010 public void setForceUnlocked(boolean forceUnlocked) {
1011 mForceUnlocked = forceUnlocked;
1012 if (mIsSummaryWithChildren) {
1013 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
1014 for (ExpandableNotificationRow child : notificationChildren) {
1015 child.setForceUnlocked(forceUnlocked);
1016 }
1017 }
1018 }
1019
Selim Cineke9bad242016-06-15 11:46:37 -07001020 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -07001021 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -07001022 mGroupParentWhenDismissed = mNotificationParent;
1023 mRefocusOnDismiss = fromAccessibility;
1024 mChildAfterViewWhenDismissed = null;
1025 if (isChildInGroup()) {
1026 List<ExpandableNotificationRow> notificationChildren =
1027 mNotificationParent.getNotificationChildren();
1028 int i = notificationChildren.indexOf(this);
1029 if (i != -1 && i < notificationChildren.size() - 1) {
1030 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
1031 }
1032 }
Selim Cinek3f19f602016-05-02 18:01:56 -07001033 }
1034
1035 public boolean isDismissed() {
1036 return mDismissed;
1037 }
1038
1039 public boolean keepInParent() {
1040 return mKeepInParent;
1041 }
1042
1043 public void setKeepInParent(boolean keepInParent) {
1044 mKeepInParent = keepInParent;
1045 }
1046
Selim Cinekd9b7dd42017-11-10 17:53:47 -08001047 @Override
Selim Cinek3f19f602016-05-02 18:01:56 -07001048 public boolean isRemoved() {
1049 return mRemoved;
1050 }
1051
Adrian Roosd009ab12016-05-20 17:58:53 -07001052 public void setRemoved() {
1053 mRemoved = true;
Selim Cinekef8c2252017-02-10 14:52:18 -08001054 mTranslationWhenRemoved = getTranslationY();
1055 mWasChildInGroupWhenRemoved = isChildInGroup();
1056 if (isChildInGroup()) {
1057 mTranslationWhenRemoved += getNotificationParent().getTranslationY();
1058 }
Adrian Roosd009ab12016-05-20 17:58:53 -07001059 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -07001060 }
1061
Selim Cinekef8c2252017-02-10 14:52:18 -08001062 public boolean wasChildInGroupWhenRemoved() {
1063 return mWasChildInGroupWhenRemoved;
1064 }
1065
1066 public float getTranslationWhenRemoved() {
1067 return mTranslationWhenRemoved;
1068 }
1069
Selim Cinekd1395642016-04-28 12:22:42 -07001070 public NotificationChildrenContainer getChildrenContainer() {
1071 return mChildrenContainer;
1072 }
1073
Selim Cinekcafa87f2016-10-26 17:00:17 -07001074 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07001075 boolean wasAboveShelf = isAboveShelf();
Selim Cinekcafa87f2016-10-26 17:00:17 -07001076 mHeadsupDisappearRunning = headsUpAnimatingAway;
1077 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
Selim Cinek5cf1d052017-06-01 17:36:46 -07001078 if (isAboveShelf() != wasAboveShelf) {
1079 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
1080 }
Selim Cinekcafa87f2016-10-26 17:00:17 -07001081 }
1082
1083 /**
1084 * @return if the view was just heads upped and is now animating away. During such a time the
1085 * layout needs to be kept consistent
1086 */
1087 public boolean isHeadsUpAnimatingAway() {
1088 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -07001089 }
1090
Selim Cineke9bad242016-06-15 11:46:37 -07001091 public View getChildAfterViewWhenDismissed() {
1092 return mChildAfterViewWhenDismissed;
1093 }
1094
1095 public View getGroupParentWhenDismissed() {
1096 return mGroupParentWhenDismissed;
1097 }
1098
Selim Cinek9e624e72016-07-20 13:46:49 -07001099 public void performDismiss() {
Selim Cineke9079112016-12-14 14:41:01 -08001100 if (mOnDismissRunnable != null) {
1101 mOnDismissRunnable.run();
1102 }
Selim Cinek9e624e72016-07-20 13:46:49 -07001103 }
1104
Selim Cineke9079112016-12-14 14:41:01 -08001105 public void setOnDismissRunnable(Runnable onDismissRunnable) {
1106 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -07001107 }
1108
Selim Cinek281c2022016-10-13 19:14:43 -07001109 public View getNotificationIcon() {
Selim Cinek414ad332017-02-24 19:06:12 -08001110 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek281c2022016-10-13 19:14:43 -07001111 if (notificationHeader != null) {
1112 return notificationHeader.getIcon();
1113 }
1114 return null;
1115 }
1116
1117 /**
1118 * @return whether the notification is currently showing a view with an icon.
1119 */
1120 public boolean isShowingIcon() {
Mady Mellor434180c2017-02-13 11:29:42 -08001121 if (areGutsExposed()) {
1122 return false;
1123 }
Selim Cinek2ffa02f2017-03-06 15:56:37 -08001124 return getVisibleNotificationHeader() != null;
Selim Cinek281c2022016-10-13 19:14:43 -07001125 }
1126
Selim Cinek0242fbb2016-10-19 13:38:32 -07001127 /**
1128 * Set how much this notification is transformed into an icon.
1129 *
Selim Cinek2b549f42016-11-22 16:38:51 -08001130 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
1131 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -08001132 * @param isLastChild is this the last child in the list. If true, then the transformation is
1133 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -07001134 */
Selim Cinek2b549f42016-11-22 16:38:51 -08001135 public void setContentTransformationAmount(float contentTransformationAmount,
1136 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -08001137 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001138 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001139 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001140 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001141 if (changeTransformation) {
1142 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -08001143 }
1144 }
1145
1146 /**
1147 * Set the icons to be visible of this notification.
1148 */
1149 public void setIconsVisible(boolean iconsVisible) {
1150 if (iconsVisible != mIconsVisible) {
1151 mIconsVisible = iconsVisible;
1152 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -07001153 }
1154 }
1155
Selim Cinekdb167372016-11-17 15:41:17 -08001156 @Override
1157 protected void onBelowSpeedBumpChanged() {
1158 updateIconVisibilities();
1159 }
1160
Selim Cinek875a3a12016-11-18 17:52:16 -08001161 private void updateContentTransformation() {
1162 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -08001163 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -08001164 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -08001165 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001166 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001167 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -08001168 translationY *= 0.4f;
1169 } else {
1170 contentAlpha = 1.0f;
1171 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001172 for (NotificationContentView l : mLayouts) {
1173 l.setAlpha(contentAlpha);
1174 l.setTranslationY(translationY);
1175 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001176 if (mChildrenContainer != null) {
1177 mChildrenContainer.setAlpha(contentAlpha);
1178 mChildrenContainer.setTranslationY(translationY);
1179 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -07001180 }
1181 }
1182
1183 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -08001184 boolean visible = isChildInGroup()
1185 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
1186 || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -08001187 for (NotificationContentView l : mLayouts) {
1188 l.setIconsVisible(visible);
1189 }
Selim Cinekdb167372016-11-17 15:41:17 -08001190 if (mChildrenContainer != null) {
1191 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001192 }
1193 }
1194
Selim Cinek875a3a12016-11-18 17:52:16 -08001195 /**
1196 * Get the relative top padding of a view relative to this view. This recursively walks up the
1197 * hierarchy and does the corresponding measuring.
1198 *
1199 * @param view the view to the the padding for. The requested view has to be a child of this
1200 * notification.
1201 * @return the toppadding
1202 */
1203 public int getRelativeTopPadding(View view) {
1204 int topPadding = 0;
1205 while (view.getParent() instanceof ViewGroup) {
1206 topPadding += view.getTop();
1207 view = (View) view.getParent();
1208 if (view instanceof ExpandableNotificationRow) {
1209 return topPadding;
1210 }
1211 }
1212 return topPadding;
1213 }
1214
Selim Cineka1d97902016-12-14 16:31:40 -08001215 public float getContentTranslation() {
1216 return mPrivateLayout.getTranslationY();
1217 }
1218
Selim Cinek6743c0b2017-01-18 18:24:01 -08001219 public void setIsLowPriority(boolean isLowPriority) {
1220 mIsLowPriority = isLowPriority;
1221 mPrivateLayout.setIsLowPriority(isLowPriority);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001222 mNotificationInflater.setIsLowPriority(mIsLowPriority);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001223 if (mChildrenContainer != null) {
1224 mChildrenContainer.setIsLowPriority(isLowPriority);
1225 }
1226 }
1227
Selim Cinek55a3e732017-05-25 18:30:10 -07001228
1229 public void setLowPriorityStateUpdated(boolean lowPriorityStateUpdated) {
1230 mLowPriorityStateUpdated = lowPriorityStateUpdated;
1231 }
1232
1233 public boolean hasLowPriorityStateUpdated() {
1234 return mLowPriorityStateUpdated;
1235 }
1236
Selim Cinek414ad332017-02-24 19:06:12 -08001237 public boolean isLowPriority() {
1238 return mIsLowPriority;
1239 }
1240
Selim Cinek7d1009b2017-01-25 15:28:28 -08001241 public void setUseIncreasedCollapsedHeight(boolean use) {
1242 mUseIncreasedCollapsedHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001243 mNotificationInflater.setUsesIncreasedHeight(use);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001244 }
1245
Selim Cinek87ed69b2017-02-09 15:59:43 -08001246 public void setUseIncreasedHeadsUpHeight(boolean use) {
1247 mUseIncreasedHeadsUpHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001248 mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
1249 }
1250
1251 public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
1252 mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001253 }
1254
Selim Cinek5ba22542017-04-20 15:16:10 -07001255 public void setInflationCallback(InflationCallback callback) {
1256 mNotificationInflater.setInflationCallback(callback);
Selim Cinekc478f902017-02-22 20:55:44 -08001257 }
1258
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001259 public void setNeedsRedaction(boolean needsRedaction) {
1260 mNotificationInflater.setRedactAmbient(needsRedaction);
1261 }
1262
Selim Cinek5ba22542017-04-20 15:16:10 -07001263 @VisibleForTesting
1264 public NotificationInflater getNotificationInflater() {
1265 return mNotificationInflater;
1266 }
1267
Adrian Roos6f6e1592017-05-02 16:22:53 -07001268 public int getNotificationColorAmbient() {
1269 return mNotificationColorAmbient;
1270 }
1271
Chris Wren78403d72014-07-28 10:23:24 +01001272 public interface ExpansionLogger {
Anthony Chen6bf88a02017-04-10 14:41:44 -07001273 void logNotificationExpansion(String key, boolean userAction, boolean expanded);
Chris Wren78403d72014-07-28 10:23:24 +01001274 }
Selim Cinek1685e632014-04-08 02:27:49 +02001275
Chris Wren51c75102013-07-16 20:49:17 -04001276 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1277 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001278 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001279 mNotificationInflater = new NotificationInflater(this);
Mady Mellor95d743c2017-01-10 12:05:27 -08001280 mMenuRow = new NotificationMenuRow(mContext);
Selim Cinek01af3342016-02-09 19:25:31 -08001281 initDimens();
1282 }
1283
1284 private void initDimens() {
Selim Cineke62255c2017-09-28 18:23:23 -07001285 mNotificationMinHeightLegacy = NotificationUtils.getFontScaledHeight(mContext,
1286 R.dimen.notification_min_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001287 mNotificationMinHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1288 R.dimen.notification_min_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001289 mNotificationMinHeight = NotificationUtils.getFontScaledHeight(mContext,
1290 R.dimen.notification_min_height);
1291 mNotificationMinHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001292 R.dimen.notification_min_height_increased);
Selim Cineke62255c2017-09-28 18:23:23 -07001293 mNotificationMaxHeight = NotificationUtils.getFontScaledHeight(mContext,
1294 R.dimen.notification_max_height);
1295 mNotificationAmbientHeight = NotificationUtils.getFontScaledHeight(mContext,
1296 R.dimen.notification_ambient_height);
1297 mMaxHeadsUpHeightLegacy = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek77019c72015-12-09 10:18:02 -08001298 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001299 mMaxHeadsUpHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1300 R.dimen.notification_max_heads_up_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001301 mMaxHeadsUpHeight = NotificationUtils.getFontScaledHeight(mContext,
1302 R.dimen.notification_max_heads_up_height);
1303 mMaxHeadsUpHeightIncreased = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001304 R.dimen.notification_max_heads_up_height_increased);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001305
Anthony Chen7acbb772017-04-07 16:45:25 -07001306 Resources res = getResources();
1307 mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
1308 R.dimen.notification_divider_height_increased);
1309 mIconTransformContentShiftNoIcon = res.getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001310 R.dimen.notification_icon_transform_content_shift);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001311 mEnableNonGroupedNotificationExpand =
1312 res.getBoolean(R.bool.config_enableNonGroupedNotificationExpand);
1313 mShowGroupBackgroundWhenExpanded =
1314 res.getBoolean(R.bool.config_showGroupNotificationBgWhenExpanded);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001315 }
1316
1317 /**
Christoph Studera7fe6312014-06-27 19:32:44 +02001318 * Resets this view so it can be re-used for an updated notification.
1319 */
1320 public void reset() {
Jorim Jaggiae441282014-08-01 02:45:18 +02001321 mShowingPublicInitialized = false;
Selim Cinek31094df2014-08-14 19:28:15 +02001322 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001323 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001324 }
1325
Dan Sandler1d958f82018-01-09 21:10:26 -05001326 public void showBlockingHelper(boolean show) {
1327 mHelperButton.setVisibility(show ? View.VISIBLE : View.GONE);
1328 }
1329
Jorim Jaggi251957d2014-04-09 04:24:09 +02001330 @Override
1331 protected void onFinishInflate() {
1332 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001333 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1334 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001335 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1336
Dan Sandler1d958f82018-01-09 21:10:26 -05001337 final NotificationGutsManager gutsMan = Dependency.get(NotificationGutsManager.class);
1338 mHelperButton = findViewById(R.id.helper);
1339 mHelperButton.setOnClickListener(view -> {
1340 doLongClickCallback();
1341 });
1342
Adrian Rooseb434ff2017-01-11 11:18:48 -08001343 for (NotificationContentView l : mLayouts) {
1344 l.setExpandClickListener(mExpandClickListener);
1345 l.setContainingNotification(this);
1346 }
Selim Cinekab29aeb2015-02-20 18:18:32 +01001347 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1348 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001349 @Override
1350 public void onInflate(ViewStub stub, View inflated) {
1351 mGuts = (NotificationGuts) inflated;
1352 mGuts.setClipTopAmount(getClipTopAmount());
1353 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001354 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001355 }
1356 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001357 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1358 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1359
1360 @Override
1361 public void onInflate(ViewStub stub, View inflated) {
1362 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001363 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek414ad332017-02-24 19:06:12 -08001364 mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001365 mChildrenContainer.onNotificationUpdated();
Anthony Chen7acbb772017-04-07 16:45:25 -07001366
1367 if (mShouldTranslateContents) {
1368 mTranslateableViews.add(mChildrenContainer);
1369 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001370 }
1371 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001372
Anthony Chen7acbb772017-04-07 16:45:25 -07001373 if (mShouldTranslateContents) {
1374 // Add the views that we translate to reveal the menu
1375 mTranslateableViews = new ArrayList<>();
1376 for (int i = 0; i < getChildCount(); i++) {
1377 mTranslateableViews.add(getChildAt(i));
1378 }
1379 // Remove views that don't translate
1380 mTranslateableViews.remove(mChildrenContainerStub);
1381 mTranslateableViews.remove(mGutsStub);
Mady Mellor4b80b102016-01-22 08:03:58 -08001382 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001383 }
1384
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001385 private void doLongClickCallback() {
1386 doLongClickCallback(getWidth() / 2, getHeight() / 2);
1387 }
1388
1389 public void doLongClickCallback(int x, int y) {
1390 createMenu();
1391 MenuItem menuItem = getProvider().getLongpressMenuItem(mContext);
1392 if (mLongPressListener != null && menuItem != null) {
1393 mLongPressListener.onLongPress(this, x, y, menuItem);
1394 }
1395 }
1396
1397 @Override
1398 public boolean onKeyDown(int keyCode, KeyEvent event) {
1399 if (KeyEvent.isConfirmKey(keyCode)) {
1400 event.startTracking();
1401 return true;
1402 }
1403 return super.onKeyDown(keyCode, event);
1404 }
1405
1406 @Override
1407 public boolean onKeyUp(int keyCode, KeyEvent event) {
1408 if (KeyEvent.isConfirmKey(keyCode)) {
1409 if (!event.isCanceled()) {
1410 performClick();
1411 }
1412 return true;
1413 }
1414 return super.onKeyUp(keyCode, event);
1415 }
1416
1417 @Override
1418 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
1419 if (KeyEvent.isConfirmKey(keyCode)) {
1420 doLongClickCallback();
1421 return true;
1422 }
1423 return false;
1424 }
1425
Mady Mellor4b80b102016-01-22 08:03:58 -08001426 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001427 if (mTranslateAnim != null) {
1428 mTranslateAnim.cancel();
1429 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001430
1431 if (!mShouldTranslateContents) {
1432 setTranslationX(0);
1433 } else if (mTranslateableViews != null) {
Mady Mellor4b80b102016-01-22 08:03:58 -08001434 for (int i = 0; i < mTranslateableViews.size(); i++) {
1435 mTranslateableViews.get(i).setTranslationX(0);
1436 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001437 invalidateOutline();
Mady Mellor4b80b102016-01-22 08:03:58 -08001438 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001439
Mady Mellor95d743c2017-01-10 12:05:27 -08001440 mMenuRow.resetMenu();
Mady Mellor4b80b102016-01-22 08:03:58 -08001441 }
1442
1443 public void animateTranslateNotification(final float leftTarget) {
1444 if (mTranslateAnim != null) {
1445 mTranslateAnim.cancel();
1446 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001447 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001448 if (mTranslateAnim != null) {
1449 mTranslateAnim.start();
1450 }
1451 }
1452
1453 @Override
1454 public void setTranslation(float translationX) {
1455 if (areGutsExposed()) {
1456 // Don't translate if guts are showing.
1457 return;
1458 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001459 if (!mShouldTranslateContents) {
1460 setTranslationX(translationX);
1461 } else if (mTranslateableViews != null) {
1462 // Translate the group of views
1463 for (int i = 0; i < mTranslateableViews.size(); i++) {
1464 if (mTranslateableViews.get(i) != null) {
1465 mTranslateableViews.get(i).setTranslationX(translationX);
1466 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001467 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001468 invalidateOutline();
Mady Mellor34958fa2016-02-23 09:52:17 -08001469 }
Mady Mellor95d743c2017-01-10 12:05:27 -08001470 if (mMenuRow.getMenuView() != null) {
1471 mMenuRow.onTranslationUpdate(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001472 }
1473 }
1474
1475 @Override
1476 public float getTranslation() {
Anthony Chene04afcb2017-04-21 13:51:32 -07001477 if (!mShouldTranslateContents) {
Anthony Chen7acbb772017-04-07 16:45:25 -07001478 return getTranslationX();
1479 }
1480
Mady Mellor34958fa2016-02-23 09:52:17 -08001481 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1482 // All of the views in the list should have same translation, just use first one.
1483 return mTranslateableViews.get(0).getTranslationX();
1484 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001485
Mady Mellor34958fa2016-02-23 09:52:17 -08001486 return 0;
1487 }
1488
1489 public Animator getTranslateViewAnimator(final float leftTarget,
1490 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001491 if (mTranslateAnim != null) {
1492 mTranslateAnim.cancel();
1493 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001494 if (areGutsExposed()) {
1495 // No translation if guts are exposed.
1496 return null;
1497 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001498 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1499 leftTarget);
1500 if (listener != null) {
1501 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001502 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001503 translateAnim.addListener(new AnimatorListenerAdapter() {
1504 boolean cancelled = false;
1505
1506 @Override
1507 public void onAnimationCancel(Animator anim) {
1508 cancelled = true;
1509 }
1510
1511 @Override
1512 public void onAnimationEnd(Animator anim) {
Mady Mellor95d743c2017-01-10 12:05:27 -08001513 if (!cancelled && leftTarget == 0) {
1514 mMenuRow.resetMenu();
Mady Mellorb0a82462016-04-30 17:31:02 -07001515 mTranslateAnim = null;
1516 }
1517 }
1518 });
1519 mTranslateAnim = translateAnim;
1520 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001521 }
1522
Selim Cinekab29aeb2015-02-20 18:18:32 +01001523 public void inflateGuts() {
1524 if (mGuts == null) {
1525 mGutsStub.inflate();
1526 }
1527 }
1528
Selim Cinekda42d652015-12-04 15:51:16 -08001529 private void updateChildrenVisibility() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08001530 mPrivateLayout.setVisibility(!shouldShowPublic() && !mIsSummaryWithChildren ? VISIBLE
Selim Cinekd84a5932015-12-15 11:45:36 -08001531 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001532 if (mChildrenContainer != null) {
Selim Cinek0b9cf462017-12-07 16:31:03 -08001533 mChildrenContainer.setVisibility(!shouldShowPublic() && mIsSummaryWithChildren ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001534 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001535 }
Selim Cinekda42d652015-12-04 15:51:16 -08001536 // The limits might have changed if the view suddenly became a group or vice versa
1537 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001538 }
1539
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001540 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001541 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1542 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001543 // Add a record for the entire layout since its content is somehow small.
1544 // The event comes from a leaf view that is interacted with.
1545 AccessibilityEvent record = AccessibilityEvent.obtain();
1546 onInitializeAccessibilityEvent(record);
1547 dispatchPopulateAccessibilityEvent(record);
1548 event.appendRecord(record);
1549 return true;
1550 }
1551 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001552 }
Chris Wren51c75102013-07-16 20:49:17 -04001553
John Spurlocke15452b2014-08-21 09:44:39 -04001554 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001555 public void setDark(boolean dark, boolean fade, long delay) {
1556 super.setDark(dark, fade, delay);
Lucas Dupincecc7c22017-09-12 16:02:45 -07001557 mDark = dark;
Adrian Roos28f90c72017-05-08 17:24:26 -07001558 if (!mIsHeadsUp) {
1559 // Only fade the showing view of the pulsing notification.
1560 fade = false;
1561 }
John Spurlocke15452b2014-08-21 09:44:39 -04001562 final NotificationContentView showing = getShowingLayout();
1563 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001564 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001565 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001566 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001567 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001568 }
Selim Cineka7c69632017-06-07 15:51:29 -07001569 updateShelfIconColor();
John Spurlocke15452b2014-08-21 09:44:39 -04001570 }
1571
Lucas Dupincecc7c22017-09-12 16:02:45 -07001572 /**
1573 * Tap sounds should not be played when we're unlocking.
1574 * Doing so would cause audio collision and the system would feel unpolished.
1575 */
1576 @Override
1577 public boolean isSoundEffectsEnabled() {
1578 final boolean mute = mDark && mSecureStateProvider != null &&
1579 !mSecureStateProvider.getAsBoolean();
1580 return !mute && super.isSoundEffectsEnabled();
1581 }
1582
Chris Wren51c75102013-07-16 20:49:17 -04001583 public boolean isExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08001584 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001585 return !mChildrenExpanded;
1586 }
Anthony Chen6bf88a02017-04-10 14:41:44 -07001587 return mEnableNonGroupedNotificationExpand && mExpandable;
Chris Wren51c75102013-07-16 20:49:17 -04001588 }
1589
1590 public void setExpandable(boolean expandable) {
1591 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001592 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001593 }
1594
Selim Cinek4ffd6362015-12-29 15:12:23 +01001595 @Override
1596 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001597 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1598 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001599 }
1600
Selim Cinek1685e632014-04-08 02:27:49 +02001601 /**
1602 * @return whether the user has changed the expansion state
1603 */
1604 public boolean hasUserChangedExpansion() {
1605 return mHasUserChangedExpansion;
1606 }
1607
Chris Wren51c75102013-07-16 20:49:17 -04001608 public boolean isUserExpanded() {
1609 return mUserExpanded;
1610 }
1611
Selim Cinek1685e632014-04-08 02:27:49 +02001612 /**
1613 * Set this notification to be expanded by the user
1614 *
1615 * @param userExpanded whether the user wants this notification to be expanded
1616 */
Chris Wren51c75102013-07-16 20:49:17 -04001617 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001618 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1619 }
1620
1621 /**
1622 * Set this notification to be expanded by the user
1623 *
1624 * @param userExpanded whether the user wants this notification to be expanded
1625 * @param allowChildExpansion whether a call to this method allows expanding children
1626 */
1627 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001628 mFalsingManager.setNotificationExpanded();
Selim Cinek0b9cf462017-12-07 16:31:03 -08001629 if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
Selim Cinek414ad332017-02-24 19:06:12 -08001630 && !mChildrenContainer.showingAsLowPriority()) {
Chris Wren698b1702016-05-23 11:16:32 -04001631 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001632 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -08001633 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001634 return;
1635 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001636 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001637 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001638 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001639 mUserExpanded = userExpanded;
Selim Cinek414ad332017-02-24 19:06:12 -08001640 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07001641 if (!wasExpanded && isExpanded()
1642 && getActualHeight() != getIntrinsicHeight()) {
1643 notifyHeightChanged(true /* needsAnimation */);
1644 }
Chris Wren51c75102013-07-16 20:49:17 -04001645 }
1646
Selim Cinekccd14fb2014-08-12 18:53:24 +02001647 public void resetUserExpansion() {
Selim Cinek414ad332017-02-24 19:06:12 -08001648 boolean changed = mUserExpanded;
Selim Cinekccd14fb2014-08-12 18:53:24 +02001649 mHasUserChangedExpansion = false;
1650 mUserExpanded = false;
Selim Cinek414ad332017-02-24 19:06:12 -08001651 if (changed && mIsSummaryWithChildren) {
1652 mChildrenContainer.onExpansionChanged();
1653 }
1654 updateShelfIconColor();
Selim Cinekccd14fb2014-08-12 18:53:24 +02001655 }
1656
Chris Wren51c75102013-07-16 20:49:17 -04001657 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001658 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001659 }
1660
1661 public void setUserLocked(boolean userLocked) {
1662 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001663 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07001664 // This is intentionally not guarded with mIsSummaryWithChildren since we might have had
1665 // children but not anymore.
1666 if (mChildrenContainer != null) {
Selim Cinek42357e02016-02-24 18:48:01 -08001667 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07001668 if (mIsSummaryWithChildren && (userLocked || !isGroupExpanded())) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001669 updateBackgroundForGroupState();
1670 }
Selim Cinek42357e02016-02-24 18:48:01 -08001671 }
Chris Wren51c75102013-07-16 20:49:17 -04001672 }
1673
Selim Cinek1685e632014-04-08 02:27:49 +02001674 /**
1675 * @return has the system set this notification to be expanded
1676 */
1677 public boolean isSystemExpanded() {
1678 return mIsSystemExpanded;
1679 }
1680
1681 /**
1682 * Set this notification to be expanded by the system.
1683 *
1684 * @param expand whether the system wants this notification to be expanded.
1685 */
1686 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001687 if (expand != mIsSystemExpanded) {
1688 final boolean wasExpanded = isExpanded();
1689 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001690 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek414ad332017-02-24 19:06:12 -08001691 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001692 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001693 mChildrenContainer.updateGroupOverflow();
1694 }
Selim Cinek31094df2014-08-14 19:28:15 +02001695 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001696 }
1697
1698 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001699 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001700 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001701 public void setOnKeyguard(boolean onKeyguard) {
1702 if (onKeyguard != mOnKeyguard) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07001703 boolean wasAboveShelf = isAboveShelf();
Selim Cinek31094df2014-08-14 19:28:15 +02001704 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001705 mOnKeyguard = onKeyguard;
Selim Cinek414ad332017-02-24 19:06:12 -08001706 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cinek31094df2014-08-14 19:28:15 +02001707 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001708 if (mIsSummaryWithChildren) {
1709 mChildrenContainer.updateGroupOverflow();
1710 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001711 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001712 }
Selim Cinek5cf1d052017-06-01 17:36:46 -07001713 if (isAboveShelf() != wasAboveShelf) {
1714 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
1715 }
Selim Cinek31094df2014-08-14 19:28:15 +02001716 }
Selim Cinek1685e632014-04-08 02:27:49 +02001717 }
1718
1719 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001720 * @return Can the underlying notification be cleared? This can be different from whether the
1721 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1722 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001723 */
1724 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001725 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1726 return false;
1727 }
1728 if (mIsSummaryWithChildren) {
1729 List<ExpandableNotificationRow> notificationChildren =
1730 mChildrenContainer.getNotificationChildren();
1731 for (int i = 0; i < notificationChildren.size(); i++) {
1732 ExpandableNotificationRow child = notificationChildren.get(i);
1733 if (!child.isClearable()) {
1734 return false;
1735 }
1736 }
1737 }
1738 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001739 }
1740
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001741 @Override
1742 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001743 if (isUserLocked()) {
1744 return getActualHeight();
1745 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001746 if (mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07001747 return mGuts.getIntrinsicHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001748 } else if ((isChildInGroup() && !isGroupExpanded())) {
1749 return mPrivateLayout.getMinHeight();
1750 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1751 return getMinHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07001752 } else if (mIsSummaryWithChildren && (!mOnKeyguard || mShowAmbient)) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001753 return mChildrenContainer.getIntrinsicHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07001754 } else if (isHeadsUpAllowed() && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07001755 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001756 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1757 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001758 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001759 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001760 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001761 }
Selim Cinek31aada42015-12-18 17:51:15 -08001762 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001763 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001764 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001765 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001766 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001767 }
Selim Cinek1685e632014-04-08 02:27:49 +02001768
Adrian Roos6f6e1592017-05-02 16:22:53 -07001769 private boolean isHeadsUpAllowed() {
1770 return !mOnKeyguard && !mShowAmbient;
1771 }
1772
Mady Mellor43c2cd12016-12-12 21:05:13 -08001773 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001774 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001775 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001776 }
1777
Selim Cinek263398f2015-10-21 17:40:23 -07001778 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05001779 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001780 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1781 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
Selim Cinek414ad332017-02-24 19:06:12 -08001782 mChildrenContainer.recreateNotificationHeader(mExpandClickListener
1783 );
Selim Cinek263398f2015-10-21 17:40:23 -07001784 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001785 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001786 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001787 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001788 updateChildrenVisibility();
Selim Cinek2871bef2017-11-22 08:40:00 -08001789 applyChildrenRoundness();
Selim Cinek263398f2015-10-21 17:40:23 -07001790 }
1791
Mady Mellorb0a82462016-04-30 17:31:02 -07001792 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001793 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001794 mChildrenContainer.updateChildrenHeaderAppearance();
1795 }
1796 }
1797
Selim Cinek1685e632014-04-08 02:27:49 +02001798 /**
1799 * Check whether the view state is currently expanded. This is given by the system in {@link
1800 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1801 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1802 * view can differ from this state, if layout params are modified from outside.
1803 *
1804 * @return whether the view state is currently expanded.
1805 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001806 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001807 return isExpanded(false /* allowOnKeyguard */);
1808 }
1809
1810 public boolean isExpanded(boolean allowOnKeyguard) {
1811 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001812 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1813 || isUserExpanded());
1814 }
1815
1816 private boolean isSystemChildExpanded() {
1817 return mIsSystemChildExpanded;
1818 }
1819
1820 public void setSystemChildExpanded(boolean expanded) {
1821 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001822 }
1823
Mady Mellor035badd2017-04-04 18:45:30 -07001824 public void setLayoutListener(LayoutListener listener) {
1825 mLayoutListener = listener;
1826 }
1827
1828 public void removeListener() {
1829 mLayoutListener = null;
1830 }
1831
Selim Cinek1685e632014-04-08 02:27:49 +02001832 @Override
1833 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1834 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001835 updateMaxHeights();
Mady Mellor95d743c2017-01-10 12:05:27 -08001836 if (mMenuRow.getMenuView() != null) {
1837 mMenuRow.onHeightUpdate();
Mady Mellora6edc872016-04-26 11:01:03 -07001838 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001839 updateContentShiftHeight();
Mady Mellor035badd2017-04-04 18:45:30 -07001840 if (mLayoutListener != null) {
1841 mLayoutListener.onLayout();
1842 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001843 }
1844
1845 /**
1846 * Updates the content shift height such that the header is completely hidden when coming from
1847 * the top.
1848 */
1849 private void updateContentShiftHeight() {
Selim Cinek414ad332017-02-24 19:06:12 -08001850 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek875a3a12016-11-18 17:52:16 -08001851 if (notificationHeader != null) {
1852 CachingIconView icon = notificationHeader.getIcon();
1853 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1854 } else {
1855 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1856 }
Selim Cinek1685e632014-04-08 02:27:49 +02001857 }
1858
Selim Cinek8d490d42015-04-10 00:05:50 -07001859 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001860 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001861 View expandedChild = mPrivateLayout.getExpandedChild();
1862 if (expandedChild == null) {
1863 expandedChild = mPrivateLayout.getContractedChild();
1864 }
1865 mMaxExpandHeight = expandedChild.getHeight();
1866 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001867 if (headsUpChild == null) {
1868 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001869 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001870 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001871 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001872 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001873 }
1874 }
1875
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001876 @Override
1877 public void notifyHeightChanged(boolean needsAnimation) {
1878 super.notifyHeightChanged(needsAnimation);
1879 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1880 }
1881
Selim Cinek3c76d502016-02-19 15:16:33 -08001882 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001883 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001884 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001885 }
1886
Mady Mellor43c2cd12016-12-12 21:05:13 -08001887 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001888 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001889 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001890 if (mIsSummaryWithChildren) {
1891 List<ExpandableNotificationRow> notificationChildren =
1892 mChildrenContainer.getNotificationChildren();
1893 for (int i = 0; i < notificationChildren.size(); i++) {
1894 ExpandableNotificationRow child = notificationChildren.get(i);
1895 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1896 }
1897 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001898 }
1899
Mady Mellor43c2cd12016-12-12 21:05:13 -08001900 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001901 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1902 long duration) {
1903 boolean oldShowingPublic = mShowingPublic;
1904 mShowingPublic = mSensitive && hideSensitive;
1905 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1906 return;
1907 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001908
1909 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001910 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001911
Jorim Jaggiae441282014-08-01 02:45:18 +02001912 if (!animated) {
1913 mPublicLayout.animate().cancel();
1914 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001915 if (mChildrenContainer != null) {
1916 mChildrenContainer.animate().cancel();
1917 mChildrenContainer.setAlpha(1f);
1918 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001919 mPublicLayout.setAlpha(1f);
1920 mPrivateLayout.setAlpha(1f);
1921 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001922 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001923 } else {
Selim Cinek0b9cf462017-12-07 16:31:03 -08001924 animateShowingPublic(delay, duration, mShowingPublic);
Jorim Jaggiae441282014-08-01 02:45:18 +02001925 }
Selim Cinekc3179332016-03-04 14:44:56 -08001926 NotificationContentView showingLayout = getShowingLayout();
1927 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001928 mPrivateLayout.updateExpandButtons(isExpandable());
Lucas Dupinb6ed63b2017-05-30 16:17:42 -07001929 updateShelfIconColor();
Adrian Roose5726a22016-12-19 14:26:51 -08001930 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02001931 mShowingPublicInitialized = true;
1932 }
1933
Selim Cinek0b9cf462017-12-07 16:31:03 -08001934 private void animateShowingPublic(long delay, long duration, boolean showingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001935 View[] privateViews = mIsSummaryWithChildren
1936 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001937 : new View[] {mPrivateLayout};
1938 View[] publicViews = new View[] {mPublicLayout};
Selim Cinek0b9cf462017-12-07 16:31:03 -08001939 View[] hiddenChildren = showingPublic ? privateViews : publicViews;
1940 View[] shownChildren = showingPublic ? publicViews : privateViews;
Selim Cinekd84a5932015-12-15 11:45:36 -08001941 for (final View hiddenView : hiddenChildren) {
1942 hiddenView.setVisibility(View.VISIBLE);
1943 hiddenView.animate().cancel();
1944 hiddenView.animate()
1945 .alpha(0f)
1946 .setStartDelay(delay)
1947 .setDuration(duration)
1948 .withEndAction(new Runnable() {
1949 @Override
1950 public void run() {
1951 hiddenView.setVisibility(View.INVISIBLE);
1952 }
1953 });
1954 }
1955 for (View showView : shownChildren) {
1956 showView.setVisibility(View.VISIBLE);
1957 showView.setAlpha(0f);
1958 showView.animate().cancel();
1959 showView.animate()
1960 .alpha(1f)
1961 .setStartDelay(delay)
1962 .setDuration(duration);
1963 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001964 }
1965
Mady Mellor43c2cd12016-12-12 21:05:13 -08001966 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08001967 public boolean mustStayOnScreen() {
Selim Cinek9b9d6e12017-11-30 12:29:47 +01001968 return mIsHeadsUp && mMustStayOnScreen;
Selim Cinek3776fe02016-02-04 13:32:43 -08001969 }
1970
Selim Cinek9e624e72016-07-20 13:46:49 -07001971 /**
1972 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1973 * otherwise some state might not be updated. To request about the general clearability
1974 * see {@link #isClearable()}.
1975 */
1976 public boolean canViewBeDismissed() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08001977 return isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
1978 }
1979
1980 private boolean shouldShowPublic() {
1981 return mSensitive && mHideSensitiveForIntrinsicHeight;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001982 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001983
Ricky Waicd35def2016-05-03 11:07:07 +01001984 public void makeActionsVisibile() {
1985 setUserExpanded(true, true);
1986 if (isChildInGroup()) {
1987 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1988 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001989 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001990 }
1991
Selim Cinekb5605e52015-02-20 18:21:41 +01001992 public void setChildrenExpanded(boolean expanded, boolean animate) {
1993 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001994 if (mChildrenContainer != null) {
1995 mChildrenContainer.setChildrenExpanded(expanded);
1996 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001997 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001998 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001999 }
2000
Selim Cinekb5605e52015-02-20 18:21:41 +01002001 public static void applyTint(View v, int color) {
2002 int alpha;
2003 if (color != 0) {
2004 alpha = COLORED_DIVIDER_ALPHA;
2005 } else {
2006 color = 0xff000000;
2007 alpha = DEFAULT_DIVIDER_ALPHA;
2008 }
2009 if (v.getBackground() instanceof ColorDrawable) {
2010 ColorDrawable background = (ColorDrawable) v.getBackground();
2011 background.mutate();
2012 background.setColor(color);
2013 background.setAlpha(alpha);
2014 }
2015 }
2016
Selim Cinek1685e632014-04-08 02:27:49 +02002017 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01002018 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04002019 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02002020
Mady Mellor34958fa2016-02-23 09:52:17 -08002021 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002022 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08002023 }
2024
Jorim Jaggibe565df2014-04-28 17:51:23 +02002025 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002026 public boolean isContentExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002027 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002028 return true;
2029 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002030 NotificationContentView showingLayout = getShowingLayout();
2031 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002032 }
2033
2034 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07002035 protected View getContentView() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002036 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cineka5703182016-05-11 21:23:16 -04002037 return mChildrenContainer;
2038 }
Selim Cinek560e64d2015-06-09 19:58:11 -07002039 return getShowingLayout();
2040 }
2041
2042 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07002043 protected void onAppearAnimationFinished(boolean wasAppearing) {
2044 super.onAppearAnimationFinished(wasAppearing);
2045 if (wasAppearing) {
2046 // During the animation the visible view might have changed, so let's make sure all
2047 // alphas are reset
2048 if (mChildrenContainer != null) {
2049 mChildrenContainer.setAlpha(1.0f);
2050 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
2051 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08002052 for (NotificationContentView l : mLayouts) {
2053 l.setAlpha(1.0f);
2054 l.setLayerType(LAYER_TYPE_NONE, null);
2055 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07002056 }
2057 }
2058
2059 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07002060 public int getExtraBottomPadding() {
2061 if (mIsSummaryWithChildren && isGroupExpanded()) {
2062 return mIncreasedPaddingBetweenElements;
2063 }
2064 return 0;
2065 }
2066
2067 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02002068 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinek4ca6c632017-02-23 18:03:37 -08002069 boolean changed = height != getActualHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +01002070 super.setActualHeight(height, notifyListeners);
Selim Cinek4ca6c632017-02-23 18:03:37 -08002071 if (changed && isRemoved()) {
2072 // TODO: remove this once we found the gfx bug for this.
2073 // This is a hack since a removed view sometimes would just stay blank. it occured
2074 // when sending yourself a message and then clicking on it.
2075 ViewGroup parent = (ViewGroup) getParent();
2076 if (parent != null) {
2077 parent.invalidate();
2078 }
2079 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002080 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08002081 mGuts.setActualHeight(height);
2082 return;
2083 }
Selim Cinekeef84282015-10-30 16:28:00 -07002084 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002085 for (NotificationContentView l : mLayouts) {
2086 l.setContentHeight(contentHeight);
2087 }
Selim Cinek42357e02016-02-24 18:48:01 -08002088 if (mIsSummaryWithChildren) {
2089 mChildrenContainer.setActualHeight(height);
2090 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002091 if (mGuts != null) {
2092 mGuts.setActualHeight(height);
2093 }
Mady Mellor54540972017-06-07 11:55:36 -07002094 if (mMenuRow.getMenuView() != null) {
2095 mMenuRow.onHeightUpdate();
2096 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002097 }
2098
2099 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01002100 public int getMaxContentHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002101 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002102 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002103 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002104 NotificationContentView showingLayout = getShowingLayout();
2105 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02002106 }
2107
2108 @Override
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002109 public int getMinHeight(boolean ignoreTemporaryStates) {
2110 if (!ignoreTemporaryStates && mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07002111 return mGuts.getIntrinsicHeight();
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002112 } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp
2113 && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08002114 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
Selim Cinek0b9cf462017-12-07 16:31:03 -08002115 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !shouldShowPublic()) {
Selim Cinekb55386d2015-12-16 17:26:49 -08002116 return mChildrenContainer.getMinHeight();
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002117 } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08002118 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08002119 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002120 NotificationContentView showingLayout = getShowingLayout();
2121 return showingLayout.getMinHeight();
2122 }
2123
2124 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07002125 public int getCollapsedHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002126 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek567e8452016-03-24 10:54:56 -07002127 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002128 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002129 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002130 }
2131
2132 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02002133 public void setClipTopAmount(int clipTopAmount) {
2134 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002135 for (NotificationContentView l : mLayouts) {
2136 l.setClipTopAmount(clipTopAmount);
2137 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002138 if (mGuts != null) {
2139 mGuts.setClipTopAmount(clipTopAmount);
2140 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002141 }
2142
Selim Cineka686b2c2016-10-26 13:58:27 -07002143 @Override
2144 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek65d418e2016-11-29 15:42:34 -08002145 if (clipBottomAmount != mClipBottomAmount) {
2146 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002147 for (NotificationContentView l : mLayouts) {
2148 l.setClipBottomAmount(clipBottomAmount);
2149 }
Selim Cinek65d418e2016-11-29 15:42:34 -08002150 if (mGuts != null) {
2151 mGuts.setClipBottomAmount(clipBottomAmount);
2152 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002153 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08002154 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08002155 // We have to update this even if it hasn't changed, since the children locations can
2156 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08002157 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
2158 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002159 }
2160
Selim Cinek31094df2014-08-14 19:28:15 +02002161 public boolean isMaxExpandHeightInitialized() {
2162 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02002163 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002164
Selim Cinek42357e02016-02-24 18:48:01 -08002165 public NotificationContentView getShowingLayout() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002166 return shouldShowPublic() ? mPublicLayout : mPrivateLayout;
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002167 }
Chris Wren78403d72014-07-28 10:23:24 +01002168
Selim Cinek1a48bab2017-02-17 19:38:40 -08002169 public void setLegacy(boolean legacy) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08002170 for (NotificationContentView l : mLayouts) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08002171 l.setLegacy(legacy);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002172 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07002173 }
2174
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002175 @Override
2176 protected void updateBackgroundTint() {
2177 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07002178 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002179 if (mIsSummaryWithChildren) {
2180 List<ExpandableNotificationRow> notificationChildren =
2181 mChildrenContainer.getNotificationChildren();
2182 for (int i = 0; i < notificationChildren.size(); i++) {
2183 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07002184 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002185 }
2186 }
2187 }
2188
Mady Mellorb0a82462016-04-30 17:31:02 -07002189 /**
2190 * Called when a group has finished animating from collapsed or expanded state.
2191 */
2192 public void onFinishedExpansionChange() {
2193 mGroupExpansionChanging = false;
2194 updateBackgroundForGroupState();
2195 }
2196
2197 /**
2198 * Updates the parent and children backgrounds in a group based on the expansion state.
2199 */
2200 public void updateBackgroundForGroupState() {
2201 if (mIsSummaryWithChildren) {
2202 // Only when the group has finished expanding do we hide its background.
Anthony Chen6bf88a02017-04-10 14:41:44 -07002203 mShowNoBackground = !mShowGroupBackgroundWhenExpanded && isGroupExpanded()
2204 && !isGroupExpansionChanging() && !isUserLocked();
Mady Mellorb0a82462016-04-30 17:31:02 -07002205 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
2206 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
2207 for (int i = 0; i < children.size(); i++) {
2208 children.get(i).updateBackgroundForGroupState();
2209 }
2210 } else if (isChildInGroup()) {
2211 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
2212 // Only show a background if the group is expanded OR if it is expanding / collapsing
Anthony Chen6bf88a02017-04-10 14:41:44 -07002213 // and has a custom background color.
Mady Mellorb0a82462016-04-30 17:31:02 -07002214 final boolean showBackground = isGroupExpanded()
2215 || ((mNotificationParent.isGroupExpansionChanging()
Anthony Chen6bf88a02017-04-10 14:41:44 -07002216 || mNotificationParent.isUserLocked()) && childColor != 0);
Mady Mellorb0a82462016-04-30 17:31:02 -07002217 mShowNoBackground = !showBackground;
2218 } else {
2219 // Only children or parents ever need no background.
2220 mShowNoBackground = false;
2221 }
2222 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002223 updateBackground();
2224 }
2225
Adrian Roos4a579672016-05-24 16:54:37 -07002226 public int getPositionOfChild(ExpandableNotificationRow childRow) {
2227 if (mIsSummaryWithChildren) {
2228 return mChildrenContainer.getPositionInLinearLayout(childRow);
2229 }
2230 return 0;
2231 }
2232
Chris Wren78403d72014-07-28 10:23:24 +01002233 public void setExpansionLogger(ExpansionLogger logger, String key) {
2234 mLogger = logger;
2235 mLoggingKey = key;
2236 }
2237
Chris Wren6abeeb92016-05-26 14:44:38 -04002238 public void onExpandedByGesture(boolean userExpanded) {
2239 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
2240 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
2241 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
2242 }
2243 MetricsLogger.action(mContext, event, userExpanded);
2244 }
2245
Selim Cinek6183d122016-01-14 18:48:41 -08002246 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08002247 public float getIncreasedPaddingAmount() {
2248 if (mIsSummaryWithChildren) {
2249 if (isGroupExpanded()) {
2250 return 1.0f;
2251 } else if (isUserLocked()) {
Selim Cinek414ad332017-02-24 19:06:12 -08002252 return mChildrenContainer.getIncreasedPaddingAmount();
Selim Cinek42357e02016-02-24 18:48:01 -08002253 }
Selim Cinek99104832017-01-25 14:47:33 -08002254 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08002255 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08002256 }
2257 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08002258 }
2259
Selim Cineka7ed2c12017-01-23 20:47:24 -08002260 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08002261 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08002262 }
2263
Selim Cinek61633a82016-01-25 15:54:10 -08002264 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08002265 protected boolean disallowSingleClick(MotionEvent event) {
2266 float x = event.getX();
2267 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08002268 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002269 if (header != null && header.isInTouchRect(x - getTranslation(), y)) {
2270 return true;
2271 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002272 if ((!mIsSummaryWithChildren || shouldShowPublic())
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002273 && getShowingLayout().disallowSingleClick(x, y)) {
2274 return true;
Selim Cinek6183d122016-01-14 18:48:41 -08002275 }
2276 return super.disallowSingleClick(event);
2277 }
2278
Selim Cinek414ad332017-02-24 19:06:12 -08002279 private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04002280 boolean nowExpanded = isExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08002281 if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
Chris Wren698b1702016-05-23 11:16:32 -04002282 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
2283 }
Selim Cinek414ad332017-02-24 19:06:12 -08002284 if (nowExpanded != wasExpanded) {
2285 updateShelfIconColor();
2286 if (mLogger != null) {
2287 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded);
2288 }
2289 if (mIsSummaryWithChildren) {
2290 mChildrenContainer.onExpansionChanged();
2291 }
Chris Wren78403d72014-07-28 10:23:24 +01002292 }
2293 }
Selim Cinek570981d2015-12-01 11:37:01 -08002294
Selim Cineke9bad242016-06-15 11:46:37 -07002295 @Override
2296 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2297 super.onInitializeAccessibilityNodeInfoInternal(info);
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002298 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
Selim Cineke9bad242016-06-15 11:46:37 -07002299 if (canViewBeDismissed()) {
2300 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
2301 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002302 boolean expandable = shouldShowPublic();
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002303 boolean isExpanded = false;
2304 if (!expandable) {
2305 if (mIsSummaryWithChildren) {
2306 expandable = true;
2307 if (!mIsLowPriority || isExpanded()) {
2308 isExpanded = isGroupExpanded();
2309 }
2310 } else {
2311 expandable = mPrivateLayout.isContentExpandable();
2312 isExpanded = isExpanded();
2313 }
2314 }
2315 if (expandable) {
2316 if (isExpanded) {
2317 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
2318 } else {
2319 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
2320 }
2321 }
Selim Cineke9bad242016-06-15 11:46:37 -07002322 }
2323
2324 @Override
2325 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
2326 if (super.performAccessibilityActionInternal(action, arguments)) {
2327 return true;
2328 }
2329 switch (action) {
2330 case AccessibilityNodeInfo.ACTION_DISMISS:
2331 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
2332 true /* fromAccessibility */);
2333 return true;
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002334 case AccessibilityNodeInfo.ACTION_COLLAPSE:
2335 case AccessibilityNodeInfo.ACTION_EXPAND:
2336 mExpandClickListener.onClick(this);
2337 return true;
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002338 case AccessibilityNodeInfo.ACTION_LONG_CLICK:
2339 doLongClickCallback();
2340 return true;
Selim Cineke9bad242016-06-15 11:46:37 -07002341 }
2342 return false;
2343 }
2344
2345 public boolean shouldRefocusOnDismiss() {
2346 return mRefocusOnDismiss || isAccessibilityFocused();
2347 }
2348
Selim Cinek570981d2015-12-01 11:37:01 -08002349 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08002350 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08002351 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002352
2353 @Override
2354 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
2355 return new NotificationViewState(stackScrollState);
2356 }
2357
Selim Cinekd127d792016-11-01 19:11:41 -07002358 @Override
2359 public boolean isAboveShelf() {
Selim Cinekc8007c52017-02-28 16:09:56 -08002360 return !isOnKeyguard()
2361 && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf));
Selim Cinekd127d792016-11-01 19:11:41 -07002362 }
2363
Adrian Roos0aac04f2016-12-08 15:59:29 -08002364 public void setShowAmbient(boolean showAmbient) {
2365 if (showAmbient != mShowAmbient) {
2366 mShowAmbient = showAmbient;
Adrian Roos6f6e1592017-05-02 16:22:53 -07002367 if (mChildrenContainer != null) {
2368 mChildrenContainer.notifyShowAmbientChanged();
2369 }
Adrian Roos0aac04f2016-12-08 15:59:29 -08002370 notifyHeightChanged(false /* needsAnimation */);
2371 }
2372 }
2373
Selim Cinek0fe07392017-11-09 13:26:34 -08002374 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08002375 protected boolean childNeedsClipping(View child) {
2376 if (child instanceof NotificationContentView) {
2377 NotificationContentView contentView = (NotificationContentView) child;
2378 if (isClippingNeeded()) {
2379 return true;
Selim Cinek86bfcee2018-01-17 11:00:47 -08002380 } else if (!hasNoRounding()
2381 && contentView.shouldClipToRounding(getCurrentTopRoundness() != 0.0f,
2382 getCurrentBottomRoundness() != 0.0f)) {
Selim Cinek515b2032017-11-15 10:20:19 -08002383 return true;
2384 }
2385 } else if (child == mChildrenContainer) {
Selim Cinekb95fd182017-12-21 13:03:32 -08002386 if (isClippingNeeded() || !hasNoRounding()) {
Selim Cinek515b2032017-11-15 10:20:19 -08002387 return true;
2388 }
2389 } else if (child instanceof NotificationGuts) {
Selim Cinekb95fd182017-12-21 13:03:32 -08002390 return !hasNoRounding();
Selim Cinek515b2032017-11-15 10:20:19 -08002391 }
2392 return super.childNeedsClipping(child);
2393 }
2394
2395 @Override
Selim Cinek2871bef2017-11-22 08:40:00 -08002396 protected void applyRoundness() {
2397 super.applyRoundness();
2398 applyChildrenRoundness();
2399 }
2400
2401 private void applyChildrenRoundness() {
2402 if (mIsSummaryWithChildren) {
2403 mChildrenContainer.setCurrentBottomRoundness(getCurrentBottomRoundness());
2404 }
2405 }
2406
2407 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08002408 public Path getCustomClipPath(View child) {
2409 if (child instanceof NotificationGuts) {
Selim Cinek2871bef2017-11-22 08:40:00 -08002410 return getClipPath(true, /* ignoreTranslation */
2411 false /* clipRoundedToBottom */);
2412 }
2413 if (child instanceof NotificationChildrenContainer) {
2414 return getClipPath(false, /* ignoreTranslation */
2415 true /* clipRoundedToBottom */);
Selim Cinek515b2032017-11-15 10:20:19 -08002416 }
2417 return super.getCustomClipPath(child);
2418 }
2419
Selim Cinekb95fd182017-12-21 13:03:32 -08002420 private boolean hasNoRounding() {
2421 return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f;
Selim Cinek0fe07392017-11-09 13:26:34 -08002422 }
2423
Adrian Roos6f6e1592017-05-02 16:22:53 -07002424 public boolean isShowingAmbient() {
2425 return mShowAmbient;
2426 }
2427
Selim Cinekd127d792016-11-01 19:11:41 -07002428 public void setAboveShelf(boolean aboveShelf) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07002429 boolean wasAboveShelf = isAboveShelf();
Selim Cinekd127d792016-11-01 19:11:41 -07002430 mAboveShelf = aboveShelf;
Selim Cinek5cf1d052017-06-01 17:36:46 -07002431 if (isAboveShelf() != wasAboveShelf) {
2432 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
2433 }
Selim Cinekd127d792016-11-01 19:11:41 -07002434 }
2435
Selim Cinekd4776a52017-02-14 18:50:16 -08002436 public static class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08002437
2438 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07002439
Selim Cinekbbcebde2016-11-09 18:28:20 -08002440
2441 private NotificationViewState(StackScrollState stackScrollState) {
2442 mOverallState = stackScrollState;
2443 }
2444
2445 @Override
2446 public void applyToView(View view) {
2447 super.applyToView(view);
2448 if (view instanceof ExpandableNotificationRow) {
2449 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinekbbcebde2016-11-09 18:28:20 -08002450 row.applyChildrenState(mOverallState);
2451 }
2452 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002453
2454 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08002455 protected void onYTranslationAnimationFinished(View view) {
2456 super.onYTranslationAnimationFinished(view);
Selim Cinekd4776a52017-02-14 18:50:16 -08002457 if (view instanceof ExpandableNotificationRow) {
2458 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
2459 if (row.isHeadsUpAnimatingAway()) {
2460 row.setHeadsUpAnimatingAway(false);
2461 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002462 }
2463 }
2464
2465 @Override
2466 public void animateTo(View child, AnimationProperties properties) {
2467 super.animateTo(child, properties);
2468 if (child instanceof ExpandableNotificationRow) {
2469 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
2470 row.startChildAnimation(mOverallState, properties);
2471 }
2472 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002473 }
Selim Cinek817abe72017-05-24 11:08:55 -07002474
2475 @VisibleForTesting
2476 protected void setChildrenContainer(NotificationChildrenContainer childrenContainer) {
2477 mChildrenContainer = childrenContainer;
2478 }
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002479
2480 /**
2481 * Equivalent to View.OnLongClickListener with coordinates
2482 */
2483 public interface LongPressListener {
2484 /**
2485 * Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
2486 * @return whether the longpress was handled
2487 */
2488 boolean onLongPress(View v, int x, int y, MenuItem item);
2489 }
Chris Wren51c75102013-07-16 20:49:17 -04002490}