blob: 29687228902f024acf08b07ed878e4e79b606c81 [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;
Rohan Shah63411fc2018-03-28 19:05:52 -070027import android.app.NotificationChannel;
Chris Wren51c75102013-07-16 20:49:17 -040028import android.content.Context;
Rohan Shah63411fc2018-03-28 19:05:52 -070029import android.content.pm.PackageInfo;
30import android.content.pm.PackageManager;
Mady Mellor9d03a522017-04-04 18:45:30 -070031import android.content.res.Configuration;
Julia Reynoldsb5867452018-02-28 16:31:35 -050032import android.content.res.Resources;
Selim Cinek515b2032017-11-15 10:20:19 -080033import android.graphics.Path;
Selim Cinekcab4a602014-09-03 14:47:57 +020034import android.graphics.drawable.AnimatedVectorDrawable;
35import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010036import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020037import android.graphics.drawable.Drawable;
Rohan Shah4ed1b2a2018-03-30 13:26:01 -070038import android.os.AsyncTask;
Selim Cinekda42d652015-12-04 15:51:16 -080039import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070040import android.os.Bundle;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020041import android.service.notification.StatusBarNotification;
Julia Reynoldsfc640012018-02-21 12:25:27 -050042import android.util.ArraySet;
Chris Wren51c75102013-07-16 20:49:17 -040043import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070044import android.util.FloatProperty;
Rohan Shah63411fc2018-03-28 19:05:52 -070045import android.util.Log;
Selim Cinek2627d722018-01-19 12:16:49 -080046import android.util.MathUtils;
Mady Mellorb0a82462016-04-30 17:31:02 -070047import android.util.Property;
Geoffrey Pitsch409db272017-08-28 14:51:52 +000048import android.view.KeyEvent;
Selim Cinek01af3342016-02-09 19:25:31 -080049import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080050import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080051import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050052import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080053import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020054import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020055import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070056import android.view.accessibility.AccessibilityNodeInfo;
Mady Mellorb3a6aed2018-05-11 13:24:07 -070057import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Selim Cinek98713a42015-09-21 15:47:20 +020058import android.widget.Chronometer;
Mady Mellor95d743c2017-01-10 12:05:27 -080059import android.widget.FrameLayout;
Selim Cinekcab4a602014-09-03 14:47:57 +020060import android.widget.ImageView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080061import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010062
Selim Cinek5ba22542017-04-20 15:16:10 -070063import com.android.internal.annotations.VisibleForTesting;
Chris Wren698b1702016-05-23 11:16:32 -040064import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010065import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070066import com.android.internal.util.NotificationColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080067import com.android.internal.widget.CachingIconView;
Mady Mellor95d743c2017-01-10 12:05:27 -080068import com.android.systemui.Dependency;
Selim Cinek0242fbb2016-10-19 13:38:32 -070069import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050070import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070071import com.android.systemui.classifier.FalsingManager;
Mady Mellor95d743c2017-01-10 12:05:27 -080072import com.android.systemui.plugins.PluginListener;
73import com.android.systemui.plugins.PluginManager;
74import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
75import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
76import com.android.systemui.statusbar.NotificationGuts.GutsContent;
Selim Cinek5cf1d052017-06-01 17:36:46 -070077import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
Selim Cinek2627d722018-01-19 12:16:49 -080078import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
Selim Cinekc897bd32016-03-18 17:32:31 -070079import com.android.systemui.statusbar.notification.HybridNotificationView;
Rohan Shahda5dcdd2018-04-27 17:21:50 -070080import com.android.systemui.statusbar.notification.NotificationCounters;
Selim Cinek1a48bab2017-02-17 19:38:40 -080081import com.android.systemui.statusbar.notification.NotificationInflater;
Selim Cinek6743c0b2017-01-18 18:24:01 -080082import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cineke62255c2017-09-28 18:23:23 -070083import com.android.systemui.statusbar.notification.NotificationViewWrapper;
Selim Cineka7d4f822016-12-06 14:34:47 -080084import com.android.systemui.statusbar.notification.VisualStabilityManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010085import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050086import com.android.systemui.statusbar.phone.StatusBar;
Selim Cinek31aada42015-12-18 17:51:15 -080087import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek2627d722018-01-19 12:16:49 -080088import com.android.systemui.statusbar.stack.AmbientState;
Selim Cinek0cfbef42016-11-09 19:06:36 -080089import com.android.systemui.statusbar.stack.AnimationProperties;
90import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010091import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
92import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010093
Mady Mellor4b80b102016-01-22 08:03:58 -080094import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010095import java.util.List;
Lucas Dupincecc7c22017-09-12 16:02:45 -070096import java.util.function.BooleanSupplier;
Selim Cinek8875de12018-03-22 10:14:32 -070097import java.util.function.Consumer;
Dan Sandlera5e0f412014-01-23 15:11:54 -050098
Rohan Shah63411fc2018-03-28 19:05:52 -070099/**
100 * View representing a notification item - this can be either the individual child notification or
101 * the group summary (which contains 1 or more child notifications).
102 */
Mady Mellor95d743c2017-01-10 12:05:27 -0800103public class ExpandableNotificationRow extends ActivatableNotificationView
104 implements PluginListener<NotificationMenuRowPlugin> {
Selim Cinekb5605e52015-02-20 18:21:41 +0100105
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700106 private static final boolean DEBUG = false;
Selim Cinekb5605e52015-02-20 18:21:41 +0100107 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
108 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Mady Mellor95d743c2017-01-10 12:05:27 -0800109 private static final int MENU_VIEW_INDEX = 0;
Rohan Shah63411fc2018-03-28 19:05:52 -0700110 private static final String TAG = "ExpandableNotifRow";
Mady Mellor95d743c2017-01-10 12:05:27 -0800111
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700112 /**
113 * Listener for when {@link ExpandableNotificationRow} is laid out.
114 */
Mady Mellor035badd2017-04-04 18:45:30 -0700115 public interface LayoutListener {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700116 void onLayout();
Mady Mellor035badd2017-04-04 18:45:30 -0700117 }
118
119 private LayoutListener mLayoutListener;
Lucas Dupincecc7c22017-09-12 16:02:45 -0700120 private boolean mDark;
Selim Cinek55a3e732017-05-25 18:30:10 -0700121 private boolean mLowPriorityStateUpdated;
Selim Cinek1a48bab2017-02-17 19:38:40 -0800122 private final NotificationInflater mNotificationInflater;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700123 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800124 private int mIconTransformContentShiftNoIcon;
Selim Cinek01af3342016-02-09 19:25:31 -0800125 private int mNotificationMinHeightLegacy;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800126 private int mNotificationMinHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800127 private int mMaxHeadsUpHeightLegacy;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800128 private int mMaxHeadsUpHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800129 private int mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800130 private int mMaxHeadsUpHeightIncreased;
Selim Cinek01af3342016-02-09 19:25:31 -0800131 private int mNotificationMinHeight;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800132 private int mNotificationMinHeightLarge;
Selim Cinek01af3342016-02-09 19:25:31 -0800133 private int mNotificationMaxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800134 private int mNotificationAmbientHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -0700135 private int mIncreasedPaddingBetweenElements;
Selim Cinek2627d722018-01-19 12:16:49 -0800136 private int mNotificationLaunchHeight;
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100137 private boolean mMustStayOnScreen;
Chris Wren51c75102013-07-16 20:49:17 -0400138
Selim Cinek1685e632014-04-08 02:27:49 +0200139 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -0400140 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +0200141 /** Has the user actively changed the expansion state of this row */
142 private boolean mHasUserChangedExpansion;
143 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -0400144 private boolean mUserExpanded;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700145 /** Whether the blocking helper is showing on this notification (even if dismissed) */
146 private boolean mIsBlockingHelperShowing;
Selim Cinek31aada42015-12-18 17:51:15 -0800147
148 /**
149 * Has this notification been expanded while it was pinned
150 */
151 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +0200152 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -0400153 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +0200154 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -0500155 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +0200156 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -0800157 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +0200158 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700159 private boolean mHideSensitiveForIntrinsicHeight;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800160 private float mHeaderVisibleAmount = 1.0f;
Chris Wren51c75102013-07-16 20:49:17 -0400161
Selim Cinek1685e632014-04-08 02:27:49 +0200162 /**
163 * Is this notification expanded by the system. The expansion state can be overridden by the
164 * user expansion.
165 */
166 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200167
168 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700169 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200170 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700171 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200172
Mady Mellorb0a82462016-04-30 17:31:02 -0700173 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800174 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200175 private NotificationContentView mPublicLayout;
176 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800177 private NotificationContentView[] mLayouts;
Selim Cinek4bb59342016-04-08 19:29:35 -0700178 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100179 private ExpansionLogger mLogger;
180 private String mLoggingKey;
Selim Cinek8d490d42015-04-10 00:05:50 -0700181 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800182 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200183 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700184 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100185 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200186 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100187 private ViewStub mChildrenContainerStub;
188 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100189 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700190 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100191 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor95d743c2017-01-10 12:05:27 -0800192 private NotificationMenuRowPlugin mMenuRow;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100193 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100194 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700195 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700196 private FalsingManager mFalsingManager;
Selim Cinek2627d722018-01-19 12:16:49 -0800197 private boolean mExpandAnimationRunning;
Selim Cinek5cf1d052017-06-01 17:36:46 -0700198 private AboveShelfChangedListener mAboveShelfChangedListener;
Selim Cinek31aada42015-12-18 17:51:15 -0800199 private HeadsUpManager mHeadsUpManager;
Selim Cinek8875de12018-03-22 10:14:32 -0700200 private Consumer<Boolean> mHeadsUpAnimatingAwayListener;
Selim Cinekc25989e2018-02-16 16:42:14 -0800201 private boolean mChildIsExpanding;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200202
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700203 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800204 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700205 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700206 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800207 private OnExpandClickListener mOnExpandClickListener;
Julia Reynoldsb5867452018-02-28 16:31:35 -0500208 private View.OnClickListener mOnAppOpsClickListener;
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000209
210 // Listener will be called when receiving a long click event.
211 // Use #setLongPressPosition to optionally assign positional data with the long press.
212 private LongPressListener mLongPressListener;
213
Mady Mellorb0a82462016-04-30 17:31:02 -0700214 private boolean mGroupExpansionChanging;
215
Anthony Chen6bf88a02017-04-10 14:41:44 -0700216 /**
Lucas Dupincecc7c22017-09-12 16:02:45 -0700217 * A supplier that returns true if keyguard is secure.
218 */
219 private BooleanSupplier mSecureStateProvider;
220
221 /**
Anthony Chen6bf88a02017-04-10 14:41:44 -0700222 * Whether or not a notification that is not part of a group of notifications can be manually
223 * expanded by the user.
224 */
225 private boolean mEnableNonGroupedNotificationExpand;
226
227 /**
228 * Whether or not to update the background of the header of the notification when its expanded.
229 * If {@code true}, the header background will disappear when expanded.
230 */
231 private boolean mShowGroupBackgroundWhenExpanded;
232
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800233 private OnClickListener mExpandClickListener = new OnClickListener() {
234 @Override
235 public void onClick(View v) {
Selim Cinek0b9cf462017-12-07 16:31:03 -0800236 if (!shouldShowPublic() && (!mIsLowPriority || isExpanded())
Selim Cinek414ad332017-02-24 19:06:12 -0800237 && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700238 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400239 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
240 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
241 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400242 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
243 nowExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -0800244 onExpansionChanged(true /* userAction */, wasExpanded);
Anthony Chen6bf88a02017-04-10 14:41:44 -0700245 } else if (mEnableNonGroupedNotificationExpand) {
Selim Cineke9bad242016-06-15 11:46:37 -0700246 if (v.isAccessibilityFocused()) {
247 mPrivateLayout.setFocusOnVisibilityChange();
248 }
Selim Cinek31aada42015-12-18 17:51:15 -0800249 boolean nowExpanded;
250 if (isPinned()) {
251 nowExpanded = !mExpandedWhenPinned;
252 mExpandedWhenPinned = nowExpanded;
253 } else {
254 nowExpanded = !isExpanded();
255 setUserExpanded(nowExpanded);
256 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800257 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800258 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400259 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
260 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800261 }
262 }
263 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700264 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700265 private boolean mDismissed;
266 private boolean mKeepInParent;
267 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700268 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
269 new FloatProperty<ExpandableNotificationRow>("translate") {
270 @Override
271 public void setValue(ExpandableNotificationRow object, float value) {
272 object.setTranslation(value);
273 }
274
275 @Override
276 public Float get(ExpandableNotificationRow object) {
277 return object.getTranslation();
278 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700279 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700280 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700281 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700282 private View mChildAfterViewWhenDismissed;
283 private View mGroupParentWhenDismissed;
284 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800285 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700286 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700287 private boolean mAboveShelf;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800288 private boolean mShowAmbient;
Selim Cinek875a3a12016-11-18 17:52:16 -0800289 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800290 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800291 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800292 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800293 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800294 private boolean mUseIncreasedHeadsUpHeight;
Selim Cinekef8c2252017-02-10 14:52:18 -0800295 private float mTranslationWhenRemoved;
296 private boolean mWasChildInGroupWhenRemoved;
Adrian Roos6f6e1592017-05-02 16:22:53 -0700297 private int mNotificationColorAmbient;
Selim Cinek2627d722018-01-19 12:16:49 -0800298 private NotificationViewState mNotificationViewState;
Mady Mellorb0a82462016-04-30 17:31:02 -0700299
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700300 private SystemNotificationAsyncTask mSystemNotificationAsyncTask =
301 new SystemNotificationAsyncTask();
302
303 /**
304 * Returns whether the given {@code statusBarNotification} is a system notification.
305 * <b>Note</b>, this should be run in the background thread if possible as it makes multiple IPC
306 * calls.
307 */
308 private static Boolean isSystemNotification(
309 Context context, StatusBarNotification statusBarNotification) {
310 PackageManager packageManager = StatusBar.getPackageManagerForUser(
311 context, statusBarNotification.getUser().getIdentifier());
312 Boolean isSystemNotification = null;
313
314 try {
315 PackageInfo packageInfo = packageManager.getPackageInfo(
316 statusBarNotification.getPackageName(), PackageManager.GET_SIGNATURES);
317
318 isSystemNotification =
319 com.android.settingslib.Utils.isSystemPackage(
320 context.getResources(), packageManager, packageInfo);
321 } catch (PackageManager.NameNotFoundException e) {
322 Log.e(TAG, "cacheIsSystemNotification: Could not find package info");
323 }
324 return isSystemNotification;
325 }
326
Mady Mellor43c2cd12016-12-12 21:05:13 -0800327 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700328 public boolean isGroupExpansionChanging() {
329 if (isChildInGroup()) {
330 return mNotificationParent.isGroupExpansionChanging();
331 }
332 return mGroupExpansionChanging;
333 }
334
335 public void setGroupExpansionChanging(boolean changing) {
336 mGroupExpansionChanging = changing;
337 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700338
Adrian Roos599be342016-06-13 14:54:39 -0700339 @Override
340 public void setActualHeightAnimating(boolean animating) {
341 if (mPrivateLayout != null) {
342 mPrivateLayout.setContentHeightAnimating(animating);
343 }
344 }
345
Selim Cinek8d490d42015-04-10 00:05:50 -0700346 public NotificationContentView getPrivateLayout() {
347 return mPrivateLayout;
348 }
349
350 public NotificationContentView getPublicLayout() {
351 return mPublicLayout;
352 }
353
Selim Cinekcab4a602014-09-03 14:47:57 +0200354 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800355 for (NotificationContentView l : mLayouts) {
356 setIconAnimationRunning(running, l);
357 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800358 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700359 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek414ad332017-02-24 19:06:12 -0800360 setIconAnimationRunningForChild(running, mChildrenContainer.getLowPriorityHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800361 List<ExpandableNotificationRow> notificationChildren =
362 mChildrenContainer.getNotificationChildren();
363 for (int i = 0; i < notificationChildren.size(); i++) {
364 ExpandableNotificationRow child = notificationChildren.get(i);
365 child.setIconAnimationRunning(running);
366 }
367 }
368 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200369 }
370
371 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
372 if (layout != null) {
373 View contractedChild = layout.getContractedChild();
374 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700375 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200376 setIconAnimationRunningForChild(running, contractedChild);
377 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700378 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200379 }
380 }
381
382 private void setIconAnimationRunningForChild(boolean running, View child) {
383 if (child != null) {
384 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
385 setIconRunning(icon, running);
386 ImageView rightIcon = (ImageView) child.findViewById(
387 com.android.internal.R.id.right_icon);
388 setIconRunning(rightIcon, running);
389 }
390 }
391
392 private void setIconRunning(ImageView imageView, boolean running) {
393 if (imageView != null) {
394 Drawable drawable = imageView.getDrawable();
395 if (drawable instanceof AnimationDrawable) {
396 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
397 if (running) {
398 animationDrawable.start();
399 } else {
400 animationDrawable.stop();
401 }
402 } else if (drawable instanceof AnimatedVectorDrawable) {
403 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
404 if (running) {
405 animationDrawable.start();
406 } else {
407 animationDrawable.stop();
408 }
409 }
410 }
411 }
412
Selim Cinek5ba22542017-04-20 15:16:10 -0700413 public void updateNotification(NotificationData.Entry entry) {
Selim Cinekda42d652015-12-04 15:51:16 -0800414 mEntry = entry;
415 mStatusBarNotification = entry.notification;
Selim Cinek1a48bab2017-02-17 19:38:40 -0800416 mNotificationInflater.inflateNotificationViews();
Rohan Shah63411fc2018-03-28 19:05:52 -0700417
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700418 cacheIsSystemNotification();
Rohan Shah63411fc2018-03-28 19:05:52 -0700419 }
420
421 /**
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700422 * Caches whether or not this row contains a system notification. Note, this is only cached
423 * once per notification as the packageInfo can't technically change for a notification row.
Rohan Shah63411fc2018-03-28 19:05:52 -0700424 */
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700425 private void cacheIsSystemNotification() {
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400426 if (mEntry != null && mEntry.mIsSystemNotification == null) {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700427 if (mSystemNotificationAsyncTask.getStatus() == AsyncTask.Status.PENDING) {
428 // Run async task once, only if it hasn't already been executed. Note this is
429 // executed in serial - no need to parallelize this small task.
430 mSystemNotificationAsyncTask.execute();
Rohan Shah63411fc2018-03-28 19:05:52 -0700431 }
432 }
433 }
434
435 /**
Rohan Shahca0447e2018-03-30 15:18:27 -0700436 * Returns whether this row is considered non-blockable (i.e. it's a non-blockable system notif
437 * or is in a whitelist).
Rohan Shah63411fc2018-03-28 19:05:52 -0700438 */
439 public boolean getIsNonblockable() {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700440 boolean isNonblockable = Dependency.get(NotificationBlockingHelperManager.class)
Rohan Shah63411fc2018-03-28 19:05:52 -0700441 .isNonblockablePackage(mStatusBarNotification.getPackageName());
442
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700443 // If the SystemNotifAsyncTask hasn't finished running or retrieved a value, we'll try once
444 // again, but in-place on the main thread this time. This should rarely ever get called.
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400445 if (mEntry != null && mEntry.mIsSystemNotification == null) {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700446 if (DEBUG) {
447 Log.d(TAG, "Retrieving isSystemNotification on main thread");
448 }
449 mSystemNotificationAsyncTask.cancel(true /* mayInterruptIfRunning */);
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400450 mEntry.mIsSystemNotification = isSystemNotification(mContext, mStatusBarNotification);
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700451 }
452
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400453 if (!isNonblockable && mEntry != null && mEntry.mIsSystemNotification != null) {
454 if (mEntry.mIsSystemNotification) {
Rohan Shah63411fc2018-03-28 19:05:52 -0700455 if (mEntry.channel != null
456 && !mEntry.channel.isBlockableSystem()) {
457 isNonblockable = true;
458 }
459 }
460 }
461 return isNonblockable;
Selim Cinekc478f902017-02-22 20:55:44 -0800462 }
463
Selim Cinek5ba22542017-04-20 15:16:10 -0700464 public void onNotificationUpdated() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800465 for (NotificationContentView l : mLayouts) {
Selim Cinekc478f902017-02-22 20:55:44 -0800466 l.onNotificationUpdated(mEntry);
Adrian Rooseb434ff2017-01-11 11:18:48 -0800467 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800468 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800469 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700470 updateNotificationColor();
Mady Mellor4c197602017-04-10 17:57:52 -0700471 if (mMenuRow != null) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700472 mMenuRow.onNotificationUpdated(mStatusBarNotification);
Beverly3f56f052018-05-08 14:56:03 -0400473 mMenuRow.setAppName(mAppName);
Mady Mellor4c197602017-04-10 17:57:52 -0700474 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800475 if (mIsSummaryWithChildren) {
Selim Cinek414ad332017-02-24 19:06:12 -0800476 mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
Selim Cinekc897bd32016-03-18 17:32:31 -0700477 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800478 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800479 if (mIconAnimationRunning) {
480 setIconAnimationRunning(true);
481 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800482 if (mNotificationParent != null) {
483 mNotificationParent.updateChildrenHeaderAppearance();
484 }
Selim Cinek263398f2015-10-21 17:40:23 -0700485 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800486 // The public layouts expand button is always visible
487 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800488 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700489 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800490 updateShelfIconColor();
Selim Cinekfe24fb72018-02-13 14:34:55 -0800491 updateRippleAllowed();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800492 }
493
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700494 @VisibleForTesting
495 void updateShelfIconColor() {
Selim Cinek6743c0b2017-01-18 18:24:01 -0800496 StatusBarIconView expandedIcon = mEntry.expandedIcon;
497 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
498 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
499 NotificationColorUtil.getInstance(mContext));
Selim Cinek875ba9b2017-02-13 16:20:17 -0800500 int color = StatusBarIconView.NO_COLOR;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800501 if (colorize) {
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700502 NotificationHeaderView header = getVisibleNotificationHeader();
503 if (header != null) {
504 color = header.getOriginalIconColor();
505 } else {
506 color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
507 getBackgroundColorWithoutTint());
508 }
Selim Cinek6743c0b2017-01-18 18:24:01 -0800509 }
Selim Cinek875ba9b2017-02-13 16:20:17 -0800510 expandedIcon.setStaticDrawableColor(color);
Selim Cinekda42d652015-12-04 15:51:16 -0800511 }
512
Selim Cinek5cf1d052017-06-01 17:36:46 -0700513 public void setAboveShelfChangedListener(AboveShelfChangedListener aboveShelfChangedListener) {
514 mAboveShelfChangedListener = aboveShelfChangedListener;
515 }
516
Lucas Dupincecc7c22017-09-12 16:02:45 -0700517 /**
518 * Sets a supplier that can determine whether the keyguard is secure or not.
519 * @param secureStateProvider A function that returns true if keyguard is secure.
520 */
521 public void setSecureStateProvider(BooleanSupplier secureStateProvider) {
522 mSecureStateProvider = secureStateProvider;
523 }
524
Selim Cinek4705f292017-04-24 22:18:48 -0700525 @Override
526 public boolean isDimmable() {
527 if (!getShowingLayout().isDimmable()) {
528 return false;
529 }
530 return super.isDimmable();
531 }
532
Selim Cinekda42d652015-12-04 15:51:16 -0800533 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800534 for (NotificationContentView l : mLayouts) {
535 updateLimitsForView(l);
536 }
Selim Cineka1744872016-03-11 15:36:06 -0800537 }
538
539 private void updateLimitsForView(NotificationContentView layout) {
540 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800541 != com.android.internal.R.id.status_bar_latest_event_content;
542 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800543 boolean beforeP = mEntry.targetSdk < Build.VERSION_CODES.P;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800544 int minHeight;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800545 if (customView && beforeP && !mIsSummaryWithChildren) {
546 minHeight = beforeN ? mNotificationMinHeightLegacy : mNotificationMinHeightBeforeP;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800547 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
548 minHeight = mNotificationMinHeightLarge;
549 } else {
550 minHeight = mNotificationMinHeight;
551 }
Selim Cineka1744872016-03-11 15:36:06 -0800552 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
553 layout.getHeadsUpChild().getId()
554 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800555 int headsUpheight;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800556 if (headsUpCustom && beforeP) {
557 headsUpheight = beforeN ? mMaxHeadsUpHeightLegacy : mMaxHeadsUpHeightBeforeP;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800558 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
559 headsUpheight = mMaxHeadsUpHeightIncreased;
560 } else {
561 headsUpheight = mMaxHeadsUpHeight;
562 }
Selim Cineke62255c2017-09-28 18:23:23 -0700563 NotificationViewWrapper headsUpWrapper = layout.getVisibleWrapper(
564 NotificationContentView.VISIBLE_TYPE_HEADSUP);
565 if (headsUpWrapper != null) {
566 headsUpheight = Math.max(headsUpheight, headsUpWrapper.getMinLayoutHeight());
567 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800568 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
569 mNotificationAmbientHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200570 }
571
572 public StatusBarNotification getStatusBarNotification() {
573 return mStatusBarNotification;
574 }
575
Selim Cinek281c2022016-10-13 19:14:43 -0700576 public NotificationData.Entry getEntry() {
577 return mEntry;
578 }
579
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700580 public boolean isHeadsUp() {
581 return mIsHeadsUp;
582 }
583
Selim Cinek1a521f32014-11-03 17:39:29 +0100584 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinek5cf1d052017-06-01 17:36:46 -0700585 boolean wasAboveShelf = isAboveShelf();
Selim Cinekc80fdb12015-04-13 15:09:08 -0700586 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100587 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700588 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700589 if (mIsSummaryWithChildren) {
590 // The overflow might change since we allow more lines as HUN.
591 mChildrenContainer.updateGroupOverflow();
592 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700593 if (intrinsicBefore != getIntrinsicHeight()) {
594 notifyHeightChanged(false /* needsAnimation */);
595 }
Selim Cinekd127d792016-11-01 19:11:41 -0700596 if (isHeadsUp) {
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100597 mMustStayOnScreen = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700598 setAboveShelf(true);
Selim Cinek5cf1d052017-06-01 17:36:46 -0700599 } else if (isAboveShelf() != wasAboveShelf) {
600 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
Selim Cinekd127d792016-11-01 19:11:41 -0700601 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100602 }
603
Selim Cinekb5605e52015-02-20 18:21:41 +0100604 public void setGroupManager(NotificationGroupManager groupManager) {
605 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700606 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100607 }
608
Adrian Roosb88b1a12015-12-09 18:51:05 -0800609 public void setRemoteInputController(RemoteInputController r) {
610 mPrivateLayout.setRemoteInputController(r);
611 }
612
Mady Mellor3fd273e2016-03-15 21:08:14 -0700613 public void setAppName(String appName) {
614 mAppName = appName;
Mady Mellor95d743c2017-01-10 12:05:27 -0800615 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800616 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700617 }
618 }
619
Selim Cinekb5605e52015-02-20 18:21:41 +0100620 public void addChildNotification(ExpandableNotificationRow row) {
621 addChildNotification(row, -1);
622 }
623
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800624 /**
625 * Set the how much the header should be visible. A value of 0 will make the header fully gone
626 * and a value of 1 will make the notification look just like normal.
627 * This is being used for heads up notifications, when they are pinned to the top of the screen
628 * and the header content is extracted to the statusbar.
629 *
630 * @param headerVisibleAmount the amount the header should be visible.
631 */
632 public void setHeaderVisibleAmount(float headerVisibleAmount) {
633 if (mHeaderVisibleAmount != headerVisibleAmount) {
634 mHeaderVisibleAmount = headerVisibleAmount;
635 mPrivateLayout.setHeaderVisibleAmount(headerVisibleAmount);
636 if (mChildrenContainer != null) {
637 mChildrenContainer.setHeaderVisibleAmount(headerVisibleAmount);
638 }
639 notifyHeightChanged(false /* needsAnimation */);
640 }
641 }
642
Selim Cinek99e9adf2018-03-15 09:17:47 -0700643 @Override
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800644 public float getHeaderVisibleAmount() {
645 return mHeaderVisibleAmount;
646 }
647
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100648 @Override
649 public void setHeadsUpIsVisible() {
650 super.setHeadsUpIsVisible();
651 mMustStayOnScreen = false;
652 }
653
Selim Cinekb5605e52015-02-20 18:21:41 +0100654 /**
655 * Add a child notification to this view.
656 *
657 * @param row the row to add
658 * @param childIndex the index to add it at, if -1 it will be added at the end
659 */
660 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
661 if (mChildrenContainer == null) {
662 mChildrenContainerStub.inflate();
663 }
664 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700665 onChildrenCountChanged();
666 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100667 }
668
669 public void removeChildNotification(ExpandableNotificationRow row) {
670 if (mChildrenContainer != null) {
671 mChildrenContainer.removeNotification(row);
672 }
Selim Cinek263398f2015-10-21 17:40:23 -0700673 onChildrenCountChanged();
674 row.setIsChildInGroup(false, null);
Selim Cinek2871bef2017-11-22 08:40:00 -0800675 row.setBottomRoundness(0.0f, false /* animate */);
Selim Cinek263398f2015-10-21 17:40:23 -0700676 }
677
Mady Mellor43c2cd12016-12-12 21:05:13 -0800678 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700679 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700680 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700681 }
682
Rohan Shah524cf7b2018-03-15 14:40:02 -0700683 /**
684 * @return whether this notification is the only child in the group summary
685 */
686 public boolean isOnlyChildInGroup() {
687 return mGroupManager.isOnlyChildInGroup(getStatusBarNotification());
688 }
689
Selim Cinek388df6d2015-10-22 13:25:11 -0700690 public ExpandableNotificationRow getNotificationParent() {
691 return mNotificationParent;
692 }
693
Selim Cinek263398f2015-10-21 17:40:23 -0700694 /**
695 * @param isChildInGroup Is this notification now in a group
696 * @param parent the new parent notification
697 */
Selim Cinekc25989e2018-02-16 16:42:14 -0800698 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500699 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cinekc25989e2018-02-16 16:42:14 -0800700 if (mExpandAnimationRunning && !isChildInGroup && mNotificationParent != null) {
701 mNotificationParent.setChildIsExpanding(false);
702 mNotificationParent.setExtraWidthForClipping(0.0f);
703 mNotificationParent.setMinimumHeightForClipping(0);
704 }
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700705 mNotificationParent = childInGroup ? parent : null;
706 mPrivateLayout.setIsChildInGroup(childInGroup);
Selim Cinek5ba22542017-04-20 15:16:10 -0700707 mNotificationInflater.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400708 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700709 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700710 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700711 if (mNotificationParent != null) {
Selim Cinek9ce32852017-02-15 16:21:10 -0800712 setOverrideTintColor(NO_COLOR, 0.0f);
Selim Cinekeccf4942018-05-30 09:55:36 -0700713 // Let's reset the distance to top roundness, as this isn't applied to group children
714 setDistanceToTopRoundness(NO_ROUNDNESS);
Mady Mellorb0a82462016-04-30 17:31:02 -0700715 mNotificationParent.updateBackgroundForGroupState();
716 }
Selim Cinekdb167372016-11-17 15:41:17 -0800717 updateIconVisibilities();
Selim Cinek2871bef2017-11-22 08:40:00 -0800718 updateBackgroundClipping();
Selim Cinek34d93b02015-10-22 12:30:38 -0700719 }
720
721 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800722 public boolean onTouchEvent(MotionEvent event) {
723 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
724 || !isChildInGroup() || isGroupExpanded()) {
725 return super.onTouchEvent(event);
726 } else {
727 return false;
728 }
729 }
730
731 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800732 protected boolean handleSlideBack() {
Mady Mellor95d743c2017-01-10 12:05:27 -0800733 if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800734 animateTranslateNotification(0 /* targetLeft */);
735 return true;
736 }
737 return false;
738 }
739
740 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700741 protected boolean shouldHideBackground() {
742 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700743 }
744
745 @Override
746 public boolean isSummaryWithChildren() {
747 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100748 }
749
750 @Override
751 public boolean areChildrenExpanded() {
752 return mChildrenExpanded;
753 }
754
755 public List<ExpandableNotificationRow> getNotificationChildren() {
756 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
757 }
758
Selim Cinekeef84282015-10-30 16:28:00 -0700759 public int getNumberOfNotificationChildren() {
760 if (mChildrenContainer == null) {
761 return 0;
762 }
763 return mChildrenContainer.getNotificationChildren().size();
764 }
765
Selim Cinekb5605e52015-02-20 18:21:41 +0100766 /**
767 * Apply the order given in the list to the children.
768 *
769 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800770 * @param visualStabilityManager
771 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100772 * @return whether the list order has changed
773 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800774 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
775 VisualStabilityManager visualStabilityManager,
776 VisualStabilityManager.Callback callback) {
777 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
778 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100779 }
780
Selim Cinekc25989e2018-02-16 16:42:14 -0800781 public void getChildrenStates(StackScrollState resultState,
782 AmbientState ambientState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700783 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800784 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekc25989e2018-02-16 16:42:14 -0800785 mChildrenContainer.getState(resultState, parentState, ambientState);
Selim Cinekb5605e52015-02-20 18:21:41 +0100786 }
787 }
788
789 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700790 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100791 mChildrenContainer.applyState(state);
792 }
793 }
794
795 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700796 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100797 mChildrenContainer.prepareExpansionChanged(state);
798 }
799 }
800
Selim Cinek0cfbef42016-11-09 19:06:36 -0800801 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700802 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800803 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100804 }
805 }
806
807 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800808 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100809 return this;
810 } else {
811 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
812 return view == null ? this : view;
813 }
814 }
815
Selim Cinekab29aeb2015-02-20 18:18:32 +0100816 public NotificationGuts getGuts() {
817 return mGuts;
818 }
819
Selim Cinek684a4422015-04-15 16:18:39 -0700820 /**
821 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
822 * the notification will be rendered on top of the screen.
823 *
824 * @param pinned whether it is pinned
825 */
826 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700827 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek5cf1d052017-06-01 17:36:46 -0700828 boolean wasAboveShelf = isAboveShelf();
Selim Cinek684a4422015-04-15 16:18:39 -0700829 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700830 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700831 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700832 }
Selim Cinek31aada42015-12-18 17:51:15 -0800833 if (pinned) {
834 setIconAnimationRunning(true);
835 mExpandedWhenPinned = false;
836 } else if (mExpandedWhenPinned) {
837 setUserExpanded(true);
838 }
Selim Cinek98713a42015-09-21 15:47:20 +0200839 setChronometerRunning(mLastChronometerRunning);
Selim Cinek5cf1d052017-06-01 17:36:46 -0700840 if (isAboveShelf() != wasAboveShelf) {
841 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
842 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700843 }
844
Selim Cinek29aab962018-02-27 17:05:45 -0800845 @Override
Selim Cinek684a4422015-04-15 16:18:39 -0700846 public boolean isPinned() {
847 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700848 }
849
Selim Cinekd127d792016-11-01 19:11:41 -0700850 @Override
851 public int getPinnedHeadsUpHeight() {
852 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
853 }
854
Selim Cinek31aada42015-12-18 17:51:15 -0800855 /**
856 * @param atLeastMinHeight should the value returned be at least the minimum height.
857 * Used to avoid cyclic calls
858 * @return the height of the heads up notification when pinned
859 */
Selim Cinekd127d792016-11-01 19:11:41 -0700860 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800861 if (mIsSummaryWithChildren) {
862 return mChildrenContainer.getIntrinsicHeight();
863 }
Selim Cinek31aada42015-12-18 17:51:15 -0800864 if(mExpandedWhenPinned) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800865 return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
Selim Cinek31aada42015-12-18 17:51:15 -0800866 } else if (atLeastMinHeight) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800867 return Math.max(getCollapsedHeight(), getHeadsUpHeight());
Selim Cinek31aada42015-12-18 17:51:15 -0800868 } else {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800869 return getHeadsUpHeight();
Selim Cinek31aada42015-12-18 17:51:15 -0800870 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700871 }
872
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700873 /**
874 * Mark whether this notification was just clicked, i.e. the user has just clicked this
875 * notification in this frame.
876 */
877 public void setJustClicked(boolean justClicked) {
878 mJustClicked = justClicked;
879 }
880
881 /**
882 * @return true if this notification has been clicked in this frame, false otherwise
883 */
884 public boolean wasJustClicked() {
885 return mJustClicked;
886 }
887
Selim Cinek98713a42015-09-21 15:47:20 +0200888 public void setChronometerRunning(boolean running) {
889 mLastChronometerRunning = running;
890 setChronometerRunning(running, mPrivateLayout);
891 setChronometerRunning(running, mPublicLayout);
892 if (mChildrenContainer != null) {
893 List<ExpandableNotificationRow> notificationChildren =
894 mChildrenContainer.getNotificationChildren();
895 for (int i = 0; i < notificationChildren.size(); i++) {
896 ExpandableNotificationRow child = notificationChildren.get(i);
897 child.setChronometerRunning(running);
898 }
899 }
900 }
901
902 private void setChronometerRunning(boolean running, NotificationContentView layout) {
903 if (layout != null) {
904 running = running || isPinned();
905 View contractedChild = layout.getContractedChild();
906 View expandedChild = layout.getExpandedChild();
907 View headsUpChild = layout.getHeadsUpChild();
908 setChronometerRunningForChild(running, contractedChild);
909 setChronometerRunningForChild(running, expandedChild);
910 setChronometerRunningForChild(running, headsUpChild);
911 }
912 }
913
914 private void setChronometerRunningForChild(boolean running, View child) {
915 if (child != null) {
916 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
917 if (chronometer instanceof Chronometer) {
918 ((Chronometer) chronometer).setStarted(running);
919 }
920 }
921 }
922
Selim Cinekea4bef72015-12-02 15:51:10 -0800923 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700924 if (mIsSummaryWithChildren) {
925 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700926 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800927 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700928 }
929
Selim Cinek414ad332017-02-24 19:06:12 -0800930 /**
931 * @return the currently visible notification header. This can be different from
932 * {@link #getNotificationHeader()} in case it is a low-priority group.
933 */
934 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinek0b9cf462017-12-07 16:31:03 -0800935 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek414ad332017-02-24 19:06:12 -0800936 return mChildrenContainer.getVisibleHeader();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800937 }
938 return getShowingLayout().getVisibleNotificationHeader();
939 }
940
Selim Cinekb26afa32017-06-29 10:28:17 +0200941
942 /**
943 * @return the contracted notification header. This can be different from
944 * {@link #getNotificationHeader()} and also {@link #getVisibleNotificationHeader()} and only
945 * returns the contracted version.
946 */
947 public NotificationHeaderView getContractedNotificationHeader() {
948 if (mIsSummaryWithChildren) {
949 return mChildrenContainer.getHeaderView();
950 }
951 return mPrivateLayout.getContractedNotificationHeader();
952 }
953
Selim Cinek570981d2015-12-01 11:37:01 -0800954 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
955 mOnExpandClickListener = onExpandClickListener;
956 }
957
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000958 public void setLongPressListener(LongPressListener longPressListener) {
959 mLongPressListener = longPressListener;
960 }
961
Selim Cinekddf1b392016-05-27 16:33:10 -0700962 @Override
963 public void setOnClickListener(@Nullable OnClickListener l) {
964 super.setOnClickListener(l);
965 mOnClickListener = l;
966 updateClickAndFocus();
967 }
968
969 private void updateClickAndFocus() {
970 boolean normalChild = !isChildInGroup() || isGroupExpanded();
971 boolean clickable = mOnClickListener != null && normalChild;
972 if (isFocusable() != normalChild) {
973 setFocusable(normalChild);
974 }
975 if (isClickable() != clickable) {
976 setClickable(clickable);
977 }
978 }
979
Selim Cinek31aada42015-12-18 17:51:15 -0800980 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
981 mHeadsUpManager = headsUpManager;
982 }
983
Mady Mellor87d79452017-01-10 11:52:52 -0800984 public void setGutsView(MenuItem item) {
Mady Mellor95d743c2017-01-10 12:05:27 -0800985 if (mGuts != null && item.getGutsView() instanceof GutsContent) {
986 ((GutsContent) item.getGutsView()).setGutsParent(mGuts);
987 mGuts.setGutsContent((GutsContent) item.getGutsView());
Mady Mellor87d79452017-01-10 11:52:52 -0800988 }
989 }
990
Mady Mellor95d743c2017-01-10 12:05:27 -0800991 @Override
992 protected void onAttachedToWindow() {
993 super.onAttachedToWindow();
994 Dependency.get(PluginManager.class).addPluginListener(this,
995 NotificationMenuRowPlugin.class, false /* Allow multiple */);
996 }
997
998 @Override
999 protected void onDetachedFromWindow() {
1000 super.onDetachedFromWindow();
1001 Dependency.get(PluginManager.class).removePluginListener(this);
1002 }
1003
1004 @Override
1005 public void onPluginConnected(NotificationMenuRowPlugin plugin, Context pluginContext) {
1006 boolean existed = mMenuRow.getMenuView() != null;
1007 if (existed) {
1008 removeView(mMenuRow.getMenuView());
1009 }
1010 mMenuRow = plugin;
1011 if (mMenuRow.useDefaultMenuItems()) {
Mady Mellor4c197602017-04-10 17:57:52 -07001012 ArrayList<MenuItem> items = new ArrayList<>();
1013 items.add(NotificationMenuRow.createInfoItem(mContext));
1014 items.add(NotificationMenuRow.createSnoozeItem(mContext));
Julia Reynoldsb5867452018-02-28 16:31:35 -05001015 items.add(NotificationMenuRow.createAppOpsItem(mContext));
Mady Mellor4c197602017-04-10 17:57:52 -07001016 mMenuRow.setMenuItems(items);
Mady Mellor95d743c2017-01-10 12:05:27 -08001017 }
1018 if (existed) {
1019 createMenu();
1020 }
1021 }
1022
1023 @Override
1024 public void onPluginDisconnected(NotificationMenuRowPlugin plugin) {
1025 boolean existed = mMenuRow.getMenuView() != null;
1026 mMenuRow = new NotificationMenuRow(mContext); // Back to default
1027 if (existed) {
1028 createMenu();
1029 }
1030 }
1031
1032 public NotificationMenuRowPlugin createMenu() {
1033 if (mMenuRow.getMenuView() == null) {
Mady Mellor4ab28202017-06-06 11:42:50 -07001034 mMenuRow.createMenu(this, mStatusBarNotification);
Mady Mellor95d743c2017-01-10 12:05:27 -08001035 mMenuRow.setAppName(mAppName);
1036 FrameLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
1037 LayoutParams.MATCH_PARENT);
1038 addView(mMenuRow.getMenuView(), MENU_VIEW_INDEX, lp);
1039 }
1040 return mMenuRow;
1041 }
1042
Mady Mellor95d743c2017-01-10 12:05:27 -08001043 public NotificationMenuRowPlugin getProvider() {
1044 return mMenuRow;
1045 }
1046
Anthony Chen9fe1ee72017-04-07 13:53:37 -07001047 @Override
Selim Cinek1a48bab2017-02-17 19:38:40 -08001048 public void onDensityOrFontScaleChanged() {
Anthony Chen9fe1ee72017-04-07 13:53:37 -07001049 super.onDensityOrFontScaleChanged();
Selim Cinek01af3342016-02-09 19:25:31 -08001050 initDimens();
Anthony Chenad4d1582017-04-10 16:07:58 -07001051 initBackground();
Selim Cinek817abe72017-05-24 11:08:55 -07001052 // Let's update our childrencontainer. This is intentionally not guarded with
1053 // mIsSummaryWithChildren since we might have had children but not anymore.
1054 if (mChildrenContainer != null) {
1055 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -08001056 }
1057 if (mGuts != null) {
1058 View oldGuts = mGuts;
1059 int index = indexOfChild(oldGuts);
1060 removeView(oldGuts);
1061 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
1062 R.layout.notification_guts, this, false);
1063 mGuts.setVisibility(oldGuts.getVisibility());
1064 addView(mGuts, index);
1065 }
Mady Mellor95d743c2017-01-10 12:05:27 -08001066 View oldMenu = mMenuRow.getMenuView();
1067 if (oldMenu != null) {
Mady Mellor761cde12017-01-10 11:36:39 -08001068 int menuIndex = indexOfChild(oldMenu);
1069 removeView(oldMenu);
Mady Mellor4ab28202017-06-06 11:42:50 -07001070 mMenuRow.createMenu(ExpandableNotificationRow.this, mStatusBarNotification);
Mady Mellor761cde12017-01-10 11:36:39 -08001071 mMenuRow.setAppName(mAppName);
Mady Mellor95d743c2017-01-10 12:05:27 -08001072 addView(mMenuRow.getMenuView(), menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -08001073 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001074 for (NotificationContentView l : mLayouts) {
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001075 l.initView();
Adrian Rooseb434ff2017-01-11 11:18:48 -08001076 l.reInflateViews();
1077 }
Selim Cinek1a48bab2017-02-17 19:38:40 -08001078 mNotificationInflater.onDensityOrFontScaleChanged();
1079 onNotificationUpdated();
Selim Cinek01af3342016-02-09 19:25:31 -08001080 }
1081
Mady Mellor9d03a522017-04-04 18:45:30 -07001082 @Override
1083 public void onConfigurationChanged(Configuration newConfig) {
1084 if (mMenuRow.getMenuView() != null) {
1085 mMenuRow.onConfigurationChanged();
1086 }
1087 }
1088
Selim Cinekc3179332016-03-04 14:44:56 -08001089 public void setContentBackground(int customBackgroundColor, boolean animate,
1090 NotificationContentView notificationContentView) {
1091 if (getShowingLayout() == notificationContentView) {
1092 setTintColor(customBackgroundColor, animate);
1093 }
1094 }
1095
Kenny Guy14d035c2018-05-02 19:10:36 +01001096 @Override
1097 protected void setBackgroundTintColor(int color) {
1098 super.setBackgroundTintColor(color);
1099 NotificationContentView view = getShowingLayout();
1100 if (view != null) {
1101 view.setBackgroundTintColor(color);
1102 }
1103 }
1104
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001105 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -08001106 for (NotificationContentView l : mLayouts) {
1107 l.closeRemoteInput();
1108 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001109 }
1110
Selim Cinekc897bd32016-03-18 17:32:31 -07001111 /**
1112 * Set by how much the single line view should be indented.
1113 */
1114 public void setSingleLineWidthIndention(int indention) {
1115 mPrivateLayout.setSingleLineWidthIndention(indention);
1116 }
1117
1118 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -07001119 return mNotificationColor;
1120 }
1121
1122 private void updateNotificationColor() {
1123 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
Selim Cinekac5f0272017-05-02 16:05:41 -07001124 getStatusBarNotification().getNotification().color,
1125 getBackgroundColorWithoutTint());
Adrian Roos6f6e1592017-05-02 16:22:53 -07001126 mNotificationColorAmbient = NotificationColorUtil.resolveAmbientColor(mContext,
1127 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -07001128 }
1129
1130 public HybridNotificationView getSingleLineView() {
1131 return mPrivateLayout.getSingleLineView();
1132 }
1133
Adrian Roos6f6e1592017-05-02 16:22:53 -07001134 public HybridNotificationView getAmbientSingleLineView() {
1135 return getShowingLayout().getAmbientSingleLineChild();
1136 }
1137
Selim Cinekf07d0622016-03-21 19:52:52 -07001138 public boolean isOnKeyguard() {
1139 return mOnKeyguard;
1140 }
1141
Selim Cinekc1e389d2016-04-07 11:02:57 -07001142 public void removeAllChildren() {
1143 List<ExpandableNotificationRow> notificationChildren
1144 = mChildrenContainer.getNotificationChildren();
1145 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
1146 for (int i = 0; i < clonedList.size(); i++) {
1147 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -07001148 if (row.keepInParent()) {
1149 continue;
1150 }
Selim Cinekc1e389d2016-04-07 11:02:57 -07001151 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -07001152 row.setIsChildInGroup(false, null);
1153 }
1154 onChildrenCountChanged();
1155 }
1156
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001157 public void setForceUnlocked(boolean forceUnlocked) {
1158 mForceUnlocked = forceUnlocked;
1159 if (mIsSummaryWithChildren) {
1160 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
1161 for (ExpandableNotificationRow child : notificationChildren) {
1162 child.setForceUnlocked(forceUnlocked);
1163 }
1164 }
1165 }
1166
Selim Cinekd03518c2018-03-15 12:13:51 -07001167 public void setDismissed(boolean fromAccessibility) {
Rohan Shahc6990a02018-03-23 17:24:17 -07001168 setLongPressListener(null);
Selim Cinekd03518c2018-03-15 12:13:51 -07001169 mDismissed = true;
Selim Cineke9bad242016-06-15 11:46:37 -07001170 mGroupParentWhenDismissed = mNotificationParent;
1171 mRefocusOnDismiss = fromAccessibility;
1172 mChildAfterViewWhenDismissed = null;
Selim Cinekd03518c2018-03-15 12:13:51 -07001173 mEntry.icon.setDismissed();
Selim Cineke9bad242016-06-15 11:46:37 -07001174 if (isChildInGroup()) {
1175 List<ExpandableNotificationRow> notificationChildren =
1176 mNotificationParent.getNotificationChildren();
1177 int i = notificationChildren.indexOf(this);
1178 if (i != -1 && i < notificationChildren.size() - 1) {
1179 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
1180 }
1181 }
Selim Cinek3f19f602016-05-02 18:01:56 -07001182 }
1183
1184 public boolean isDismissed() {
1185 return mDismissed;
1186 }
1187
1188 public boolean keepInParent() {
1189 return mKeepInParent;
1190 }
1191
1192 public void setKeepInParent(boolean keepInParent) {
1193 mKeepInParent = keepInParent;
1194 }
1195
Selim Cinekd9b7dd42017-11-10 17:53:47 -08001196 @Override
Selim Cinek3f19f602016-05-02 18:01:56 -07001197 public boolean isRemoved() {
1198 return mRemoved;
1199 }
1200
Adrian Roosd009ab12016-05-20 17:58:53 -07001201 public void setRemoved() {
1202 mRemoved = true;
Selim Cinekef8c2252017-02-10 14:52:18 -08001203 mTranslationWhenRemoved = getTranslationY();
1204 mWasChildInGroupWhenRemoved = isChildInGroup();
1205 if (isChildInGroup()) {
1206 mTranslationWhenRemoved += getNotificationParent().getTranslationY();
1207 }
Adrian Roosd009ab12016-05-20 17:58:53 -07001208 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -07001209 }
1210
Selim Cinekef8c2252017-02-10 14:52:18 -08001211 public boolean wasChildInGroupWhenRemoved() {
1212 return mWasChildInGroupWhenRemoved;
1213 }
1214
1215 public float getTranslationWhenRemoved() {
1216 return mTranslationWhenRemoved;
1217 }
1218
Selim Cinekd1395642016-04-28 12:22:42 -07001219 public NotificationChildrenContainer getChildrenContainer() {
1220 return mChildrenContainer;
1221 }
1222
Selim Cinekcafa87f2016-10-26 17:00:17 -07001223 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07001224 boolean wasAboveShelf = isAboveShelf();
Selim Cinek8875de12018-03-22 10:14:32 -07001225 boolean changed = headsUpAnimatingAway != mHeadsupDisappearRunning;
Selim Cinekcafa87f2016-10-26 17:00:17 -07001226 mHeadsupDisappearRunning = headsUpAnimatingAway;
1227 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
Selim Cinek8875de12018-03-22 10:14:32 -07001228 if (changed && mHeadsUpAnimatingAwayListener != null) {
1229 mHeadsUpAnimatingAwayListener.accept(headsUpAnimatingAway);
1230 }
Selim Cinek5cf1d052017-06-01 17:36:46 -07001231 if (isAboveShelf() != wasAboveShelf) {
1232 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
1233 }
Selim Cinekcafa87f2016-10-26 17:00:17 -07001234 }
1235
Selim Cinek8875de12018-03-22 10:14:32 -07001236 public void setHeadsUpAnimatingAwayListener(Consumer<Boolean> listener) {
1237 mHeadsUpAnimatingAwayListener = listener;
1238 }
1239
Selim Cinekcafa87f2016-10-26 17:00:17 -07001240 /**
1241 * @return if the view was just heads upped and is now animating away. During such a time the
1242 * layout needs to be kept consistent
1243 */
Selim Cinek29aab962018-02-27 17:05:45 -08001244 @Override
Selim Cinekcafa87f2016-10-26 17:00:17 -07001245 public boolean isHeadsUpAnimatingAway() {
1246 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -07001247 }
1248
Selim Cineke9bad242016-06-15 11:46:37 -07001249 public View getChildAfterViewWhenDismissed() {
1250 return mChildAfterViewWhenDismissed;
1251 }
1252
1253 public View getGroupParentWhenDismissed() {
1254 return mGroupParentWhenDismissed;
1255 }
1256
Rohan Shah524cf7b2018-03-15 14:40:02 -07001257 /**
1258 * Dismisses the notification with the option of showing the blocking helper in-place if we have
1259 * a negative user sentiment.
1260 *
1261 * @param fromAccessibility whether this dismiss is coming from an accessibility action
1262 * @return whether a blocking helper is shown in this row
1263 */
1264 public boolean performDismissWithBlockingHelper(boolean fromAccessibility) {
1265 NotificationBlockingHelperManager manager =
1266 Dependency.get(NotificationBlockingHelperManager.class);
1267 boolean isBlockingHelperShown = manager.perhapsShowBlockingHelper(this, mMenuRow);
1268
Rohan Shahda5dcdd2018-04-27 17:21:50 -07001269 Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
1270
Rohan Shah524cf7b2018-03-15 14:40:02 -07001271 // Continue with dismiss since we don't want the blocking helper to be directly associated
1272 // with a certain notification.
1273 performDismiss(fromAccessibility);
1274 return isBlockingHelperShown;
1275 }
1276
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001277 public void performDismiss(boolean fromAccessibility) {
Rohan Shah524cf7b2018-03-15 14:40:02 -07001278 if (isOnlyChildInGroup()) {
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001279 ExpandableNotificationRow groupSummary =
1280 mGroupManager.getLogicalGroupSummary(getStatusBarNotification());
1281 if (groupSummary.isClearable()) {
Rohan Shah524cf7b2018-03-15 14:40:02 -07001282 // If this is the only child in the group, dismiss the group, but don't try to show
1283 // the blocking helper affordance!
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001284 groupSummary.performDismiss(fromAccessibility);
1285 }
1286 }
Selim Cinekd03518c2018-03-15 12:13:51 -07001287 setDismissed(fromAccessibility);
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001288 if (isClearable()) {
1289 if (mOnDismissRunnable != null) {
1290 mOnDismissRunnable.run();
1291 }
Selim Cineke9079112016-12-14 14:41:01 -08001292 }
Selim Cinek9e624e72016-07-20 13:46:49 -07001293 }
1294
Rohan Shah524cf7b2018-03-15 14:40:02 -07001295 public void setBlockingHelperShowing(boolean isBlockingHelperShowing) {
1296 mIsBlockingHelperShowing = isBlockingHelperShowing;
1297 }
1298
1299 public boolean isBlockingHelperShowing() {
1300 return mIsBlockingHelperShowing;
1301 }
1302
Selim Cineke9079112016-12-14 14:41:01 -08001303 public void setOnDismissRunnable(Runnable onDismissRunnable) {
1304 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -07001305 }
1306
Selim Cinek281c2022016-10-13 19:14:43 -07001307 public View getNotificationIcon() {
Selim Cinek414ad332017-02-24 19:06:12 -08001308 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek281c2022016-10-13 19:14:43 -07001309 if (notificationHeader != null) {
1310 return notificationHeader.getIcon();
1311 }
1312 return null;
1313 }
1314
1315 /**
1316 * @return whether the notification is currently showing a view with an icon.
1317 */
1318 public boolean isShowingIcon() {
Mady Mellor434180c2017-02-13 11:29:42 -08001319 if (areGutsExposed()) {
1320 return false;
1321 }
Selim Cinek2ffa02f2017-03-06 15:56:37 -08001322 return getVisibleNotificationHeader() != null;
Selim Cinek281c2022016-10-13 19:14:43 -07001323 }
1324
Selim Cinek0242fbb2016-10-19 13:38:32 -07001325 /**
1326 * Set how much this notification is transformed into an icon.
1327 *
Selim Cinek2b549f42016-11-22 16:38:51 -08001328 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
1329 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -08001330 * @param isLastChild is this the last child in the list. If true, then the transformation is
1331 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -07001332 */
Selim Cinek2b549f42016-11-22 16:38:51 -08001333 public void setContentTransformationAmount(float contentTransformationAmount,
1334 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -08001335 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001336 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001337 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001338 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001339 if (changeTransformation) {
1340 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -08001341 }
1342 }
1343
1344 /**
1345 * Set the icons to be visible of this notification.
1346 */
1347 public void setIconsVisible(boolean iconsVisible) {
1348 if (iconsVisible != mIconsVisible) {
1349 mIconsVisible = iconsVisible;
1350 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -07001351 }
1352 }
1353
Selim Cinekdb167372016-11-17 15:41:17 -08001354 @Override
1355 protected void onBelowSpeedBumpChanged() {
1356 updateIconVisibilities();
1357 }
1358
Selim Cinek875a3a12016-11-18 17:52:16 -08001359 private void updateContentTransformation() {
Selim Cinek2627d722018-01-19 12:16:49 -08001360 if (mExpandAnimationRunning) {
1361 return;
1362 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001363 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -08001364 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -08001365 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -08001366 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001367 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001368 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -08001369 translationY *= 0.4f;
1370 } else {
1371 contentAlpha = 1.0f;
1372 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001373 for (NotificationContentView l : mLayouts) {
1374 l.setAlpha(contentAlpha);
1375 l.setTranslationY(translationY);
1376 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001377 if (mChildrenContainer != null) {
1378 mChildrenContainer.setAlpha(contentAlpha);
1379 mChildrenContainer.setTranslationY(translationY);
1380 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -07001381 }
1382 }
1383
1384 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -08001385 boolean visible = isChildInGroup()
1386 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
1387 || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -08001388 for (NotificationContentView l : mLayouts) {
1389 l.setIconsVisible(visible);
1390 }
Selim Cinekdb167372016-11-17 15:41:17 -08001391 if (mChildrenContainer != null) {
1392 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001393 }
1394 }
1395
Selim Cinek875a3a12016-11-18 17:52:16 -08001396 /**
1397 * Get the relative top padding of a view relative to this view. This recursively walks up the
1398 * hierarchy and does the corresponding measuring.
1399 *
1400 * @param view the view to the the padding for. The requested view has to be a child of this
1401 * notification.
1402 * @return the toppadding
1403 */
1404 public int getRelativeTopPadding(View view) {
1405 int topPadding = 0;
1406 while (view.getParent() instanceof ViewGroup) {
1407 topPadding += view.getTop();
1408 view = (View) view.getParent();
1409 if (view instanceof ExpandableNotificationRow) {
1410 return topPadding;
1411 }
1412 }
1413 return topPadding;
1414 }
1415
Selim Cineka1d97902016-12-14 16:31:40 -08001416 public float getContentTranslation() {
1417 return mPrivateLayout.getTranslationY();
1418 }
1419
Selim Cinek6743c0b2017-01-18 18:24:01 -08001420 public void setIsLowPriority(boolean isLowPriority) {
1421 mIsLowPriority = isLowPriority;
1422 mPrivateLayout.setIsLowPriority(isLowPriority);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001423 mNotificationInflater.setIsLowPriority(mIsLowPriority);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001424 if (mChildrenContainer != null) {
1425 mChildrenContainer.setIsLowPriority(isLowPriority);
1426 }
1427 }
1428
Selim Cinek55a3e732017-05-25 18:30:10 -07001429
1430 public void setLowPriorityStateUpdated(boolean lowPriorityStateUpdated) {
1431 mLowPriorityStateUpdated = lowPriorityStateUpdated;
1432 }
1433
1434 public boolean hasLowPriorityStateUpdated() {
1435 return mLowPriorityStateUpdated;
1436 }
1437
Selim Cinek414ad332017-02-24 19:06:12 -08001438 public boolean isLowPriority() {
1439 return mIsLowPriority;
1440 }
1441
Selim Cinek7d1009b2017-01-25 15:28:28 -08001442 public void setUseIncreasedCollapsedHeight(boolean use) {
1443 mUseIncreasedCollapsedHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001444 mNotificationInflater.setUsesIncreasedHeight(use);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001445 }
1446
Selim Cinek87ed69b2017-02-09 15:59:43 -08001447 public void setUseIncreasedHeadsUpHeight(boolean use) {
1448 mUseIncreasedHeadsUpHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001449 mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
1450 }
1451
1452 public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
1453 mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001454 }
1455
Selim Cinek5ba22542017-04-20 15:16:10 -07001456 public void setInflationCallback(InflationCallback callback) {
1457 mNotificationInflater.setInflationCallback(callback);
Selim Cinekc478f902017-02-22 20:55:44 -08001458 }
1459
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001460 public void setNeedsRedaction(boolean needsRedaction) {
1461 mNotificationInflater.setRedactAmbient(needsRedaction);
1462 }
1463
Selim Cinek5ba22542017-04-20 15:16:10 -07001464 @VisibleForTesting
1465 public NotificationInflater getNotificationInflater() {
1466 return mNotificationInflater;
1467 }
1468
Adrian Roos6f6e1592017-05-02 16:22:53 -07001469 public int getNotificationColorAmbient() {
1470 return mNotificationColorAmbient;
1471 }
1472
Chris Wren78403d72014-07-28 10:23:24 +01001473 public interface ExpansionLogger {
Anthony Chen6bf88a02017-04-10 14:41:44 -07001474 void logNotificationExpansion(String key, boolean userAction, boolean expanded);
Chris Wren78403d72014-07-28 10:23:24 +01001475 }
Selim Cinek1685e632014-04-08 02:27:49 +02001476
Chris Wren51c75102013-07-16 20:49:17 -04001477 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1478 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001479 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001480 mNotificationInflater = new NotificationInflater(this);
Mady Mellor95d743c2017-01-10 12:05:27 -08001481 mMenuRow = new NotificationMenuRow(mContext);
Selim Cinek01af3342016-02-09 19:25:31 -08001482 initDimens();
1483 }
1484
1485 private void initDimens() {
Selim Cineke62255c2017-09-28 18:23:23 -07001486 mNotificationMinHeightLegacy = NotificationUtils.getFontScaledHeight(mContext,
1487 R.dimen.notification_min_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001488 mNotificationMinHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1489 R.dimen.notification_min_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001490 mNotificationMinHeight = NotificationUtils.getFontScaledHeight(mContext,
1491 R.dimen.notification_min_height);
1492 mNotificationMinHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001493 R.dimen.notification_min_height_increased);
Selim Cineke62255c2017-09-28 18:23:23 -07001494 mNotificationMaxHeight = NotificationUtils.getFontScaledHeight(mContext,
1495 R.dimen.notification_max_height);
1496 mNotificationAmbientHeight = NotificationUtils.getFontScaledHeight(mContext,
1497 R.dimen.notification_ambient_height);
1498 mMaxHeadsUpHeightLegacy = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek77019c72015-12-09 10:18:02 -08001499 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001500 mMaxHeadsUpHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1501 R.dimen.notification_max_heads_up_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001502 mMaxHeadsUpHeight = NotificationUtils.getFontScaledHeight(mContext,
1503 R.dimen.notification_max_heads_up_height);
1504 mMaxHeadsUpHeightIncreased = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001505 R.dimen.notification_max_heads_up_height_increased);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001506
Anthony Chen7acbb772017-04-07 16:45:25 -07001507 Resources res = getResources();
1508 mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
1509 R.dimen.notification_divider_height_increased);
1510 mIconTransformContentShiftNoIcon = res.getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001511 R.dimen.notification_icon_transform_content_shift);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001512 mEnableNonGroupedNotificationExpand =
1513 res.getBoolean(R.bool.config_enableNonGroupedNotificationExpand);
1514 mShowGroupBackgroundWhenExpanded =
1515 res.getBoolean(R.bool.config_showGroupNotificationBgWhenExpanded);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001516 }
1517
1518 /**
Christoph Studera7fe6312014-06-27 19:32:44 +02001519 * Resets this view so it can be re-used for an updated notification.
1520 */
1521 public void reset() {
Jorim Jaggiae441282014-08-01 02:45:18 +02001522 mShowingPublicInitialized = false;
Selim Cinek31094df2014-08-14 19:28:15 +02001523 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001524 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001525 }
1526
Julia Reynoldsfc640012018-02-21 12:25:27 -05001527 public void showAppOpsIcons(ArraySet<Integer> activeOps) {
1528 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
1529 mChildrenContainer.getHeaderView().showAppOpsIcons(activeOps);
1530 }
1531 mPrivateLayout.showAppOpsIcons(activeOps);
1532 mPublicLayout.showAppOpsIcons(activeOps);
1533 }
1534
Julia Reynoldsb5867452018-02-28 16:31:35 -05001535 public View.OnClickListener getAppOpsOnClickListener() {
1536 return mOnAppOpsClickListener;
1537 }
1538
1539 protected void setAppOpsOnClickListener(ExpandableNotificationRow.OnAppOpsClickListener l) {
1540 mOnAppOpsClickListener = v -> {
1541 createMenu();
1542 MenuItem menuItem = getProvider().getAppOpsMenuItem(mContext);
1543 if (menuItem != null) {
1544 l.onClick(this, v.getWidth() / 2, v.getHeight() / 2, menuItem);
1545 }
1546 };
1547 }
1548
Jorim Jaggi251957d2014-04-09 04:24:09 +02001549 @Override
1550 protected void onFinishInflate() {
1551 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001552 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1553 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001554 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1555
1556 for (NotificationContentView l : mLayouts) {
1557 l.setExpandClickListener(mExpandClickListener);
1558 l.setContainingNotification(this);
1559 }
Selim Cinekab29aeb2015-02-20 18:18:32 +01001560 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1561 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001562 @Override
1563 public void onInflate(ViewStub stub, View inflated) {
1564 mGuts = (NotificationGuts) inflated;
1565 mGuts.setClipTopAmount(getClipTopAmount());
1566 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001567 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001568 }
1569 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001570 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1571 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1572
1573 @Override
1574 public void onInflate(ViewStub stub, View inflated) {
1575 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001576 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek414ad332017-02-24 19:06:12 -08001577 mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001578 mChildrenContainer.onNotificationUpdated();
Anthony Chen7acbb772017-04-07 16:45:25 -07001579
1580 if (mShouldTranslateContents) {
1581 mTranslateableViews.add(mChildrenContainer);
1582 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001583 }
1584 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001585
Anthony Chen7acbb772017-04-07 16:45:25 -07001586 if (mShouldTranslateContents) {
1587 // Add the views that we translate to reveal the menu
1588 mTranslateableViews = new ArrayList<>();
1589 for (int i = 0; i < getChildCount(); i++) {
1590 mTranslateableViews.add(getChildAt(i));
1591 }
1592 // Remove views that don't translate
1593 mTranslateableViews.remove(mChildrenContainerStub);
1594 mTranslateableViews.remove(mGutsStub);
Mady Mellor4b80b102016-01-22 08:03:58 -08001595 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001596 }
1597
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001598 private void doLongClickCallback() {
1599 doLongClickCallback(getWidth() / 2, getHeight() / 2);
1600 }
1601
1602 public void doLongClickCallback(int x, int y) {
1603 createMenu();
1604 MenuItem menuItem = getProvider().getLongpressMenuItem(mContext);
Mady Mellorb3a6aed2018-05-11 13:24:07 -07001605 doLongClickCallback(x, y, menuItem);
1606 }
1607
1608 private void doLongClickCallback(int x, int y, MenuItem menuItem) {
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001609 if (mLongPressListener != null && menuItem != null) {
1610 mLongPressListener.onLongPress(this, x, y, menuItem);
1611 }
1612 }
1613
1614 @Override
1615 public boolean onKeyDown(int keyCode, KeyEvent event) {
1616 if (KeyEvent.isConfirmKey(keyCode)) {
1617 event.startTracking();
1618 return true;
1619 }
1620 return super.onKeyDown(keyCode, event);
1621 }
1622
1623 @Override
1624 public boolean onKeyUp(int keyCode, KeyEvent event) {
1625 if (KeyEvent.isConfirmKey(keyCode)) {
1626 if (!event.isCanceled()) {
1627 performClick();
1628 }
1629 return true;
1630 }
1631 return super.onKeyUp(keyCode, event);
1632 }
1633
1634 @Override
1635 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
1636 if (KeyEvent.isConfirmKey(keyCode)) {
1637 doLongClickCallback();
1638 return true;
1639 }
1640 return false;
1641 }
1642
Mady Mellor4b80b102016-01-22 08:03:58 -08001643 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001644 if (mTranslateAnim != null) {
1645 mTranslateAnim.cancel();
1646 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001647
1648 if (!mShouldTranslateContents) {
1649 setTranslationX(0);
1650 } else if (mTranslateableViews != null) {
Mady Mellor4b80b102016-01-22 08:03:58 -08001651 for (int i = 0; i < mTranslateableViews.size(); i++) {
1652 mTranslateableViews.get(i).setTranslationX(0);
1653 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001654 invalidateOutline();
shawnlin4fbeac42018-04-30 20:32:40 +08001655 getEntry().expandedIcon.setScrollX(0);
Mady Mellor4b80b102016-01-22 08:03:58 -08001656 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001657
Mady Mellor95d743c2017-01-10 12:05:27 -08001658 mMenuRow.resetMenu();
Mady Mellor4b80b102016-01-22 08:03:58 -08001659 }
1660
Rohan Shah56eb0912018-05-10 21:49:04 -07001661 void onGutsOpened() {
1662 resetTranslation();
1663 updateContentAccessibilityImportanceForGuts(false /* isEnabled */);
1664 }
1665
1666 void onGutsClosed() {
1667 updateContentAccessibilityImportanceForGuts(true /* isEnabled */);
1668 }
1669
1670 /**
1671 * Updates whether all the non-guts content inside this row is important for accessibility.
1672 *
1673 * @param isEnabled whether the content views should be enabled for accessibility
1674 */
1675 private void updateContentAccessibilityImportanceForGuts(boolean isEnabled) {
1676 if (mChildrenContainer != null) {
1677 updateChildAccessibilityImportance(mChildrenContainer, isEnabled);
1678 }
1679 if (mLayouts != null) {
1680 for (View view : mLayouts) {
1681 updateChildAccessibilityImportance(view, isEnabled);
1682 }
1683 }
1684
1685 if (isEnabled) {
1686 this.requestAccessibilityFocus();
1687 }
1688 }
1689
1690 /**
1691 * Updates whether the given childView is important for accessibility based on
1692 * {@code isEnabled}.
1693 */
1694 private void updateChildAccessibilityImportance(View childView, boolean isEnabled) {
1695 childView.setImportantForAccessibility(isEnabled
1696 ? View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
1697 : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
1698 }
1699
Selim Cinekde4de0e2018-01-24 16:21:07 -08001700 public CharSequence getActiveRemoteInputText() {
1701 return mPrivateLayout.getActiveRemoteInputText();
1702 }
1703
Mady Mellor4b80b102016-01-22 08:03:58 -08001704 public void animateTranslateNotification(final float leftTarget) {
1705 if (mTranslateAnim != null) {
1706 mTranslateAnim.cancel();
1707 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001708 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001709 if (mTranslateAnim != null) {
1710 mTranslateAnim.start();
1711 }
1712 }
1713
1714 @Override
1715 public void setTranslation(float translationX) {
1716 if (areGutsExposed()) {
1717 // Don't translate if guts are showing.
1718 return;
1719 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001720 if (!mShouldTranslateContents) {
1721 setTranslationX(translationX);
1722 } else if (mTranslateableViews != null) {
1723 // Translate the group of views
1724 for (int i = 0; i < mTranslateableViews.size(); i++) {
1725 if (mTranslateableViews.get(i) != null) {
1726 mTranslateableViews.get(i).setTranslationX(translationX);
1727 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001728 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001729 invalidateOutline();
Selim Cinek143672c2018-03-23 20:04:32 -07001730
1731 // In order to keep the shelf in sync with this swiping, we're simply translating
1732 // it's icon by the same amount. The translation is already being used for the normal
1733 // positioning, so we can use the scrollX instead.
1734 getEntry().expandedIcon.setScrollX((int) -translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001735 }
Mady Mellor95d743c2017-01-10 12:05:27 -08001736 if (mMenuRow.getMenuView() != null) {
1737 mMenuRow.onTranslationUpdate(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001738 }
1739 }
1740
1741 @Override
1742 public float getTranslation() {
Anthony Chene04afcb2017-04-21 13:51:32 -07001743 if (!mShouldTranslateContents) {
Anthony Chen7acbb772017-04-07 16:45:25 -07001744 return getTranslationX();
1745 }
1746
Mady Mellor34958fa2016-02-23 09:52:17 -08001747 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1748 // All of the views in the list should have same translation, just use first one.
1749 return mTranslateableViews.get(0).getTranslationX();
1750 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001751
Mady Mellor34958fa2016-02-23 09:52:17 -08001752 return 0;
1753 }
1754
1755 public Animator getTranslateViewAnimator(final float leftTarget,
1756 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001757 if (mTranslateAnim != null) {
1758 mTranslateAnim.cancel();
1759 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001760 if (areGutsExposed()) {
1761 // No translation if guts are exposed.
1762 return null;
1763 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001764 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1765 leftTarget);
1766 if (listener != null) {
1767 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001768 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001769 translateAnim.addListener(new AnimatorListenerAdapter() {
1770 boolean cancelled = false;
1771
1772 @Override
1773 public void onAnimationCancel(Animator anim) {
1774 cancelled = true;
1775 }
1776
1777 @Override
1778 public void onAnimationEnd(Animator anim) {
Mady Mellor95d743c2017-01-10 12:05:27 -08001779 if (!cancelled && leftTarget == 0) {
1780 mMenuRow.resetMenu();
Mady Mellorb0a82462016-04-30 17:31:02 -07001781 mTranslateAnim = null;
1782 }
1783 }
1784 });
1785 mTranslateAnim = translateAnim;
1786 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001787 }
1788
Selim Cinekab29aeb2015-02-20 18:18:32 +01001789 public void inflateGuts() {
1790 if (mGuts == null) {
1791 mGutsStub.inflate();
1792 }
1793 }
1794
Selim Cinekda42d652015-12-04 15:51:16 -08001795 private void updateChildrenVisibility() {
Selim Cinek7fa385a2018-01-24 08:35:28 -08001796 boolean hideContentWhileLaunching = mExpandAnimationRunning && mGuts != null
1797 && mGuts.isExposed();
1798 mPrivateLayout.setVisibility(!shouldShowPublic() && !mIsSummaryWithChildren
1799 && !hideContentWhileLaunching ? VISIBLE : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001800 if (mChildrenContainer != null) {
Selim Cinek7fa385a2018-01-24 08:35:28 -08001801 mChildrenContainer.setVisibility(!shouldShowPublic() && mIsSummaryWithChildren
1802 && !hideContentWhileLaunching ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001803 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001804 }
Selim Cinekda42d652015-12-04 15:51:16 -08001805 // The limits might have changed if the view suddenly became a group or vice versa
1806 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001807 }
1808
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001809 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001810 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1811 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001812 // Add a record for the entire layout since its content is somehow small.
1813 // The event comes from a leaf view that is interacted with.
1814 AccessibilityEvent record = AccessibilityEvent.obtain();
1815 onInitializeAccessibilityEvent(record);
1816 dispatchPopulateAccessibilityEvent(record);
1817 event.appendRecord(record);
1818 return true;
1819 }
1820 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001821 }
Chris Wren51c75102013-07-16 20:49:17 -04001822
John Spurlocke15452b2014-08-21 09:44:39 -04001823 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001824 public void setDark(boolean dark, boolean fade, long delay) {
1825 super.setDark(dark, fade, delay);
Lucas Dupincecc7c22017-09-12 16:02:45 -07001826 mDark = dark;
Adrian Roos28f90c72017-05-08 17:24:26 -07001827 if (!mIsHeadsUp) {
1828 // Only fade the showing view of the pulsing notification.
1829 fade = false;
1830 }
John Spurlocke15452b2014-08-21 09:44:39 -04001831 final NotificationContentView showing = getShowingLayout();
1832 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001833 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001834 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001835 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001836 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001837 }
Selim Cineka7c69632017-06-07 15:51:29 -07001838 updateShelfIconColor();
John Spurlocke15452b2014-08-21 09:44:39 -04001839 }
1840
Selim Cinek2627d722018-01-19 12:16:49 -08001841 public void applyExpandAnimationParams(ExpandAnimationParameters params) {
1842 if (params == null) {
1843 return;
1844 }
Selim Cinek2627d722018-01-19 12:16:49 -08001845 float zProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
1846 params.getProgress(0, 50));
1847 float translationZ = MathUtils.lerp(params.getStartTranslationZ(),
1848 mNotificationLaunchHeight,
1849 zProgress);
1850 setTranslationZ(translationZ);
Selim Cinekc25989e2018-02-16 16:42:14 -08001851 float extraWidthForClipping = params.getWidth() - getWidth()
1852 + MathUtils.lerp(0, mOutlineRadius * 2, params.getProgress());
1853 setExtraWidthForClipping(extraWidthForClipping);
1854 int top = params.getTop();
1855 float interpolation = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(params.getProgress());
1856 int startClipTopAmount = params.getStartClipTopAmount();
1857 if (mNotificationParent != null) {
1858 top -= mNotificationParent.getTranslationY();
1859 mNotificationParent.setTranslationZ(translationZ);
1860 int parentStartClipTopAmount = params.getParentStartClipTopAmount();
1861 if (startClipTopAmount != 0) {
1862 int clipTopAmount = (int) MathUtils.lerp(parentStartClipTopAmount,
1863 parentStartClipTopAmount - startClipTopAmount,
1864 interpolation);
1865 mNotificationParent.setClipTopAmount(clipTopAmount);
1866 }
1867 mNotificationParent.setExtraWidthForClipping(extraWidthForClipping);
1868 mNotificationParent.setMinimumHeightForClipping(params.getHeight()
1869 + mNotificationParent.getActualHeight());
1870 } else if (startClipTopAmount != 0) {
1871 int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, interpolation);
1872 setClipTopAmount(clipTopAmount);
1873 }
1874 setTranslationY(top);
Selim Cinek2627d722018-01-19 12:16:49 -08001875 setActualHeight(params.getHeight());
Selim Cinekc25989e2018-02-16 16:42:14 -08001876
Selim Cinek2627d722018-01-19 12:16:49 -08001877 mBackgroundNormal.setExpandAnimationParams(params);
1878 }
1879
1880 public void setExpandAnimationRunning(boolean expandAnimationRunning) {
Selim Cinekc25989e2018-02-16 16:42:14 -08001881 View contentView;
1882 if (mIsSummaryWithChildren) {
1883 contentView = mChildrenContainer;
1884 } else {
1885 contentView = getShowingLayout();
1886 }
1887 if (mGuts != null && mGuts.isExposed()) {
1888 contentView = mGuts;
1889 }
Selim Cinek2627d722018-01-19 12:16:49 -08001890 if (expandAnimationRunning) {
Selim Cinek2627d722018-01-19 12:16:49 -08001891 contentView.animate()
1892 .alpha(0f)
1893 .setDuration(ActivityLaunchAnimator.ANIMATION_DURATION_FADE_CONTENT)
1894 .setInterpolator(Interpolators.ALPHA_OUT);
1895 setAboveShelf(true);
1896 mExpandAnimationRunning = true;
1897 mNotificationViewState.cancelAnimations(this);
1898 mNotificationLaunchHeight = AmbientState.getNotificationLaunchHeight(getContext());
1899 } else {
1900 mExpandAnimationRunning = false;
1901 setAboveShelf(isAboveShelf());
Selim Cinek7fa385a2018-01-24 08:35:28 -08001902 if (mGuts != null) {
1903 mGuts.setAlpha(1.0f);
1904 }
Selim Cinekc25989e2018-02-16 16:42:14 -08001905 if (contentView != null) {
1906 contentView.setAlpha(1.0f);
1907 }
1908 setExtraWidthForClipping(0.0f);
1909 if (mNotificationParent != null) {
1910 mNotificationParent.setExtraWidthForClipping(0.0f);
1911 mNotificationParent.setMinimumHeightForClipping(0);
1912 }
1913 }
1914 if (mNotificationParent != null) {
1915 mNotificationParent.setChildIsExpanding(mExpandAnimationRunning);
Selim Cinek2627d722018-01-19 12:16:49 -08001916 }
Selim Cinek7fa385a2018-01-24 08:35:28 -08001917 updateChildrenVisibility();
Selim Cinek2627d722018-01-19 12:16:49 -08001918 updateClipping();
1919 mBackgroundNormal.setExpandAnimationRunning(expandAnimationRunning);
1920 }
1921
Selim Cinekc25989e2018-02-16 16:42:14 -08001922 private void setChildIsExpanding(boolean isExpanding) {
1923 mChildIsExpanding = isExpanding;
1924 }
1925
1926 @Override
1927 public boolean hasExpandingChild() {
1928 return mChildIsExpanding;
1929 }
1930
Selim Cinek2627d722018-01-19 12:16:49 -08001931 @Override
1932 protected boolean shouldClipToActualHeight() {
Selim Cinekc25989e2018-02-16 16:42:14 -08001933 return super.shouldClipToActualHeight() && !mExpandAnimationRunning && !mChildIsExpanding;
Selim Cinek2627d722018-01-19 12:16:49 -08001934 }
1935
1936 @Override
1937 public boolean isExpandAnimationRunning() {
1938 return mExpandAnimationRunning;
1939 }
1940
Lucas Dupincecc7c22017-09-12 16:02:45 -07001941 /**
1942 * Tap sounds should not be played when we're unlocking.
1943 * Doing so would cause audio collision and the system would feel unpolished.
1944 */
1945 @Override
1946 public boolean isSoundEffectsEnabled() {
1947 final boolean mute = mDark && mSecureStateProvider != null &&
1948 !mSecureStateProvider.getAsBoolean();
1949 return !mute && super.isSoundEffectsEnabled();
1950 }
1951
Chris Wren51c75102013-07-16 20:49:17 -04001952 public boolean isExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08001953 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001954 return !mChildrenExpanded;
1955 }
Anthony Chen6bf88a02017-04-10 14:41:44 -07001956 return mEnableNonGroupedNotificationExpand && mExpandable;
Chris Wren51c75102013-07-16 20:49:17 -04001957 }
1958
1959 public void setExpandable(boolean expandable) {
1960 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001961 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001962 }
1963
Selim Cinek4ffd6362015-12-29 15:12:23 +01001964 @Override
1965 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001966 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1967 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001968 }
1969
Selim Cinek1685e632014-04-08 02:27:49 +02001970 /**
1971 * @return whether the user has changed the expansion state
1972 */
1973 public boolean hasUserChangedExpansion() {
1974 return mHasUserChangedExpansion;
1975 }
1976
Chris Wren51c75102013-07-16 20:49:17 -04001977 public boolean isUserExpanded() {
1978 return mUserExpanded;
1979 }
1980
Selim Cinek1685e632014-04-08 02:27:49 +02001981 /**
1982 * Set this notification to be expanded by the user
1983 *
1984 * @param userExpanded whether the user wants this notification to be expanded
1985 */
Chris Wren51c75102013-07-16 20:49:17 -04001986 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001987 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1988 }
1989
1990 /**
1991 * Set this notification to be expanded by the user
1992 *
1993 * @param userExpanded whether the user wants this notification to be expanded
1994 * @param allowChildExpansion whether a call to this method allows expanding children
1995 */
1996 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001997 mFalsingManager.setNotificationExpanded();
Selim Cinek0b9cf462017-12-07 16:31:03 -08001998 if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
Selim Cinek414ad332017-02-24 19:06:12 -08001999 && !mChildrenContainer.showingAsLowPriority()) {
Chris Wren698b1702016-05-23 11:16:32 -04002000 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07002001 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -08002002 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07002003 return;
2004 }
Christoph Studera7fe6312014-06-27 19:32:44 +02002005 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01002006 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02002007 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04002008 mUserExpanded = userExpanded;
Selim Cinek414ad332017-02-24 19:06:12 -08002009 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002010 if (!wasExpanded && isExpanded()
2011 && getActualHeight() != getIntrinsicHeight()) {
2012 notifyHeightChanged(true /* needsAnimation */);
2013 }
Chris Wren51c75102013-07-16 20:49:17 -04002014 }
2015
Selim Cinekccd14fb2014-08-12 18:53:24 +02002016 public void resetUserExpansion() {
Selim Cinek414ad332017-02-24 19:06:12 -08002017 boolean changed = mUserExpanded;
Selim Cinekccd14fb2014-08-12 18:53:24 +02002018 mHasUserChangedExpansion = false;
2019 mUserExpanded = false;
Selim Cinek414ad332017-02-24 19:06:12 -08002020 if (changed && mIsSummaryWithChildren) {
2021 mChildrenContainer.onExpansionChanged();
2022 }
2023 updateShelfIconColor();
Selim Cinekccd14fb2014-08-12 18:53:24 +02002024 }
2025
Chris Wren51c75102013-07-16 20:49:17 -04002026 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07002027 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04002028 }
2029
2030 public void setUserLocked(boolean userLocked) {
2031 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08002032 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07002033 // This is intentionally not guarded with mIsSummaryWithChildren since we might have had
2034 // children but not anymore.
2035 if (mChildrenContainer != null) {
Selim Cinek42357e02016-02-24 18:48:01 -08002036 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07002037 if (mIsSummaryWithChildren && (userLocked || !isGroupExpanded())) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002038 updateBackgroundForGroupState();
2039 }
Selim Cinek42357e02016-02-24 18:48:01 -08002040 }
Chris Wren51c75102013-07-16 20:49:17 -04002041 }
2042
Selim Cinek1685e632014-04-08 02:27:49 +02002043 /**
2044 * @return has the system set this notification to be expanded
2045 */
2046 public boolean isSystemExpanded() {
2047 return mIsSystemExpanded;
2048 }
2049
2050 /**
2051 * Set this notification to be expanded by the system.
2052 *
2053 * @param expand whether the system wants this notification to be expanded.
2054 */
2055 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02002056 if (expand != mIsSystemExpanded) {
2057 final boolean wasExpanded = isExpanded();
2058 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01002059 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek414ad332017-02-24 19:06:12 -08002060 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07002061 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07002062 mChildrenContainer.updateGroupOverflow();
2063 }
Selim Cinek31094df2014-08-14 19:28:15 +02002064 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02002065 }
2066
2067 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07002068 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02002069 */
Selim Cinek83bc7832015-10-22 13:26:54 -07002070 public void setOnKeyguard(boolean onKeyguard) {
2071 if (onKeyguard != mOnKeyguard) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07002072 boolean wasAboveShelf = isAboveShelf();
Selim Cinek31094df2014-08-14 19:28:15 +02002073 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07002074 mOnKeyguard = onKeyguard;
Selim Cinek414ad332017-02-24 19:06:12 -08002075 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cinek31094df2014-08-14 19:28:15 +02002076 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07002077 if (mIsSummaryWithChildren) {
2078 mChildrenContainer.updateGroupOverflow();
2079 }
Mady Mellor4b80b102016-01-22 08:03:58 -08002080 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02002081 }
Selim Cinek5cf1d052017-06-01 17:36:46 -07002082 if (isAboveShelf() != wasAboveShelf) {
2083 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
2084 }
Selim Cinek31094df2014-08-14 19:28:15 +02002085 }
Selim Cinekfe24fb72018-02-13 14:34:55 -08002086 updateRippleAllowed();
2087 }
2088
2089 private void updateRippleAllowed() {
2090 boolean allowed = isOnKeyguard()
2091 || mEntry.notification.getNotification().contentIntent == null;
2092 setRippleAllowed(allowed);
Selim Cinek1685e632014-04-08 02:27:49 +02002093 }
2094
2095 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07002096 * @return Can the underlying notification be cleared? This can be different from whether the
2097 * notification can be dismissed in case notifications are sensitive on the lockscreen.
2098 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04002099 */
2100 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07002101 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
2102 return false;
2103 }
2104 if (mIsSummaryWithChildren) {
2105 List<ExpandableNotificationRow> notificationChildren =
2106 mChildrenContainer.getNotificationChildren();
2107 for (int i = 0; i < notificationChildren.size(); i++) {
2108 ExpandableNotificationRow child = notificationChildren.get(i);
2109 if (!child.isClearable()) {
2110 return false;
2111 }
2112 }
2113 }
2114 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04002115 }
2116
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02002117 @Override
2118 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02002119 if (isUserLocked()) {
2120 return getActualHeight();
2121 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002122 if (mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07002123 return mGuts.getIntrinsicHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08002124 } else if ((isChildInGroup() && !isGroupExpanded())) {
2125 return mPrivateLayout.getMinHeight();
2126 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
2127 return getMinHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07002128 } else if (mIsSummaryWithChildren && (!mOnKeyguard || mShowAmbient)) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002129 return mChildrenContainer.getIntrinsicHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07002130 } else if (isHeadsUpAllowed() && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07002131 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08002132 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
2133 } else if (isExpanded()) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002134 return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
Selim Cinek8d490d42015-04-10 00:05:50 -07002135 } else {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002136 return Math.max(getCollapsedHeight(), getHeadsUpHeight());
Selim Cinek8d490d42015-04-10 00:05:50 -07002137 }
Selim Cinek31aada42015-12-18 17:51:15 -08002138 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07002139 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08002140 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07002141 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02002142 }
Selim Cinekb5605e52015-02-20 18:21:41 +01002143 }
Selim Cinek1685e632014-04-08 02:27:49 +02002144
Adrian Roos6f6e1592017-05-02 16:22:53 -07002145 private boolean isHeadsUpAllowed() {
2146 return !mOnKeyguard && !mShowAmbient;
2147 }
2148
Mady Mellor43c2cd12016-12-12 21:05:13 -08002149 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07002150 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07002151 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01002152 }
2153
Selim Cinek263398f2015-10-21 17:40:23 -07002154 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05002155 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07002156 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
2157 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
Selim Cinek414ad332017-02-24 19:06:12 -08002158 mChildrenContainer.recreateNotificationHeader(mExpandClickListener
2159 );
Selim Cinek263398f2015-10-21 17:40:23 -07002160 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07002161 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002162 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08002163 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08002164 updateChildrenVisibility();
Selim Cinek2871bef2017-11-22 08:40:00 -08002165 applyChildrenRoundness();
Selim Cinek263398f2015-10-21 17:40:23 -07002166 }
Rohan Shah63411fc2018-03-28 19:05:52 -07002167 /**
2168 * Returns the number of channels covered by the notification row (including its children if
2169 * it's a summary notification).
2170 */
2171 public int getNumUniqueChannels() {
2172 ArraySet<NotificationChannel> channels = new ArraySet<>();
2173
2174 channels.add(mEntry.channel);
2175
2176 // If this is a summary, then add in the children notification channels for the
2177 // same user and pkg.
2178 if (mIsSummaryWithChildren) {
2179 final List<ExpandableNotificationRow> childrenRows = getNotificationChildren();
2180 final int numChildren = childrenRows.size();
2181 for (int i = 0; i < numChildren; i++) {
2182 final ExpandableNotificationRow childRow = childrenRows.get(i);
2183 final NotificationChannel childChannel = childRow.getEntry().channel;
2184 final StatusBarNotification childSbn = childRow.getStatusBarNotification();
2185 if (childSbn.getUser().equals(mStatusBarNotification.getUser()) &&
2186 childSbn.getPackageName().equals(mStatusBarNotification.getPackageName())) {
2187 channels.add(childChannel);
2188 }
2189 }
2190 }
2191 return channels.size();
2192 }
Selim Cinek263398f2015-10-21 17:40:23 -07002193
Mady Mellorb0a82462016-04-30 17:31:02 -07002194 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07002195 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002196 mChildrenContainer.updateChildrenHeaderAppearance();
2197 }
2198 }
2199
Selim Cinek1685e632014-04-08 02:27:49 +02002200 /**
2201 * Check whether the view state is currently expanded. This is given by the system in {@link
2202 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
2203 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
2204 * view can differ from this state, if layout params are modified from outside.
2205 *
2206 * @return whether the view state is currently expanded.
2207 */
Selim Cinek83bc7832015-10-22 13:26:54 -07002208 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08002209 return isExpanded(false /* allowOnKeyguard */);
2210 }
2211
2212 public boolean isExpanded(boolean allowOnKeyguard) {
2213 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01002214 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
2215 || isUserExpanded());
2216 }
2217
2218 private boolean isSystemChildExpanded() {
2219 return mIsSystemChildExpanded;
2220 }
2221
2222 public void setSystemChildExpanded(boolean expanded) {
2223 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02002224 }
2225
Mady Mellor035badd2017-04-04 18:45:30 -07002226 public void setLayoutListener(LayoutListener listener) {
2227 mLayoutListener = listener;
2228 }
2229
2230 public void removeListener() {
2231 mLayoutListener = null;
2232 }
2233
Selim Cinek1685e632014-04-08 02:27:49 +02002234 @Override
2235 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002236 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02002237 super.onLayout(changed, left, top, right, bottom);
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002238 if (intrinsicBefore != getIntrinsicHeight()) {
2239 notifyHeightChanged(true /* needsAnimation */);
2240 }
Mady Mellor95d743c2017-01-10 12:05:27 -08002241 if (mMenuRow.getMenuView() != null) {
2242 mMenuRow.onHeightUpdate();
Mady Mellora6edc872016-04-26 11:01:03 -07002243 }
Selim Cinek875a3a12016-11-18 17:52:16 -08002244 updateContentShiftHeight();
Mady Mellor035badd2017-04-04 18:45:30 -07002245 if (mLayoutListener != null) {
2246 mLayoutListener.onLayout();
2247 }
Selim Cinek875a3a12016-11-18 17:52:16 -08002248 }
2249
2250 /**
2251 * Updates the content shift height such that the header is completely hidden when coming from
2252 * the top.
2253 */
2254 private void updateContentShiftHeight() {
Selim Cinek414ad332017-02-24 19:06:12 -08002255 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek875a3a12016-11-18 17:52:16 -08002256 if (notificationHeader != null) {
2257 CachingIconView icon = notificationHeader.getIcon();
2258 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
2259 } else {
2260 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
2261 }
Selim Cinek1685e632014-04-08 02:27:49 +02002262 }
2263
Selim Cinekfa0a2d32016-01-14 13:02:21 -08002264 @Override
2265 public void notifyHeightChanged(boolean needsAnimation) {
2266 super.notifyHeightChanged(needsAnimation);
2267 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
2268 }
2269
Selim Cinek3c76d502016-02-19 15:16:33 -08002270 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02002271 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08002272 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02002273 }
2274
Mady Mellor43c2cd12016-12-12 21:05:13 -08002275 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02002276 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07002277 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08002278 if (mIsSummaryWithChildren) {
2279 List<ExpandableNotificationRow> notificationChildren =
2280 mChildrenContainer.getNotificationChildren();
2281 for (int i = 0; i < notificationChildren.size(); i++) {
2282 ExpandableNotificationRow child = notificationChildren.get(i);
2283 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
2284 }
2285 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002286 }
2287
Mady Mellor43c2cd12016-12-12 21:05:13 -08002288 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02002289 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
2290 long duration) {
Selim Cinek69594fb2018-05-18 12:06:10 -07002291 if (getVisibility() == GONE) {
2292 // If we are GONE, the hideSensitive parameter will not be calculated and always be
2293 // false, which is incorrect, let's wait until a real call comes in later.
2294 return;
2295 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002296 boolean oldShowingPublic = mShowingPublic;
2297 mShowingPublic = mSensitive && hideSensitive;
2298 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
2299 return;
2300 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05002301
2302 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02002303 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002304
Jorim Jaggiae441282014-08-01 02:45:18 +02002305 if (!animated) {
2306 mPublicLayout.animate().cancel();
2307 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07002308 if (mChildrenContainer != null) {
2309 mChildrenContainer.animate().cancel();
2310 mChildrenContainer.setAlpha(1f);
2311 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002312 mPublicLayout.setAlpha(1f);
2313 mPrivateLayout.setAlpha(1f);
2314 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08002315 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02002316 } else {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002317 animateShowingPublic(delay, duration, mShowingPublic);
Jorim Jaggiae441282014-08-01 02:45:18 +02002318 }
Selim Cinekc3179332016-03-04 14:44:56 -08002319 NotificationContentView showingLayout = getShowingLayout();
2320 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002321 mPrivateLayout.updateExpandButtons(isExpandable());
Lucas Dupinb6ed63b2017-05-30 16:17:42 -07002322 updateShelfIconColor();
Adrian Roose5726a22016-12-19 14:26:51 -08002323 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02002324 mShowingPublicInitialized = true;
2325 }
2326
Selim Cinek0b9cf462017-12-07 16:31:03 -08002327 private void animateShowingPublic(long delay, long duration, boolean showingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002328 View[] privateViews = mIsSummaryWithChildren
2329 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08002330 : new View[] {mPrivateLayout};
2331 View[] publicViews = new View[] {mPublicLayout};
Selim Cinek0b9cf462017-12-07 16:31:03 -08002332 View[] hiddenChildren = showingPublic ? privateViews : publicViews;
2333 View[] shownChildren = showingPublic ? publicViews : privateViews;
Selim Cinekd84a5932015-12-15 11:45:36 -08002334 for (final View hiddenView : hiddenChildren) {
2335 hiddenView.setVisibility(View.VISIBLE);
2336 hiddenView.animate().cancel();
2337 hiddenView.animate()
2338 .alpha(0f)
2339 .setStartDelay(delay)
2340 .setDuration(duration)
2341 .withEndAction(new Runnable() {
2342 @Override
2343 public void run() {
2344 hiddenView.setVisibility(View.INVISIBLE);
2345 }
2346 });
2347 }
2348 for (View showView : shownChildren) {
2349 showView.setVisibility(View.VISIBLE);
2350 showView.setAlpha(0f);
2351 showView.animate().cancel();
2352 showView.animate()
2353 .alpha(1f)
2354 .setStartDelay(delay)
2355 .setDuration(duration);
2356 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04002357 }
2358
Mady Mellor43c2cd12016-12-12 21:05:13 -08002359 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08002360 public boolean mustStayOnScreen() {
Selim Cinek9b9d6e12017-11-30 12:29:47 +01002361 return mIsHeadsUp && mMustStayOnScreen;
Selim Cinek3776fe02016-02-04 13:32:43 -08002362 }
2363
Selim Cinek9e624e72016-07-20 13:46:49 -07002364 /**
2365 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
2366 * otherwise some state might not be updated. To request about the general clearability
2367 * see {@link #isClearable()}.
2368 */
2369 public boolean canViewBeDismissed() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002370 return isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
2371 }
2372
2373 private boolean shouldShowPublic() {
2374 return mSensitive && mHideSensitiveForIntrinsicHeight;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002375 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02002376
Ricky Waicd35def2016-05-03 11:07:07 +01002377 public void makeActionsVisibile() {
2378 setUserExpanded(true, true);
2379 if (isChildInGroup()) {
2380 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
2381 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07002382 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01002383 }
2384
Selim Cinekb5605e52015-02-20 18:21:41 +01002385 public void setChildrenExpanded(boolean expanded, boolean animate) {
2386 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07002387 if (mChildrenContainer != null) {
2388 mChildrenContainer.setChildrenExpanded(expanded);
2389 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07002390 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07002391 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01002392 }
2393
Selim Cinekb5605e52015-02-20 18:21:41 +01002394 public static void applyTint(View v, int color) {
2395 int alpha;
2396 if (color != 0) {
2397 alpha = COLORED_DIVIDER_ALPHA;
2398 } else {
2399 color = 0xff000000;
2400 alpha = DEFAULT_DIVIDER_ALPHA;
2401 }
2402 if (v.getBackground() instanceof ColorDrawable) {
2403 ColorDrawable background = (ColorDrawable) v.getBackground();
2404 background.mutate();
2405 background.setColor(color);
2406 background.setAlpha(alpha);
2407 }
2408 }
2409
Selim Cinek1685e632014-04-08 02:27:49 +02002410 public int getMaxExpandHeight() {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002411 return mPrivateLayout.getExpandHeight();
2412 }
2413
2414
2415 private int getHeadsUpHeight() {
2416 return mPrivateLayout.getHeadsUpHeight();
Chris Wren51c75102013-07-16 20:49:17 -04002417 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02002418
Mady Mellor34958fa2016-02-23 09:52:17 -08002419 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002420 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08002421 }
2422
Jorim Jaggibe565df2014-04-28 17:51:23 +02002423 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002424 public boolean isContentExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002425 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002426 return true;
2427 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002428 NotificationContentView showingLayout = getShowingLayout();
2429 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002430 }
2431
2432 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07002433 protected View getContentView() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002434 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cineka5703182016-05-11 21:23:16 -04002435 return mChildrenContainer;
2436 }
Selim Cinek560e64d2015-06-09 19:58:11 -07002437 return getShowingLayout();
2438 }
2439
2440 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07002441 protected void onAppearAnimationFinished(boolean wasAppearing) {
2442 super.onAppearAnimationFinished(wasAppearing);
2443 if (wasAppearing) {
2444 // During the animation the visible view might have changed, so let's make sure all
2445 // alphas are reset
2446 if (mChildrenContainer != null) {
2447 mChildrenContainer.setAlpha(1.0f);
2448 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
2449 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08002450 for (NotificationContentView l : mLayouts) {
2451 l.setAlpha(1.0f);
2452 l.setLayerType(LAYER_TYPE_NONE, null);
2453 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07002454 }
2455 }
2456
2457 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07002458 public int getExtraBottomPadding() {
2459 if (mIsSummaryWithChildren && isGroupExpanded()) {
2460 return mIncreasedPaddingBetweenElements;
2461 }
2462 return 0;
2463 }
2464
2465 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02002466 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinek4ca6c632017-02-23 18:03:37 -08002467 boolean changed = height != getActualHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +01002468 super.setActualHeight(height, notifyListeners);
Selim Cinek4ca6c632017-02-23 18:03:37 -08002469 if (changed && isRemoved()) {
2470 // TODO: remove this once we found the gfx bug for this.
2471 // This is a hack since a removed view sometimes would just stay blank. it occured
2472 // when sending yourself a message and then clicking on it.
2473 ViewGroup parent = (ViewGroup) getParent();
2474 if (parent != null) {
2475 parent.invalidate();
2476 }
2477 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002478 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08002479 mGuts.setActualHeight(height);
2480 return;
2481 }
Selim Cinekeef84282015-10-30 16:28:00 -07002482 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002483 for (NotificationContentView l : mLayouts) {
2484 l.setContentHeight(contentHeight);
2485 }
Selim Cinek42357e02016-02-24 18:48:01 -08002486 if (mIsSummaryWithChildren) {
2487 mChildrenContainer.setActualHeight(height);
2488 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002489 if (mGuts != null) {
2490 mGuts.setActualHeight(height);
2491 }
Mady Mellor54540972017-06-07 11:55:36 -07002492 if (mMenuRow.getMenuView() != null) {
2493 mMenuRow.onHeightUpdate();
2494 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002495 }
2496
2497 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01002498 public int getMaxContentHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002499 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002500 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002501 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002502 NotificationContentView showingLayout = getShowingLayout();
2503 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02002504 }
2505
2506 @Override
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002507 public int getMinHeight(boolean ignoreTemporaryStates) {
2508 if (!ignoreTemporaryStates && mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07002509 return mGuts.getIntrinsicHeight();
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002510 } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp
2511 && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08002512 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
Selim Cinek0b9cf462017-12-07 16:31:03 -08002513 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !shouldShowPublic()) {
Selim Cinekb55386d2015-12-16 17:26:49 -08002514 return mChildrenContainer.getMinHeight();
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002515 } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002516 return getHeadsUpHeight();
Selim Cinekb55386d2015-12-16 17:26:49 -08002517 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002518 NotificationContentView showingLayout = getShowingLayout();
2519 return showingLayout.getMinHeight();
2520 }
2521
2522 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07002523 public int getCollapsedHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002524 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek567e8452016-03-24 10:54:56 -07002525 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002526 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002527 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002528 }
2529
2530 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02002531 public void setClipTopAmount(int clipTopAmount) {
2532 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002533 for (NotificationContentView l : mLayouts) {
2534 l.setClipTopAmount(clipTopAmount);
2535 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002536 if (mGuts != null) {
2537 mGuts.setClipTopAmount(clipTopAmount);
2538 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002539 }
2540
Selim Cineka686b2c2016-10-26 13:58:27 -07002541 @Override
2542 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek2627d722018-01-19 12:16:49 -08002543 if (mExpandAnimationRunning) {
2544 return;
2545 }
Selim Cinek65d418e2016-11-29 15:42:34 -08002546 if (clipBottomAmount != mClipBottomAmount) {
2547 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002548 for (NotificationContentView l : mLayouts) {
2549 l.setClipBottomAmount(clipBottomAmount);
2550 }
Selim Cinek65d418e2016-11-29 15:42:34 -08002551 if (mGuts != null) {
2552 mGuts.setClipBottomAmount(clipBottomAmount);
2553 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002554 }
Selim Cinekc25989e2018-02-16 16:42:14 -08002555 if (mChildrenContainer != null && !mChildIsExpanding) {
Selim Cinek65d418e2016-11-29 15:42:34 -08002556 // We have to update this even if it hasn't changed, since the children locations can
2557 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08002558 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
2559 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002560 }
2561
Selim Cinek42357e02016-02-24 18:48:01 -08002562 public NotificationContentView getShowingLayout() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002563 return shouldShowPublic() ? mPublicLayout : mPrivateLayout;
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002564 }
Chris Wren78403d72014-07-28 10:23:24 +01002565
Selim Cinek1a48bab2017-02-17 19:38:40 -08002566 public void setLegacy(boolean legacy) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08002567 for (NotificationContentView l : mLayouts) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08002568 l.setLegacy(legacy);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002569 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07002570 }
2571
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002572 @Override
2573 protected void updateBackgroundTint() {
2574 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07002575 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002576 if (mIsSummaryWithChildren) {
2577 List<ExpandableNotificationRow> notificationChildren =
2578 mChildrenContainer.getNotificationChildren();
2579 for (int i = 0; i < notificationChildren.size(); i++) {
2580 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07002581 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002582 }
2583 }
2584 }
2585
Mady Mellorb0a82462016-04-30 17:31:02 -07002586 /**
2587 * Called when a group has finished animating from collapsed or expanded state.
2588 */
2589 public void onFinishedExpansionChange() {
2590 mGroupExpansionChanging = false;
2591 updateBackgroundForGroupState();
2592 }
2593
2594 /**
2595 * Updates the parent and children backgrounds in a group based on the expansion state.
2596 */
2597 public void updateBackgroundForGroupState() {
2598 if (mIsSummaryWithChildren) {
2599 // Only when the group has finished expanding do we hide its background.
Anthony Chen6bf88a02017-04-10 14:41:44 -07002600 mShowNoBackground = !mShowGroupBackgroundWhenExpanded && isGroupExpanded()
2601 && !isGroupExpansionChanging() && !isUserLocked();
Mady Mellorb0a82462016-04-30 17:31:02 -07002602 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
2603 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
2604 for (int i = 0; i < children.size(); i++) {
2605 children.get(i).updateBackgroundForGroupState();
2606 }
2607 } else if (isChildInGroup()) {
2608 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
2609 // Only show a background if the group is expanded OR if it is expanding / collapsing
Anthony Chen6bf88a02017-04-10 14:41:44 -07002610 // and has a custom background color.
Mady Mellorb0a82462016-04-30 17:31:02 -07002611 final boolean showBackground = isGroupExpanded()
2612 || ((mNotificationParent.isGroupExpansionChanging()
Anthony Chen6bf88a02017-04-10 14:41:44 -07002613 || mNotificationParent.isUserLocked()) && childColor != 0);
Mady Mellorb0a82462016-04-30 17:31:02 -07002614 mShowNoBackground = !showBackground;
2615 } else {
2616 // Only children or parents ever need no background.
2617 mShowNoBackground = false;
2618 }
2619 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002620 updateBackground();
2621 }
2622
Adrian Roos4a579672016-05-24 16:54:37 -07002623 public int getPositionOfChild(ExpandableNotificationRow childRow) {
2624 if (mIsSummaryWithChildren) {
2625 return mChildrenContainer.getPositionInLinearLayout(childRow);
2626 }
2627 return 0;
2628 }
2629
Chris Wren78403d72014-07-28 10:23:24 +01002630 public void setExpansionLogger(ExpansionLogger logger, String key) {
2631 mLogger = logger;
2632 mLoggingKey = key;
2633 }
2634
Chris Wren6abeeb92016-05-26 14:44:38 -04002635 public void onExpandedByGesture(boolean userExpanded) {
2636 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
2637 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
2638 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
2639 }
2640 MetricsLogger.action(mContext, event, userExpanded);
2641 }
2642
Selim Cinek6183d122016-01-14 18:48:41 -08002643 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08002644 public float getIncreasedPaddingAmount() {
2645 if (mIsSummaryWithChildren) {
2646 if (isGroupExpanded()) {
2647 return 1.0f;
2648 } else if (isUserLocked()) {
Selim Cinek414ad332017-02-24 19:06:12 -08002649 return mChildrenContainer.getIncreasedPaddingAmount();
Selim Cinek42357e02016-02-24 18:48:01 -08002650 }
Selim Cinek99104832017-01-25 14:47:33 -08002651 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08002652 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08002653 }
2654 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08002655 }
2656
Selim Cineka7ed2c12017-01-23 20:47:24 -08002657 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08002658 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08002659 }
2660
Selim Cinek61633a82016-01-25 15:54:10 -08002661 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08002662 protected boolean disallowSingleClick(MotionEvent event) {
dongwan0605.kimc4ddef42018-05-06 17:40:23 +09002663 if (areGutsExposed()) {
2664 return false;
2665 }
Selim Cinek6183d122016-01-14 18:48:41 -08002666 float x = event.getX();
2667 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08002668 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002669 if (header != null && header.isInTouchRect(x - getTranslation(), y)) {
2670 return true;
2671 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002672 if ((!mIsSummaryWithChildren || shouldShowPublic())
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002673 && getShowingLayout().disallowSingleClick(x, y)) {
2674 return true;
Selim Cinek6183d122016-01-14 18:48:41 -08002675 }
2676 return super.disallowSingleClick(event);
2677 }
2678
Selim Cinek414ad332017-02-24 19:06:12 -08002679 private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04002680 boolean nowExpanded = isExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08002681 if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
Chris Wren698b1702016-05-23 11:16:32 -04002682 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
2683 }
Selim Cinek414ad332017-02-24 19:06:12 -08002684 if (nowExpanded != wasExpanded) {
2685 updateShelfIconColor();
2686 if (mLogger != null) {
2687 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded);
2688 }
2689 if (mIsSummaryWithChildren) {
2690 mChildrenContainer.onExpansionChanged();
2691 }
Chris Wren78403d72014-07-28 10:23:24 +01002692 }
2693 }
Selim Cinek570981d2015-12-01 11:37:01 -08002694
Selim Cineke9bad242016-06-15 11:46:37 -07002695 @Override
2696 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2697 super.onInitializeAccessibilityNodeInfoInternal(info);
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002698 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
Selim Cineke9bad242016-06-15 11:46:37 -07002699 if (canViewBeDismissed()) {
2700 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
2701 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002702 boolean expandable = shouldShowPublic();
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002703 boolean isExpanded = false;
2704 if (!expandable) {
2705 if (mIsSummaryWithChildren) {
2706 expandable = true;
2707 if (!mIsLowPriority || isExpanded()) {
2708 isExpanded = isGroupExpanded();
2709 }
2710 } else {
2711 expandable = mPrivateLayout.isContentExpandable();
2712 isExpanded = isExpanded();
2713 }
2714 }
2715 if (expandable) {
2716 if (isExpanded) {
2717 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
2718 } else {
2719 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
2720 }
2721 }
Mady Mellorb3a6aed2018-05-11 13:24:07 -07002722 NotificationMenuRowPlugin provider = getProvider();
2723 if (provider != null) {
2724 MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
2725 if (snoozeMenu != null) {
2726 AccessibilityAction action = new AccessibilityAction(R.id.action_snooze,
2727 getContext().getResources()
2728 .getString(R.string.notification_menu_snooze_action));
2729 info.addAction(action);
2730 }
2731 }
Selim Cineke9bad242016-06-15 11:46:37 -07002732 }
2733
2734 @Override
2735 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
2736 if (super.performAccessibilityActionInternal(action, arguments)) {
2737 return true;
2738 }
2739 switch (action) {
2740 case AccessibilityNodeInfo.ACTION_DISMISS:
Rohan Shah524cf7b2018-03-15 14:40:02 -07002741 performDismissWithBlockingHelper(true /* fromAccessibility */);
Selim Cineke9bad242016-06-15 11:46:37 -07002742 return true;
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002743 case AccessibilityNodeInfo.ACTION_COLLAPSE:
2744 case AccessibilityNodeInfo.ACTION_EXPAND:
2745 mExpandClickListener.onClick(this);
2746 return true;
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002747 case AccessibilityNodeInfo.ACTION_LONG_CLICK:
2748 doLongClickCallback();
2749 return true;
Jason Monk4c9d66e2018-08-09 09:38:21 -04002750 default:
2751 if (action == R.id.action_snooze) {
2752 NotificationMenuRowPlugin provider = getProvider();
2753 if (provider == null) {
2754 provider = createMenu();
2755 }
2756 MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
2757 if (snoozeMenu != null) {
2758 doLongClickCallback(getWidth() / 2, getHeight() / 2, snoozeMenu);
2759 }
2760 return true;
Mady Mellorb3a6aed2018-05-11 13:24:07 -07002761 }
Selim Cineke9bad242016-06-15 11:46:37 -07002762 }
2763 return false;
2764 }
2765
2766 public boolean shouldRefocusOnDismiss() {
2767 return mRefocusOnDismiss || isAccessibilityFocused();
2768 }
2769
Selim Cinek570981d2015-12-01 11:37:01 -08002770 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08002771 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08002772 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002773
2774 @Override
2775 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
Selim Cinek2627d722018-01-19 12:16:49 -08002776 mNotificationViewState = new NotificationViewState(stackScrollState);
2777 return mNotificationViewState;
Selim Cinekbbcebde2016-11-09 18:28:20 -08002778 }
2779
Selim Cinekf93bf3e2018-05-08 14:43:21 -07002780 public NotificationViewState getViewState() {
2781 return mNotificationViewState;
2782 }
2783
Selim Cinekd127d792016-11-01 19:11:41 -07002784 @Override
2785 public boolean isAboveShelf() {
Selim Cinekc8007c52017-02-28 16:09:56 -08002786 return !isOnKeyguard()
Selim Cinek2627d722018-01-19 12:16:49 -08002787 && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf)
Selim Cinekc25989e2018-02-16 16:42:14 -08002788 || mExpandAnimationRunning || mChildIsExpanding);
Selim Cinekd127d792016-11-01 19:11:41 -07002789 }
2790
Adrian Roos0aac04f2016-12-08 15:59:29 -08002791 public void setShowAmbient(boolean showAmbient) {
2792 if (showAmbient != mShowAmbient) {
2793 mShowAmbient = showAmbient;
Adrian Roos6f6e1592017-05-02 16:22:53 -07002794 if (mChildrenContainer != null) {
2795 mChildrenContainer.notifyShowAmbientChanged();
2796 }
Adrian Roos0aac04f2016-12-08 15:59:29 -08002797 notifyHeightChanged(false /* needsAnimation */);
2798 }
2799 }
2800
Selim Cinek0fe07392017-11-09 13:26:34 -08002801 @Override
Tony Huangc092c432018-05-18 17:38:54 +08002802 public boolean topAmountNeedsClipping() {
2803 if (isGroupExpanded()) {
2804 return true;
2805 }
2806 if (isGroupExpansionChanging()) {
2807 return true;
2808 }
2809 if (getShowingLayout().shouldClipToRounding(true /* topRounded */,
2810 false /* bottomRounded */)) {
2811 return true;
2812 }
2813 if (mGuts != null && mGuts.getAlpha() != 0.0f) {
2814 return true;
2815 }
2816 return false;
2817 }
2818
2819 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08002820 protected boolean childNeedsClipping(View child) {
2821 if (child instanceof NotificationContentView) {
2822 NotificationContentView contentView = (NotificationContentView) child;
2823 if (isClippingNeeded()) {
2824 return true;
Selim Cinek86bfcee2018-01-17 11:00:47 -08002825 } else if (!hasNoRounding()
2826 && contentView.shouldClipToRounding(getCurrentTopRoundness() != 0.0f,
2827 getCurrentBottomRoundness() != 0.0f)) {
Selim Cinek515b2032017-11-15 10:20:19 -08002828 return true;
2829 }
2830 } else if (child == mChildrenContainer) {
Selim Cinekc25989e2018-02-16 16:42:14 -08002831 if (!mChildIsExpanding && (isClippingNeeded() || !hasNoRounding())) {
Selim Cinek515b2032017-11-15 10:20:19 -08002832 return true;
2833 }
2834 } else if (child instanceof NotificationGuts) {
Selim Cinekb95fd182017-12-21 13:03:32 -08002835 return !hasNoRounding();
Selim Cinek515b2032017-11-15 10:20:19 -08002836 }
2837 return super.childNeedsClipping(child);
2838 }
2839
2840 @Override
Selim Cinek2871bef2017-11-22 08:40:00 -08002841 protected void applyRoundness() {
2842 super.applyRoundness();
2843 applyChildrenRoundness();
2844 }
2845
2846 private void applyChildrenRoundness() {
2847 if (mIsSummaryWithChildren) {
2848 mChildrenContainer.setCurrentBottomRoundness(getCurrentBottomRoundness());
2849 }
2850 }
2851
2852 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08002853 public Path getCustomClipPath(View child) {
2854 if (child instanceof NotificationGuts) {
Selim Cinek2871bef2017-11-22 08:40:00 -08002855 return getClipPath(true, /* ignoreTranslation */
2856 false /* clipRoundedToBottom */);
2857 }
2858 if (child instanceof NotificationChildrenContainer) {
2859 return getClipPath(false, /* ignoreTranslation */
2860 true /* clipRoundedToBottom */);
Selim Cinek515b2032017-11-15 10:20:19 -08002861 }
2862 return super.getCustomClipPath(child);
2863 }
2864
Selim Cinekb95fd182017-12-21 13:03:32 -08002865 private boolean hasNoRounding() {
2866 return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f;
Selim Cinek0fe07392017-11-09 13:26:34 -08002867 }
2868
Adrian Roos6f6e1592017-05-02 16:22:53 -07002869 public boolean isShowingAmbient() {
2870 return mShowAmbient;
2871 }
2872
Selim Cinekd127d792016-11-01 19:11:41 -07002873 public void setAboveShelf(boolean aboveShelf) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07002874 boolean wasAboveShelf = isAboveShelf();
Selim Cinekd127d792016-11-01 19:11:41 -07002875 mAboveShelf = aboveShelf;
Selim Cinek5cf1d052017-06-01 17:36:46 -07002876 if (isAboveShelf() != wasAboveShelf) {
2877 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
2878 }
Selim Cinekd127d792016-11-01 19:11:41 -07002879 }
2880
Selim Cinekd4776a52017-02-14 18:50:16 -08002881 public static class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08002882
2883 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07002884
Selim Cinekbbcebde2016-11-09 18:28:20 -08002885
2886 private NotificationViewState(StackScrollState stackScrollState) {
2887 mOverallState = stackScrollState;
2888 }
2889
2890 @Override
2891 public void applyToView(View view) {
Selim Cinekbbcebde2016-11-09 18:28:20 -08002892 if (view instanceof ExpandableNotificationRow) {
2893 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinek2627d722018-01-19 12:16:49 -08002894 if (row.isExpandAnimationRunning()) {
2895 return;
2896 }
Selim Cinekc25989e2018-02-16 16:42:14 -08002897 handleFixedTranslationZ(row);
Selim Cinek2627d722018-01-19 12:16:49 -08002898 super.applyToView(view);
Selim Cinekbbcebde2016-11-09 18:28:20 -08002899 row.applyChildrenState(mOverallState);
2900 }
2901 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002902
Selim Cinekc25989e2018-02-16 16:42:14 -08002903 private void handleFixedTranslationZ(ExpandableNotificationRow row) {
2904 if (row.hasExpandingChild()) {
2905 zTranslation = row.getTranslationZ();
2906 clipTopAmount = row.getClipTopAmount();
2907 }
2908 }
2909
Selim Cinek0cfbef42016-11-09 19:06:36 -08002910 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08002911 protected void onYTranslationAnimationFinished(View view) {
2912 super.onYTranslationAnimationFinished(view);
Selim Cinekd4776a52017-02-14 18:50:16 -08002913 if (view instanceof ExpandableNotificationRow) {
2914 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
2915 if (row.isHeadsUpAnimatingAway()) {
2916 row.setHeadsUpAnimatingAway(false);
2917 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002918 }
2919 }
2920
2921 @Override
2922 public void animateTo(View child, AnimationProperties properties) {
Selim Cinek0cfbef42016-11-09 19:06:36 -08002923 if (child instanceof ExpandableNotificationRow) {
2924 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
Selim Cinek2627d722018-01-19 12:16:49 -08002925 if (row.isExpandAnimationRunning()) {
2926 return;
2927 }
Selim Cinekc25989e2018-02-16 16:42:14 -08002928 handleFixedTranslationZ(row);
Selim Cinek2627d722018-01-19 12:16:49 -08002929 super.animateTo(child, properties);
Selim Cinek0cfbef42016-11-09 19:06:36 -08002930 row.startChildAnimation(mOverallState, properties);
2931 }
2932 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002933 }
Selim Cinek817abe72017-05-24 11:08:55 -07002934
2935 @VisibleForTesting
2936 protected void setChildrenContainer(NotificationChildrenContainer childrenContainer) {
2937 mChildrenContainer = childrenContainer;
2938 }
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002939
Julia Reynoldsfc640012018-02-21 12:25:27 -05002940 @VisibleForTesting
2941 protected void setPrivateLayout(NotificationContentView privateLayout) {
2942 mPrivateLayout = privateLayout;
2943 }
2944
2945 @VisibleForTesting
2946 protected void setPublicLayout(NotificationContentView publicLayout) {
2947 mPublicLayout = publicLayout;
2948 }
2949
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002950 /**
2951 * Equivalent to View.OnLongClickListener with coordinates
2952 */
2953 public interface LongPressListener {
2954 /**
2955 * Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
2956 * @return whether the longpress was handled
2957 */
2958 boolean onLongPress(View v, int x, int y, MenuItem item);
2959 }
Julia Reynoldsb5867452018-02-28 16:31:35 -05002960
2961 /**
2962 * Equivalent to View.OnClickListener with coordinates
2963 */
2964 public interface OnAppOpsClickListener {
2965 /**
2966 * Equivalent to {@link View.OnClickListener#onClick(View)} with coordinates
2967 * @return whether the click was handled
2968 */
2969 boolean onClick(View v, int x, int y, MenuItem item);
2970 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07002971
2972 /**
2973 * Background task for executing IPCs to check if the notification is a system notification. The
2974 * output is used for both the blocking helper and the notification info.
2975 */
2976 private class SystemNotificationAsyncTask extends AsyncTask<Void, Void, Boolean> {
2977
2978 @Override
2979 protected Boolean doInBackground(Void... voids) {
2980 return isSystemNotification(mContext, mStatusBarNotification);
2981 }
2982
2983 @Override
2984 protected void onPostExecute(Boolean result) {
Julia Reynoldsaa96cf32018-04-17 09:09:04 -04002985 if (mEntry != null) {
2986 mEntry.mIsSystemNotification = result;
2987 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07002988 }
2989 }
Chris Wren51c75102013-07-16 20:49:17 -04002990}