blob: 1056ecc9bf6aa2e805ad3b1bcfd1faf0547df911 [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 Cinek2627d722018-01-19 12:16:49 -080019import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
Selim Cinek5ba22542017-04-20 15:16:10 -070020import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;
Selim Cinekc478f902017-02-22 20:55:44 -080021
Mady Mellor4b80b102016-01-22 08:03:58 -080022import android.animation.Animator;
23import android.animation.AnimatorListenerAdapter;
Mady Mellor4b80b102016-01-22 08:03:58 -080024import android.animation.ObjectAnimator;
Mady Mellor4b80b102016-01-22 08:03:58 -080025import android.animation.ValueAnimator.AnimatorUpdateListener;
Selim Cinekddf1b392016-05-27 16:33:10 -070026import android.annotation.Nullable;
Chris Wren51c75102013-07-16 20:49:17 -040027import android.content.Context;
Anthony Chen7acbb772017-04-07 16:45:25 -070028import android.content.res.Resources;
Mady Mellor9d03a522017-04-04 18:45:30 -070029import android.content.res.Configuration;
Selim Cinek515b2032017-11-15 10:20:19 -080030import android.graphics.Path;
Selim Cinekcab4a602014-09-03 14:47:57 +020031import android.graphics.drawable.AnimatedVectorDrawable;
32import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010033import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020034import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080035import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070036import android.os.Bundle;
Dan Sandler1d958f82018-01-09 21:10:26 -050037import android.service.notification.NotificationListenerService;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020038import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040039import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070040import android.util.FloatProperty;
Selim Cinek2627d722018-01-19 12:16:49 -080041import android.util.MathUtils;
Mady Mellorb0a82462016-04-30 17:31:02 -070042import android.util.Property;
Geoffrey Pitsch409db272017-08-28 14:51:52 +000043import android.view.KeyEvent;
Selim Cinek01af3342016-02-09 19:25:31 -080044import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080045import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080046import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050047import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080048import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020049import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020050import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070051import android.view.accessibility.AccessibilityNodeInfo;
Selim Cinek98713a42015-09-21 15:47:20 +020052import android.widget.Chronometer;
Mady Mellor95d743c2017-01-10 12:05:27 -080053import android.widget.FrameLayout;
Selim Cinekcab4a602014-09-03 14:47:57 +020054import android.widget.ImageView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080055import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010056
Selim Cinek5ba22542017-04-20 15:16:10 -070057import com.android.internal.annotations.VisibleForTesting;
Chris Wren698b1702016-05-23 11:16:32 -040058import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010059import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070060import com.android.internal.util.NotificationColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080061import com.android.internal.widget.CachingIconView;
Mady Mellor95d743c2017-01-10 12:05:27 -080062import com.android.systemui.Dependency;
Selim Cinek0242fbb2016-10-19 13:38:32 -070063import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050064import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070065import com.android.systemui.classifier.FalsingManager;
Mady Mellor95d743c2017-01-10 12:05:27 -080066import com.android.systemui.plugins.PluginListener;
67import com.android.systemui.plugins.PluginManager;
68import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
69import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
70import com.android.systemui.statusbar.NotificationGuts.GutsContent;
Selim Cinek5cf1d052017-06-01 17:36:46 -070071import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
Selim Cinek2627d722018-01-19 12:16:49 -080072import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
Selim Cinekc897bd32016-03-18 17:32:31 -070073import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080074import com.android.systemui.statusbar.notification.NotificationInflater;
Selim Cinek6743c0b2017-01-18 18:24:01 -080075import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cineke62255c2017-09-28 18:23:23 -070076import com.android.systemui.statusbar.notification.NotificationViewWrapper;
Selim Cineka7d4f822016-12-06 14:34:47 -080077import com.android.systemui.statusbar.notification.VisualStabilityManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010078import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050079import com.android.systemui.statusbar.phone.StatusBar;
Selim Cinek31aada42015-12-18 17:51:15 -080080import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek2627d722018-01-19 12:16:49 -080081import com.android.systemui.statusbar.stack.AmbientState;
Selim Cinek0cfbef42016-11-09 19:06:36 -080082import com.android.systemui.statusbar.stack.AnimationProperties;
83import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010084import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070085import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010086import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010087
Mady Mellor4b80b102016-01-22 08:03:58 -080088import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010089import java.util.List;
Lucas Dupincecc7c22017-09-12 16:02:45 -070090import java.util.function.BooleanSupplier;
Dan Sandlera5e0f412014-01-23 15:11:54 -050091
Mady Mellor95d743c2017-01-10 12:05:27 -080092public class ExpandableNotificationRow extends ActivatableNotificationView
93 implements PluginListener<NotificationMenuRowPlugin> {
Selim Cinekb5605e52015-02-20 18:21:41 +010094
95 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
96 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Mady Mellor95d743c2017-01-10 12:05:27 -080097 private static final int MENU_VIEW_INDEX = 0;
98
Mady Mellor035badd2017-04-04 18:45:30 -070099 public interface LayoutListener {
100 public void onLayout();
101 }
102
103 private LayoutListener mLayoutListener;
Lucas Dupincecc7c22017-09-12 16:02:45 -0700104 private boolean mDark;
Selim Cinek55a3e732017-05-25 18:30:10 -0700105 private boolean mLowPriorityStateUpdated;
Selim Cinek1a48bab2017-02-17 19:38:40 -0800106 private final NotificationInflater mNotificationInflater;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700107 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800108 private int mIconTransformContentShiftNoIcon;
Selim Cinek01af3342016-02-09 19:25:31 -0800109 private int mNotificationMinHeightLegacy;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800110 private int mNotificationMinHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800111 private int mMaxHeadsUpHeightLegacy;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800112 private int mMaxHeadsUpHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800113 private int mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800114 private int mMaxHeadsUpHeightIncreased;
Selim Cinek01af3342016-02-09 19:25:31 -0800115 private int mNotificationMinHeight;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800116 private int mNotificationMinHeightLarge;
Selim Cinek01af3342016-02-09 19:25:31 -0800117 private int mNotificationMaxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800118 private int mNotificationAmbientHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -0700119 private int mIncreasedPaddingBetweenElements;
Selim Cinek2627d722018-01-19 12:16:49 -0800120 private int mNotificationLaunchHeight;
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100121 private boolean mMustStayOnScreen;
Chris Wren51c75102013-07-16 20:49:17 -0400122
Selim Cinek1685e632014-04-08 02:27:49 +0200123 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -0400124 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +0200125 /** Has the user actively changed the expansion state of this row */
126 private boolean mHasUserChangedExpansion;
127 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -0400128 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -0800129
130 /**
131 * Has this notification been expanded while it was pinned
132 */
133 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +0200134 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -0400135 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +0200136 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -0500137 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +0200138 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -0800139 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +0200140 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700141 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400142
Selim Cinek1685e632014-04-08 02:27:49 +0200143 /**
144 * Is this notification expanded by the system. The expansion state can be overridden by the
145 * user expansion.
146 */
147 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200148
149 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700150 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200151 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700152 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200153
Mady Mellorb0a82462016-04-30 17:31:02 -0700154 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800155 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200156 private NotificationContentView mPublicLayout;
157 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800158 private NotificationContentView[] mLayouts;
Selim Cinek1685e632014-04-08 02:27:49 +0200159 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700160 private int mHeadsUpHeight;
Selim Cinek4bb59342016-04-08 19:29:35 -0700161 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100162 private ExpansionLogger mLogger;
163 private String mLoggingKey;
Selim Cinek8d490d42015-04-10 00:05:50 -0700164 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800165 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200166 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700167 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100168 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200169 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100170 private ViewStub mChildrenContainerStub;
171 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100172 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700173 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100174 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor95d743c2017-01-10 12:05:27 -0800175 private NotificationMenuRowPlugin mMenuRow;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100176 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100177 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700178 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700179 private FalsingManager mFalsingManager;
Selim Cinek2627d722018-01-19 12:16:49 -0800180 private boolean mExpandAnimationRunning;
Selim Cinek5cf1d052017-06-01 17:36:46 -0700181 private AboveShelfChangedListener mAboveShelfChangedListener;
Selim Cinek31aada42015-12-18 17:51:15 -0800182 private HeadsUpManager mHeadsUpManager;
Dan Sandler1d958f82018-01-09 21:10:26 -0500183 private View mHelperButton;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200184
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700185 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800186 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700187 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700188 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800189 private OnExpandClickListener mOnExpandClickListener;
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000190
191 // Listener will be called when receiving a long click event.
192 // Use #setLongPressPosition to optionally assign positional data with the long press.
193 private LongPressListener mLongPressListener;
194
Mady Mellorb0a82462016-04-30 17:31:02 -0700195 private boolean mGroupExpansionChanging;
196
Anthony Chen6bf88a02017-04-10 14:41:44 -0700197 /**
Lucas Dupincecc7c22017-09-12 16:02:45 -0700198 * A supplier that returns true if keyguard is secure.
199 */
200 private BooleanSupplier mSecureStateProvider;
201
202 /**
Anthony Chen6bf88a02017-04-10 14:41:44 -0700203 * Whether or not a notification that is not part of a group of notifications can be manually
204 * expanded by the user.
205 */
206 private boolean mEnableNonGroupedNotificationExpand;
207
208 /**
209 * Whether or not to update the background of the header of the notification when its expanded.
210 * If {@code true}, the header background will disappear when expanded.
211 */
212 private boolean mShowGroupBackgroundWhenExpanded;
213
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800214 private OnClickListener mExpandClickListener = new OnClickListener() {
215 @Override
216 public void onClick(View v) {
Selim Cinek0b9cf462017-12-07 16:31:03 -0800217 if (!shouldShowPublic() && (!mIsLowPriority || isExpanded())
Selim Cinek414ad332017-02-24 19:06:12 -0800218 && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700219 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400220 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
221 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
222 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400223 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
224 nowExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -0800225 onExpansionChanged(true /* userAction */, wasExpanded);
Anthony Chen6bf88a02017-04-10 14:41:44 -0700226 } else if (mEnableNonGroupedNotificationExpand) {
Selim Cineke9bad242016-06-15 11:46:37 -0700227 if (v.isAccessibilityFocused()) {
228 mPrivateLayout.setFocusOnVisibilityChange();
229 }
Selim Cinek31aada42015-12-18 17:51:15 -0800230 boolean nowExpanded;
231 if (isPinned()) {
232 nowExpanded = !mExpandedWhenPinned;
233 mExpandedWhenPinned = nowExpanded;
234 } else {
235 nowExpanded = !isExpanded();
236 setUserExpanded(nowExpanded);
237 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800238 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800239 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400240 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
241 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800242 }
243 }
244 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700245 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700246 private boolean mDismissed;
247 private boolean mKeepInParent;
248 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700249 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
250 new FloatProperty<ExpandableNotificationRow>("translate") {
251 @Override
252 public void setValue(ExpandableNotificationRow object, float value) {
253 object.setTranslation(value);
254 }
255
256 @Override
257 public Float get(ExpandableNotificationRow object) {
258 return object.getTranslation();
259 }
260 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700261 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700262 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700263 private View mChildAfterViewWhenDismissed;
264 private View mGroupParentWhenDismissed;
265 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800266 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700267 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700268 private boolean mAboveShelf;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800269 private boolean mShowAmbient;
Selim Cinek875a3a12016-11-18 17:52:16 -0800270 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800271 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800272 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800273 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800274 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800275 private boolean mUseIncreasedHeadsUpHeight;
Selim Cinekef8c2252017-02-10 14:52:18 -0800276 private float mTranslationWhenRemoved;
277 private boolean mWasChildInGroupWhenRemoved;
Adrian Roos6f6e1592017-05-02 16:22:53 -0700278 private int mNotificationColorAmbient;
Selim Cinek2627d722018-01-19 12:16:49 -0800279 private NotificationViewState mNotificationViewState;
Mady Mellorb0a82462016-04-30 17:31:02 -0700280
Mady Mellor43c2cd12016-12-12 21:05:13 -0800281 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700282 public boolean isGroupExpansionChanging() {
283 if (isChildInGroup()) {
284 return mNotificationParent.isGroupExpansionChanging();
285 }
286 return mGroupExpansionChanging;
287 }
288
289 public void setGroupExpansionChanging(boolean changing) {
290 mGroupExpansionChanging = changing;
291 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700292
Adrian Roos599be342016-06-13 14:54:39 -0700293 @Override
294 public void setActualHeightAnimating(boolean animating) {
295 if (mPrivateLayout != null) {
296 mPrivateLayout.setContentHeightAnimating(animating);
297 }
298 }
299
Selim Cinek8d490d42015-04-10 00:05:50 -0700300 public NotificationContentView getPrivateLayout() {
301 return mPrivateLayout;
302 }
303
304 public NotificationContentView getPublicLayout() {
305 return mPublicLayout;
306 }
307
Selim Cinekcab4a602014-09-03 14:47:57 +0200308 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800309 for (NotificationContentView l : mLayouts) {
310 setIconAnimationRunning(running, l);
311 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800312 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700313 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek414ad332017-02-24 19:06:12 -0800314 setIconAnimationRunningForChild(running, mChildrenContainer.getLowPriorityHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800315 List<ExpandableNotificationRow> notificationChildren =
316 mChildrenContainer.getNotificationChildren();
317 for (int i = 0; i < notificationChildren.size(); i++) {
318 ExpandableNotificationRow child = notificationChildren.get(i);
319 child.setIconAnimationRunning(running);
320 }
321 }
322 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200323 }
324
325 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
326 if (layout != null) {
327 View contractedChild = layout.getContractedChild();
328 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700329 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200330 setIconAnimationRunningForChild(running, contractedChild);
331 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700332 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200333 }
334 }
335
336 private void setIconAnimationRunningForChild(boolean running, View child) {
337 if (child != null) {
338 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
339 setIconRunning(icon, running);
340 ImageView rightIcon = (ImageView) child.findViewById(
341 com.android.internal.R.id.right_icon);
342 setIconRunning(rightIcon, running);
343 }
344 }
345
346 private void setIconRunning(ImageView imageView, boolean running) {
347 if (imageView != null) {
348 Drawable drawable = imageView.getDrawable();
349 if (drawable instanceof AnimationDrawable) {
350 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
351 if (running) {
352 animationDrawable.start();
353 } else {
354 animationDrawable.stop();
355 }
356 } else if (drawable instanceof AnimatedVectorDrawable) {
357 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
358 if (running) {
359 animationDrawable.start();
360 } else {
361 animationDrawable.stop();
362 }
363 }
364 }
365 }
366
Selim Cinek5ba22542017-04-20 15:16:10 -0700367 public void updateNotification(NotificationData.Entry entry) {
Selim Cinekda42d652015-12-04 15:51:16 -0800368 mEntry = entry;
369 mStatusBarNotification = entry.notification;
Selim Cinek1a48bab2017-02-17 19:38:40 -0800370 mNotificationInflater.inflateNotificationViews();
Selim Cinekc478f902017-02-22 20:55:44 -0800371 }
372
Selim Cinek2627d722018-01-19 12:16:49 -0800373 @Override
374 public void setPressed(boolean pressed) {
375 if (isOnKeyguard() || mEntry.notification.getNotification().contentIntent == null) {
376 // We're dropping the ripple if we have a collapse / launch animation
377 super.setPressed(pressed);
378 }
379 }
380
Selim Cinek5ba22542017-04-20 15:16:10 -0700381 public void onNotificationUpdated() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800382 for (NotificationContentView l : mLayouts) {
Selim Cinekc478f902017-02-22 20:55:44 -0800383 l.onNotificationUpdated(mEntry);
Adrian Rooseb434ff2017-01-11 11:18:48 -0800384 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800385 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800386 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700387 updateNotificationColor();
Mady Mellor4c197602017-04-10 17:57:52 -0700388 if (mMenuRow != null) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700389 mMenuRow.onNotificationUpdated(mStatusBarNotification);
Mady Mellor4c197602017-04-10 17:57:52 -0700390 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800391 if (mIsSummaryWithChildren) {
Selim Cinek414ad332017-02-24 19:06:12 -0800392 mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
Selim Cinekc897bd32016-03-18 17:32:31 -0700393 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800394 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800395 if (mIconAnimationRunning) {
396 setIconAnimationRunning(true);
397 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800398 if (mNotificationParent != null) {
399 mNotificationParent.updateChildrenHeaderAppearance();
400 }
Selim Cinek263398f2015-10-21 17:40:23 -0700401 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800402 // The public layouts expand button is always visible
403 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800404 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700405 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800406 updateShelfIconColor();
Dan Sandler1d958f82018-01-09 21:10:26 -0500407
408 showBlockingHelper(mEntry.userSentiment ==
409 NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE);
Selim Cinek6743c0b2017-01-18 18:24:01 -0800410 }
411
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700412 @VisibleForTesting
413 void updateShelfIconColor() {
Selim Cinek6743c0b2017-01-18 18:24:01 -0800414 StatusBarIconView expandedIcon = mEntry.expandedIcon;
415 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
416 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
417 NotificationColorUtil.getInstance(mContext));
Selim Cinek875ba9b2017-02-13 16:20:17 -0800418 int color = StatusBarIconView.NO_COLOR;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800419 if (colorize) {
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700420 NotificationHeaderView header = getVisibleNotificationHeader();
421 if (header != null) {
422 color = header.getOriginalIconColor();
423 } else {
424 color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
425 getBackgroundColorWithoutTint());
426 }
Selim Cinek6743c0b2017-01-18 18:24:01 -0800427 }
Selim Cinek875ba9b2017-02-13 16:20:17 -0800428 expandedIcon.setStaticDrawableColor(color);
Selim Cinekda42d652015-12-04 15:51:16 -0800429 }
430
Selim Cinek5cf1d052017-06-01 17:36:46 -0700431 public void setAboveShelfChangedListener(AboveShelfChangedListener aboveShelfChangedListener) {
432 mAboveShelfChangedListener = aboveShelfChangedListener;
433 }
434
Lucas Dupincecc7c22017-09-12 16:02:45 -0700435 /**
436 * Sets a supplier that can determine whether the keyguard is secure or not.
437 * @param secureStateProvider A function that returns true if keyguard is secure.
438 */
439 public void setSecureStateProvider(BooleanSupplier secureStateProvider) {
440 mSecureStateProvider = secureStateProvider;
441 }
442
Selim Cinek4705f292017-04-24 22:18:48 -0700443 @Override
444 public boolean isDimmable() {
445 if (!getShowingLayout().isDimmable()) {
446 return false;
447 }
448 return super.isDimmable();
449 }
450
Selim Cinekda42d652015-12-04 15:51:16 -0800451 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800452 for (NotificationContentView l : mLayouts) {
453 updateLimitsForView(l);
454 }
Selim Cineka1744872016-03-11 15:36:06 -0800455 }
456
457 private void updateLimitsForView(NotificationContentView layout) {
458 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800459 != com.android.internal.R.id.status_bar_latest_event_content;
460 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800461 boolean beforeP = mEntry.targetSdk < Build.VERSION_CODES.P;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800462 int minHeight;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800463 if (customView && beforeP && !mIsSummaryWithChildren) {
464 minHeight = beforeN ? mNotificationMinHeightLegacy : mNotificationMinHeightBeforeP;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800465 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
466 minHeight = mNotificationMinHeightLarge;
467 } else {
468 minHeight = mNotificationMinHeight;
469 }
Selim Cineka1744872016-03-11 15:36:06 -0800470 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
471 layout.getHeadsUpChild().getId()
472 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800473 int headsUpheight;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800474 if (headsUpCustom && beforeP) {
475 headsUpheight = beforeN ? mMaxHeadsUpHeightLegacy : mMaxHeadsUpHeightBeforeP;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800476 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
477 headsUpheight = mMaxHeadsUpHeightIncreased;
478 } else {
479 headsUpheight = mMaxHeadsUpHeight;
480 }
Selim Cineke62255c2017-09-28 18:23:23 -0700481 NotificationViewWrapper headsUpWrapper = layout.getVisibleWrapper(
482 NotificationContentView.VISIBLE_TYPE_HEADSUP);
483 if (headsUpWrapper != null) {
484 headsUpheight = Math.max(headsUpheight, headsUpWrapper.getMinLayoutHeight());
485 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800486 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
487 mNotificationAmbientHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200488 }
489
490 public StatusBarNotification getStatusBarNotification() {
491 return mStatusBarNotification;
492 }
493
Selim Cinek281c2022016-10-13 19:14:43 -0700494 public NotificationData.Entry getEntry() {
495 return mEntry;
496 }
497
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700498 public boolean isHeadsUp() {
499 return mIsHeadsUp;
500 }
501
Selim Cinek1a521f32014-11-03 17:39:29 +0100502 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinek5cf1d052017-06-01 17:36:46 -0700503 boolean wasAboveShelf = isAboveShelf();
Selim Cinekc80fdb12015-04-13 15:09:08 -0700504 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100505 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700506 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700507 if (mIsSummaryWithChildren) {
508 // The overflow might change since we allow more lines as HUN.
509 mChildrenContainer.updateGroupOverflow();
510 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700511 if (intrinsicBefore != getIntrinsicHeight()) {
512 notifyHeightChanged(false /* needsAnimation */);
513 }
Selim Cinekd127d792016-11-01 19:11:41 -0700514 if (isHeadsUp) {
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100515 mMustStayOnScreen = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700516 setAboveShelf(true);
Selim Cinek5cf1d052017-06-01 17:36:46 -0700517 } else if (isAboveShelf() != wasAboveShelf) {
518 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
Selim Cinekd127d792016-11-01 19:11:41 -0700519 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100520 }
521
Selim Cinekb5605e52015-02-20 18:21:41 +0100522 public void setGroupManager(NotificationGroupManager groupManager) {
523 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700524 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100525 }
526
Adrian Roosb88b1a12015-12-09 18:51:05 -0800527 public void setRemoteInputController(RemoteInputController r) {
528 mPrivateLayout.setRemoteInputController(r);
529 }
530
Mady Mellor3fd273e2016-03-15 21:08:14 -0700531 public void setAppName(String appName) {
532 mAppName = appName;
Mady Mellor95d743c2017-01-10 12:05:27 -0800533 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800534 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700535 }
536 }
537
Selim Cinekb5605e52015-02-20 18:21:41 +0100538 public void addChildNotification(ExpandableNotificationRow row) {
539 addChildNotification(row, -1);
540 }
541
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100542 @Override
543 public void setHeadsUpIsVisible() {
544 super.setHeadsUpIsVisible();
545 mMustStayOnScreen = false;
546 }
547
Selim Cinekb5605e52015-02-20 18:21:41 +0100548 /**
549 * Add a child notification to this view.
550 *
551 * @param row the row to add
552 * @param childIndex the index to add it at, if -1 it will be added at the end
553 */
554 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
555 if (mChildrenContainer == null) {
556 mChildrenContainerStub.inflate();
557 }
558 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700559 onChildrenCountChanged();
560 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100561 }
562
563 public void removeChildNotification(ExpandableNotificationRow row) {
564 if (mChildrenContainer != null) {
565 mChildrenContainer.removeNotification(row);
566 }
Selim Cinek263398f2015-10-21 17:40:23 -0700567 onChildrenCountChanged();
568 row.setIsChildInGroup(false, null);
Selim Cinek2871bef2017-11-22 08:40:00 -0800569 row.setBottomRoundness(0.0f, false /* animate */);
Selim Cinek263398f2015-10-21 17:40:23 -0700570 }
571
Mady Mellor43c2cd12016-12-12 21:05:13 -0800572 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700573 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700574 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700575 }
576
Selim Cinek388df6d2015-10-22 13:25:11 -0700577 public ExpandableNotificationRow getNotificationParent() {
578 return mNotificationParent;
579 }
580
Selim Cinek263398f2015-10-21 17:40:23 -0700581 /**
582 * @param isChildInGroup Is this notification now in a group
583 * @param parent the new parent notification
584 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700585 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500586 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700587 mNotificationParent = childInGroup ? parent : null;
588 mPrivateLayout.setIsChildInGroup(childInGroup);
Selim Cinek5ba22542017-04-20 15:16:10 -0700589 mNotificationInflater.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400590 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700591 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700592 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700593 if (mNotificationParent != null) {
Selim Cinek9ce32852017-02-15 16:21:10 -0800594 setOverrideTintColor(NO_COLOR, 0.0f);
Mady Mellorb0a82462016-04-30 17:31:02 -0700595 mNotificationParent.updateBackgroundForGroupState();
596 }
Selim Cinekdb167372016-11-17 15:41:17 -0800597 updateIconVisibilities();
Selim Cinek2871bef2017-11-22 08:40:00 -0800598 updateBackgroundClipping();
Selim Cinek34d93b02015-10-22 12:30:38 -0700599 }
600
601 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800602 public boolean onTouchEvent(MotionEvent event) {
603 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
604 || !isChildInGroup() || isGroupExpanded()) {
605 return super.onTouchEvent(event);
606 } else {
607 return false;
608 }
609 }
610
611 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800612 protected boolean handleSlideBack() {
Mady Mellor95d743c2017-01-10 12:05:27 -0800613 if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800614 animateTranslateNotification(0 /* targetLeft */);
615 return true;
616 }
617 return false;
618 }
619
620 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700621 protected boolean shouldHideBackground() {
622 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700623 }
624
625 @Override
626 public boolean isSummaryWithChildren() {
627 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100628 }
629
630 @Override
631 public boolean areChildrenExpanded() {
632 return mChildrenExpanded;
633 }
634
635 public List<ExpandableNotificationRow> getNotificationChildren() {
636 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
637 }
638
Selim Cinekeef84282015-10-30 16:28:00 -0700639 public int getNumberOfNotificationChildren() {
640 if (mChildrenContainer == null) {
641 return 0;
642 }
643 return mChildrenContainer.getNotificationChildren().size();
644 }
645
Selim Cinekb5605e52015-02-20 18:21:41 +0100646 /**
647 * Apply the order given in the list to the children.
648 *
649 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800650 * @param visualStabilityManager
651 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100652 * @return whether the list order has changed
653 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800654 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
655 VisualStabilityManager visualStabilityManager,
656 VisualStabilityManager.Callback callback) {
657 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
658 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100659 }
660
661 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700662 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800663 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100664 mChildrenContainer.getState(resultState, parentState);
665 }
666 }
667
668 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700669 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100670 mChildrenContainer.applyState(state);
671 }
672 }
673
674 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700675 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100676 mChildrenContainer.prepareExpansionChanged(state);
677 }
678 }
679
Selim Cinek0cfbef42016-11-09 19:06:36 -0800680 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700681 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800682 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100683 }
684 }
685
686 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800687 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100688 return this;
689 } else {
690 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
691 return view == null ? this : view;
692 }
693 }
694
Selim Cinekab29aeb2015-02-20 18:18:32 +0100695 public NotificationGuts getGuts() {
696 return mGuts;
697 }
698
Selim Cinek684a4422015-04-15 16:18:39 -0700699 /**
700 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
701 * the notification will be rendered on top of the screen.
702 *
703 * @param pinned whether it is pinned
704 */
705 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700706 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek5cf1d052017-06-01 17:36:46 -0700707 boolean wasAboveShelf = isAboveShelf();
Selim Cinek684a4422015-04-15 16:18:39 -0700708 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700709 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700710 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700711 }
Selim Cinek31aada42015-12-18 17:51:15 -0800712 if (pinned) {
713 setIconAnimationRunning(true);
714 mExpandedWhenPinned = false;
715 } else if (mExpandedWhenPinned) {
716 setUserExpanded(true);
717 }
Selim Cinek98713a42015-09-21 15:47:20 +0200718 setChronometerRunning(mLastChronometerRunning);
Selim Cinek5cf1d052017-06-01 17:36:46 -0700719 if (isAboveShelf() != wasAboveShelf) {
720 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
721 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700722 }
723
Selim Cinek684a4422015-04-15 16:18:39 -0700724 public boolean isPinned() {
725 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700726 }
727
Selim Cinekd127d792016-11-01 19:11:41 -0700728 @Override
729 public int getPinnedHeadsUpHeight() {
730 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
731 }
732
Selim Cinek31aada42015-12-18 17:51:15 -0800733 /**
734 * @param atLeastMinHeight should the value returned be at least the minimum height.
735 * Used to avoid cyclic calls
736 * @return the height of the heads up notification when pinned
737 */
Selim Cinekd127d792016-11-01 19:11:41 -0700738 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800739 if (mIsSummaryWithChildren) {
740 return mChildrenContainer.getIntrinsicHeight();
741 }
Selim Cinek31aada42015-12-18 17:51:15 -0800742 if(mExpandedWhenPinned) {
743 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
744 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700745 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800746 } else {
747 return mHeadsUpHeight;
748 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700749 }
750
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700751 /**
752 * Mark whether this notification was just clicked, i.e. the user has just clicked this
753 * notification in this frame.
754 */
755 public void setJustClicked(boolean justClicked) {
756 mJustClicked = justClicked;
757 }
758
759 /**
760 * @return true if this notification has been clicked in this frame, false otherwise
761 */
762 public boolean wasJustClicked() {
763 return mJustClicked;
764 }
765
Selim Cinek98713a42015-09-21 15:47:20 +0200766 public void setChronometerRunning(boolean running) {
767 mLastChronometerRunning = running;
768 setChronometerRunning(running, mPrivateLayout);
769 setChronometerRunning(running, mPublicLayout);
770 if (mChildrenContainer != null) {
771 List<ExpandableNotificationRow> notificationChildren =
772 mChildrenContainer.getNotificationChildren();
773 for (int i = 0; i < notificationChildren.size(); i++) {
774 ExpandableNotificationRow child = notificationChildren.get(i);
775 child.setChronometerRunning(running);
776 }
777 }
778 }
779
780 private void setChronometerRunning(boolean running, NotificationContentView layout) {
781 if (layout != null) {
782 running = running || isPinned();
783 View contractedChild = layout.getContractedChild();
784 View expandedChild = layout.getExpandedChild();
785 View headsUpChild = layout.getHeadsUpChild();
786 setChronometerRunningForChild(running, contractedChild);
787 setChronometerRunningForChild(running, expandedChild);
788 setChronometerRunningForChild(running, headsUpChild);
789 }
790 }
791
792 private void setChronometerRunningForChild(boolean running, View child) {
793 if (child != null) {
794 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
795 if (chronometer instanceof Chronometer) {
796 ((Chronometer) chronometer).setStarted(running);
797 }
798 }
799 }
800
Selim Cinekea4bef72015-12-02 15:51:10 -0800801 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700802 if (mIsSummaryWithChildren) {
803 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700804 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800805 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700806 }
807
Selim Cinek414ad332017-02-24 19:06:12 -0800808 /**
809 * @return the currently visible notification header. This can be different from
810 * {@link #getNotificationHeader()} in case it is a low-priority group.
811 */
812 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinek0b9cf462017-12-07 16:31:03 -0800813 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek414ad332017-02-24 19:06:12 -0800814 return mChildrenContainer.getVisibleHeader();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800815 }
816 return getShowingLayout().getVisibleNotificationHeader();
817 }
818
Selim Cinekb26afa32017-06-29 10:28:17 +0200819
820 /**
821 * @return the contracted notification header. This can be different from
822 * {@link #getNotificationHeader()} and also {@link #getVisibleNotificationHeader()} and only
823 * returns the contracted version.
824 */
825 public NotificationHeaderView getContractedNotificationHeader() {
826 if (mIsSummaryWithChildren) {
827 return mChildrenContainer.getHeaderView();
828 }
829 return mPrivateLayout.getContractedNotificationHeader();
830 }
831
Selim Cinek570981d2015-12-01 11:37:01 -0800832 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
833 mOnExpandClickListener = onExpandClickListener;
834 }
835
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000836 public void setLongPressListener(LongPressListener longPressListener) {
837 mLongPressListener = longPressListener;
838 }
839
Selim Cinekddf1b392016-05-27 16:33:10 -0700840 @Override
841 public void setOnClickListener(@Nullable OnClickListener l) {
842 super.setOnClickListener(l);
843 mOnClickListener = l;
844 updateClickAndFocus();
845 }
846
847 private void updateClickAndFocus() {
848 boolean normalChild = !isChildInGroup() || isGroupExpanded();
849 boolean clickable = mOnClickListener != null && normalChild;
850 if (isFocusable() != normalChild) {
851 setFocusable(normalChild);
852 }
853 if (isClickable() != clickable) {
854 setClickable(clickable);
855 }
856 }
857
Selim Cinek31aada42015-12-18 17:51:15 -0800858 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
859 mHeadsUpManager = headsUpManager;
860 }
861
Mady Mellor87d79452017-01-10 11:52:52 -0800862 public void setGutsView(MenuItem item) {
Mady Mellor95d743c2017-01-10 12:05:27 -0800863 if (mGuts != null && item.getGutsView() instanceof GutsContent) {
864 ((GutsContent) item.getGutsView()).setGutsParent(mGuts);
865 mGuts.setGutsContent((GutsContent) item.getGutsView());
Mady Mellor87d79452017-01-10 11:52:52 -0800866 }
867 }
868
Mady Mellor95d743c2017-01-10 12:05:27 -0800869 @Override
870 protected void onAttachedToWindow() {
871 super.onAttachedToWindow();
872 Dependency.get(PluginManager.class).addPluginListener(this,
873 NotificationMenuRowPlugin.class, false /* Allow multiple */);
874 }
875
876 @Override
877 protected void onDetachedFromWindow() {
878 super.onDetachedFromWindow();
879 Dependency.get(PluginManager.class).removePluginListener(this);
880 }
881
882 @Override
883 public void onPluginConnected(NotificationMenuRowPlugin plugin, Context pluginContext) {
884 boolean existed = mMenuRow.getMenuView() != null;
885 if (existed) {
886 removeView(mMenuRow.getMenuView());
887 }
888 mMenuRow = plugin;
889 if (mMenuRow.useDefaultMenuItems()) {
Mady Mellor4c197602017-04-10 17:57:52 -0700890 ArrayList<MenuItem> items = new ArrayList<>();
891 items.add(NotificationMenuRow.createInfoItem(mContext));
892 items.add(NotificationMenuRow.createSnoozeItem(mContext));
893 mMenuRow.setMenuItems(items);
Mady Mellor95d743c2017-01-10 12:05:27 -0800894 }
895 if (existed) {
896 createMenu();
897 }
898 }
899
900 @Override
901 public void onPluginDisconnected(NotificationMenuRowPlugin plugin) {
902 boolean existed = mMenuRow.getMenuView() != null;
903 mMenuRow = new NotificationMenuRow(mContext); // Back to default
904 if (existed) {
905 createMenu();
906 }
907 }
908
909 public NotificationMenuRowPlugin createMenu() {
910 if (mMenuRow.getMenuView() == null) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700911 mMenuRow.createMenu(this, mStatusBarNotification);
Mady Mellor95d743c2017-01-10 12:05:27 -0800912 mMenuRow.setAppName(mAppName);
913 FrameLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
914 LayoutParams.MATCH_PARENT);
915 addView(mMenuRow.getMenuView(), MENU_VIEW_INDEX, lp);
916 }
917 return mMenuRow;
918 }
919
Mady Mellor95d743c2017-01-10 12:05:27 -0800920 public NotificationMenuRowPlugin getProvider() {
921 return mMenuRow;
922 }
923
Anthony Chen9fe1ee72017-04-07 13:53:37 -0700924 @Override
Selim Cinek1a48bab2017-02-17 19:38:40 -0800925 public void onDensityOrFontScaleChanged() {
Anthony Chen9fe1ee72017-04-07 13:53:37 -0700926 super.onDensityOrFontScaleChanged();
Selim Cinek01af3342016-02-09 19:25:31 -0800927 initDimens();
Anthony Chenad4d1582017-04-10 16:07:58 -0700928 initBackground();
Selim Cinek817abe72017-05-24 11:08:55 -0700929 // Let's update our childrencontainer. This is intentionally not guarded with
930 // mIsSummaryWithChildren since we might have had children but not anymore.
931 if (mChildrenContainer != null) {
932 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800933 }
934 if (mGuts != null) {
935 View oldGuts = mGuts;
936 int index = indexOfChild(oldGuts);
937 removeView(oldGuts);
938 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
939 R.layout.notification_guts, this, false);
940 mGuts.setVisibility(oldGuts.getVisibility());
941 addView(mGuts, index);
942 }
Mady Mellor95d743c2017-01-10 12:05:27 -0800943 View oldMenu = mMenuRow.getMenuView();
944 if (oldMenu != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800945 int menuIndex = indexOfChild(oldMenu);
946 removeView(oldMenu);
Mady Mellor4ab28202017-06-06 11:42:50 -0700947 mMenuRow.createMenu(ExpandableNotificationRow.this, mStatusBarNotification);
Mady Mellor761cde12017-01-10 11:36:39 -0800948 mMenuRow.setAppName(mAppName);
Mady Mellor95d743c2017-01-10 12:05:27 -0800949 addView(mMenuRow.getMenuView(), menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -0800950 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800951 for (NotificationContentView l : mLayouts) {
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800952 l.initView();
Adrian Rooseb434ff2017-01-11 11:18:48 -0800953 l.reInflateViews();
954 }
Selim Cinek1a48bab2017-02-17 19:38:40 -0800955 mNotificationInflater.onDensityOrFontScaleChanged();
956 onNotificationUpdated();
Selim Cinek01af3342016-02-09 19:25:31 -0800957 }
958
Mady Mellor9d03a522017-04-04 18:45:30 -0700959 @Override
960 public void onConfigurationChanged(Configuration newConfig) {
961 if (mMenuRow.getMenuView() != null) {
962 mMenuRow.onConfigurationChanged();
963 }
964 }
965
Selim Cinekc3179332016-03-04 14:44:56 -0800966 public void setContentBackground(int customBackgroundColor, boolean animate,
967 NotificationContentView notificationContentView) {
968 if (getShowingLayout() == notificationContentView) {
969 setTintColor(customBackgroundColor, animate);
970 }
971 }
972
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700973 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800974 for (NotificationContentView l : mLayouts) {
975 l.closeRemoteInput();
976 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700977 }
978
Selim Cinekc897bd32016-03-18 17:32:31 -0700979 /**
980 * Set by how much the single line view should be indented.
981 */
982 public void setSingleLineWidthIndention(int indention) {
983 mPrivateLayout.setSingleLineWidthIndention(indention);
984 }
985
986 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700987 return mNotificationColor;
988 }
989
990 private void updateNotificationColor() {
991 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
Selim Cinekac5f0272017-05-02 16:05:41 -0700992 getStatusBarNotification().getNotification().color,
993 getBackgroundColorWithoutTint());
Adrian Roos6f6e1592017-05-02 16:22:53 -0700994 mNotificationColorAmbient = NotificationColorUtil.resolveAmbientColor(mContext,
995 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700996 }
997
998 public HybridNotificationView getSingleLineView() {
999 return mPrivateLayout.getSingleLineView();
1000 }
1001
Adrian Roos6f6e1592017-05-02 16:22:53 -07001002 public HybridNotificationView getAmbientSingleLineView() {
1003 return getShowingLayout().getAmbientSingleLineChild();
1004 }
1005
Selim Cinekf07d0622016-03-21 19:52:52 -07001006 public boolean isOnKeyguard() {
1007 return mOnKeyguard;
1008 }
1009
Selim Cinekc1e389d2016-04-07 11:02:57 -07001010 public void removeAllChildren() {
1011 List<ExpandableNotificationRow> notificationChildren
1012 = mChildrenContainer.getNotificationChildren();
1013 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
1014 for (int i = 0; i < clonedList.size(); i++) {
1015 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -07001016 if (row.keepInParent()) {
1017 continue;
1018 }
Selim Cinekc1e389d2016-04-07 11:02:57 -07001019 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -07001020 row.setIsChildInGroup(false, null);
1021 }
1022 onChildrenCountChanged();
1023 }
1024
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001025 public void setForceUnlocked(boolean forceUnlocked) {
1026 mForceUnlocked = forceUnlocked;
1027 if (mIsSummaryWithChildren) {
1028 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
1029 for (ExpandableNotificationRow child : notificationChildren) {
1030 child.setForceUnlocked(forceUnlocked);
1031 }
1032 }
1033 }
1034
Selim Cineke9bad242016-06-15 11:46:37 -07001035 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -07001036 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -07001037 mGroupParentWhenDismissed = mNotificationParent;
1038 mRefocusOnDismiss = fromAccessibility;
1039 mChildAfterViewWhenDismissed = null;
1040 if (isChildInGroup()) {
1041 List<ExpandableNotificationRow> notificationChildren =
1042 mNotificationParent.getNotificationChildren();
1043 int i = notificationChildren.indexOf(this);
1044 if (i != -1 && i < notificationChildren.size() - 1) {
1045 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
1046 }
1047 }
Selim Cinek3f19f602016-05-02 18:01:56 -07001048 }
1049
1050 public boolean isDismissed() {
1051 return mDismissed;
1052 }
1053
1054 public boolean keepInParent() {
1055 return mKeepInParent;
1056 }
1057
1058 public void setKeepInParent(boolean keepInParent) {
1059 mKeepInParent = keepInParent;
1060 }
1061
Selim Cinekd9b7dd42017-11-10 17:53:47 -08001062 @Override
Selim Cinek3f19f602016-05-02 18:01:56 -07001063 public boolean isRemoved() {
1064 return mRemoved;
1065 }
1066
Adrian Roosd009ab12016-05-20 17:58:53 -07001067 public void setRemoved() {
1068 mRemoved = true;
Selim Cinekef8c2252017-02-10 14:52:18 -08001069 mTranslationWhenRemoved = getTranslationY();
1070 mWasChildInGroupWhenRemoved = isChildInGroup();
1071 if (isChildInGroup()) {
1072 mTranslationWhenRemoved += getNotificationParent().getTranslationY();
1073 }
Adrian Roosd009ab12016-05-20 17:58:53 -07001074 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -07001075 }
1076
Selim Cinekef8c2252017-02-10 14:52:18 -08001077 public boolean wasChildInGroupWhenRemoved() {
1078 return mWasChildInGroupWhenRemoved;
1079 }
1080
1081 public float getTranslationWhenRemoved() {
1082 return mTranslationWhenRemoved;
1083 }
1084
Selim Cinekd1395642016-04-28 12:22:42 -07001085 public NotificationChildrenContainer getChildrenContainer() {
1086 return mChildrenContainer;
1087 }
1088
Selim Cinekcafa87f2016-10-26 17:00:17 -07001089 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07001090 boolean wasAboveShelf = isAboveShelf();
Selim Cinekcafa87f2016-10-26 17:00:17 -07001091 mHeadsupDisappearRunning = headsUpAnimatingAway;
1092 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
Selim Cinek5cf1d052017-06-01 17:36:46 -07001093 if (isAboveShelf() != wasAboveShelf) {
1094 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
1095 }
Selim Cinekcafa87f2016-10-26 17:00:17 -07001096 }
1097
1098 /**
1099 * @return if the view was just heads upped and is now animating away. During such a time the
1100 * layout needs to be kept consistent
1101 */
1102 public boolean isHeadsUpAnimatingAway() {
1103 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -07001104 }
1105
Selim Cineke9bad242016-06-15 11:46:37 -07001106 public View getChildAfterViewWhenDismissed() {
1107 return mChildAfterViewWhenDismissed;
1108 }
1109
1110 public View getGroupParentWhenDismissed() {
1111 return mGroupParentWhenDismissed;
1112 }
1113
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001114 public void performDismiss(boolean fromAccessibility) {
1115 if (mGroupManager.isOnlyChildInGroup(getStatusBarNotification())) {
1116 ExpandableNotificationRow groupSummary =
1117 mGroupManager.getLogicalGroupSummary(getStatusBarNotification());
1118 if (groupSummary.isClearable()) {
1119 groupSummary.performDismiss(fromAccessibility);
1120 }
1121 }
1122 setDismissed(true, fromAccessibility);
1123 if (isClearable()) {
1124 if (mOnDismissRunnable != null) {
1125 mOnDismissRunnable.run();
1126 }
Selim Cineke9079112016-12-14 14:41:01 -08001127 }
Selim Cinek9e624e72016-07-20 13:46:49 -07001128 }
1129
Selim Cineke9079112016-12-14 14:41:01 -08001130 public void setOnDismissRunnable(Runnable onDismissRunnable) {
1131 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -07001132 }
1133
Selim Cinek281c2022016-10-13 19:14:43 -07001134 public View getNotificationIcon() {
Selim Cinek414ad332017-02-24 19:06:12 -08001135 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek281c2022016-10-13 19:14:43 -07001136 if (notificationHeader != null) {
1137 return notificationHeader.getIcon();
1138 }
1139 return null;
1140 }
1141
1142 /**
1143 * @return whether the notification is currently showing a view with an icon.
1144 */
1145 public boolean isShowingIcon() {
Mady Mellor434180c2017-02-13 11:29:42 -08001146 if (areGutsExposed()) {
1147 return false;
1148 }
Selim Cinek2ffa02f2017-03-06 15:56:37 -08001149 return getVisibleNotificationHeader() != null;
Selim Cinek281c2022016-10-13 19:14:43 -07001150 }
1151
Selim Cinek0242fbb2016-10-19 13:38:32 -07001152 /**
1153 * Set how much this notification is transformed into an icon.
1154 *
Selim Cinek2b549f42016-11-22 16:38:51 -08001155 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
1156 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -08001157 * @param isLastChild is this the last child in the list. If true, then the transformation is
1158 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -07001159 */
Selim Cinek2b549f42016-11-22 16:38:51 -08001160 public void setContentTransformationAmount(float contentTransformationAmount,
1161 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -08001162 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001163 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001164 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001165 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001166 if (changeTransformation) {
1167 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -08001168 }
1169 }
1170
1171 /**
1172 * Set the icons to be visible of this notification.
1173 */
1174 public void setIconsVisible(boolean iconsVisible) {
1175 if (iconsVisible != mIconsVisible) {
1176 mIconsVisible = iconsVisible;
1177 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -07001178 }
1179 }
1180
Selim Cinekdb167372016-11-17 15:41:17 -08001181 @Override
1182 protected void onBelowSpeedBumpChanged() {
1183 updateIconVisibilities();
1184 }
1185
Selim Cinek875a3a12016-11-18 17:52:16 -08001186 private void updateContentTransformation() {
Selim Cinek2627d722018-01-19 12:16:49 -08001187 if (mExpandAnimationRunning) {
1188 return;
1189 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001190 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -08001191 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -08001192 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -08001193 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001194 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001195 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -08001196 translationY *= 0.4f;
1197 } else {
1198 contentAlpha = 1.0f;
1199 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001200 for (NotificationContentView l : mLayouts) {
1201 l.setAlpha(contentAlpha);
1202 l.setTranslationY(translationY);
1203 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001204 if (mChildrenContainer != null) {
1205 mChildrenContainer.setAlpha(contentAlpha);
1206 mChildrenContainer.setTranslationY(translationY);
1207 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -07001208 }
1209 }
1210
1211 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -08001212 boolean visible = isChildInGroup()
1213 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
1214 || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -08001215 for (NotificationContentView l : mLayouts) {
1216 l.setIconsVisible(visible);
1217 }
Selim Cinekdb167372016-11-17 15:41:17 -08001218 if (mChildrenContainer != null) {
1219 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001220 }
1221 }
1222
Selim Cinek875a3a12016-11-18 17:52:16 -08001223 /**
1224 * Get the relative top padding of a view relative to this view. This recursively walks up the
1225 * hierarchy and does the corresponding measuring.
1226 *
1227 * @param view the view to the the padding for. The requested view has to be a child of this
1228 * notification.
1229 * @return the toppadding
1230 */
1231 public int getRelativeTopPadding(View view) {
1232 int topPadding = 0;
1233 while (view.getParent() instanceof ViewGroup) {
1234 topPadding += view.getTop();
1235 view = (View) view.getParent();
1236 if (view instanceof ExpandableNotificationRow) {
1237 return topPadding;
1238 }
1239 }
1240 return topPadding;
1241 }
1242
Selim Cineka1d97902016-12-14 16:31:40 -08001243 public float getContentTranslation() {
1244 return mPrivateLayout.getTranslationY();
1245 }
1246
Selim Cinek6743c0b2017-01-18 18:24:01 -08001247 public void setIsLowPriority(boolean isLowPriority) {
1248 mIsLowPriority = isLowPriority;
1249 mPrivateLayout.setIsLowPriority(isLowPriority);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001250 mNotificationInflater.setIsLowPriority(mIsLowPriority);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001251 if (mChildrenContainer != null) {
1252 mChildrenContainer.setIsLowPriority(isLowPriority);
1253 }
1254 }
1255
Selim Cinek55a3e732017-05-25 18:30:10 -07001256
1257 public void setLowPriorityStateUpdated(boolean lowPriorityStateUpdated) {
1258 mLowPriorityStateUpdated = lowPriorityStateUpdated;
1259 }
1260
1261 public boolean hasLowPriorityStateUpdated() {
1262 return mLowPriorityStateUpdated;
1263 }
1264
Selim Cinek414ad332017-02-24 19:06:12 -08001265 public boolean isLowPriority() {
1266 return mIsLowPriority;
1267 }
1268
Selim Cinek7d1009b2017-01-25 15:28:28 -08001269 public void setUseIncreasedCollapsedHeight(boolean use) {
1270 mUseIncreasedCollapsedHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001271 mNotificationInflater.setUsesIncreasedHeight(use);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001272 }
1273
Selim Cinek87ed69b2017-02-09 15:59:43 -08001274 public void setUseIncreasedHeadsUpHeight(boolean use) {
1275 mUseIncreasedHeadsUpHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001276 mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
1277 }
1278
1279 public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
1280 mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001281 }
1282
Selim Cinek5ba22542017-04-20 15:16:10 -07001283 public void setInflationCallback(InflationCallback callback) {
1284 mNotificationInflater.setInflationCallback(callback);
Selim Cinekc478f902017-02-22 20:55:44 -08001285 }
1286
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001287 public void setNeedsRedaction(boolean needsRedaction) {
1288 mNotificationInflater.setRedactAmbient(needsRedaction);
1289 }
1290
Selim Cinek5ba22542017-04-20 15:16:10 -07001291 @VisibleForTesting
1292 public NotificationInflater getNotificationInflater() {
1293 return mNotificationInflater;
1294 }
1295
Adrian Roos6f6e1592017-05-02 16:22:53 -07001296 public int getNotificationColorAmbient() {
1297 return mNotificationColorAmbient;
1298 }
1299
Chris Wren78403d72014-07-28 10:23:24 +01001300 public interface ExpansionLogger {
Anthony Chen6bf88a02017-04-10 14:41:44 -07001301 void logNotificationExpansion(String key, boolean userAction, boolean expanded);
Chris Wren78403d72014-07-28 10:23:24 +01001302 }
Selim Cinek1685e632014-04-08 02:27:49 +02001303
Chris Wren51c75102013-07-16 20:49:17 -04001304 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1305 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001306 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001307 mNotificationInflater = new NotificationInflater(this);
Mady Mellor95d743c2017-01-10 12:05:27 -08001308 mMenuRow = new NotificationMenuRow(mContext);
Selim Cinek01af3342016-02-09 19:25:31 -08001309 initDimens();
1310 }
1311
1312 private void initDimens() {
Selim Cineke62255c2017-09-28 18:23:23 -07001313 mNotificationMinHeightLegacy = NotificationUtils.getFontScaledHeight(mContext,
1314 R.dimen.notification_min_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001315 mNotificationMinHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1316 R.dimen.notification_min_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001317 mNotificationMinHeight = NotificationUtils.getFontScaledHeight(mContext,
1318 R.dimen.notification_min_height);
1319 mNotificationMinHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001320 R.dimen.notification_min_height_increased);
Selim Cineke62255c2017-09-28 18:23:23 -07001321 mNotificationMaxHeight = NotificationUtils.getFontScaledHeight(mContext,
1322 R.dimen.notification_max_height);
1323 mNotificationAmbientHeight = NotificationUtils.getFontScaledHeight(mContext,
1324 R.dimen.notification_ambient_height);
1325 mMaxHeadsUpHeightLegacy = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek77019c72015-12-09 10:18:02 -08001326 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001327 mMaxHeadsUpHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1328 R.dimen.notification_max_heads_up_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001329 mMaxHeadsUpHeight = NotificationUtils.getFontScaledHeight(mContext,
1330 R.dimen.notification_max_heads_up_height);
1331 mMaxHeadsUpHeightIncreased = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001332 R.dimen.notification_max_heads_up_height_increased);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001333
Anthony Chen7acbb772017-04-07 16:45:25 -07001334 Resources res = getResources();
1335 mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
1336 R.dimen.notification_divider_height_increased);
1337 mIconTransformContentShiftNoIcon = res.getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001338 R.dimen.notification_icon_transform_content_shift);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001339 mEnableNonGroupedNotificationExpand =
1340 res.getBoolean(R.bool.config_enableNonGroupedNotificationExpand);
1341 mShowGroupBackgroundWhenExpanded =
1342 res.getBoolean(R.bool.config_showGroupNotificationBgWhenExpanded);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001343 }
1344
1345 /**
Christoph Studera7fe6312014-06-27 19:32:44 +02001346 * Resets this view so it can be re-used for an updated notification.
1347 */
1348 public void reset() {
Jorim Jaggiae441282014-08-01 02:45:18 +02001349 mShowingPublicInitialized = false;
Selim Cinek31094df2014-08-14 19:28:15 +02001350 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001351 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001352 }
1353
Dan Sandler1d958f82018-01-09 21:10:26 -05001354 public void showBlockingHelper(boolean show) {
1355 mHelperButton.setVisibility(show ? View.VISIBLE : View.GONE);
1356 }
1357
Jorim Jaggi251957d2014-04-09 04:24:09 +02001358 @Override
1359 protected void onFinishInflate() {
1360 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001361 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1362 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001363 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1364
Dan Sandler1d958f82018-01-09 21:10:26 -05001365 final NotificationGutsManager gutsMan = Dependency.get(NotificationGutsManager.class);
1366 mHelperButton = findViewById(R.id.helper);
1367 mHelperButton.setOnClickListener(view -> {
1368 doLongClickCallback();
1369 });
1370
Adrian Rooseb434ff2017-01-11 11:18:48 -08001371 for (NotificationContentView l : mLayouts) {
1372 l.setExpandClickListener(mExpandClickListener);
1373 l.setContainingNotification(this);
1374 }
Selim Cinekab29aeb2015-02-20 18:18:32 +01001375 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1376 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001377 @Override
1378 public void onInflate(ViewStub stub, View inflated) {
1379 mGuts = (NotificationGuts) inflated;
1380 mGuts.setClipTopAmount(getClipTopAmount());
1381 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001382 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001383 }
1384 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001385 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1386 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1387
1388 @Override
1389 public void onInflate(ViewStub stub, View inflated) {
1390 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001391 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek414ad332017-02-24 19:06:12 -08001392 mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001393 mChildrenContainer.onNotificationUpdated();
Anthony Chen7acbb772017-04-07 16:45:25 -07001394
1395 if (mShouldTranslateContents) {
1396 mTranslateableViews.add(mChildrenContainer);
1397 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001398 }
1399 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001400
Anthony Chen7acbb772017-04-07 16:45:25 -07001401 if (mShouldTranslateContents) {
1402 // Add the views that we translate to reveal the menu
1403 mTranslateableViews = new ArrayList<>();
1404 for (int i = 0; i < getChildCount(); i++) {
1405 mTranslateableViews.add(getChildAt(i));
1406 }
1407 // Remove views that don't translate
1408 mTranslateableViews.remove(mChildrenContainerStub);
1409 mTranslateableViews.remove(mGutsStub);
Mady Mellor4b80b102016-01-22 08:03:58 -08001410 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001411 }
1412
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001413 private void doLongClickCallback() {
1414 doLongClickCallback(getWidth() / 2, getHeight() / 2);
1415 }
1416
1417 public void doLongClickCallback(int x, int y) {
1418 createMenu();
1419 MenuItem menuItem = getProvider().getLongpressMenuItem(mContext);
1420 if (mLongPressListener != null && menuItem != null) {
1421 mLongPressListener.onLongPress(this, x, y, menuItem);
1422 }
1423 }
1424
1425 @Override
1426 public boolean onKeyDown(int keyCode, KeyEvent event) {
1427 if (KeyEvent.isConfirmKey(keyCode)) {
1428 event.startTracking();
1429 return true;
1430 }
1431 return super.onKeyDown(keyCode, event);
1432 }
1433
1434 @Override
1435 public boolean onKeyUp(int keyCode, KeyEvent event) {
1436 if (KeyEvent.isConfirmKey(keyCode)) {
1437 if (!event.isCanceled()) {
1438 performClick();
1439 }
1440 return true;
1441 }
1442 return super.onKeyUp(keyCode, event);
1443 }
1444
1445 @Override
1446 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
1447 if (KeyEvent.isConfirmKey(keyCode)) {
1448 doLongClickCallback();
1449 return true;
1450 }
1451 return false;
1452 }
1453
Mady Mellor4b80b102016-01-22 08:03:58 -08001454 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001455 if (mTranslateAnim != null) {
1456 mTranslateAnim.cancel();
1457 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001458
1459 if (!mShouldTranslateContents) {
1460 setTranslationX(0);
1461 } else if (mTranslateableViews != null) {
Mady Mellor4b80b102016-01-22 08:03:58 -08001462 for (int i = 0; i < mTranslateableViews.size(); i++) {
1463 mTranslateableViews.get(i).setTranslationX(0);
1464 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001465 invalidateOutline();
Mady Mellor4b80b102016-01-22 08:03:58 -08001466 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001467
Mady Mellor95d743c2017-01-10 12:05:27 -08001468 mMenuRow.resetMenu();
Mady Mellor4b80b102016-01-22 08:03:58 -08001469 }
1470
Selim Cinekde4de0e2018-01-24 16:21:07 -08001471 public CharSequence getActiveRemoteInputText() {
1472 return mPrivateLayout.getActiveRemoteInputText();
1473 }
1474
1475
Mady Mellor4b80b102016-01-22 08:03:58 -08001476 public void animateTranslateNotification(final float leftTarget) {
1477 if (mTranslateAnim != null) {
1478 mTranslateAnim.cancel();
1479 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001480 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001481 if (mTranslateAnim != null) {
1482 mTranslateAnim.start();
1483 }
1484 }
1485
1486 @Override
1487 public void setTranslation(float translationX) {
1488 if (areGutsExposed()) {
1489 // Don't translate if guts are showing.
1490 return;
1491 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001492 if (!mShouldTranslateContents) {
1493 setTranslationX(translationX);
1494 } else if (mTranslateableViews != null) {
1495 // Translate the group of views
1496 for (int i = 0; i < mTranslateableViews.size(); i++) {
1497 if (mTranslateableViews.get(i) != null) {
1498 mTranslateableViews.get(i).setTranslationX(translationX);
1499 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001500 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001501 invalidateOutline();
Mady Mellor34958fa2016-02-23 09:52:17 -08001502 }
Mady Mellor95d743c2017-01-10 12:05:27 -08001503 if (mMenuRow.getMenuView() != null) {
1504 mMenuRow.onTranslationUpdate(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001505 }
1506 }
1507
1508 @Override
1509 public float getTranslation() {
Anthony Chene04afcb2017-04-21 13:51:32 -07001510 if (!mShouldTranslateContents) {
Anthony Chen7acbb772017-04-07 16:45:25 -07001511 return getTranslationX();
1512 }
1513
Mady Mellor34958fa2016-02-23 09:52:17 -08001514 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1515 // All of the views in the list should have same translation, just use first one.
1516 return mTranslateableViews.get(0).getTranslationX();
1517 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001518
Mady Mellor34958fa2016-02-23 09:52:17 -08001519 return 0;
1520 }
1521
1522 public Animator getTranslateViewAnimator(final float leftTarget,
1523 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001524 if (mTranslateAnim != null) {
1525 mTranslateAnim.cancel();
1526 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001527 if (areGutsExposed()) {
1528 // No translation if guts are exposed.
1529 return null;
1530 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001531 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1532 leftTarget);
1533 if (listener != null) {
1534 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001535 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001536 translateAnim.addListener(new AnimatorListenerAdapter() {
1537 boolean cancelled = false;
1538
1539 @Override
1540 public void onAnimationCancel(Animator anim) {
1541 cancelled = true;
1542 }
1543
1544 @Override
1545 public void onAnimationEnd(Animator anim) {
Mady Mellor95d743c2017-01-10 12:05:27 -08001546 if (!cancelled && leftTarget == 0) {
1547 mMenuRow.resetMenu();
Mady Mellorb0a82462016-04-30 17:31:02 -07001548 mTranslateAnim = null;
1549 }
1550 }
1551 });
1552 mTranslateAnim = translateAnim;
1553 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001554 }
1555
Selim Cinekab29aeb2015-02-20 18:18:32 +01001556 public void inflateGuts() {
1557 if (mGuts == null) {
1558 mGutsStub.inflate();
1559 }
1560 }
1561
Selim Cinekda42d652015-12-04 15:51:16 -08001562 private void updateChildrenVisibility() {
Selim Cinek7fa385a2018-01-24 08:35:28 -08001563 boolean hideContentWhileLaunching = mExpandAnimationRunning && mGuts != null
1564 && mGuts.isExposed();
1565 mPrivateLayout.setVisibility(!shouldShowPublic() && !mIsSummaryWithChildren
1566 && !hideContentWhileLaunching ? VISIBLE : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001567 if (mChildrenContainer != null) {
Selim Cinek7fa385a2018-01-24 08:35:28 -08001568 mChildrenContainer.setVisibility(!shouldShowPublic() && mIsSummaryWithChildren
1569 && !hideContentWhileLaunching ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001570 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001571 }
Selim Cinekda42d652015-12-04 15:51:16 -08001572 // The limits might have changed if the view suddenly became a group or vice versa
1573 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001574 }
1575
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001576 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001577 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1578 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001579 // Add a record for the entire layout since its content is somehow small.
1580 // The event comes from a leaf view that is interacted with.
1581 AccessibilityEvent record = AccessibilityEvent.obtain();
1582 onInitializeAccessibilityEvent(record);
1583 dispatchPopulateAccessibilityEvent(record);
1584 event.appendRecord(record);
1585 return true;
1586 }
1587 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001588 }
Chris Wren51c75102013-07-16 20:49:17 -04001589
John Spurlocke15452b2014-08-21 09:44:39 -04001590 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001591 public void setDark(boolean dark, boolean fade, long delay) {
1592 super.setDark(dark, fade, delay);
Lucas Dupincecc7c22017-09-12 16:02:45 -07001593 mDark = dark;
Adrian Roos28f90c72017-05-08 17:24:26 -07001594 if (!mIsHeadsUp) {
1595 // Only fade the showing view of the pulsing notification.
1596 fade = false;
1597 }
John Spurlocke15452b2014-08-21 09:44:39 -04001598 final NotificationContentView showing = getShowingLayout();
1599 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001600 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001601 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001602 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001603 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001604 }
Selim Cineka7c69632017-06-07 15:51:29 -07001605 updateShelfIconColor();
John Spurlocke15452b2014-08-21 09:44:39 -04001606 }
1607
Selim Cinek2627d722018-01-19 12:16:49 -08001608 public void applyExpandAnimationParams(ExpandAnimationParameters params) {
1609 if (params == null) {
1610 return;
1611 }
1612 setTranslationY(params.getTop());
1613 float zProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
1614 params.getProgress(0, 50));
1615 float translationZ = MathUtils.lerp(params.getStartTranslationZ(),
1616 mNotificationLaunchHeight,
1617 zProgress);
1618 setTranslationZ(translationZ);
1619 setActualHeight(params.getHeight());
1620 mBackgroundNormal.setExpandAnimationParams(params);
1621 }
1622
1623 public void setExpandAnimationRunning(boolean expandAnimationRunning) {
1624 if (expandAnimationRunning) {
1625 View contentView;
1626 if (mIsSummaryWithChildren) {
1627 contentView = mChildrenContainer;
1628 } else {
1629 contentView = getShowingLayout();
1630 }
Selim Cinek7fa385a2018-01-24 08:35:28 -08001631 if (mGuts != null && mGuts.isExposed()) {
1632 contentView = mGuts;
1633 }
Selim Cinek2627d722018-01-19 12:16:49 -08001634 contentView.animate()
1635 .alpha(0f)
1636 .setDuration(ActivityLaunchAnimator.ANIMATION_DURATION_FADE_CONTENT)
1637 .setInterpolator(Interpolators.ALPHA_OUT);
1638 setAboveShelf(true);
1639 mExpandAnimationRunning = true;
1640 mNotificationViewState.cancelAnimations(this);
1641 mNotificationLaunchHeight = AmbientState.getNotificationLaunchHeight(getContext());
1642 } else {
1643 mExpandAnimationRunning = false;
1644 setAboveShelf(isAboveShelf());
Selim Cinek7fa385a2018-01-24 08:35:28 -08001645 if (mGuts != null) {
1646 mGuts.setAlpha(1.0f);
1647 }
Selim Cinek2627d722018-01-19 12:16:49 -08001648 }
Selim Cinek7fa385a2018-01-24 08:35:28 -08001649 updateChildrenVisibility();
Selim Cinek2627d722018-01-19 12:16:49 -08001650 updateClipping();
1651 mBackgroundNormal.setExpandAnimationRunning(expandAnimationRunning);
1652 }
1653
1654 @Override
1655 protected boolean shouldClipToActualHeight() {
1656 return super.shouldClipToActualHeight() && !mExpandAnimationRunning;
1657 }
1658
1659 @Override
1660 public boolean isExpandAnimationRunning() {
1661 return mExpandAnimationRunning;
1662 }
1663
Lucas Dupincecc7c22017-09-12 16:02:45 -07001664 /**
1665 * Tap sounds should not be played when we're unlocking.
1666 * Doing so would cause audio collision and the system would feel unpolished.
1667 */
1668 @Override
1669 public boolean isSoundEffectsEnabled() {
1670 final boolean mute = mDark && mSecureStateProvider != null &&
1671 !mSecureStateProvider.getAsBoolean();
1672 return !mute && super.isSoundEffectsEnabled();
1673 }
1674
Chris Wren51c75102013-07-16 20:49:17 -04001675 public boolean isExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08001676 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001677 return !mChildrenExpanded;
1678 }
Anthony Chen6bf88a02017-04-10 14:41:44 -07001679 return mEnableNonGroupedNotificationExpand && mExpandable;
Chris Wren51c75102013-07-16 20:49:17 -04001680 }
1681
1682 public void setExpandable(boolean expandable) {
1683 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001684 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001685 }
1686
Selim Cinek4ffd6362015-12-29 15:12:23 +01001687 @Override
1688 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001689 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1690 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001691 }
1692
Selim Cinek1685e632014-04-08 02:27:49 +02001693 /**
1694 * @return whether the user has changed the expansion state
1695 */
1696 public boolean hasUserChangedExpansion() {
1697 return mHasUserChangedExpansion;
1698 }
1699
Chris Wren51c75102013-07-16 20:49:17 -04001700 public boolean isUserExpanded() {
1701 return mUserExpanded;
1702 }
1703
Selim Cinek1685e632014-04-08 02:27:49 +02001704 /**
1705 * Set this notification to be expanded by the user
1706 *
1707 * @param userExpanded whether the user wants this notification to be expanded
1708 */
Chris Wren51c75102013-07-16 20:49:17 -04001709 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001710 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1711 }
1712
1713 /**
1714 * Set this notification to be expanded by the user
1715 *
1716 * @param userExpanded whether the user wants this notification to be expanded
1717 * @param allowChildExpansion whether a call to this method allows expanding children
1718 */
1719 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001720 mFalsingManager.setNotificationExpanded();
Selim Cinek0b9cf462017-12-07 16:31:03 -08001721 if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
Selim Cinek414ad332017-02-24 19:06:12 -08001722 && !mChildrenContainer.showingAsLowPriority()) {
Chris Wren698b1702016-05-23 11:16:32 -04001723 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001724 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -08001725 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001726 return;
1727 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001728 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001729 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001730 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001731 mUserExpanded = userExpanded;
Selim Cinek414ad332017-02-24 19:06:12 -08001732 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07001733 if (!wasExpanded && isExpanded()
1734 && getActualHeight() != getIntrinsicHeight()) {
1735 notifyHeightChanged(true /* needsAnimation */);
1736 }
Chris Wren51c75102013-07-16 20:49:17 -04001737 }
1738
Selim Cinekccd14fb2014-08-12 18:53:24 +02001739 public void resetUserExpansion() {
Selim Cinek414ad332017-02-24 19:06:12 -08001740 boolean changed = mUserExpanded;
Selim Cinekccd14fb2014-08-12 18:53:24 +02001741 mHasUserChangedExpansion = false;
1742 mUserExpanded = false;
Selim Cinek414ad332017-02-24 19:06:12 -08001743 if (changed && mIsSummaryWithChildren) {
1744 mChildrenContainer.onExpansionChanged();
1745 }
1746 updateShelfIconColor();
Selim Cinekccd14fb2014-08-12 18:53:24 +02001747 }
1748
Chris Wren51c75102013-07-16 20:49:17 -04001749 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001750 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001751 }
1752
1753 public void setUserLocked(boolean userLocked) {
1754 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001755 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07001756 // This is intentionally not guarded with mIsSummaryWithChildren since we might have had
1757 // children but not anymore.
1758 if (mChildrenContainer != null) {
Selim Cinek42357e02016-02-24 18:48:01 -08001759 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07001760 if (mIsSummaryWithChildren && (userLocked || !isGroupExpanded())) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001761 updateBackgroundForGroupState();
1762 }
Selim Cinek42357e02016-02-24 18:48:01 -08001763 }
Chris Wren51c75102013-07-16 20:49:17 -04001764 }
1765
Selim Cinek1685e632014-04-08 02:27:49 +02001766 /**
1767 * @return has the system set this notification to be expanded
1768 */
1769 public boolean isSystemExpanded() {
1770 return mIsSystemExpanded;
1771 }
1772
1773 /**
1774 * Set this notification to be expanded by the system.
1775 *
1776 * @param expand whether the system wants this notification to be expanded.
1777 */
1778 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001779 if (expand != mIsSystemExpanded) {
1780 final boolean wasExpanded = isExpanded();
1781 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001782 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek414ad332017-02-24 19:06:12 -08001783 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001784 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001785 mChildrenContainer.updateGroupOverflow();
1786 }
Selim Cinek31094df2014-08-14 19:28:15 +02001787 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001788 }
1789
1790 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001791 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001792 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001793 public void setOnKeyguard(boolean onKeyguard) {
1794 if (onKeyguard != mOnKeyguard) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07001795 boolean wasAboveShelf = isAboveShelf();
Selim Cinek31094df2014-08-14 19:28:15 +02001796 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001797 mOnKeyguard = onKeyguard;
Selim Cinek414ad332017-02-24 19:06:12 -08001798 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cinek31094df2014-08-14 19:28:15 +02001799 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001800 if (mIsSummaryWithChildren) {
1801 mChildrenContainer.updateGroupOverflow();
1802 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001803 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001804 }
Selim Cinek5cf1d052017-06-01 17:36:46 -07001805 if (isAboveShelf() != wasAboveShelf) {
1806 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
1807 }
Selim Cinek31094df2014-08-14 19:28:15 +02001808 }
Selim Cinek1685e632014-04-08 02:27:49 +02001809 }
1810
1811 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001812 * @return Can the underlying notification be cleared? This can be different from whether the
1813 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1814 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001815 */
1816 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001817 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1818 return false;
1819 }
1820 if (mIsSummaryWithChildren) {
1821 List<ExpandableNotificationRow> notificationChildren =
1822 mChildrenContainer.getNotificationChildren();
1823 for (int i = 0; i < notificationChildren.size(); i++) {
1824 ExpandableNotificationRow child = notificationChildren.get(i);
1825 if (!child.isClearable()) {
1826 return false;
1827 }
1828 }
1829 }
1830 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001831 }
1832
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001833 @Override
1834 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001835 if (isUserLocked()) {
1836 return getActualHeight();
1837 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001838 if (mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07001839 return mGuts.getIntrinsicHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001840 } else if ((isChildInGroup() && !isGroupExpanded())) {
1841 return mPrivateLayout.getMinHeight();
1842 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1843 return getMinHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07001844 } else if (mIsSummaryWithChildren && (!mOnKeyguard || mShowAmbient)) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001845 return mChildrenContainer.getIntrinsicHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07001846 } else if (isHeadsUpAllowed() && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07001847 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001848 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1849 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001850 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001851 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001852 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001853 }
Selim Cinek31aada42015-12-18 17:51:15 -08001854 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001855 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001856 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001857 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001858 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001859 }
Selim Cinek1685e632014-04-08 02:27:49 +02001860
Adrian Roos6f6e1592017-05-02 16:22:53 -07001861 private boolean isHeadsUpAllowed() {
1862 return !mOnKeyguard && !mShowAmbient;
1863 }
1864
Mady Mellor43c2cd12016-12-12 21:05:13 -08001865 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001866 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001867 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001868 }
1869
Selim Cinek263398f2015-10-21 17:40:23 -07001870 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05001871 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001872 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1873 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
Selim Cinek414ad332017-02-24 19:06:12 -08001874 mChildrenContainer.recreateNotificationHeader(mExpandClickListener
1875 );
Selim Cinek263398f2015-10-21 17:40:23 -07001876 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001877 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001878 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001879 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001880 updateChildrenVisibility();
Selim Cinek2871bef2017-11-22 08:40:00 -08001881 applyChildrenRoundness();
Selim Cinek263398f2015-10-21 17:40:23 -07001882 }
1883
Mady Mellorb0a82462016-04-30 17:31:02 -07001884 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001885 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001886 mChildrenContainer.updateChildrenHeaderAppearance();
1887 }
1888 }
1889
Selim Cinek1685e632014-04-08 02:27:49 +02001890 /**
1891 * Check whether the view state is currently expanded. This is given by the system in {@link
1892 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1893 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1894 * view can differ from this state, if layout params are modified from outside.
1895 *
1896 * @return whether the view state is currently expanded.
1897 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001898 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001899 return isExpanded(false /* allowOnKeyguard */);
1900 }
1901
1902 public boolean isExpanded(boolean allowOnKeyguard) {
1903 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001904 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1905 || isUserExpanded());
1906 }
1907
1908 private boolean isSystemChildExpanded() {
1909 return mIsSystemChildExpanded;
1910 }
1911
1912 public void setSystemChildExpanded(boolean expanded) {
1913 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001914 }
1915
Mady Mellor035badd2017-04-04 18:45:30 -07001916 public void setLayoutListener(LayoutListener listener) {
1917 mLayoutListener = listener;
1918 }
1919
1920 public void removeListener() {
1921 mLayoutListener = null;
1922 }
1923
Selim Cinek1685e632014-04-08 02:27:49 +02001924 @Override
1925 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1926 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001927 updateMaxHeights();
Mady Mellor95d743c2017-01-10 12:05:27 -08001928 if (mMenuRow.getMenuView() != null) {
1929 mMenuRow.onHeightUpdate();
Mady Mellora6edc872016-04-26 11:01:03 -07001930 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001931 updateContentShiftHeight();
Mady Mellor035badd2017-04-04 18:45:30 -07001932 if (mLayoutListener != null) {
1933 mLayoutListener.onLayout();
1934 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001935 }
1936
1937 /**
1938 * Updates the content shift height such that the header is completely hidden when coming from
1939 * the top.
1940 */
1941 private void updateContentShiftHeight() {
Selim Cinek414ad332017-02-24 19:06:12 -08001942 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek875a3a12016-11-18 17:52:16 -08001943 if (notificationHeader != null) {
1944 CachingIconView icon = notificationHeader.getIcon();
1945 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1946 } else {
1947 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1948 }
Selim Cinek1685e632014-04-08 02:27:49 +02001949 }
1950
Selim Cinek8d490d42015-04-10 00:05:50 -07001951 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001952 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001953 View expandedChild = mPrivateLayout.getExpandedChild();
1954 if (expandedChild == null) {
1955 expandedChild = mPrivateLayout.getContractedChild();
1956 }
1957 mMaxExpandHeight = expandedChild.getHeight();
1958 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001959 if (headsUpChild == null) {
1960 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001961 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001962 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001963 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001964 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001965 }
1966 }
1967
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001968 @Override
1969 public void notifyHeightChanged(boolean needsAnimation) {
1970 super.notifyHeightChanged(needsAnimation);
1971 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1972 }
1973
Selim Cinek3c76d502016-02-19 15:16:33 -08001974 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001975 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001976 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001977 }
1978
Mady Mellor43c2cd12016-12-12 21:05:13 -08001979 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001980 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001981 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001982 if (mIsSummaryWithChildren) {
1983 List<ExpandableNotificationRow> notificationChildren =
1984 mChildrenContainer.getNotificationChildren();
1985 for (int i = 0; i < notificationChildren.size(); i++) {
1986 ExpandableNotificationRow child = notificationChildren.get(i);
1987 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1988 }
1989 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001990 }
1991
Mady Mellor43c2cd12016-12-12 21:05:13 -08001992 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001993 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1994 long duration) {
1995 boolean oldShowingPublic = mShowingPublic;
1996 mShowingPublic = mSensitive && hideSensitive;
1997 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1998 return;
1999 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05002000
2001 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02002002 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002003
Jorim Jaggiae441282014-08-01 02:45:18 +02002004 if (!animated) {
2005 mPublicLayout.animate().cancel();
2006 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07002007 if (mChildrenContainer != null) {
2008 mChildrenContainer.animate().cancel();
2009 mChildrenContainer.setAlpha(1f);
2010 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002011 mPublicLayout.setAlpha(1f);
2012 mPrivateLayout.setAlpha(1f);
2013 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08002014 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02002015 } else {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002016 animateShowingPublic(delay, duration, mShowingPublic);
Jorim Jaggiae441282014-08-01 02:45:18 +02002017 }
Selim Cinekc3179332016-03-04 14:44:56 -08002018 NotificationContentView showingLayout = getShowingLayout();
2019 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002020 mPrivateLayout.updateExpandButtons(isExpandable());
Lucas Dupinb6ed63b2017-05-30 16:17:42 -07002021 updateShelfIconColor();
Adrian Roose5726a22016-12-19 14:26:51 -08002022 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02002023 mShowingPublicInitialized = true;
2024 }
2025
Selim Cinek0b9cf462017-12-07 16:31:03 -08002026 private void animateShowingPublic(long delay, long duration, boolean showingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002027 View[] privateViews = mIsSummaryWithChildren
2028 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08002029 : new View[] {mPrivateLayout};
2030 View[] publicViews = new View[] {mPublicLayout};
Selim Cinek0b9cf462017-12-07 16:31:03 -08002031 View[] hiddenChildren = showingPublic ? privateViews : publicViews;
2032 View[] shownChildren = showingPublic ? publicViews : privateViews;
Selim Cinekd84a5932015-12-15 11:45:36 -08002033 for (final View hiddenView : hiddenChildren) {
2034 hiddenView.setVisibility(View.VISIBLE);
2035 hiddenView.animate().cancel();
2036 hiddenView.animate()
2037 .alpha(0f)
2038 .setStartDelay(delay)
2039 .setDuration(duration)
2040 .withEndAction(new Runnable() {
2041 @Override
2042 public void run() {
2043 hiddenView.setVisibility(View.INVISIBLE);
2044 }
2045 });
2046 }
2047 for (View showView : shownChildren) {
2048 showView.setVisibility(View.VISIBLE);
2049 showView.setAlpha(0f);
2050 showView.animate().cancel();
2051 showView.animate()
2052 .alpha(1f)
2053 .setStartDelay(delay)
2054 .setDuration(duration);
2055 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04002056 }
2057
Mady Mellor43c2cd12016-12-12 21:05:13 -08002058 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08002059 public boolean mustStayOnScreen() {
Selim Cinek9b9d6e12017-11-30 12:29:47 +01002060 return mIsHeadsUp && mMustStayOnScreen;
Selim Cinek3776fe02016-02-04 13:32:43 -08002061 }
2062
Selim Cinek9e624e72016-07-20 13:46:49 -07002063 /**
2064 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
2065 * otherwise some state might not be updated. To request about the general clearability
2066 * see {@link #isClearable()}.
2067 */
2068 public boolean canViewBeDismissed() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002069 return isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
2070 }
2071
2072 private boolean shouldShowPublic() {
2073 return mSensitive && mHideSensitiveForIntrinsicHeight;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002074 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02002075
Ricky Waicd35def2016-05-03 11:07:07 +01002076 public void makeActionsVisibile() {
2077 setUserExpanded(true, true);
2078 if (isChildInGroup()) {
2079 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
2080 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07002081 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01002082 }
2083
Selim Cinekb5605e52015-02-20 18:21:41 +01002084 public void setChildrenExpanded(boolean expanded, boolean animate) {
2085 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07002086 if (mChildrenContainer != null) {
2087 mChildrenContainer.setChildrenExpanded(expanded);
2088 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07002089 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07002090 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01002091 }
2092
Selim Cinekb5605e52015-02-20 18:21:41 +01002093 public static void applyTint(View v, int color) {
2094 int alpha;
2095 if (color != 0) {
2096 alpha = COLORED_DIVIDER_ALPHA;
2097 } else {
2098 color = 0xff000000;
2099 alpha = DEFAULT_DIVIDER_ALPHA;
2100 }
2101 if (v.getBackground() instanceof ColorDrawable) {
2102 ColorDrawable background = (ColorDrawable) v.getBackground();
2103 background.mutate();
2104 background.setColor(color);
2105 background.setAlpha(alpha);
2106 }
2107 }
2108
Selim Cinek1685e632014-04-08 02:27:49 +02002109 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01002110 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04002111 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02002112
Mady Mellor34958fa2016-02-23 09:52:17 -08002113 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002114 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08002115 }
2116
Jorim Jaggibe565df2014-04-28 17:51:23 +02002117 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002118 public boolean isContentExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002119 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002120 return true;
2121 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002122 NotificationContentView showingLayout = getShowingLayout();
2123 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002124 }
2125
2126 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07002127 protected View getContentView() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002128 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cineka5703182016-05-11 21:23:16 -04002129 return mChildrenContainer;
2130 }
Selim Cinek560e64d2015-06-09 19:58:11 -07002131 return getShowingLayout();
2132 }
2133
2134 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07002135 protected void onAppearAnimationFinished(boolean wasAppearing) {
2136 super.onAppearAnimationFinished(wasAppearing);
2137 if (wasAppearing) {
2138 // During the animation the visible view might have changed, so let's make sure all
2139 // alphas are reset
2140 if (mChildrenContainer != null) {
2141 mChildrenContainer.setAlpha(1.0f);
2142 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
2143 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08002144 for (NotificationContentView l : mLayouts) {
2145 l.setAlpha(1.0f);
2146 l.setLayerType(LAYER_TYPE_NONE, null);
2147 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07002148 }
2149 }
2150
2151 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07002152 public int getExtraBottomPadding() {
2153 if (mIsSummaryWithChildren && isGroupExpanded()) {
2154 return mIncreasedPaddingBetweenElements;
2155 }
2156 return 0;
2157 }
2158
2159 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02002160 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinek4ca6c632017-02-23 18:03:37 -08002161 boolean changed = height != getActualHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +01002162 super.setActualHeight(height, notifyListeners);
Selim Cinek4ca6c632017-02-23 18:03:37 -08002163 if (changed && isRemoved()) {
2164 // TODO: remove this once we found the gfx bug for this.
2165 // This is a hack since a removed view sometimes would just stay blank. it occured
2166 // when sending yourself a message and then clicking on it.
2167 ViewGroup parent = (ViewGroup) getParent();
2168 if (parent != null) {
2169 parent.invalidate();
2170 }
2171 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002172 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08002173 mGuts.setActualHeight(height);
2174 return;
2175 }
Selim Cinekeef84282015-10-30 16:28:00 -07002176 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002177 for (NotificationContentView l : mLayouts) {
2178 l.setContentHeight(contentHeight);
2179 }
Selim Cinek42357e02016-02-24 18:48:01 -08002180 if (mIsSummaryWithChildren) {
2181 mChildrenContainer.setActualHeight(height);
2182 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002183 if (mGuts != null) {
2184 mGuts.setActualHeight(height);
2185 }
Mady Mellor54540972017-06-07 11:55:36 -07002186 if (mMenuRow.getMenuView() != null) {
2187 mMenuRow.onHeightUpdate();
2188 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002189 }
2190
2191 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01002192 public int getMaxContentHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002193 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002194 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002195 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002196 NotificationContentView showingLayout = getShowingLayout();
2197 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02002198 }
2199
2200 @Override
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002201 public int getMinHeight(boolean ignoreTemporaryStates) {
2202 if (!ignoreTemporaryStates && mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07002203 return mGuts.getIntrinsicHeight();
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002204 } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp
2205 && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08002206 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
Selim Cinek0b9cf462017-12-07 16:31:03 -08002207 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !shouldShowPublic()) {
Selim Cinekb55386d2015-12-16 17:26:49 -08002208 return mChildrenContainer.getMinHeight();
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002209 } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08002210 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08002211 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002212 NotificationContentView showingLayout = getShowingLayout();
2213 return showingLayout.getMinHeight();
2214 }
2215
2216 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07002217 public int getCollapsedHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002218 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek567e8452016-03-24 10:54:56 -07002219 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002220 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002221 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002222 }
2223
2224 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02002225 public void setClipTopAmount(int clipTopAmount) {
2226 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002227 for (NotificationContentView l : mLayouts) {
2228 l.setClipTopAmount(clipTopAmount);
2229 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002230 if (mGuts != null) {
2231 mGuts.setClipTopAmount(clipTopAmount);
2232 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002233 }
2234
Selim Cineka686b2c2016-10-26 13:58:27 -07002235 @Override
2236 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek2627d722018-01-19 12:16:49 -08002237 if (mExpandAnimationRunning) {
2238 return;
2239 }
Selim Cinek65d418e2016-11-29 15:42:34 -08002240 if (clipBottomAmount != mClipBottomAmount) {
2241 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002242 for (NotificationContentView l : mLayouts) {
2243 l.setClipBottomAmount(clipBottomAmount);
2244 }
Selim Cinek65d418e2016-11-29 15:42:34 -08002245 if (mGuts != null) {
2246 mGuts.setClipBottomAmount(clipBottomAmount);
2247 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002248 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08002249 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08002250 // We have to update this even if it hasn't changed, since the children locations can
2251 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08002252 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
2253 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002254 }
2255
Selim Cinek31094df2014-08-14 19:28:15 +02002256 public boolean isMaxExpandHeightInitialized() {
2257 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02002258 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002259
Selim Cinek42357e02016-02-24 18:48:01 -08002260 public NotificationContentView getShowingLayout() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002261 return shouldShowPublic() ? mPublicLayout : mPrivateLayout;
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002262 }
Chris Wren78403d72014-07-28 10:23:24 +01002263
Selim Cinek1a48bab2017-02-17 19:38:40 -08002264 public void setLegacy(boolean legacy) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08002265 for (NotificationContentView l : mLayouts) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08002266 l.setLegacy(legacy);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002267 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07002268 }
2269
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002270 @Override
2271 protected void updateBackgroundTint() {
2272 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07002273 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002274 if (mIsSummaryWithChildren) {
2275 List<ExpandableNotificationRow> notificationChildren =
2276 mChildrenContainer.getNotificationChildren();
2277 for (int i = 0; i < notificationChildren.size(); i++) {
2278 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07002279 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002280 }
2281 }
2282 }
2283
Mady Mellorb0a82462016-04-30 17:31:02 -07002284 /**
2285 * Called when a group has finished animating from collapsed or expanded state.
2286 */
2287 public void onFinishedExpansionChange() {
2288 mGroupExpansionChanging = false;
2289 updateBackgroundForGroupState();
2290 }
2291
2292 /**
2293 * Updates the parent and children backgrounds in a group based on the expansion state.
2294 */
2295 public void updateBackgroundForGroupState() {
2296 if (mIsSummaryWithChildren) {
2297 // Only when the group has finished expanding do we hide its background.
Anthony Chen6bf88a02017-04-10 14:41:44 -07002298 mShowNoBackground = !mShowGroupBackgroundWhenExpanded && isGroupExpanded()
2299 && !isGroupExpansionChanging() && !isUserLocked();
Mady Mellorb0a82462016-04-30 17:31:02 -07002300 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
2301 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
2302 for (int i = 0; i < children.size(); i++) {
2303 children.get(i).updateBackgroundForGroupState();
2304 }
2305 } else if (isChildInGroup()) {
2306 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
2307 // Only show a background if the group is expanded OR if it is expanding / collapsing
Anthony Chen6bf88a02017-04-10 14:41:44 -07002308 // and has a custom background color.
Mady Mellorb0a82462016-04-30 17:31:02 -07002309 final boolean showBackground = isGroupExpanded()
2310 || ((mNotificationParent.isGroupExpansionChanging()
Anthony Chen6bf88a02017-04-10 14:41:44 -07002311 || mNotificationParent.isUserLocked()) && childColor != 0);
Mady Mellorb0a82462016-04-30 17:31:02 -07002312 mShowNoBackground = !showBackground;
2313 } else {
2314 // Only children or parents ever need no background.
2315 mShowNoBackground = false;
2316 }
2317 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002318 updateBackground();
2319 }
2320
Adrian Roos4a579672016-05-24 16:54:37 -07002321 public int getPositionOfChild(ExpandableNotificationRow childRow) {
2322 if (mIsSummaryWithChildren) {
2323 return mChildrenContainer.getPositionInLinearLayout(childRow);
2324 }
2325 return 0;
2326 }
2327
Chris Wren78403d72014-07-28 10:23:24 +01002328 public void setExpansionLogger(ExpansionLogger logger, String key) {
2329 mLogger = logger;
2330 mLoggingKey = key;
2331 }
2332
Chris Wren6abeeb92016-05-26 14:44:38 -04002333 public void onExpandedByGesture(boolean userExpanded) {
2334 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
2335 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
2336 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
2337 }
2338 MetricsLogger.action(mContext, event, userExpanded);
2339 }
2340
Selim Cinek6183d122016-01-14 18:48:41 -08002341 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08002342 public float getIncreasedPaddingAmount() {
2343 if (mIsSummaryWithChildren) {
2344 if (isGroupExpanded()) {
2345 return 1.0f;
2346 } else if (isUserLocked()) {
Selim Cinek414ad332017-02-24 19:06:12 -08002347 return mChildrenContainer.getIncreasedPaddingAmount();
Selim Cinek42357e02016-02-24 18:48:01 -08002348 }
Selim Cinek99104832017-01-25 14:47:33 -08002349 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08002350 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08002351 }
2352 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08002353 }
2354
Selim Cineka7ed2c12017-01-23 20:47:24 -08002355 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08002356 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08002357 }
2358
Selim Cinek61633a82016-01-25 15:54:10 -08002359 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08002360 protected boolean disallowSingleClick(MotionEvent event) {
2361 float x = event.getX();
2362 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08002363 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002364 if (header != null && header.isInTouchRect(x - getTranslation(), y)) {
2365 return true;
2366 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002367 if ((!mIsSummaryWithChildren || shouldShowPublic())
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002368 && getShowingLayout().disallowSingleClick(x, y)) {
2369 return true;
Selim Cinek6183d122016-01-14 18:48:41 -08002370 }
2371 return super.disallowSingleClick(event);
2372 }
2373
Selim Cinek414ad332017-02-24 19:06:12 -08002374 private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04002375 boolean nowExpanded = isExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08002376 if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
Chris Wren698b1702016-05-23 11:16:32 -04002377 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
2378 }
Selim Cinek414ad332017-02-24 19:06:12 -08002379 if (nowExpanded != wasExpanded) {
2380 updateShelfIconColor();
2381 if (mLogger != null) {
2382 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded);
2383 }
2384 if (mIsSummaryWithChildren) {
2385 mChildrenContainer.onExpansionChanged();
2386 }
Chris Wren78403d72014-07-28 10:23:24 +01002387 }
2388 }
Selim Cinek570981d2015-12-01 11:37:01 -08002389
Selim Cineke9bad242016-06-15 11:46:37 -07002390 @Override
2391 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2392 super.onInitializeAccessibilityNodeInfoInternal(info);
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002393 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
Selim Cineke9bad242016-06-15 11:46:37 -07002394 if (canViewBeDismissed()) {
2395 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
2396 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002397 boolean expandable = shouldShowPublic();
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002398 boolean isExpanded = false;
2399 if (!expandable) {
2400 if (mIsSummaryWithChildren) {
2401 expandable = true;
2402 if (!mIsLowPriority || isExpanded()) {
2403 isExpanded = isGroupExpanded();
2404 }
2405 } else {
2406 expandable = mPrivateLayout.isContentExpandable();
2407 isExpanded = isExpanded();
2408 }
2409 }
2410 if (expandable) {
2411 if (isExpanded) {
2412 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
2413 } else {
2414 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
2415 }
2416 }
Selim Cineke9bad242016-06-15 11:46:37 -07002417 }
2418
2419 @Override
2420 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
2421 if (super.performAccessibilityActionInternal(action, arguments)) {
2422 return true;
2423 }
2424 switch (action) {
2425 case AccessibilityNodeInfo.ACTION_DISMISS:
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09002426 performDismiss(true /* fromAccessibility */);
Selim Cineke9bad242016-06-15 11:46:37 -07002427 return true;
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002428 case AccessibilityNodeInfo.ACTION_COLLAPSE:
2429 case AccessibilityNodeInfo.ACTION_EXPAND:
2430 mExpandClickListener.onClick(this);
2431 return true;
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002432 case AccessibilityNodeInfo.ACTION_LONG_CLICK:
2433 doLongClickCallback();
2434 return true;
Selim Cineke9bad242016-06-15 11:46:37 -07002435 }
2436 return false;
2437 }
2438
2439 public boolean shouldRefocusOnDismiss() {
2440 return mRefocusOnDismiss || isAccessibilityFocused();
2441 }
2442
Selim Cinek570981d2015-12-01 11:37:01 -08002443 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08002444 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08002445 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002446
2447 @Override
2448 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
Selim Cinek2627d722018-01-19 12:16:49 -08002449 mNotificationViewState = new NotificationViewState(stackScrollState);
2450 return mNotificationViewState;
Selim Cinekbbcebde2016-11-09 18:28:20 -08002451 }
2452
Selim Cinekd127d792016-11-01 19:11:41 -07002453 @Override
2454 public boolean isAboveShelf() {
Selim Cinekc8007c52017-02-28 16:09:56 -08002455 return !isOnKeyguard()
Selim Cinek2627d722018-01-19 12:16:49 -08002456 && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf)
2457 || mExpandAnimationRunning);
Selim Cinekd127d792016-11-01 19:11:41 -07002458 }
2459
Adrian Roos0aac04f2016-12-08 15:59:29 -08002460 public void setShowAmbient(boolean showAmbient) {
2461 if (showAmbient != mShowAmbient) {
2462 mShowAmbient = showAmbient;
Adrian Roos6f6e1592017-05-02 16:22:53 -07002463 if (mChildrenContainer != null) {
2464 mChildrenContainer.notifyShowAmbientChanged();
2465 }
Adrian Roos0aac04f2016-12-08 15:59:29 -08002466 notifyHeightChanged(false /* needsAnimation */);
2467 }
2468 }
2469
Selim Cinek0fe07392017-11-09 13:26:34 -08002470 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08002471 protected boolean childNeedsClipping(View child) {
2472 if (child instanceof NotificationContentView) {
2473 NotificationContentView contentView = (NotificationContentView) child;
2474 if (isClippingNeeded()) {
2475 return true;
Selim Cinek86bfcee2018-01-17 11:00:47 -08002476 } else if (!hasNoRounding()
2477 && contentView.shouldClipToRounding(getCurrentTopRoundness() != 0.0f,
2478 getCurrentBottomRoundness() != 0.0f)) {
Selim Cinek515b2032017-11-15 10:20:19 -08002479 return true;
2480 }
2481 } else if (child == mChildrenContainer) {
Selim Cinekb95fd182017-12-21 13:03:32 -08002482 if (isClippingNeeded() || !hasNoRounding()) {
Selim Cinek515b2032017-11-15 10:20:19 -08002483 return true;
2484 }
2485 } else if (child instanceof NotificationGuts) {
Selim Cinekb95fd182017-12-21 13:03:32 -08002486 return !hasNoRounding();
Selim Cinek515b2032017-11-15 10:20:19 -08002487 }
2488 return super.childNeedsClipping(child);
2489 }
2490
2491 @Override
Selim Cinek2871bef2017-11-22 08:40:00 -08002492 protected void applyRoundness() {
2493 super.applyRoundness();
2494 applyChildrenRoundness();
2495 }
2496
2497 private void applyChildrenRoundness() {
2498 if (mIsSummaryWithChildren) {
2499 mChildrenContainer.setCurrentBottomRoundness(getCurrentBottomRoundness());
2500 }
2501 }
2502
2503 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08002504 public Path getCustomClipPath(View child) {
2505 if (child instanceof NotificationGuts) {
Selim Cinek2871bef2017-11-22 08:40:00 -08002506 return getClipPath(true, /* ignoreTranslation */
2507 false /* clipRoundedToBottom */);
2508 }
2509 if (child instanceof NotificationChildrenContainer) {
2510 return getClipPath(false, /* ignoreTranslation */
2511 true /* clipRoundedToBottom */);
Selim Cinek515b2032017-11-15 10:20:19 -08002512 }
2513 return super.getCustomClipPath(child);
2514 }
2515
Selim Cinekb95fd182017-12-21 13:03:32 -08002516 private boolean hasNoRounding() {
2517 return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f;
Selim Cinek0fe07392017-11-09 13:26:34 -08002518 }
2519
Adrian Roos6f6e1592017-05-02 16:22:53 -07002520 public boolean isShowingAmbient() {
2521 return mShowAmbient;
2522 }
2523
Selim Cinekd127d792016-11-01 19:11:41 -07002524 public void setAboveShelf(boolean aboveShelf) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07002525 boolean wasAboveShelf = isAboveShelf();
Selim Cinekd127d792016-11-01 19:11:41 -07002526 mAboveShelf = aboveShelf;
Selim Cinek5cf1d052017-06-01 17:36:46 -07002527 if (isAboveShelf() != wasAboveShelf) {
2528 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
2529 }
Selim Cinekd127d792016-11-01 19:11:41 -07002530 }
2531
Selim Cinekd4776a52017-02-14 18:50:16 -08002532 public static class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08002533
2534 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07002535
Selim Cinekbbcebde2016-11-09 18:28:20 -08002536
2537 private NotificationViewState(StackScrollState stackScrollState) {
2538 mOverallState = stackScrollState;
2539 }
2540
2541 @Override
2542 public void applyToView(View view) {
Selim Cinekbbcebde2016-11-09 18:28:20 -08002543 if (view instanceof ExpandableNotificationRow) {
2544 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinek2627d722018-01-19 12:16:49 -08002545 if (row.isExpandAnimationRunning()) {
2546 return;
2547 }
2548 super.applyToView(view);
Selim Cinekbbcebde2016-11-09 18:28:20 -08002549 row.applyChildrenState(mOverallState);
2550 }
2551 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002552
2553 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08002554 protected void onYTranslationAnimationFinished(View view) {
2555 super.onYTranslationAnimationFinished(view);
Selim Cinekd4776a52017-02-14 18:50:16 -08002556 if (view instanceof ExpandableNotificationRow) {
2557 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
2558 if (row.isHeadsUpAnimatingAway()) {
2559 row.setHeadsUpAnimatingAway(false);
2560 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002561 }
2562 }
2563
2564 @Override
2565 public void animateTo(View child, AnimationProperties properties) {
Selim Cinek0cfbef42016-11-09 19:06:36 -08002566 if (child instanceof ExpandableNotificationRow) {
2567 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
Selim Cinek2627d722018-01-19 12:16:49 -08002568 if (row.isExpandAnimationRunning()) {
2569 return;
2570 }
2571 super.animateTo(child, properties);
Selim Cinek0cfbef42016-11-09 19:06:36 -08002572 row.startChildAnimation(mOverallState, properties);
2573 }
2574 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002575 }
Selim Cinek817abe72017-05-24 11:08:55 -07002576
2577 @VisibleForTesting
2578 protected void setChildrenContainer(NotificationChildrenContainer childrenContainer) {
2579 mChildrenContainer = childrenContainer;
2580 }
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002581
2582 /**
2583 * Equivalent to View.OnLongClickListener with coordinates
2584 */
2585 public interface LongPressListener {
2586 /**
2587 * Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
2588 * @return whether the longpress was handled
2589 */
2590 boolean onLongPress(View v, int x, int y, MenuItem item);
2591 }
Chris Wren51c75102013-07-16 20:49:17 -04002592}