blob: 2b643d0a2fea9cf49c6012a352038983ffaa6710 [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
Rohan Shah20790b82018-07-02 17:21:04 -070014 * limitations under the License
Chris Wren51c75102013-07-16 20:49:17 -040015 */
16
Rohan Shah20790b82018-07-02 17:21:04 -070017package com.android.systemui.statusbar.notification.row;
Chris Wren51c75102013-07-16 20:49:17 -040018
Dave Mankoffa4d195d2018-11-16 13:33:27 -050019import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
Ned Burns1a5e22f2019-02-14 15:11:52 -050020import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT;
21import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP;
22import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_PUBLIC;
23import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationCallback;
Dave Mankoffa4d195d2018-11-16 13:33:27 -050024import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
25import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
26import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
Selim Cinekc478f902017-02-22 20:55:44 -080027
Mady Mellor4b80b102016-01-22 08:03:58 -080028import android.animation.Animator;
29import android.animation.AnimatorListenerAdapter;
Mady Mellor4b80b102016-01-22 08:03:58 -080030import android.animation.ObjectAnimator;
Mady Mellor4b80b102016-01-22 08:03:58 -080031import android.animation.ValueAnimator.AnimatorUpdateListener;
Kevind4660b22018-09-27 10:57:35 -070032import android.annotation.NonNull;
Selim Cinekddf1b392016-05-27 16:33:10 -070033import android.annotation.Nullable;
Rohan Shah63411fc2018-03-28 19:05:52 -070034import android.app.NotificationChannel;
Chris Wren51c75102013-07-16 20:49:17 -040035import android.content.Context;
Rohan Shah63411fc2018-03-28 19:05:52 -070036import android.content.pm.PackageInfo;
37import android.content.pm.PackageManager;
Mady Mellor9d03a522017-04-04 18:45:30 -070038import android.content.res.Configuration;
Julia Reynoldsb5867452018-02-28 16:31:35 -050039import android.content.res.Resources;
Selim Cinek515b2032017-11-15 10:20:19 -080040import android.graphics.Path;
Selim Cinekcab4a602014-09-03 14:47:57 +020041import android.graphics.drawable.AnimatedVectorDrawable;
42import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010043import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020044import android.graphics.drawable.Drawable;
Rohan Shah4ed1b2a2018-03-30 13:26:01 -070045import android.os.AsyncTask;
Selim Cinekda42d652015-12-04 15:51:16 -080046import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070047import android.os.Bundle;
Kevin38ce6fa2018-10-17 16:00:14 -070048import android.os.SystemClock;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020049import android.service.notification.StatusBarNotification;
Julia Reynoldsfc640012018-02-21 12:25:27 -050050import android.util.ArraySet;
Chris Wren51c75102013-07-16 20:49:17 -040051import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070052import android.util.FloatProperty;
Rohan Shah63411fc2018-03-28 19:05:52 -070053import android.util.Log;
Selim Cinek2627d722018-01-19 12:16:49 -080054import android.util.MathUtils;
Mady Mellorb0a82462016-04-30 17:31:02 -070055import android.util.Property;
Geoffrey Pitsch409db272017-08-28 14:51:52 +000056import android.view.KeyEvent;
Selim Cinek01af3342016-02-09 19:25:31 -080057import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080058import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080059import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050060import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080061import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020062import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020063import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070064import android.view.accessibility.AccessibilityNodeInfo;
Mady Mellorb3a6aed2018-05-11 13:24:07 -070065import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Selim Cinek98713a42015-09-21 15:47:20 +020066import android.widget.Chronometer;
Mady Mellor95d743c2017-01-10 12:05:27 -080067import android.widget.FrameLayout;
Selim Cinekcab4a602014-09-03 14:47:57 +020068import android.widget.ImageView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080069import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010070
Selim Cinek5ba22542017-04-20 15:16:10 -070071import com.android.internal.annotations.VisibleForTesting;
Chris Wren698b1702016-05-23 11:16:32 -040072import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010073import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Lucas Dupina291d192018-06-07 13:59:42 -070074import com.android.internal.util.ContrastColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080075import com.android.internal.widget.CachingIconView;
Mady Mellor95d743c2017-01-10 12:05:27 -080076import com.android.systemui.Dependency;
Selim Cinek0242fbb2016-10-19 13:38:32 -070077import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050078import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070079import com.android.systemui.classifier.FalsingManager;
Mady Mellor95d743c2017-01-10 12:05:27 -080080import com.android.systemui.plugins.PluginListener;
Mady Mellor95d743c2017-01-10 12:05:27 -080081import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
82import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
Kevin38ce6fa2018-10-17 16:00:14 -070083import com.android.systemui.shared.plugins.PluginManager;
Rohan Shah20790b82018-07-02 17:21:04 -070084import com.android.systemui.statusbar.RemoteInputController;
85import com.android.systemui.statusbar.StatusBarIconView;
Selim Cinek5cf1d052017-06-01 17:36:46 -070086import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
Selim Cinek2627d722018-01-19 12:16:49 -080087import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
Selim Cinek6743c0b2017-01-18 18:24:01 -080088import com.android.systemui.statusbar.notification.NotificationUtils;
Kevin38ce6fa2018-10-17 16:00:14 -070089import com.android.systemui.statusbar.notification.VisualStabilityManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050090import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Kevin38ce6fa2018-10-17 16:00:14 -070091import com.android.systemui.statusbar.notification.logging.NotificationCounters;
Ned Burns1a5e22f2019-02-14 15:11:52 -050092import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
Beth Thibodeaucb395352019-01-25 15:39:54 -050093import com.android.systemui.statusbar.notification.row.wrapper.NotificationMediaTemplateViewWrapper;
Rohan Shah20790b82018-07-02 17:21:04 -070094import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
Rohan Shah20790b82018-07-02 17:21:04 -070095import com.android.systemui.statusbar.notification.stack.AmbientState;
96import com.android.systemui.statusbar.notification.stack.AnimationProperties;
97import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
98import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
Evan Laird94492852018-10-25 13:43:01 -040099import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
Kevin38ce6fa2018-10-17 16:00:14 -0700100import com.android.systemui.statusbar.phone.NotificationGroupManager;
101import com.android.systemui.statusbar.phone.StatusBar;
102import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100103
Selim Cinek30887662018-10-15 17:37:21 -0700104import java.io.FileDescriptor;
105import java.io.PrintWriter;
Mady Mellor4b80b102016-01-22 08:03:58 -0800106import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +0100107import java.util.List;
Ned Burns3da3c782019-01-08 21:14:39 -0500108import java.util.concurrent.TimeUnit;
Lucas Dupincecc7c22017-09-12 16:02:45 -0700109import java.util.function.BooleanSupplier;
Selim Cinek8875de12018-03-22 10:14:32 -0700110import java.util.function.Consumer;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500111
Rohan Shah63411fc2018-03-28 19:05:52 -0700112/**
113 * View representing a notification item - this can be either the individual child notification or
114 * the group summary (which contains 1 or more child notifications).
115 */
Mady Mellor95d743c2017-01-10 12:05:27 -0800116public class ExpandableNotificationRow extends ActivatableNotificationView
117 implements PluginListener<NotificationMenuRowPlugin> {
Selim Cinekb5605e52015-02-20 18:21:41 +0100118
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700119 private static final boolean DEBUG = false;
Selim Cinekb5605e52015-02-20 18:21:41 +0100120 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
121 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Mady Mellor95d743c2017-01-10 12:05:27 -0800122 private static final int MENU_VIEW_INDEX = 0;
Rohan Shah63411fc2018-03-28 19:05:52 -0700123 private static final String TAG = "ExpandableNotifRow";
felkachange6c03a02018-05-24 15:38:04 +0800124 public static final float DEFAULT_HEADER_VISIBLE_AMOUNT = 1.0f;
Ned Burns3da3c782019-01-08 21:14:39 -0500125 private static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
Selim Cinekab9c7b22018-12-11 18:15:47 -0800126 private boolean mUpdateBackgroundOnUpdate;
Nadia Benbernou7a18c812019-02-08 16:23:10 -0500127 private boolean mNotificationTranslationFinished = false;
Mady Mellor95d743c2017-01-10 12:05:27 -0800128
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700129 /**
130 * Listener for when {@link ExpandableNotificationRow} is laid out.
131 */
Mady Mellor035badd2017-04-04 18:45:30 -0700132 public interface LayoutListener {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700133 void onLayout();
Mady Mellor035badd2017-04-04 18:45:30 -0700134 }
135
136 private LayoutListener mLayoutListener;
Ned Burns1a5e22f2019-02-14 15:11:52 -0500137 private final NotificationContentInflater mNotificationInflater;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700138 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800139 private int mIconTransformContentShiftNoIcon;
Rohan Shahb9d500a2018-06-25 16:27:16 -0700140 private int mMaxHeadsUpHeightBeforeN;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800141 private int mMaxHeadsUpHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800142 private int mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800143 private int mMaxHeadsUpHeightIncreased;
Rohan Shahb9d500a2018-06-25 16:27:16 -0700144 private int mNotificationMinHeightBeforeN;
145 private int mNotificationMinHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800146 private int mNotificationMinHeight;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800147 private int mNotificationMinHeightLarge;
Beth Thibodeaucb395352019-01-25 15:39:54 -0500148 private int mNotificationMinHeightMedia;
Selim Cinek01af3342016-02-09 19:25:31 -0800149 private int mNotificationMaxHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -0700150 private int mIncreasedPaddingBetweenElements;
Selim Cinek2627d722018-01-19 12:16:49 -0800151 private int mNotificationLaunchHeight;
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100152 private boolean mMustStayOnScreen;
Chris Wren51c75102013-07-16 20:49:17 -0400153
Selim Cinek1685e632014-04-08 02:27:49 +0200154 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -0400155 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +0200156 /** Has the user actively changed the expansion state of this row */
157 private boolean mHasUserChangedExpansion;
158 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -0400159 private boolean mUserExpanded;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700160 /** Whether the blocking helper is showing on this notification (even if dismissed) */
161 private boolean mIsBlockingHelperShowing;
Selim Cinek31aada42015-12-18 17:51:15 -0800162
163 /**
164 * Has this notification been expanded while it was pinned
165 */
166 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +0200167 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -0400168 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +0200169 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -0500170 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +0200171 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -0800172 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +0200173 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700174 private boolean mHideSensitiveForIntrinsicHeight;
felkachange6c03a02018-05-24 15:38:04 +0800175 private float mHeaderVisibleAmount = DEFAULT_HEADER_VISIBLE_AMOUNT;
Chris Wren51c75102013-07-16 20:49:17 -0400176
Selim Cinek1685e632014-04-08 02:27:49 +0200177 /**
178 * Is this notification expanded by the system. The expansion state can be overridden by the
179 * user expansion.
180 */
181 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200182
183 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700184 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200185 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700186 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200187
Kevina97ea052018-09-11 13:53:18 -0700188 /**
189 * Whether or not the row is currently on the doze screen.
190 */
191 private boolean mOnAmbient;
192
Mady Mellorb0a82462016-04-30 17:31:02 -0700193 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800194 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200195 private NotificationContentView mPublicLayout;
196 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800197 private NotificationContentView[] mLayouts;
Selim Cinek4bb59342016-04-08 19:29:35 -0700198 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100199 private ExpansionLogger mLogger;
200 private String mLoggingKey;
Selim Cinek8d490d42015-04-10 00:05:50 -0700201 private NotificationGuts mGuts;
Ned Burnsf81c4c42019-01-07 14:10:43 -0500202 private NotificationEntry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200203 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700204 private String mAppName;
Kevina97ea052018-09-11 13:53:18 -0700205
206 /**
207 * Whether or not the notification is using the heads up view and should peek from the top.
208 */
Selim Cinek1a521f32014-11-03 17:39:29 +0100209 private boolean mIsHeadsUp;
Kevina97ea052018-09-11 13:53:18 -0700210
211 /**
212 * Whether or not the notification is using the ambient display view and is pulsing. This
213 * occurs when a high priority notification alerts while the phone is dozing or is on AOD.
214 */
215 private boolean mIsAmbientPulsing;
216
Kevin38ce6fa2018-10-17 16:00:14 -0700217 /**
218 * Whether or not the notification should be redacted on the lock screen, i.e has sensitive
219 * content which should be redacted on the lock screen.
220 */
221 private boolean mNeedsRedaction;
Selim Cinek98713a42015-09-21 15:47:20 +0200222 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100223 private ViewStub mChildrenContainerStub;
224 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100225 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700226 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100227 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor95d743c2017-01-10 12:05:27 -0800228 private NotificationMenuRowPlugin mMenuRow;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100229 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100230 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700231 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700232 private FalsingManager mFalsingManager;
Selim Cinek2627d722018-01-19 12:16:49 -0800233 private boolean mExpandAnimationRunning;
Selim Cinek5cf1d052017-06-01 17:36:46 -0700234 private AboveShelfChangedListener mAboveShelfChangedListener;
Selim Cinek31aada42015-12-18 17:51:15 -0800235 private HeadsUpManager mHeadsUpManager;
Selim Cinek8875de12018-03-22 10:14:32 -0700236 private Consumer<Boolean> mHeadsUpAnimatingAwayListener;
Selim Cinekc25989e2018-02-16 16:42:14 -0800237 private boolean mChildIsExpanding;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200238
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700239 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800240 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700241 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700242 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800243 private OnExpandClickListener mOnExpandClickListener;
Julia Reynoldsb5867452018-02-28 16:31:35 -0500244 private View.OnClickListener mOnAppOpsClickListener;
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000245
246 // Listener will be called when receiving a long click event.
247 // Use #setLongPressPosition to optionally assign positional data with the long press.
248 private LongPressListener mLongPressListener;
249
Mady Mellorb0a82462016-04-30 17:31:02 -0700250 private boolean mGroupExpansionChanging;
251
Anthony Chen6bf88a02017-04-10 14:41:44 -0700252 /**
Lucas Dupincecc7c22017-09-12 16:02:45 -0700253 * A supplier that returns true if keyguard is secure.
254 */
255 private BooleanSupplier mSecureStateProvider;
256
257 /**
Anthony Chen6bf88a02017-04-10 14:41:44 -0700258 * Whether or not a notification that is not part of a group of notifications can be manually
259 * expanded by the user.
260 */
261 private boolean mEnableNonGroupedNotificationExpand;
262
263 /**
264 * Whether or not to update the background of the header of the notification when its expanded.
265 * If {@code true}, the header background will disappear when expanded.
266 */
267 private boolean mShowGroupBackgroundWhenExpanded;
268
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800269 private OnClickListener mExpandClickListener = new OnClickListener() {
270 @Override
271 public void onClick(View v) {
Selim Cinek0b9cf462017-12-07 16:31:03 -0800272 if (!shouldShowPublic() && (!mIsLowPriority || isExpanded())
Selim Cinek414ad332017-02-24 19:06:12 -0800273 && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700274 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400275 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
276 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
277 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400278 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
279 nowExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -0800280 onExpansionChanged(true /* userAction */, wasExpanded);
Anthony Chen6bf88a02017-04-10 14:41:44 -0700281 } else if (mEnableNonGroupedNotificationExpand) {
Selim Cineke9bad242016-06-15 11:46:37 -0700282 if (v.isAccessibilityFocused()) {
283 mPrivateLayout.setFocusOnVisibilityChange();
284 }
Selim Cinek31aada42015-12-18 17:51:15 -0800285 boolean nowExpanded;
286 if (isPinned()) {
287 nowExpanded = !mExpandedWhenPinned;
288 mExpandedWhenPinned = nowExpanded;
289 } else {
290 nowExpanded = !isExpanded();
291 setUserExpanded(nowExpanded);
292 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800293 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800294 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400295 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
296 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800297 }
298 }
299 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700300 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700301 private boolean mDismissed;
302 private boolean mKeepInParent;
303 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700304 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
305 new FloatProperty<ExpandableNotificationRow>("translate") {
306 @Override
307 public void setValue(ExpandableNotificationRow object, float value) {
308 object.setTranslation(value);
309 }
310
311 @Override
312 public Float get(ExpandableNotificationRow object) {
313 return object.getTranslation();
314 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700315 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700316 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700317 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700318 private View mChildAfterViewWhenDismissed;
319 private View mGroupParentWhenDismissed;
320 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800321 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700322 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700323 private boolean mAboveShelf;
Selim Cinek875a3a12016-11-18 17:52:16 -0800324 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800325 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800326 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800327 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800328 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800329 private boolean mUseIncreasedHeadsUpHeight;
Selim Cinekef8c2252017-02-10 14:52:18 -0800330 private float mTranslationWhenRemoved;
331 private boolean mWasChildInGroupWhenRemoved;
Adrian Roos6f6e1592017-05-02 16:22:53 -0700332 private int mNotificationColorAmbient;
Ahan Wude396fa2018-05-08 20:42:24 +0800333 private NotificationInlineImageResolver mImageResolver;
Mady Mellorb0a82462016-04-30 17:31:02 -0700334
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700335 private SystemNotificationAsyncTask mSystemNotificationAsyncTask =
336 new SystemNotificationAsyncTask();
Mady Mellorc3d6f7d2018-11-07 09:36:56 -0800337 private int mStatusBarState = -1;
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700338
339 /**
340 * Returns whether the given {@code statusBarNotification} is a system notification.
341 * <b>Note</b>, this should be run in the background thread if possible as it makes multiple IPC
342 * calls.
343 */
344 private static Boolean isSystemNotification(
345 Context context, StatusBarNotification statusBarNotification) {
346 PackageManager packageManager = StatusBar.getPackageManagerForUser(
347 context, statusBarNotification.getUser().getIdentifier());
348 Boolean isSystemNotification = null;
349
350 try {
351 PackageInfo packageInfo = packageManager.getPackageInfo(
352 statusBarNotification.getPackageName(), PackageManager.GET_SIGNATURES);
353
354 isSystemNotification =
355 com.android.settingslib.Utils.isSystemPackage(
356 context.getResources(), packageManager, packageInfo);
357 } catch (PackageManager.NameNotFoundException e) {
358 Log.e(TAG, "cacheIsSystemNotification: Could not find package info");
359 }
360 return isSystemNotification;
361 }
362
Mady Mellor43c2cd12016-12-12 21:05:13 -0800363 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700364 public boolean isGroupExpansionChanging() {
365 if (isChildInGroup()) {
366 return mNotificationParent.isGroupExpansionChanging();
367 }
368 return mGroupExpansionChanging;
369 }
370
371 public void setGroupExpansionChanging(boolean changing) {
372 mGroupExpansionChanging = changing;
373 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700374
Adrian Roos599be342016-06-13 14:54:39 -0700375 @Override
376 public void setActualHeightAnimating(boolean animating) {
377 if (mPrivateLayout != null) {
378 mPrivateLayout.setContentHeightAnimating(animating);
379 }
380 }
381
Selim Cinek8d490d42015-04-10 00:05:50 -0700382 public NotificationContentView getPrivateLayout() {
383 return mPrivateLayout;
384 }
385
386 public NotificationContentView getPublicLayout() {
387 return mPublicLayout;
388 }
389
Selim Cinekcab4a602014-09-03 14:47:57 +0200390 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800391 for (NotificationContentView l : mLayouts) {
392 setIconAnimationRunning(running, l);
393 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800394 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700395 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek414ad332017-02-24 19:06:12 -0800396 setIconAnimationRunningForChild(running, mChildrenContainer.getLowPriorityHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800397 List<ExpandableNotificationRow> notificationChildren =
398 mChildrenContainer.getNotificationChildren();
399 for (int i = 0; i < notificationChildren.size(); i++) {
400 ExpandableNotificationRow child = notificationChildren.get(i);
401 child.setIconAnimationRunning(running);
402 }
403 }
404 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200405 }
406
407 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
408 if (layout != null) {
409 View contractedChild = layout.getContractedChild();
410 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700411 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200412 setIconAnimationRunningForChild(running, contractedChild);
413 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700414 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200415 }
416 }
417
418 private void setIconAnimationRunningForChild(boolean running, View child) {
419 if (child != null) {
420 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
421 setIconRunning(icon, running);
422 ImageView rightIcon = (ImageView) child.findViewById(
423 com.android.internal.R.id.right_icon);
424 setIconRunning(rightIcon, running);
425 }
426 }
427
428 private void setIconRunning(ImageView imageView, boolean running) {
429 if (imageView != null) {
430 Drawable drawable = imageView.getDrawable();
431 if (drawable instanceof AnimationDrawable) {
432 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
433 if (running) {
434 animationDrawable.start();
435 } else {
436 animationDrawable.stop();
437 }
438 } else if (drawable instanceof AnimatedVectorDrawable) {
439 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
440 if (running) {
441 animationDrawable.start();
442 } else {
443 animationDrawable.stop();
444 }
445 }
446 }
447 }
448
Kevind4660b22018-09-27 10:57:35 -0700449 /**
450 * Set the entry for the row.
451 *
452 * @param entry the entry this row is tied to
453 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500454 public void setEntry(@NonNull NotificationEntry entry) {
Selim Cinekda42d652015-12-04 15:51:16 -0800455 mEntry = entry;
456 mStatusBarNotification = entry.notification;
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700457 cacheIsSystemNotification();
Rohan Shah63411fc2018-03-28 19:05:52 -0700458 }
459
460 /**
Kevin01a53cb2018-11-09 18:19:54 -0800461 * Inflate views based off the inflation flags set. Inflation happens asynchronously.
Kevind4660b22018-09-27 10:57:35 -0700462 */
463 public void inflateViews() {
464 mNotificationInflater.inflateNotificationViews();
465 }
466
467 /**
Kevind5022f92018-10-08 18:30:26 -0700468 * Marks a content view as freeable, setting it so that future inflations do not reinflate
469 * and ensuring that the view is freed when it is safe to remove.
470 *
471 * @param inflationFlag flag corresponding to the content view to be freed
472 */
473 public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) {
474 // View should not be reinflated in the future
475 updateInflationFlag(inflationFlag, false);
476 Runnable freeViewRunnable = () ->
477 mNotificationInflater.freeNotificationView(inflationFlag);
478 switch (inflationFlag) {
479 case FLAG_CONTENT_VIEW_HEADS_UP:
480 getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_HEADSUP,
481 freeViewRunnable);
482 break;
483 case FLAG_CONTENT_VIEW_AMBIENT:
484 getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT,
485 freeViewRunnable);
486 getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT,
487 freeViewRunnable);
488 break;
Kevin38ce6fa2018-10-17 16:00:14 -0700489 case FLAG_CONTENT_VIEW_PUBLIC:
490 getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_CONTRACTED,
491 freeViewRunnable);
Kevind5022f92018-10-08 18:30:26 -0700492 default:
493 break;
494 }
495 }
496
497 /**
Kevind4660b22018-09-27 10:57:35 -0700498 * Update whether or not a content view should be inflated.
499 *
500 * @param flag the flag corresponding to the content view
501 * @param shouldInflate true if it should be inflated, false if it should not
502 */
503 public void updateInflationFlag(@InflationFlag int flag, boolean shouldInflate) {
504 mNotificationInflater.updateInflationFlag(flag, shouldInflate);
505 }
506
507 /**
Kevin01a53cb2018-11-09 18:19:54 -0800508 * Whether or not a content view should be inflated.
509 *
510 * @param flag the flag corresponding to the content view
511 * @return true if the flag is set, false otherwise
512 */
513 public boolean isInflationFlagSet(@InflationFlag int flag) {
514 return mNotificationInflater.isInflationFlagSet(flag);
515 }
516
517 /**
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700518 * Caches whether or not this row contains a system notification. Note, this is only cached
519 * once per notification as the packageInfo can't technically change for a notification row.
Rohan Shah63411fc2018-03-28 19:05:52 -0700520 */
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700521 private void cacheIsSystemNotification() {
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400522 if (mEntry != null && mEntry.mIsSystemNotification == null) {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700523 if (mSystemNotificationAsyncTask.getStatus() == AsyncTask.Status.PENDING) {
524 // Run async task once, only if it hasn't already been executed. Note this is
525 // executed in serial - no need to parallelize this small task.
526 mSystemNotificationAsyncTask.execute();
Rohan Shah63411fc2018-03-28 19:05:52 -0700527 }
528 }
529 }
530
531 /**
Rohan Shahca0447e2018-03-30 15:18:27 -0700532 * Returns whether this row is considered non-blockable (i.e. it's a non-blockable system notif
533 * or is in a whitelist).
Rohan Shah63411fc2018-03-28 19:05:52 -0700534 */
535 public boolean getIsNonblockable() {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700536 boolean isNonblockable = Dependency.get(NotificationBlockingHelperManager.class)
Julia Reynolds0abae112018-06-08 10:36:57 -0400537 .isNonblockable(mStatusBarNotification.getPackageName(),
538 mEntry.channel.getId());
Rohan Shah63411fc2018-03-28 19:05:52 -0700539
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700540 // If the SystemNotifAsyncTask hasn't finished running or retrieved a value, we'll try once
541 // again, but in-place on the main thread this time. This should rarely ever get called.
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400542 if (mEntry != null && mEntry.mIsSystemNotification == null) {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700543 if (DEBUG) {
544 Log.d(TAG, "Retrieving isSystemNotification on main thread");
545 }
546 mSystemNotificationAsyncTask.cancel(true /* mayInterruptIfRunning */);
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400547 mEntry.mIsSystemNotification = isSystemNotification(mContext, mStatusBarNotification);
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700548 }
549
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400550 if (!isNonblockable && mEntry != null && mEntry.mIsSystemNotification != null) {
551 if (mEntry.mIsSystemNotification) {
Rohan Shah63411fc2018-03-28 19:05:52 -0700552 if (mEntry.channel != null
553 && !mEntry.channel.isBlockableSystem()) {
554 isNonblockable = true;
555 }
556 }
557 }
558 return isNonblockable;
Selim Cinekc478f902017-02-22 20:55:44 -0800559 }
560
Selim Cinek5ba22542017-04-20 15:16:10 -0700561 public void onNotificationUpdated() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800562 for (NotificationContentView l : mLayouts) {
Selim Cinekc478f902017-02-22 20:55:44 -0800563 l.onNotificationUpdated(mEntry);
Adrian Rooseb434ff2017-01-11 11:18:48 -0800564 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800565 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800566 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700567 updateNotificationColor();
Mady Mellor4c197602017-04-10 17:57:52 -0700568 if (mMenuRow != null) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700569 mMenuRow.onNotificationUpdated(mStatusBarNotification);
Beverly3f56f052018-05-08 14:56:03 -0400570 mMenuRow.setAppName(mAppName);
Mady Mellor4c197602017-04-10 17:57:52 -0700571 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800572 if (mIsSummaryWithChildren) {
Selim Cinek414ad332017-02-24 19:06:12 -0800573 mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
Selim Cinekc897bd32016-03-18 17:32:31 -0700574 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800575 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800576 if (mIconAnimationRunning) {
577 setIconAnimationRunning(true);
578 }
Kevin38ce6fa2018-10-17 16:00:14 -0700579 if (mLastChronometerRunning) {
580 setChronometerRunning(true);
581 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800582 if (mNotificationParent != null) {
583 mNotificationParent.updateChildrenHeaderAppearance();
584 }
Selim Cinek263398f2015-10-21 17:40:23 -0700585 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800586 // The public layouts expand button is always visible
587 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800588 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700589 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800590 updateShelfIconColor();
Selim Cinekfe24fb72018-02-13 14:34:55 -0800591 updateRippleAllowed();
Selim Cinekab9c7b22018-12-11 18:15:47 -0800592 if (mUpdateBackgroundOnUpdate) {
593 mUpdateBackgroundOnUpdate = false;
594 updateBackgroundColors();
595 }
Selim Cinek6743c0b2017-01-18 18:24:01 -0800596 }
597
Gus Prevas33fbc152018-12-04 13:17:32 -0500598 /** Called when the notification's ranking was changed (but nothing else changed). */
599 public void onNotificationRankingUpdated() {
600 if (mMenuRow != null) {
601 mMenuRow.onNotificationUpdated(mStatusBarNotification);
602 }
603 }
604
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700605 @VisibleForTesting
606 void updateShelfIconColor() {
Selim Cinek6743c0b2017-01-18 18:24:01 -0800607 StatusBarIconView expandedIcon = mEntry.expandedIcon;
608 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
609 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
Lucas Dupina291d192018-06-07 13:59:42 -0700610 ContrastColorUtil.getInstance(mContext));
Selim Cinek875ba9b2017-02-13 16:20:17 -0800611 int color = StatusBarIconView.NO_COLOR;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800612 if (colorize) {
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700613 NotificationHeaderView header = getVisibleNotificationHeader();
614 if (header != null) {
615 color = header.getOriginalIconColor();
616 } else {
617 color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
618 getBackgroundColorWithoutTint());
619 }
Selim Cinek6743c0b2017-01-18 18:24:01 -0800620 }
Selim Cinek875ba9b2017-02-13 16:20:17 -0800621 expandedIcon.setStaticDrawableColor(color);
Selim Cinekda42d652015-12-04 15:51:16 -0800622 }
623
Selim Cinek5cf1d052017-06-01 17:36:46 -0700624 public void setAboveShelfChangedListener(AboveShelfChangedListener aboveShelfChangedListener) {
625 mAboveShelfChangedListener = aboveShelfChangedListener;
626 }
627
Lucas Dupincecc7c22017-09-12 16:02:45 -0700628 /**
629 * Sets a supplier that can determine whether the keyguard is secure or not.
630 * @param secureStateProvider A function that returns true if keyguard is secure.
631 */
632 public void setSecureStateProvider(BooleanSupplier secureStateProvider) {
633 mSecureStateProvider = secureStateProvider;
634 }
635
Selim Cinek4705f292017-04-24 22:18:48 -0700636 @Override
637 public boolean isDimmable() {
638 if (!getShowingLayout().isDimmable()) {
639 return false;
640 }
641 return super.isDimmable();
642 }
643
Selim Cinekda42d652015-12-04 15:51:16 -0800644 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800645 for (NotificationContentView l : mLayouts) {
646 updateLimitsForView(l);
647 }
Selim Cineka1744872016-03-11 15:36:06 -0800648 }
649
650 private void updateLimitsForView(NotificationContentView layout) {
Kevin38ce6fa2018-10-17 16:00:14 -0700651 boolean customView = layout.getContractedChild() != null
652 && layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800653 != com.android.internal.R.id.status_bar_latest_event_content;
654 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800655 boolean beforeP = mEntry.targetSdk < Build.VERSION_CODES.P;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800656 int minHeight;
Beth Thibodeaucb395352019-01-25 15:39:54 -0500657
658 View expandedView = layout.getExpandedChild();
659 boolean isMediaLayout = expandedView != null
660 && expandedView.findViewById(com.android.internal.R.id.media_actions) != null;
661
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800662 if (customView && beforeP && !mIsSummaryWithChildren) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700663 minHeight = beforeN ? mNotificationMinHeightBeforeN : mNotificationMinHeightBeforeP;
Beth Thibodeaucb395352019-01-25 15:39:54 -0500664 } else if (isMediaLayout && !NotificationMediaTemplateViewWrapper.HIDE_COMPACT_SCRUBBER) {
665 minHeight = mNotificationMinHeightMedia;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800666 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
667 minHeight = mNotificationMinHeightLarge;
668 } else {
669 minHeight = mNotificationMinHeight;
670 }
Selim Cineka1744872016-03-11 15:36:06 -0800671 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
672 layout.getHeadsUpChild().getId()
673 != com.android.internal.R.id.status_bar_latest_event_content;
Rohan Shahb9d500a2018-06-25 16:27:16 -0700674 int headsUpHeight;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800675 if (headsUpCustom && beforeP) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700676 headsUpHeight = beforeN ? mMaxHeadsUpHeightBeforeN : mMaxHeadsUpHeightBeforeP;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800677 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700678 headsUpHeight = mMaxHeadsUpHeightIncreased;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800679 } else {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700680 headsUpHeight = mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800681 }
Selim Cineke62255c2017-09-28 18:23:23 -0700682 NotificationViewWrapper headsUpWrapper = layout.getVisibleWrapper(
Kevind5022f92018-10-08 18:30:26 -0700683 VISIBLE_TYPE_HEADSUP);
Selim Cineke62255c2017-09-28 18:23:23 -0700684 if (headsUpWrapper != null) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700685 headsUpHeight = Math.max(headsUpHeight, headsUpWrapper.getMinLayoutHeight());
Selim Cineke62255c2017-09-28 18:23:23 -0700686 }
Lucas Dupin00be88f2019-01-03 17:50:52 -0800687 layout.setHeights(minHeight, headsUpHeight, mNotificationMaxHeight, headsUpHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200688 }
689
690 public StatusBarNotification getStatusBarNotification() {
691 return mStatusBarNotification;
692 }
693
Ned Burnsf81c4c42019-01-07 14:10:43 -0500694 public NotificationEntry getEntry() {
Selim Cinek281c2022016-10-13 19:14:43 -0700695 return mEntry;
696 }
697
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700698 public boolean isHeadsUp() {
699 return mIsHeadsUp;
700 }
701
Selim Cinek1a521f32014-11-03 17:39:29 +0100702 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinek5cf1d052017-06-01 17:36:46 -0700703 boolean wasAboveShelf = isAboveShelf();
Selim Cinekc80fdb12015-04-13 15:09:08 -0700704 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100705 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700706 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700707 if (mIsSummaryWithChildren) {
708 // The overflow might change since we allow more lines as HUN.
709 mChildrenContainer.updateGroupOverflow();
710 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700711 if (intrinsicBefore != getIntrinsicHeight()) {
712 notifyHeightChanged(false /* needsAnimation */);
713 }
Selim Cinekd127d792016-11-01 19:11:41 -0700714 if (isHeadsUp) {
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100715 mMustStayOnScreen = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700716 setAboveShelf(true);
Kevind5022f92018-10-08 18:30:26 -0700717 } else if (isAboveShelf() != wasAboveShelf) {
718 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
Selim Cinekd127d792016-11-01 19:11:41 -0700719 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100720 }
721
Kevina97ea052018-09-11 13:53:18 -0700722 public boolean isAmbientPulsing() {
723 return mIsAmbientPulsing;
724 }
725
726 public void setAmbientPulsing(boolean isAmbientPulsing) {
727 mIsAmbientPulsing = isAmbientPulsing;
728 }
729
Selim Cinekb5605e52015-02-20 18:21:41 +0100730 public void setGroupManager(NotificationGroupManager groupManager) {
731 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700732 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100733 }
734
Adrian Roosb88b1a12015-12-09 18:51:05 -0800735 public void setRemoteInputController(RemoteInputController r) {
736 mPrivateLayout.setRemoteInputController(r);
737 }
738
Mady Mellor3fd273e2016-03-15 21:08:14 -0700739 public void setAppName(String appName) {
740 mAppName = appName;
Mady Mellor95d743c2017-01-10 12:05:27 -0800741 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800742 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700743 }
744 }
745
Selim Cinekb5605e52015-02-20 18:21:41 +0100746 public void addChildNotification(ExpandableNotificationRow row) {
747 addChildNotification(row, -1);
748 }
749
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800750 /**
751 * Set the how much the header should be visible. A value of 0 will make the header fully gone
752 * and a value of 1 will make the notification look just like normal.
753 * This is being used for heads up notifications, when they are pinned to the top of the screen
754 * and the header content is extracted to the statusbar.
755 *
756 * @param headerVisibleAmount the amount the header should be visible.
757 */
758 public void setHeaderVisibleAmount(float headerVisibleAmount) {
759 if (mHeaderVisibleAmount != headerVisibleAmount) {
760 mHeaderVisibleAmount = headerVisibleAmount;
761 mPrivateLayout.setHeaderVisibleAmount(headerVisibleAmount);
762 if (mChildrenContainer != null) {
763 mChildrenContainer.setHeaderVisibleAmount(headerVisibleAmount);
764 }
765 notifyHeightChanged(false /* needsAnimation */);
766 }
767 }
768
Selim Cinek99e9adf2018-03-15 09:17:47 -0700769 @Override
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800770 public float getHeaderVisibleAmount() {
771 return mHeaderVisibleAmount;
772 }
773
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100774 @Override
775 public void setHeadsUpIsVisible() {
776 super.setHeadsUpIsVisible();
777 mMustStayOnScreen = false;
778 }
779
Selim Cinekb5605e52015-02-20 18:21:41 +0100780 /**
781 * Add a child notification to this view.
782 *
783 * @param row the row to add
784 * @param childIndex the index to add it at, if -1 it will be added at the end
785 */
786 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
787 if (mChildrenContainer == null) {
788 mChildrenContainerStub.inflate();
789 }
790 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700791 onChildrenCountChanged();
792 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100793 }
794
795 public void removeChildNotification(ExpandableNotificationRow row) {
796 if (mChildrenContainer != null) {
797 mChildrenContainer.removeNotification(row);
798 }
Selim Cinek263398f2015-10-21 17:40:23 -0700799 onChildrenCountChanged();
800 row.setIsChildInGroup(false, null);
Selim Cinek2871bef2017-11-22 08:40:00 -0800801 row.setBottomRoundness(0.0f, false /* animate */);
Selim Cinek263398f2015-10-21 17:40:23 -0700802 }
803
Mady Mellor43c2cd12016-12-12 21:05:13 -0800804 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700805 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700806 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700807 }
808
Rohan Shah524cf7b2018-03-15 14:40:02 -0700809 /**
810 * @return whether this notification is the only child in the group summary
811 */
812 public boolean isOnlyChildInGroup() {
813 return mGroupManager.isOnlyChildInGroup(getStatusBarNotification());
814 }
815
Selim Cinek388df6d2015-10-22 13:25:11 -0700816 public ExpandableNotificationRow getNotificationParent() {
817 return mNotificationParent;
818 }
819
Selim Cinek263398f2015-10-21 17:40:23 -0700820 /**
821 * @param isChildInGroup Is this notification now in a group
822 * @param parent the new parent notification
823 */
Selim Cinekc25989e2018-02-16 16:42:14 -0800824 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500825 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cinekc25989e2018-02-16 16:42:14 -0800826 if (mExpandAnimationRunning && !isChildInGroup && mNotificationParent != null) {
827 mNotificationParent.setChildIsExpanding(false);
828 mNotificationParent.setExtraWidthForClipping(0.0f);
829 mNotificationParent.setMinimumHeightForClipping(0);
830 }
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700831 mNotificationParent = childInGroup ? parent : null;
832 mPrivateLayout.setIsChildInGroup(childInGroup);
Selim Cinek5ba22542017-04-20 15:16:10 -0700833 mNotificationInflater.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400834 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700835 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700836 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700837 if (mNotificationParent != null) {
Selim Cinek9ce32852017-02-15 16:21:10 -0800838 setOverrideTintColor(NO_COLOR, 0.0f);
Selim Cinekeccf4942018-05-30 09:55:36 -0700839 // Let's reset the distance to top roundness, as this isn't applied to group children
840 setDistanceToTopRoundness(NO_ROUNDNESS);
Mady Mellorb0a82462016-04-30 17:31:02 -0700841 mNotificationParent.updateBackgroundForGroupState();
842 }
Selim Cinekdb167372016-11-17 15:41:17 -0800843 updateIconVisibilities();
Selim Cinek2871bef2017-11-22 08:40:00 -0800844 updateBackgroundClipping();
Selim Cinek34d93b02015-10-22 12:30:38 -0700845 }
846
847 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800848 public boolean onTouchEvent(MotionEvent event) {
849 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
850 || !isChildInGroup() || isGroupExpanded()) {
851 return super.onTouchEvent(event);
852 } else {
853 return false;
854 }
855 }
856
857 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800858 protected boolean handleSlideBack() {
Mady Mellor95d743c2017-01-10 12:05:27 -0800859 if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800860 animateTranslateNotification(0 /* targetLeft */);
861 return true;
862 }
863 return false;
864 }
865
866 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700867 protected boolean shouldHideBackground() {
868 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700869 }
870
871 @Override
872 public boolean isSummaryWithChildren() {
873 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100874 }
875
876 @Override
877 public boolean areChildrenExpanded() {
878 return mChildrenExpanded;
879 }
880
881 public List<ExpandableNotificationRow> getNotificationChildren() {
882 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
883 }
884
Selim Cinekeef84282015-10-30 16:28:00 -0700885 public int getNumberOfNotificationChildren() {
886 if (mChildrenContainer == null) {
887 return 0;
888 }
889 return mChildrenContainer.getNotificationChildren().size();
890 }
891
Selim Cinekb5605e52015-02-20 18:21:41 +0100892 /**
893 * Apply the order given in the list to the children.
894 *
895 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800896 * @param visualStabilityManager
897 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100898 * @return whether the list order has changed
899 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800900 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
901 VisualStabilityManager visualStabilityManager,
902 VisualStabilityManager.Callback callback) {
903 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
904 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100905 }
906
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500907 /** Updates states of all children. */
908 public void updateChildrenStates(AmbientState ambientState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700909 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500910 ExpandableViewState parentState = getViewState();
911 mChildrenContainer.updateState(parentState, ambientState);
Selim Cinekb5605e52015-02-20 18:21:41 +0100912 }
913 }
914
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500915 /** Applies children states. */
916 public void applyChildrenState() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700917 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500918 mChildrenContainer.applyState();
Selim Cinekb5605e52015-02-20 18:21:41 +0100919 }
920 }
921
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500922 /** Prepares expansion changed. */
923 public void prepareExpansionChanged() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700924 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500925 mChildrenContainer.prepareExpansionChanged();
Selim Cinekb5605e52015-02-20 18:21:41 +0100926 }
927 }
928
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500929 /** Starts child animations. */
930 public void startChildAnimation(AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700931 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500932 mChildrenContainer.startAnimationToState(properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100933 }
934 }
935
936 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800937 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100938 return this;
939 } else {
940 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
941 return view == null ? this : view;
942 }
943 }
944
Selim Cinekab29aeb2015-02-20 18:18:32 +0100945 public NotificationGuts getGuts() {
946 return mGuts;
947 }
948
Selim Cinek684a4422015-04-15 16:18:39 -0700949 /**
950 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
951 * the notification will be rendered on top of the screen.
952 *
953 * @param pinned whether it is pinned
954 */
955 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700956 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek5cf1d052017-06-01 17:36:46 -0700957 boolean wasAboveShelf = isAboveShelf();
Selim Cinek684a4422015-04-15 16:18:39 -0700958 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700959 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700960 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700961 }
Selim Cinek31aada42015-12-18 17:51:15 -0800962 if (pinned) {
963 setIconAnimationRunning(true);
964 mExpandedWhenPinned = false;
965 } else if (mExpandedWhenPinned) {
966 setUserExpanded(true);
967 }
Selim Cinek98713a42015-09-21 15:47:20 +0200968 setChronometerRunning(mLastChronometerRunning);
Selim Cinek5cf1d052017-06-01 17:36:46 -0700969 if (isAboveShelf() != wasAboveShelf) {
970 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
971 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700972 }
973
Selim Cinek29aab962018-02-27 17:05:45 -0800974 @Override
Selim Cinek684a4422015-04-15 16:18:39 -0700975 public boolean isPinned() {
976 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700977 }
978
Selim Cinekd127d792016-11-01 19:11:41 -0700979 @Override
980 public int getPinnedHeadsUpHeight() {
981 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
982 }
983
Selim Cinek31aada42015-12-18 17:51:15 -0800984 /**
985 * @param atLeastMinHeight should the value returned be at least the minimum height.
986 * Used to avoid cyclic calls
987 * @return the height of the heads up notification when pinned
988 */
Selim Cinekd127d792016-11-01 19:11:41 -0700989 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800990 if (mIsSummaryWithChildren) {
991 return mChildrenContainer.getIntrinsicHeight();
992 }
Selim Cinek31aada42015-12-18 17:51:15 -0800993 if(mExpandedWhenPinned) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800994 return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
Selim Cinek31aada42015-12-18 17:51:15 -0800995 } else if (atLeastMinHeight) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800996 return Math.max(getCollapsedHeight(), getHeadsUpHeight());
Selim Cinek31aada42015-12-18 17:51:15 -0800997 } else {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800998 return getHeadsUpHeight();
Selim Cinek31aada42015-12-18 17:51:15 -0800999 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001000 }
1001
Jorim Jaggi5eb67c22015-08-19 19:50:49 -07001002 /**
1003 * Mark whether this notification was just clicked, i.e. the user has just clicked this
1004 * notification in this frame.
1005 */
1006 public void setJustClicked(boolean justClicked) {
1007 mJustClicked = justClicked;
1008 }
1009
1010 /**
1011 * @return true if this notification has been clicked in this frame, false otherwise
1012 */
1013 public boolean wasJustClicked() {
1014 return mJustClicked;
1015 }
1016
Selim Cinek98713a42015-09-21 15:47:20 +02001017 public void setChronometerRunning(boolean running) {
1018 mLastChronometerRunning = running;
1019 setChronometerRunning(running, mPrivateLayout);
1020 setChronometerRunning(running, mPublicLayout);
1021 if (mChildrenContainer != null) {
1022 List<ExpandableNotificationRow> notificationChildren =
1023 mChildrenContainer.getNotificationChildren();
1024 for (int i = 0; i < notificationChildren.size(); i++) {
1025 ExpandableNotificationRow child = notificationChildren.get(i);
1026 child.setChronometerRunning(running);
1027 }
1028 }
1029 }
1030
1031 private void setChronometerRunning(boolean running, NotificationContentView layout) {
1032 if (layout != null) {
1033 running = running || isPinned();
1034 View contractedChild = layout.getContractedChild();
1035 View expandedChild = layout.getExpandedChild();
1036 View headsUpChild = layout.getHeadsUpChild();
1037 setChronometerRunningForChild(running, contractedChild);
1038 setChronometerRunningForChild(running, expandedChild);
1039 setChronometerRunningForChild(running, headsUpChild);
1040 }
1041 }
1042
1043 private void setChronometerRunningForChild(boolean running, View child) {
1044 if (child != null) {
1045 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
1046 if (chronometer instanceof Chronometer) {
1047 ((Chronometer) chronometer).setStarted(running);
1048 }
1049 }
1050 }
1051
Selim Cinekea4bef72015-12-02 15:51:10 -08001052 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -07001053 if (mIsSummaryWithChildren) {
1054 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -07001055 }
Selim Cinekea4bef72015-12-02 15:51:10 -08001056 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -07001057 }
1058
Selim Cinek414ad332017-02-24 19:06:12 -08001059 /**
1060 * @return the currently visible notification header. This can be different from
1061 * {@link #getNotificationHeader()} in case it is a low-priority group.
1062 */
1063 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08001064 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek414ad332017-02-24 19:06:12 -08001065 return mChildrenContainer.getVisibleHeader();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001066 }
1067 return getShowingLayout().getVisibleNotificationHeader();
1068 }
1069
Selim Cinekb26afa32017-06-29 10:28:17 +02001070
1071 /**
1072 * @return the contracted notification header. This can be different from
1073 * {@link #getNotificationHeader()} and also {@link #getVisibleNotificationHeader()} and only
1074 * returns the contracted version.
1075 */
1076 public NotificationHeaderView getContractedNotificationHeader() {
1077 if (mIsSummaryWithChildren) {
1078 return mChildrenContainer.getHeaderView();
1079 }
1080 return mPrivateLayout.getContractedNotificationHeader();
1081 }
1082
Selim Cinek570981d2015-12-01 11:37:01 -08001083 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
1084 mOnExpandClickListener = onExpandClickListener;
1085 }
1086
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001087 public void setLongPressListener(LongPressListener longPressListener) {
1088 mLongPressListener = longPressListener;
1089 }
1090
Selim Cinekddf1b392016-05-27 16:33:10 -07001091 @Override
1092 public void setOnClickListener(@Nullable OnClickListener l) {
1093 super.setOnClickListener(l);
1094 mOnClickListener = l;
1095 updateClickAndFocus();
1096 }
1097
1098 private void updateClickAndFocus() {
1099 boolean normalChild = !isChildInGroup() || isGroupExpanded();
1100 boolean clickable = mOnClickListener != null && normalChild;
1101 if (isFocusable() != normalChild) {
1102 setFocusable(normalChild);
1103 }
1104 if (isClickable() != clickable) {
1105 setClickable(clickable);
1106 }
1107 }
1108
Selim Cinek31aada42015-12-18 17:51:15 -08001109 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
1110 mHeadsUpManager = headsUpManager;
1111 }
1112
Gustav Senntond0e84532018-12-03 16:48:36 +00001113 public HeadsUpManager getHeadsUpManager() {
1114 return mHeadsUpManager;
1115 }
1116
Mady Mellor87d79452017-01-10 11:52:52 -08001117 public void setGutsView(MenuItem item) {
Rohan Shah20790b82018-07-02 17:21:04 -07001118 if (mGuts != null && item.getGutsView() instanceof NotificationGuts.GutsContent) {
1119 ((NotificationGuts.GutsContent) item.getGutsView()).setGutsParent(mGuts);
1120 mGuts.setGutsContent((NotificationGuts.GutsContent) item.getGutsView());
Mady Mellor87d79452017-01-10 11:52:52 -08001121 }
1122 }
1123
Mady Mellor95d743c2017-01-10 12:05:27 -08001124 @Override
1125 protected void onAttachedToWindow() {
1126 super.onAttachedToWindow();
Aaron Heuckroth1dd67cb2018-06-14 14:28:08 -04001127 mEntry.setInitializationTime(SystemClock.elapsedRealtime());
Mady Mellor95d743c2017-01-10 12:05:27 -08001128 Dependency.get(PluginManager.class).addPluginListener(this,
1129 NotificationMenuRowPlugin.class, false /* Allow multiple */);
1130 }
1131
1132 @Override
1133 protected void onDetachedFromWindow() {
1134 super.onDetachedFromWindow();
1135 Dependency.get(PluginManager.class).removePluginListener(this);
1136 }
1137
1138 @Override
1139 public void onPluginConnected(NotificationMenuRowPlugin plugin, Context pluginContext) {
1140 boolean existed = mMenuRow.getMenuView() != null;
1141 if (existed) {
1142 removeView(mMenuRow.getMenuView());
1143 }
1144 mMenuRow = plugin;
Aaron Heuckroth266cb342018-09-07 14:52:04 -04001145 if (mMenuRow.shouldUseDefaultMenuItems()) {
Mady Mellor4c197602017-04-10 17:57:52 -07001146 ArrayList<MenuItem> items = new ArrayList<>();
1147 items.add(NotificationMenuRow.createInfoItem(mContext));
1148 items.add(NotificationMenuRow.createSnoozeItem(mContext));
Julia Reynoldsb5867452018-02-28 16:31:35 -05001149 items.add(NotificationMenuRow.createAppOpsItem(mContext));
Mady Mellor4c197602017-04-10 17:57:52 -07001150 mMenuRow.setMenuItems(items);
Mady Mellor95d743c2017-01-10 12:05:27 -08001151 }
1152 if (existed) {
1153 createMenu();
1154 }
1155 }
1156
1157 @Override
1158 public void onPluginDisconnected(NotificationMenuRowPlugin plugin) {
1159 boolean existed = mMenuRow.getMenuView() != null;
1160 mMenuRow = new NotificationMenuRow(mContext); // Back to default
1161 if (existed) {
1162 createMenu();
1163 }
1164 }
1165
1166 public NotificationMenuRowPlugin createMenu() {
1167 if (mMenuRow.getMenuView() == null) {
Mady Mellor4ab28202017-06-06 11:42:50 -07001168 mMenuRow.createMenu(this, mStatusBarNotification);
Mady Mellor95d743c2017-01-10 12:05:27 -08001169 mMenuRow.setAppName(mAppName);
1170 FrameLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
1171 LayoutParams.MATCH_PARENT);
1172 addView(mMenuRow.getMenuView(), MENU_VIEW_INDEX, lp);
1173 }
1174 return mMenuRow;
1175 }
1176
Mady Mellor95d743c2017-01-10 12:05:27 -08001177 public NotificationMenuRowPlugin getProvider() {
1178 return mMenuRow;
1179 }
1180
Anthony Chen9fe1ee72017-04-07 13:53:37 -07001181 @Override
Selim Cinek1a48bab2017-02-17 19:38:40 -08001182 public void onDensityOrFontScaleChanged() {
Anthony Chen9fe1ee72017-04-07 13:53:37 -07001183 super.onDensityOrFontScaleChanged();
Selim Cinek01af3342016-02-09 19:25:31 -08001184 initDimens();
Anthony Chenad4d1582017-04-10 16:07:58 -07001185 initBackground();
Lucas Dupinf03e7522018-06-25 16:21:13 -07001186 reInflateViews();
1187 }
1188
1189 private void reInflateViews() {
Selim Cinek817abe72017-05-24 11:08:55 -07001190 // Let's update our childrencontainer. This is intentionally not guarded with
1191 // mIsSummaryWithChildren since we might have had children but not anymore.
1192 if (mChildrenContainer != null) {
1193 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -08001194 }
1195 if (mGuts != null) {
1196 View oldGuts = mGuts;
1197 int index = indexOfChild(oldGuts);
1198 removeView(oldGuts);
1199 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
1200 R.layout.notification_guts, this, false);
1201 mGuts.setVisibility(oldGuts.getVisibility());
1202 addView(mGuts, index);
1203 }
Mady Mellor95d743c2017-01-10 12:05:27 -08001204 View oldMenu = mMenuRow.getMenuView();
1205 if (oldMenu != null) {
Mady Mellor761cde12017-01-10 11:36:39 -08001206 int menuIndex = indexOfChild(oldMenu);
1207 removeView(oldMenu);
Mady Mellor4ab28202017-06-06 11:42:50 -07001208 mMenuRow.createMenu(ExpandableNotificationRow.this, mStatusBarNotification);
Mady Mellor761cde12017-01-10 11:36:39 -08001209 mMenuRow.setAppName(mAppName);
Mady Mellor95d743c2017-01-10 12:05:27 -08001210 addView(mMenuRow.getMenuView(), menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -08001211 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001212 for (NotificationContentView l : mLayouts) {
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001213 l.initView();
Adrian Rooseb434ff2017-01-11 11:18:48 -08001214 l.reInflateViews();
1215 }
Amin Shaikhc3f0b062019-02-12 19:00:17 -05001216 mStatusBarNotification.clearPackageContext();
Lucas Dupinf03e7522018-06-25 16:21:13 -07001217 mNotificationInflater.clearCachesAndReInflate();
Selim Cinek1a48bab2017-02-17 19:38:40 -08001218 onNotificationUpdated();
Selim Cinek01af3342016-02-09 19:25:31 -08001219 }
1220
Mady Mellor9d03a522017-04-04 18:45:30 -07001221 @Override
1222 public void onConfigurationChanged(Configuration newConfig) {
1223 if (mMenuRow.getMenuView() != null) {
1224 mMenuRow.onConfigurationChanged();
1225 }
1226 }
1227
Lucas Dupinf03e7522018-06-25 16:21:13 -07001228 public void onUiModeChanged() {
Selim Cinekab9c7b22018-12-11 18:15:47 -08001229 mUpdateBackgroundOnUpdate = true;
Lucas Dupinf03e7522018-06-25 16:21:13 -07001230 reInflateViews();
1231 if (mChildrenContainer != null) {
1232 for (ExpandableNotificationRow child : mChildrenContainer.getNotificationChildren()) {
1233 child.onUiModeChanged();
1234 }
1235 }
1236 }
1237
Selim Cinekc3179332016-03-04 14:44:56 -08001238 public void setContentBackground(int customBackgroundColor, boolean animate,
1239 NotificationContentView notificationContentView) {
1240 if (getShowingLayout() == notificationContentView) {
1241 setTintColor(customBackgroundColor, animate);
1242 }
1243 }
1244
Kenny Guy14d035c2018-05-02 19:10:36 +01001245 @Override
1246 protected void setBackgroundTintColor(int color) {
1247 super.setBackgroundTintColor(color);
1248 NotificationContentView view = getShowingLayout();
1249 if (view != null) {
1250 view.setBackgroundTintColor(color);
1251 }
1252 }
1253
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001254 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -08001255 for (NotificationContentView l : mLayouts) {
1256 l.closeRemoteInput();
1257 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001258 }
1259
Selim Cinekc897bd32016-03-18 17:32:31 -07001260 /**
1261 * Set by how much the single line view should be indented.
1262 */
1263 public void setSingleLineWidthIndention(int indention) {
1264 mPrivateLayout.setSingleLineWidthIndention(indention);
1265 }
1266
1267 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -07001268 return mNotificationColor;
1269 }
1270
1271 private void updateNotificationColor() {
Lucas Dupind26facc2018-09-10 18:07:30 -07001272 Configuration currentConfig = getResources().getConfiguration();
1273 boolean nightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
1274 == Configuration.UI_MODE_NIGHT_YES;
1275
Lucas Dupina291d192018-06-07 13:59:42 -07001276 mNotificationColor = ContrastColorUtil.resolveContrastColor(mContext,
Selim Cinekac5f0272017-05-02 16:05:41 -07001277 getStatusBarNotification().getNotification().color,
Lucas Dupind26facc2018-09-10 18:07:30 -07001278 getBackgroundColorWithoutTint(), nightMode);
Lucas Dupina291d192018-06-07 13:59:42 -07001279 mNotificationColorAmbient = ContrastColorUtil.resolveAmbientColor(mContext,
Adrian Roos6f6e1592017-05-02 16:22:53 -07001280 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -07001281 }
1282
1283 public HybridNotificationView getSingleLineView() {
1284 return mPrivateLayout.getSingleLineView();
1285 }
1286
Adrian Roos6f6e1592017-05-02 16:22:53 -07001287 public HybridNotificationView getAmbientSingleLineView() {
1288 return getShowingLayout().getAmbientSingleLineChild();
1289 }
1290
Selim Cinekf07d0622016-03-21 19:52:52 -07001291 public boolean isOnKeyguard() {
1292 return mOnKeyguard;
1293 }
1294
Selim Cinekc1e389d2016-04-07 11:02:57 -07001295 public void removeAllChildren() {
1296 List<ExpandableNotificationRow> notificationChildren
1297 = mChildrenContainer.getNotificationChildren();
1298 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
1299 for (int i = 0; i < clonedList.size(); i++) {
1300 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -07001301 if (row.keepInParent()) {
1302 continue;
1303 }
Selim Cinekc1e389d2016-04-07 11:02:57 -07001304 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -07001305 row.setIsChildInGroup(false, null);
1306 }
1307 onChildrenCountChanged();
1308 }
1309
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001310 public void setForceUnlocked(boolean forceUnlocked) {
1311 mForceUnlocked = forceUnlocked;
1312 if (mIsSummaryWithChildren) {
1313 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
1314 for (ExpandableNotificationRow child : notificationChildren) {
1315 child.setForceUnlocked(forceUnlocked);
1316 }
1317 }
1318 }
1319
Selim Cinekd03518c2018-03-15 12:13:51 -07001320 public void setDismissed(boolean fromAccessibility) {
Rohan Shahc6990a02018-03-23 17:24:17 -07001321 setLongPressListener(null);
Selim Cinekd03518c2018-03-15 12:13:51 -07001322 mDismissed = true;
Selim Cineke9bad242016-06-15 11:46:37 -07001323 mGroupParentWhenDismissed = mNotificationParent;
1324 mRefocusOnDismiss = fromAccessibility;
1325 mChildAfterViewWhenDismissed = null;
Selim Cinekd03518c2018-03-15 12:13:51 -07001326 mEntry.icon.setDismissed();
Selim Cineke9bad242016-06-15 11:46:37 -07001327 if (isChildInGroup()) {
1328 List<ExpandableNotificationRow> notificationChildren =
1329 mNotificationParent.getNotificationChildren();
1330 int i = notificationChildren.indexOf(this);
1331 if (i != -1 && i < notificationChildren.size() - 1) {
1332 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
1333 }
1334 }
Selim Cinek3f19f602016-05-02 18:01:56 -07001335 }
1336
1337 public boolean isDismissed() {
1338 return mDismissed;
1339 }
1340
1341 public boolean keepInParent() {
1342 return mKeepInParent;
1343 }
1344
1345 public void setKeepInParent(boolean keepInParent) {
1346 mKeepInParent = keepInParent;
1347 }
1348
Selim Cinekd9b7dd42017-11-10 17:53:47 -08001349 @Override
Selim Cinek3f19f602016-05-02 18:01:56 -07001350 public boolean isRemoved() {
1351 return mRemoved;
1352 }
1353
Adrian Roosd009ab12016-05-20 17:58:53 -07001354 public void setRemoved() {
1355 mRemoved = true;
Selim Cinekef8c2252017-02-10 14:52:18 -08001356 mTranslationWhenRemoved = getTranslationY();
1357 mWasChildInGroupWhenRemoved = isChildInGroup();
1358 if (isChildInGroup()) {
1359 mTranslationWhenRemoved += getNotificationParent().getTranslationY();
1360 }
Adrian Roosd009ab12016-05-20 17:58:53 -07001361 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -07001362 }
1363
Selim Cinekef8c2252017-02-10 14:52:18 -08001364 public boolean wasChildInGroupWhenRemoved() {
1365 return mWasChildInGroupWhenRemoved;
1366 }
1367
1368 public float getTranslationWhenRemoved() {
1369 return mTranslationWhenRemoved;
1370 }
1371
Selim Cinekd1395642016-04-28 12:22:42 -07001372 public NotificationChildrenContainer getChildrenContainer() {
1373 return mChildrenContainer;
1374 }
1375
Selim Cinekcafa87f2016-10-26 17:00:17 -07001376 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07001377 boolean wasAboveShelf = isAboveShelf();
Selim Cinek8875de12018-03-22 10:14:32 -07001378 boolean changed = headsUpAnimatingAway != mHeadsupDisappearRunning;
Selim Cinekcafa87f2016-10-26 17:00:17 -07001379 mHeadsupDisappearRunning = headsUpAnimatingAway;
1380 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
Selim Cinek8875de12018-03-22 10:14:32 -07001381 if (changed && mHeadsUpAnimatingAwayListener != null) {
1382 mHeadsUpAnimatingAwayListener.accept(headsUpAnimatingAway);
1383 }
Selim Cinek5cf1d052017-06-01 17:36:46 -07001384 if (isAboveShelf() != wasAboveShelf) {
1385 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
1386 }
Selim Cinekcafa87f2016-10-26 17:00:17 -07001387 }
1388
Selim Cinek8875de12018-03-22 10:14:32 -07001389 public void setHeadsUpAnimatingAwayListener(Consumer<Boolean> listener) {
1390 mHeadsUpAnimatingAwayListener = listener;
1391 }
1392
Selim Cinekcafa87f2016-10-26 17:00:17 -07001393 /**
1394 * @return if the view was just heads upped and is now animating away. During such a time the
1395 * layout needs to be kept consistent
1396 */
Selim Cinek29aab962018-02-27 17:05:45 -08001397 @Override
Selim Cinekcafa87f2016-10-26 17:00:17 -07001398 public boolean isHeadsUpAnimatingAway() {
1399 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -07001400 }
1401
Selim Cineke9bad242016-06-15 11:46:37 -07001402 public View getChildAfterViewWhenDismissed() {
1403 return mChildAfterViewWhenDismissed;
1404 }
1405
1406 public View getGroupParentWhenDismissed() {
1407 return mGroupParentWhenDismissed;
1408 }
1409
Rohan Shah524cf7b2018-03-15 14:40:02 -07001410 /**
1411 * Dismisses the notification with the option of showing the blocking helper in-place if we have
1412 * a negative user sentiment.
1413 *
1414 * @param fromAccessibility whether this dismiss is coming from an accessibility action
1415 * @return whether a blocking helper is shown in this row
1416 */
1417 public boolean performDismissWithBlockingHelper(boolean fromAccessibility) {
1418 NotificationBlockingHelperManager manager =
1419 Dependency.get(NotificationBlockingHelperManager.class);
1420 boolean isBlockingHelperShown = manager.perhapsShowBlockingHelper(this, mMenuRow);
1421
Rohan Shahda5dcdd2018-04-27 17:21:50 -07001422 Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
1423
Rohan Shah524cf7b2018-03-15 14:40:02 -07001424 // Continue with dismiss since we don't want the blocking helper to be directly associated
1425 // with a certain notification.
1426 performDismiss(fromAccessibility);
1427 return isBlockingHelperShown;
1428 }
1429
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001430 public void performDismiss(boolean fromAccessibility) {
Rohan Shah524cf7b2018-03-15 14:40:02 -07001431 if (isOnlyChildInGroup()) {
Ned Burnsf81c4c42019-01-07 14:10:43 -05001432 NotificationEntry groupSummary =
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001433 mGroupManager.getLogicalGroupSummary(getStatusBarNotification());
1434 if (groupSummary.isClearable()) {
Rohan Shah524cf7b2018-03-15 14:40:02 -07001435 // If this is the only child in the group, dismiss the group, but don't try to show
1436 // the blocking helper affordance!
Evan Laird94492852018-10-25 13:43:01 -04001437 groupSummary.getRow().performDismiss(fromAccessibility);
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001438 }
1439 }
Selim Cinekd03518c2018-03-15 12:13:51 -07001440 setDismissed(fromAccessibility);
Evan Laird94492852018-10-25 13:43:01 -04001441 if (mEntry.isClearable()) {
Julia Reynoldsfd4099d2018-08-21 11:06:06 -04001442 // TODO: track dismiss sentiment
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001443 if (mOnDismissRunnable != null) {
1444 mOnDismissRunnable.run();
1445 }
Selim Cineke9079112016-12-14 14:41:01 -08001446 }
Selim Cinek9e624e72016-07-20 13:46:49 -07001447 }
1448
Rohan Shah524cf7b2018-03-15 14:40:02 -07001449 public void setBlockingHelperShowing(boolean isBlockingHelperShowing) {
1450 mIsBlockingHelperShowing = isBlockingHelperShowing;
1451 }
1452
1453 public boolean isBlockingHelperShowing() {
1454 return mIsBlockingHelperShowing;
1455 }
1456
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001457 public boolean isBlockingHelperShowingAndTranslationFinished() {
1458 return mIsBlockingHelperShowing && mNotificationTranslationFinished;
1459 }
1460
Selim Cineke9079112016-12-14 14:41:01 -08001461 public void setOnDismissRunnable(Runnable onDismissRunnable) {
1462 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -07001463 }
1464
Selim Cinek281c2022016-10-13 19:14:43 -07001465 public View getNotificationIcon() {
Selim Cinek414ad332017-02-24 19:06:12 -08001466 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek281c2022016-10-13 19:14:43 -07001467 if (notificationHeader != null) {
1468 return notificationHeader.getIcon();
1469 }
1470 return null;
1471 }
1472
1473 /**
1474 * @return whether the notification is currently showing a view with an icon.
1475 */
1476 public boolean isShowingIcon() {
Mady Mellor434180c2017-02-13 11:29:42 -08001477 if (areGutsExposed()) {
1478 return false;
1479 }
Selim Cinek2ffa02f2017-03-06 15:56:37 -08001480 return getVisibleNotificationHeader() != null;
Selim Cinek281c2022016-10-13 19:14:43 -07001481 }
1482
Selim Cinek0242fbb2016-10-19 13:38:32 -07001483 /**
1484 * Set how much this notification is transformed into an icon.
1485 *
Selim Cinek2b549f42016-11-22 16:38:51 -08001486 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
1487 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -08001488 * @param isLastChild is this the last child in the list. If true, then the transformation is
1489 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -07001490 */
Selim Cinek2b549f42016-11-22 16:38:51 -08001491 public void setContentTransformationAmount(float contentTransformationAmount,
1492 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -08001493 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001494 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001495 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001496 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001497 if (changeTransformation) {
1498 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -08001499 }
1500 }
1501
1502 /**
1503 * Set the icons to be visible of this notification.
1504 */
1505 public void setIconsVisible(boolean iconsVisible) {
1506 if (iconsVisible != mIconsVisible) {
1507 mIconsVisible = iconsVisible;
1508 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -07001509 }
1510 }
1511
Selim Cinekdb167372016-11-17 15:41:17 -08001512 @Override
1513 protected void onBelowSpeedBumpChanged() {
1514 updateIconVisibilities();
1515 }
1516
Selim Cinek875a3a12016-11-18 17:52:16 -08001517 private void updateContentTransformation() {
Selim Cinek2627d722018-01-19 12:16:49 -08001518 if (mExpandAnimationRunning) {
1519 return;
1520 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001521 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -08001522 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -08001523 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -08001524 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001525 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001526 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -08001527 translationY *= 0.4f;
1528 } else {
1529 contentAlpha = 1.0f;
1530 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001531 for (NotificationContentView l : mLayouts) {
1532 l.setAlpha(contentAlpha);
1533 l.setTranslationY(translationY);
1534 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001535 if (mChildrenContainer != null) {
1536 mChildrenContainer.setAlpha(contentAlpha);
1537 mChildrenContainer.setTranslationY(translationY);
1538 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -07001539 }
1540 }
1541
1542 private void updateIconVisibilities() {
Gus Prevas4b3c0ff22018-11-02 13:15:23 -04001543 boolean visible = isChildInGroup() || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -08001544 for (NotificationContentView l : mLayouts) {
1545 l.setIconsVisible(visible);
1546 }
Selim Cinekdb167372016-11-17 15:41:17 -08001547 if (mChildrenContainer != null) {
1548 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001549 }
1550 }
1551
Selim Cinek875a3a12016-11-18 17:52:16 -08001552 /**
1553 * Get the relative top padding of a view relative to this view. This recursively walks up the
1554 * hierarchy and does the corresponding measuring.
1555 *
1556 * @param view the view to the the padding for. The requested view has to be a child of this
1557 * notification.
1558 * @return the toppadding
1559 */
1560 public int getRelativeTopPadding(View view) {
1561 int topPadding = 0;
1562 while (view.getParent() instanceof ViewGroup) {
1563 topPadding += view.getTop();
1564 view = (View) view.getParent();
1565 if (view instanceof ExpandableNotificationRow) {
1566 return topPadding;
1567 }
1568 }
1569 return topPadding;
1570 }
1571
Selim Cineka1d97902016-12-14 16:31:40 -08001572 public float getContentTranslation() {
1573 return mPrivateLayout.getTranslationY();
1574 }
1575
Selim Cinek6743c0b2017-01-18 18:24:01 -08001576 public void setIsLowPriority(boolean isLowPriority) {
1577 mIsLowPriority = isLowPriority;
1578 mPrivateLayout.setIsLowPriority(isLowPriority);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001579 mNotificationInflater.setIsLowPriority(mIsLowPriority);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001580 if (mChildrenContainer != null) {
1581 mChildrenContainer.setIsLowPriority(isLowPriority);
1582 }
1583 }
1584
Selim Cinek414ad332017-02-24 19:06:12 -08001585 public boolean isLowPriority() {
1586 return mIsLowPriority;
1587 }
1588
Selim Cinek7d1009b2017-01-25 15:28:28 -08001589 public void setUseIncreasedCollapsedHeight(boolean use) {
1590 mUseIncreasedCollapsedHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001591 mNotificationInflater.setUsesIncreasedHeight(use);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001592 }
1593
Selim Cinek87ed69b2017-02-09 15:59:43 -08001594 public void setUseIncreasedHeadsUpHeight(boolean use) {
1595 mUseIncreasedHeadsUpHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001596 mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
1597 }
1598
1599 public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
1600 mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001601 }
1602
Selim Cinek5ba22542017-04-20 15:16:10 -07001603 public void setInflationCallback(InflationCallback callback) {
1604 mNotificationInflater.setInflationCallback(callback);
Selim Cinekc478f902017-02-22 20:55:44 -08001605 }
1606
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001607 public void setNeedsRedaction(boolean needsRedaction) {
Kevin38ce6fa2018-10-17 16:00:14 -07001608 if (mNeedsRedaction != needsRedaction) {
1609 mNeedsRedaction = needsRedaction;
1610 updateInflationFlag(FLAG_CONTENT_VIEW_PUBLIC, needsRedaction /* shouldInflate */);
1611 mNotificationInflater.updateNeedsRedaction(needsRedaction);
1612 if (!needsRedaction) {
1613 freeContentViewWhenSafe(FLAG_CONTENT_VIEW_PUBLIC);
1614 }
1615 }
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001616 }
1617
Selim Cinek5ba22542017-04-20 15:16:10 -07001618 @VisibleForTesting
Ned Burns1a5e22f2019-02-14 15:11:52 -05001619 public NotificationContentInflater getNotificationInflater() {
Selim Cinek5ba22542017-04-20 15:16:10 -07001620 return mNotificationInflater;
1621 }
1622
Adrian Roos6f6e1592017-05-02 16:22:53 -07001623 public int getNotificationColorAmbient() {
1624 return mNotificationColorAmbient;
1625 }
1626
Chris Wren78403d72014-07-28 10:23:24 +01001627 public interface ExpansionLogger {
Anthony Chen6bf88a02017-04-10 14:41:44 -07001628 void logNotificationExpansion(String key, boolean userAction, boolean expanded);
Chris Wren78403d72014-07-28 10:23:24 +01001629 }
Selim Cinek1685e632014-04-08 02:27:49 +02001630
Chris Wren51c75102013-07-16 20:49:17 -04001631 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1632 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001633 mFalsingManager = FalsingManager.getInstance(context);
Ned Burns1a5e22f2019-02-14 15:11:52 -05001634 mNotificationInflater = new NotificationContentInflater(this);
Mady Mellor95d743c2017-01-10 12:05:27 -08001635 mMenuRow = new NotificationMenuRow(mContext);
Ahan Wude396fa2018-05-08 20:42:24 +08001636 mImageResolver = new NotificationInlineImageResolver(context,
1637 new NotificationInlineImageCache());
Selim Cinek01af3342016-02-09 19:25:31 -08001638 initDimens();
1639 }
1640
1641 private void initDimens() {
Rohan Shahb9d500a2018-06-25 16:27:16 -07001642 mNotificationMinHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
Selim Cineke62255c2017-09-28 18:23:23 -07001643 R.dimen.notification_min_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001644 mNotificationMinHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1645 R.dimen.notification_min_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001646 mNotificationMinHeight = NotificationUtils.getFontScaledHeight(mContext,
1647 R.dimen.notification_min_height);
1648 mNotificationMinHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001649 R.dimen.notification_min_height_increased);
Beth Thibodeaucb395352019-01-25 15:39:54 -05001650 mNotificationMinHeightMedia = NotificationUtils.getFontScaledHeight(mContext,
1651 R.dimen.notification_min_height_media);
Selim Cineke62255c2017-09-28 18:23:23 -07001652 mNotificationMaxHeight = NotificationUtils.getFontScaledHeight(mContext,
1653 R.dimen.notification_max_height);
Rohan Shahb9d500a2018-06-25 16:27:16 -07001654 mMaxHeadsUpHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek77019c72015-12-09 10:18:02 -08001655 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001656 mMaxHeadsUpHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1657 R.dimen.notification_max_heads_up_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001658 mMaxHeadsUpHeight = NotificationUtils.getFontScaledHeight(mContext,
1659 R.dimen.notification_max_heads_up_height);
1660 mMaxHeadsUpHeightIncreased = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001661 R.dimen.notification_max_heads_up_height_increased);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001662
Anthony Chen7acbb772017-04-07 16:45:25 -07001663 Resources res = getResources();
1664 mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
1665 R.dimen.notification_divider_height_increased);
1666 mIconTransformContentShiftNoIcon = res.getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001667 R.dimen.notification_icon_transform_content_shift);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001668 mEnableNonGroupedNotificationExpand =
1669 res.getBoolean(R.bool.config_enableNonGroupedNotificationExpand);
1670 mShowGroupBackgroundWhenExpanded =
1671 res.getBoolean(R.bool.config_showGroupNotificationBgWhenExpanded);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001672 }
1673
Ahan Wude396fa2018-05-08 20:42:24 +08001674 NotificationInlineImageResolver getImageResolver() {
1675 return mImageResolver;
1676 }
1677
Selim Cinekf619ffc2016-02-17 14:53:05 -08001678 /**
Christoph Studera7fe6312014-06-27 19:32:44 +02001679 * Resets this view so it can be re-used for an updated notification.
1680 */
1681 public void reset() {
Jorim Jaggiae441282014-08-01 02:45:18 +02001682 mShowingPublicInitialized = false;
Selim Cinek31094df2014-08-14 19:28:15 +02001683 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001684 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001685 }
1686
Julia Reynoldsfc640012018-02-21 12:25:27 -05001687 public void showAppOpsIcons(ArraySet<Integer> activeOps) {
1688 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
1689 mChildrenContainer.getHeaderView().showAppOpsIcons(activeOps);
1690 }
1691 mPrivateLayout.showAppOpsIcons(activeOps);
1692 mPublicLayout.showAppOpsIcons(activeOps);
1693 }
1694
Gus Prevas7306b902018-12-11 10:57:06 -05001695 /** Sets the last time the notification being displayed audibly alerted the user. */
1696 public void setLastAudiblyAlertedMs(long lastAudiblyAlertedMs) {
Gus Prevasa3226492018-10-23 11:10:09 -04001697 if (NotificationUtils.useNewInterruptionModel(mContext)) {
Ned Burns3da3c782019-01-08 21:14:39 -05001698 long timeSinceAlertedAudibly = System.currentTimeMillis() - lastAudiblyAlertedMs;
1699 boolean alertedRecently =
1700 timeSinceAlertedAudibly < RECENTLY_ALERTED_THRESHOLD_MS;
1701
1702 applyAudiblyAlertedRecently(alertedRecently);
1703
1704 removeCallbacks(mExpireRecentlyAlertedFlag);
1705 if (alertedRecently) {
1706 long timeUntilNoLongerRecent =
1707 RECENTLY_ALERTED_THRESHOLD_MS - timeSinceAlertedAudibly;
1708 postDelayed(mExpireRecentlyAlertedFlag, timeUntilNoLongerRecent);
Gus Prevasa3226492018-10-23 11:10:09 -04001709 }
Gus Prevasa3226492018-10-23 11:10:09 -04001710 }
1711 }
1712
Ned Burns3da3c782019-01-08 21:14:39 -05001713 private final Runnable mExpireRecentlyAlertedFlag = () -> applyAudiblyAlertedRecently(false);
1714
1715 private void applyAudiblyAlertedRecently(boolean audiblyAlertedRecently) {
1716 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
1717 mChildrenContainer.getHeaderView().setRecentlyAudiblyAlerted(audiblyAlertedRecently);
1718 }
1719 mPrivateLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
1720 mPublicLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
1721 }
1722
Julia Reynoldsb5867452018-02-28 16:31:35 -05001723 public View.OnClickListener getAppOpsOnClickListener() {
1724 return mOnAppOpsClickListener;
1725 }
1726
Rohan Shah20790b82018-07-02 17:21:04 -07001727 public void setAppOpsOnClickListener(ExpandableNotificationRow.OnAppOpsClickListener l) {
Julia Reynoldsb5867452018-02-28 16:31:35 -05001728 mOnAppOpsClickListener = v -> {
1729 createMenu();
1730 MenuItem menuItem = getProvider().getAppOpsMenuItem(mContext);
1731 if (menuItem != null) {
1732 l.onClick(this, v.getWidth() / 2, v.getHeight() / 2, menuItem);
1733 }
1734 };
1735 }
1736
Jorim Jaggi251957d2014-04-09 04:24:09 +02001737 @Override
1738 protected void onFinishInflate() {
1739 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001740 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1741 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001742 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1743
1744 for (NotificationContentView l : mLayouts) {
1745 l.setExpandClickListener(mExpandClickListener);
1746 l.setContainingNotification(this);
1747 }
Selim Cinekab29aeb2015-02-20 18:18:32 +01001748 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1749 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001750 @Override
1751 public void onInflate(ViewStub stub, View inflated) {
1752 mGuts = (NotificationGuts) inflated;
1753 mGuts.setClipTopAmount(getClipTopAmount());
1754 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001755 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001756 }
1757 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001758 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1759 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1760
1761 @Override
1762 public void onInflate(ViewStub stub, View inflated) {
1763 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001764 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek414ad332017-02-24 19:06:12 -08001765 mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001766 mChildrenContainer.onNotificationUpdated();
Anthony Chen7acbb772017-04-07 16:45:25 -07001767
1768 if (mShouldTranslateContents) {
1769 mTranslateableViews.add(mChildrenContainer);
1770 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001771 }
1772 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001773
Anthony Chen7acbb772017-04-07 16:45:25 -07001774 if (mShouldTranslateContents) {
1775 // Add the views that we translate to reveal the menu
1776 mTranslateableViews = new ArrayList<>();
1777 for (int i = 0; i < getChildCount(); i++) {
1778 mTranslateableViews.add(getChildAt(i));
1779 }
1780 // Remove views that don't translate
1781 mTranslateableViews.remove(mChildrenContainerStub);
1782 mTranslateableViews.remove(mGutsStub);
Mady Mellor4b80b102016-01-22 08:03:58 -08001783 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001784 }
1785
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001786 private void doLongClickCallback() {
1787 doLongClickCallback(getWidth() / 2, getHeight() / 2);
1788 }
1789
1790 public void doLongClickCallback(int x, int y) {
1791 createMenu();
1792 MenuItem menuItem = getProvider().getLongpressMenuItem(mContext);
Mady Mellorb3a6aed2018-05-11 13:24:07 -07001793 doLongClickCallback(x, y, menuItem);
1794 }
1795
1796 private void doLongClickCallback(int x, int y, MenuItem menuItem) {
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001797 if (mLongPressListener != null && menuItem != null) {
1798 mLongPressListener.onLongPress(this, x, y, menuItem);
1799 }
1800 }
1801
1802 @Override
1803 public boolean onKeyDown(int keyCode, KeyEvent event) {
1804 if (KeyEvent.isConfirmKey(keyCode)) {
1805 event.startTracking();
1806 return true;
1807 }
1808 return super.onKeyDown(keyCode, event);
1809 }
1810
1811 @Override
1812 public boolean onKeyUp(int keyCode, KeyEvent event) {
1813 if (KeyEvent.isConfirmKey(keyCode)) {
1814 if (!event.isCanceled()) {
1815 performClick();
1816 }
1817 return true;
1818 }
1819 return super.onKeyUp(keyCode, event);
1820 }
1821
1822 @Override
1823 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
1824 if (KeyEvent.isConfirmKey(keyCode)) {
1825 doLongClickCallback();
1826 return true;
1827 }
1828 return false;
1829 }
1830
Mady Mellor4b80b102016-01-22 08:03:58 -08001831 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001832 if (mTranslateAnim != null) {
1833 mTranslateAnim.cancel();
1834 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001835
1836 if (!mShouldTranslateContents) {
1837 setTranslationX(0);
1838 } else if (mTranslateableViews != null) {
Mady Mellor4b80b102016-01-22 08:03:58 -08001839 for (int i = 0; i < mTranslateableViews.size(); i++) {
1840 mTranslateableViews.get(i).setTranslationX(0);
1841 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001842 invalidateOutline();
shawnlin4fbeac42018-04-30 20:32:40 +08001843 getEntry().expandedIcon.setScrollX(0);
Mady Mellor4b80b102016-01-22 08:03:58 -08001844 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001845
Mady Mellor95d743c2017-01-10 12:05:27 -08001846 mMenuRow.resetMenu();
Mady Mellor4b80b102016-01-22 08:03:58 -08001847 }
1848
Rohan Shah56eb0912018-05-10 21:49:04 -07001849 void onGutsOpened() {
Rohan Shah56eb0912018-05-10 21:49:04 -07001850 updateContentAccessibilityImportanceForGuts(false /* isEnabled */);
1851 }
1852
1853 void onGutsClosed() {
1854 updateContentAccessibilityImportanceForGuts(true /* isEnabled */);
1855 }
1856
1857 /**
1858 * Updates whether all the non-guts content inside this row is important for accessibility.
1859 *
1860 * @param isEnabled whether the content views should be enabled for accessibility
1861 */
1862 private void updateContentAccessibilityImportanceForGuts(boolean isEnabled) {
1863 if (mChildrenContainer != null) {
1864 updateChildAccessibilityImportance(mChildrenContainer, isEnabled);
1865 }
1866 if (mLayouts != null) {
1867 for (View view : mLayouts) {
1868 updateChildAccessibilityImportance(view, isEnabled);
1869 }
1870 }
1871
1872 if (isEnabled) {
1873 this.requestAccessibilityFocus();
1874 }
1875 }
1876
1877 /**
1878 * Updates whether the given childView is important for accessibility based on
1879 * {@code isEnabled}.
1880 */
1881 private void updateChildAccessibilityImportance(View childView, boolean isEnabled) {
1882 childView.setImportantForAccessibility(isEnabled
1883 ? View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
1884 : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
1885 }
1886
Selim Cinekde4de0e2018-01-24 16:21:07 -08001887 public CharSequence getActiveRemoteInputText() {
1888 return mPrivateLayout.getActiveRemoteInputText();
1889 }
1890
Mady Mellor4b80b102016-01-22 08:03:58 -08001891 public void animateTranslateNotification(final float leftTarget) {
1892 if (mTranslateAnim != null) {
1893 mTranslateAnim.cancel();
1894 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001895 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001896 if (mTranslateAnim != null) {
1897 mTranslateAnim.start();
1898 }
1899 }
1900
1901 @Override
1902 public void setTranslation(float translationX) {
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001903 if (isBlockingHelperShowingAndTranslationFinished()) {
1904 mGuts.setTranslationX(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001905 return;
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001906 } else if (!mShouldTranslateContents) {
Anthony Chen7acbb772017-04-07 16:45:25 -07001907 setTranslationX(translationX);
1908 } else if (mTranslateableViews != null) {
1909 // Translate the group of views
1910 for (int i = 0; i < mTranslateableViews.size(); i++) {
1911 if (mTranslateableViews.get(i) != null) {
1912 mTranslateableViews.get(i).setTranslationX(translationX);
1913 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001914 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001915 invalidateOutline();
Selim Cinek143672c2018-03-23 20:04:32 -07001916
1917 // In order to keep the shelf in sync with this swiping, we're simply translating
1918 // it's icon by the same amount. The translation is already being used for the normal
1919 // positioning, so we can use the scrollX instead.
1920 getEntry().expandedIcon.setScrollX((int) -translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001921 }
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001922
Mady Mellor95d743c2017-01-10 12:05:27 -08001923 if (mMenuRow.getMenuView() != null) {
Aaron Heuckroth266cb342018-09-07 14:52:04 -04001924 mMenuRow.onParentTranslationUpdate(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001925 }
1926 }
1927
1928 @Override
1929 public float getTranslation() {
Anthony Chene04afcb2017-04-21 13:51:32 -07001930 if (!mShouldTranslateContents) {
Anthony Chen7acbb772017-04-07 16:45:25 -07001931 return getTranslationX();
1932 }
1933
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001934 if (isBlockingHelperShowingAndCanTranslate()) {
1935 return mGuts.getTranslationX();
1936 }
1937
Mady Mellor34958fa2016-02-23 09:52:17 -08001938 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1939 // All of the views in the list should have same translation, just use first one.
1940 return mTranslateableViews.get(0).getTranslationX();
1941 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001942
Mady Mellor34958fa2016-02-23 09:52:17 -08001943 return 0;
1944 }
1945
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001946 private boolean isBlockingHelperShowingAndCanTranslate() {
1947 return areGutsExposed() && mIsBlockingHelperShowing && mNotificationTranslationFinished;
1948 }
1949
Mady Mellor34958fa2016-02-23 09:52:17 -08001950 public Animator getTranslateViewAnimator(final float leftTarget,
1951 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001952 if (mTranslateAnim != null) {
1953 mTranslateAnim.cancel();
1954 }
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001955
Mady Mellorb0a82462016-04-30 17:31:02 -07001956 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1957 leftTarget);
1958 if (listener != null) {
1959 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001960 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001961 translateAnim.addListener(new AnimatorListenerAdapter() {
1962 boolean cancelled = false;
1963
1964 @Override
1965 public void onAnimationCancel(Animator anim) {
1966 cancelled = true;
1967 }
1968
1969 @Override
1970 public void onAnimationEnd(Animator anim) {
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001971 if (mIsBlockingHelperShowing) {
1972 mNotificationTranslationFinished = true;
1973 }
Mady Mellor95d743c2017-01-10 12:05:27 -08001974 if (!cancelled && leftTarget == 0) {
1975 mMenuRow.resetMenu();
Mady Mellorb0a82462016-04-30 17:31:02 -07001976 mTranslateAnim = null;
1977 }
1978 }
1979 });
1980 mTranslateAnim = translateAnim;
1981 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001982 }
1983
Selim Cinekab29aeb2015-02-20 18:18:32 +01001984 public void inflateGuts() {
1985 if (mGuts == null) {
1986 mGutsStub.inflate();
1987 }
1988 }
1989
Selim Cinekda42d652015-12-04 15:51:16 -08001990 private void updateChildrenVisibility() {
Selim Cinek7fa385a2018-01-24 08:35:28 -08001991 boolean hideContentWhileLaunching = mExpandAnimationRunning && mGuts != null
1992 && mGuts.isExposed();
1993 mPrivateLayout.setVisibility(!shouldShowPublic() && !mIsSummaryWithChildren
1994 && !hideContentWhileLaunching ? VISIBLE : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001995 if (mChildrenContainer != null) {
Selim Cinek7fa385a2018-01-24 08:35:28 -08001996 mChildrenContainer.setVisibility(!shouldShowPublic() && mIsSummaryWithChildren
1997 && !hideContentWhileLaunching ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001998 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001999 }
Selim Cinekda42d652015-12-04 15:51:16 -08002000 // The limits might have changed if the view suddenly became a group or vice versa
2001 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01002002 }
2003
Jorim Jaggife40f7d2014-04-28 15:20:04 +02002004 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08002005 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
2006 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02002007 // Add a record for the entire layout since its content is somehow small.
2008 // The event comes from a leaf view that is interacted with.
2009 AccessibilityEvent record = AccessibilityEvent.obtain();
2010 onInitializeAccessibilityEvent(record);
2011 dispatchPopulateAccessibilityEvent(record);
2012 event.appendRecord(record);
2013 return true;
2014 }
2015 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02002016 }
Chris Wren51c75102013-07-16 20:49:17 -04002017
John Spurlocke15452b2014-08-21 09:44:39 -04002018 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01002019 public void setDark(boolean dark, boolean fade, long delay) {
Lucas Dupin00be88f2019-01-03 17:50:52 -08002020 if (mDark == dark) {
2021 return;
2022 }
Jorim Jaggi4e857f42014-11-17 19:14:04 +01002023 super.setDark(dark, fade, delay);
Kevina97ea052018-09-11 13:53:18 -07002024 if (!mIsAmbientPulsing) {
Adrian Roos28f90c72017-05-08 17:24:26 -07002025 // Only fade the showing view of the pulsing notification.
2026 fade = false;
2027 }
John Spurlocke15452b2014-08-21 09:44:39 -04002028 final NotificationContentView showing = getShowingLayout();
2029 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01002030 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04002031 }
Selim Cineka7c69632017-06-07 15:51:29 -07002032 updateShelfIconColor();
John Spurlocke15452b2014-08-21 09:44:39 -04002033 }
2034
Selim Cinek2627d722018-01-19 12:16:49 -08002035 public void applyExpandAnimationParams(ExpandAnimationParameters params) {
2036 if (params == null) {
2037 return;
2038 }
Selim Cinek2627d722018-01-19 12:16:49 -08002039 float zProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
2040 params.getProgress(0, 50));
2041 float translationZ = MathUtils.lerp(params.getStartTranslationZ(),
2042 mNotificationLaunchHeight,
2043 zProgress);
2044 setTranslationZ(translationZ);
Selim Cinekc25989e2018-02-16 16:42:14 -08002045 float extraWidthForClipping = params.getWidth() - getWidth()
2046 + MathUtils.lerp(0, mOutlineRadius * 2, params.getProgress());
2047 setExtraWidthForClipping(extraWidthForClipping);
2048 int top = params.getTop();
2049 float interpolation = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(params.getProgress());
2050 int startClipTopAmount = params.getStartClipTopAmount();
2051 if (mNotificationParent != null) {
Selim Cinekc42db8d2018-12-04 13:29:25 -08002052 float parentY = mNotificationParent.getTranslationY();
2053 top -= parentY;
Selim Cinekc25989e2018-02-16 16:42:14 -08002054 mNotificationParent.setTranslationZ(translationZ);
2055 int parentStartClipTopAmount = params.getParentStartClipTopAmount();
2056 if (startClipTopAmount != 0) {
2057 int clipTopAmount = (int) MathUtils.lerp(parentStartClipTopAmount,
2058 parentStartClipTopAmount - startClipTopAmount,
2059 interpolation);
2060 mNotificationParent.setClipTopAmount(clipTopAmount);
2061 }
2062 mNotificationParent.setExtraWidthForClipping(extraWidthForClipping);
Selim Cinekc42db8d2018-12-04 13:29:25 -08002063 float clipBottom = Math.max(params.getBottom(),
2064 parentY + mNotificationParent.getActualHeight()
2065 - mNotificationParent.getClipBottomAmount());
2066 float clipTop = Math.min(params.getTop(), parentY);
2067 int minimumHeightForClipping = (int) (clipBottom - clipTop);
2068 mNotificationParent.setMinimumHeightForClipping(minimumHeightForClipping);
Selim Cinekc25989e2018-02-16 16:42:14 -08002069 } else if (startClipTopAmount != 0) {
2070 int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, interpolation);
2071 setClipTopAmount(clipTopAmount);
2072 }
2073 setTranslationY(top);
Selim Cinek2627d722018-01-19 12:16:49 -08002074 setActualHeight(params.getHeight());
Selim Cinekc25989e2018-02-16 16:42:14 -08002075
Selim Cinek2627d722018-01-19 12:16:49 -08002076 mBackgroundNormal.setExpandAnimationParams(params);
2077 }
2078
2079 public void setExpandAnimationRunning(boolean expandAnimationRunning) {
Selim Cinekc25989e2018-02-16 16:42:14 -08002080 View contentView;
2081 if (mIsSummaryWithChildren) {
2082 contentView = mChildrenContainer;
2083 } else {
2084 contentView = getShowingLayout();
2085 }
2086 if (mGuts != null && mGuts.isExposed()) {
2087 contentView = mGuts;
2088 }
Selim Cinek2627d722018-01-19 12:16:49 -08002089 if (expandAnimationRunning) {
Selim Cinek2627d722018-01-19 12:16:49 -08002090 contentView.animate()
2091 .alpha(0f)
2092 .setDuration(ActivityLaunchAnimator.ANIMATION_DURATION_FADE_CONTENT)
2093 .setInterpolator(Interpolators.ALPHA_OUT);
2094 setAboveShelf(true);
2095 mExpandAnimationRunning = true;
Dave Mankoffa4d195d2018-11-16 13:33:27 -05002096 getViewState().cancelAnimations(this);
Selim Cinek2627d722018-01-19 12:16:49 -08002097 mNotificationLaunchHeight = AmbientState.getNotificationLaunchHeight(getContext());
2098 } else {
2099 mExpandAnimationRunning = false;
2100 setAboveShelf(isAboveShelf());
Selim Cinek7fa385a2018-01-24 08:35:28 -08002101 if (mGuts != null) {
2102 mGuts.setAlpha(1.0f);
2103 }
Selim Cinekc25989e2018-02-16 16:42:14 -08002104 if (contentView != null) {
2105 contentView.setAlpha(1.0f);
2106 }
2107 setExtraWidthForClipping(0.0f);
2108 if (mNotificationParent != null) {
2109 mNotificationParent.setExtraWidthForClipping(0.0f);
2110 mNotificationParent.setMinimumHeightForClipping(0);
2111 }
2112 }
2113 if (mNotificationParent != null) {
2114 mNotificationParent.setChildIsExpanding(mExpandAnimationRunning);
Selim Cinek2627d722018-01-19 12:16:49 -08002115 }
Selim Cinek7fa385a2018-01-24 08:35:28 -08002116 updateChildrenVisibility();
Selim Cinek2627d722018-01-19 12:16:49 -08002117 updateClipping();
2118 mBackgroundNormal.setExpandAnimationRunning(expandAnimationRunning);
2119 }
2120
Selim Cinekc25989e2018-02-16 16:42:14 -08002121 private void setChildIsExpanding(boolean isExpanding) {
2122 mChildIsExpanding = isExpanding;
Selim Cinek6487ebf2018-11-28 18:57:40 -08002123 updateClipping();
2124 invalidate();
Selim Cinekc25989e2018-02-16 16:42:14 -08002125 }
2126
2127 @Override
2128 public boolean hasExpandingChild() {
2129 return mChildIsExpanding;
2130 }
2131
Selim Cinek2627d722018-01-19 12:16:49 -08002132 @Override
2133 protected boolean shouldClipToActualHeight() {
Selim Cinek53328492018-12-05 14:58:44 -08002134 return super.shouldClipToActualHeight() && !mExpandAnimationRunning;
Selim Cinek2627d722018-01-19 12:16:49 -08002135 }
2136
2137 @Override
2138 public boolean isExpandAnimationRunning() {
2139 return mExpandAnimationRunning;
2140 }
2141
Lucas Dupincecc7c22017-09-12 16:02:45 -07002142 /**
2143 * Tap sounds should not be played when we're unlocking.
2144 * Doing so would cause audio collision and the system would feel unpolished.
2145 */
2146 @Override
2147 public boolean isSoundEffectsEnabled() {
2148 final boolean mute = mDark && mSecureStateProvider != null &&
2149 !mSecureStateProvider.getAsBoolean();
2150 return !mute && super.isSoundEffectsEnabled();
2151 }
2152
Chris Wren51c75102013-07-16 20:49:17 -04002153 public boolean isExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002154 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek388df6d2015-10-22 13:25:11 -07002155 return !mChildrenExpanded;
2156 }
Anthony Chen6bf88a02017-04-10 14:41:44 -07002157 return mEnableNonGroupedNotificationExpand && mExpandable;
Chris Wren51c75102013-07-16 20:49:17 -04002158 }
2159
2160 public void setExpandable(boolean expandable) {
2161 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002162 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04002163 }
2164
Selim Cinek4ffd6362015-12-29 15:12:23 +01002165 @Override
2166 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08002167 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
2168 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01002169 }
2170
Selim Cinek1685e632014-04-08 02:27:49 +02002171 /**
2172 * @return whether the user has changed the expansion state
2173 */
2174 public boolean hasUserChangedExpansion() {
2175 return mHasUserChangedExpansion;
2176 }
2177
Chris Wren51c75102013-07-16 20:49:17 -04002178 public boolean isUserExpanded() {
2179 return mUserExpanded;
2180 }
2181
Selim Cinek1685e632014-04-08 02:27:49 +02002182 /**
2183 * Set this notification to be expanded by the user
2184 *
2185 * @param userExpanded whether the user wants this notification to be expanded
2186 */
Chris Wren51c75102013-07-16 20:49:17 -04002187 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07002188 setUserExpanded(userExpanded, false /* allowChildExpansion */);
2189 }
2190
2191 /**
2192 * Set this notification to be expanded by the user
2193 *
2194 * @param userExpanded whether the user wants this notification to be expanded
2195 * @param allowChildExpansion whether a call to this method allows expanding children
2196 */
2197 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07002198 mFalsingManager.setNotificationExpanded();
Selim Cinek0b9cf462017-12-07 16:31:03 -08002199 if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
Selim Cinek414ad332017-02-24 19:06:12 -08002200 && !mChildrenContainer.showingAsLowPriority()) {
Chris Wren698b1702016-05-23 11:16:32 -04002201 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07002202 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -08002203 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07002204 return;
2205 }
Christoph Studera7fe6312014-06-27 19:32:44 +02002206 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01002207 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02002208 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04002209 mUserExpanded = userExpanded;
Selim Cinek414ad332017-02-24 19:06:12 -08002210 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002211 if (!wasExpanded && isExpanded()
2212 && getActualHeight() != getIntrinsicHeight()) {
2213 notifyHeightChanged(true /* needsAnimation */);
2214 }
Chris Wren51c75102013-07-16 20:49:17 -04002215 }
2216
Selim Cinekccd14fb2014-08-12 18:53:24 +02002217 public void resetUserExpansion() {
Selim Cinek414ad332017-02-24 19:06:12 -08002218 boolean changed = mUserExpanded;
Selim Cinekccd14fb2014-08-12 18:53:24 +02002219 mHasUserChangedExpansion = false;
2220 mUserExpanded = false;
Selim Cinek414ad332017-02-24 19:06:12 -08002221 if (changed && mIsSummaryWithChildren) {
2222 mChildrenContainer.onExpansionChanged();
2223 }
2224 updateShelfIconColor();
Selim Cinekccd14fb2014-08-12 18:53:24 +02002225 }
2226
Chris Wren51c75102013-07-16 20:49:17 -04002227 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07002228 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04002229 }
2230
2231 public void setUserLocked(boolean userLocked) {
2232 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08002233 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07002234 // This is intentionally not guarded with mIsSummaryWithChildren since we might have had
2235 // children but not anymore.
2236 if (mChildrenContainer != null) {
Selim Cinek42357e02016-02-24 18:48:01 -08002237 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07002238 if (mIsSummaryWithChildren && (userLocked || !isGroupExpanded())) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002239 updateBackgroundForGroupState();
2240 }
Selim Cinek42357e02016-02-24 18:48:01 -08002241 }
Chris Wren51c75102013-07-16 20:49:17 -04002242 }
2243
Selim Cinek1685e632014-04-08 02:27:49 +02002244 /**
2245 * @return has the system set this notification to be expanded
2246 */
2247 public boolean isSystemExpanded() {
2248 return mIsSystemExpanded;
2249 }
2250
2251 /**
2252 * Set this notification to be expanded by the system.
2253 *
2254 * @param expand whether the system wants this notification to be expanded.
2255 */
2256 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02002257 if (expand != mIsSystemExpanded) {
2258 final boolean wasExpanded = isExpanded();
2259 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01002260 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek414ad332017-02-24 19:06:12 -08002261 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07002262 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07002263 mChildrenContainer.updateGroupOverflow();
2264 }
Selim Cinek31094df2014-08-14 19:28:15 +02002265 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02002266 }
2267
2268 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07002269 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02002270 */
Selim Cinek83bc7832015-10-22 13:26:54 -07002271 public void setOnKeyguard(boolean onKeyguard) {
2272 if (onKeyguard != mOnKeyguard) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07002273 boolean wasAboveShelf = isAboveShelf();
Selim Cinek31094df2014-08-14 19:28:15 +02002274 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07002275 mOnKeyguard = onKeyguard;
Selim Cinek414ad332017-02-24 19:06:12 -08002276 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cinek31094df2014-08-14 19:28:15 +02002277 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07002278 if (mIsSummaryWithChildren) {
2279 mChildrenContainer.updateGroupOverflow();
2280 }
Mady Mellor4b80b102016-01-22 08:03:58 -08002281 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02002282 }
Selim Cinek5cf1d052017-06-01 17:36:46 -07002283 if (isAboveShelf() != wasAboveShelf) {
2284 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
2285 }
Selim Cinek31094df2014-08-14 19:28:15 +02002286 }
Selim Cinekfe24fb72018-02-13 14:34:55 -08002287 updateRippleAllowed();
2288 }
2289
2290 private void updateRippleAllowed() {
2291 boolean allowed = isOnKeyguard()
2292 || mEntry.notification.getNotification().contentIntent == null;
2293 setRippleAllowed(allowed);
Selim Cinek1685e632014-04-08 02:27:49 +02002294 }
2295
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02002296 @Override
2297 public int getIntrinsicHeight() {
Mady Mellorc3d6f7d2018-11-07 09:36:56 -08002298 if (isShownAsBubble()) {
2299 return getMaxExpandHeight();
2300 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002301 if (isUserLocked()) {
2302 return getActualHeight();
2303 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002304 if (mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07002305 return mGuts.getIntrinsicHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08002306 } else if ((isChildInGroup() && !isGroupExpanded())) {
2307 return mPrivateLayout.getMinHeight();
2308 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
2309 return getMinHeight();
Kevina97ea052018-09-11 13:53:18 -07002310 } else if (mIsSummaryWithChildren && (!mOnKeyguard || mOnAmbient)) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002311 return mChildrenContainer.getIntrinsicHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07002312 } else if (isHeadsUpAllowed() && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07002313 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08002314 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
2315 } else if (isExpanded()) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002316 return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
Selim Cinek8d490d42015-04-10 00:05:50 -07002317 } else {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002318 return Math.max(getCollapsedHeight(), getHeadsUpHeight());
Selim Cinek8d490d42015-04-10 00:05:50 -07002319 }
Selim Cinek31aada42015-12-18 17:51:15 -08002320 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07002321 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08002322 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07002323 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02002324 }
Selim Cinekb5605e52015-02-20 18:21:41 +01002325 }
Selim Cinek1685e632014-04-08 02:27:49 +02002326
Adrian Roos6f6e1592017-05-02 16:22:53 -07002327 private boolean isHeadsUpAllowed() {
Kevina97ea052018-09-11 13:53:18 -07002328 return !mOnKeyguard && !mOnAmbient;
Adrian Roos6f6e1592017-05-02 16:22:53 -07002329 }
2330
Mady Mellorc3d6f7d2018-11-07 09:36:56 -08002331 private boolean isShownAsBubble() {
Mady Mellor3f2efdb2018-11-21 11:30:45 -08002332 return mEntry.isBubble() && !mEntry.showInShadeWhenBubble() && !mEntry.isBubbleDismissed();
Mady Mellorc3d6f7d2018-11-07 09:36:56 -08002333 }
2334
2335 /**
2336 * Set the current status bar state.
2337 * @param state should be from {@link com.android.systemui.statusbar.StatusBarState}.
2338 */
2339 public void setStatusBarState(int state) {
2340 if (mStatusBarState != state) {
2341 mStatusBarState = state;
2342 }
2343 }
2344
Mady Mellor43c2cd12016-12-12 21:05:13 -08002345 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07002346 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07002347 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01002348 }
2349
Selim Cinek263398f2015-10-21 17:40:23 -07002350 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05002351 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07002352 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
2353 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
Selim Cinek414ad332017-02-24 19:06:12 -08002354 mChildrenContainer.recreateNotificationHeader(mExpandClickListener
2355 );
Selim Cinek263398f2015-10-21 17:40:23 -07002356 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07002357 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002358 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08002359 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08002360 updateChildrenVisibility();
Selim Cinek2871bef2017-11-22 08:40:00 -08002361 applyChildrenRoundness();
Selim Cinek263398f2015-10-21 17:40:23 -07002362 }
Rohan Shah63411fc2018-03-28 19:05:52 -07002363 /**
2364 * Returns the number of channels covered by the notification row (including its children if
2365 * it's a summary notification).
2366 */
2367 public int getNumUniqueChannels() {
2368 ArraySet<NotificationChannel> channels = new ArraySet<>();
2369
2370 channels.add(mEntry.channel);
2371
2372 // If this is a summary, then add in the children notification channels for the
2373 // same user and pkg.
2374 if (mIsSummaryWithChildren) {
2375 final List<ExpandableNotificationRow> childrenRows = getNotificationChildren();
2376 final int numChildren = childrenRows.size();
2377 for (int i = 0; i < numChildren; i++) {
2378 final ExpandableNotificationRow childRow = childrenRows.get(i);
2379 final NotificationChannel childChannel = childRow.getEntry().channel;
2380 final StatusBarNotification childSbn = childRow.getStatusBarNotification();
2381 if (childSbn.getUser().equals(mStatusBarNotification.getUser()) &&
2382 childSbn.getPackageName().equals(mStatusBarNotification.getPackageName())) {
2383 channels.add(childChannel);
2384 }
2385 }
2386 }
2387 return channels.size();
2388 }
Selim Cinek263398f2015-10-21 17:40:23 -07002389
Mady Mellorb0a82462016-04-30 17:31:02 -07002390 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07002391 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002392 mChildrenContainer.updateChildrenHeaderAppearance();
2393 }
2394 }
2395
Selim Cinek1685e632014-04-08 02:27:49 +02002396 /**
2397 * Check whether the view state is currently expanded. This is given by the system in {@link
2398 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
2399 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
2400 * view can differ from this state, if layout params are modified from outside.
2401 *
2402 * @return whether the view state is currently expanded.
2403 */
Selim Cinek83bc7832015-10-22 13:26:54 -07002404 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08002405 return isExpanded(false /* allowOnKeyguard */);
2406 }
2407
2408 public boolean isExpanded(boolean allowOnKeyguard) {
2409 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01002410 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
2411 || isUserExpanded());
2412 }
2413
2414 private boolean isSystemChildExpanded() {
2415 return mIsSystemChildExpanded;
2416 }
2417
2418 public void setSystemChildExpanded(boolean expanded) {
2419 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02002420 }
2421
Mady Mellor035badd2017-04-04 18:45:30 -07002422 public void setLayoutListener(LayoutListener listener) {
2423 mLayoutListener = listener;
2424 }
2425
2426 public void removeListener() {
2427 mLayoutListener = null;
2428 }
2429
Selim Cinek1685e632014-04-08 02:27:49 +02002430 @Override
2431 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002432 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02002433 super.onLayout(changed, left, top, right, bottom);
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002434 if (intrinsicBefore != getIntrinsicHeight()) {
2435 notifyHeightChanged(true /* needsAnimation */);
2436 }
Mady Mellor95d743c2017-01-10 12:05:27 -08002437 if (mMenuRow.getMenuView() != null) {
Aaron Heuckroth266cb342018-09-07 14:52:04 -04002438 mMenuRow.onParentHeightUpdate();
Mady Mellora6edc872016-04-26 11:01:03 -07002439 }
Selim Cinek875a3a12016-11-18 17:52:16 -08002440 updateContentShiftHeight();
Mady Mellor035badd2017-04-04 18:45:30 -07002441 if (mLayoutListener != null) {
2442 mLayoutListener.onLayout();
2443 }
Selim Cinek875a3a12016-11-18 17:52:16 -08002444 }
2445
2446 /**
2447 * Updates the content shift height such that the header is completely hidden when coming from
2448 * the top.
2449 */
2450 private void updateContentShiftHeight() {
Selim Cinek414ad332017-02-24 19:06:12 -08002451 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek875a3a12016-11-18 17:52:16 -08002452 if (notificationHeader != null) {
2453 CachingIconView icon = notificationHeader.getIcon();
2454 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
2455 } else {
2456 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
2457 }
Selim Cinek1685e632014-04-08 02:27:49 +02002458 }
2459
Selim Cinekfa0a2d32016-01-14 13:02:21 -08002460 @Override
2461 public void notifyHeightChanged(boolean needsAnimation) {
2462 super.notifyHeightChanged(needsAnimation);
2463 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
2464 }
2465
Selim Cinek3c76d502016-02-19 15:16:33 -08002466 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02002467 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08002468 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02002469 }
2470
Mady Mellor43c2cd12016-12-12 21:05:13 -08002471 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02002472 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07002473 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08002474 if (mIsSummaryWithChildren) {
2475 List<ExpandableNotificationRow> notificationChildren =
2476 mChildrenContainer.getNotificationChildren();
2477 for (int i = 0; i < notificationChildren.size(); i++) {
2478 ExpandableNotificationRow child = notificationChildren.get(i);
2479 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
2480 }
2481 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002482 }
2483
Mady Mellor43c2cd12016-12-12 21:05:13 -08002484 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02002485 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
2486 long duration) {
Selim Cinek69594fb2018-05-18 12:06:10 -07002487 if (getVisibility() == GONE) {
2488 // If we are GONE, the hideSensitive parameter will not be calculated and always be
2489 // false, which is incorrect, let's wait until a real call comes in later.
2490 return;
2491 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002492 boolean oldShowingPublic = mShowingPublic;
2493 mShowingPublic = mSensitive && hideSensitive;
2494 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
2495 return;
2496 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05002497
2498 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02002499 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002500
Jorim Jaggiae441282014-08-01 02:45:18 +02002501 if (!animated) {
2502 mPublicLayout.animate().cancel();
2503 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07002504 if (mChildrenContainer != null) {
2505 mChildrenContainer.animate().cancel();
2506 mChildrenContainer.setAlpha(1f);
2507 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002508 mPublicLayout.setAlpha(1f);
2509 mPrivateLayout.setAlpha(1f);
2510 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08002511 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02002512 } else {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002513 animateShowingPublic(delay, duration, mShowingPublic);
Jorim Jaggiae441282014-08-01 02:45:18 +02002514 }
Selim Cinekc3179332016-03-04 14:44:56 -08002515 NotificationContentView showingLayout = getShowingLayout();
2516 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002517 mPrivateLayout.updateExpandButtons(isExpandable());
Lucas Dupinb6ed63b2017-05-30 16:17:42 -07002518 updateShelfIconColor();
Adrian Roose5726a22016-12-19 14:26:51 -08002519 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02002520 mShowingPublicInitialized = true;
2521 }
2522
Selim Cinek0b9cf462017-12-07 16:31:03 -08002523 private void animateShowingPublic(long delay, long duration, boolean showingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002524 View[] privateViews = mIsSummaryWithChildren
2525 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08002526 : new View[] {mPrivateLayout};
2527 View[] publicViews = new View[] {mPublicLayout};
Selim Cinek0b9cf462017-12-07 16:31:03 -08002528 View[] hiddenChildren = showingPublic ? privateViews : publicViews;
2529 View[] shownChildren = showingPublic ? publicViews : privateViews;
Selim Cinekd84a5932015-12-15 11:45:36 -08002530 for (final View hiddenView : hiddenChildren) {
2531 hiddenView.setVisibility(View.VISIBLE);
2532 hiddenView.animate().cancel();
2533 hiddenView.animate()
2534 .alpha(0f)
2535 .setStartDelay(delay)
2536 .setDuration(duration)
2537 .withEndAction(new Runnable() {
2538 @Override
2539 public void run() {
2540 hiddenView.setVisibility(View.INVISIBLE);
2541 }
2542 });
2543 }
2544 for (View showView : shownChildren) {
2545 showView.setVisibility(View.VISIBLE);
2546 showView.setAlpha(0f);
2547 showView.animate().cancel();
2548 showView.animate()
2549 .alpha(1f)
2550 .setStartDelay(delay)
2551 .setDuration(duration);
2552 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04002553 }
2554
Mady Mellor43c2cd12016-12-12 21:05:13 -08002555 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08002556 public boolean mustStayOnScreen() {
Selim Cinek9b9d6e12017-11-30 12:29:47 +01002557 return mIsHeadsUp && mMustStayOnScreen;
Selim Cinek3776fe02016-02-04 13:32:43 -08002558 }
2559
Selim Cinek9e624e72016-07-20 13:46:49 -07002560 /**
2561 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
2562 * otherwise some state might not be updated. To request about the general clearability
Ned Burnsf81c4c42019-01-07 14:10:43 -05002563 * see {@link NotificationEntry#isClearable()}.
Selim Cinek9e624e72016-07-20 13:46:49 -07002564 */
2565 public boolean canViewBeDismissed() {
Evan Laird94492852018-10-25 13:43:01 -04002566 return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
Selim Cinek0b9cf462017-12-07 16:31:03 -08002567 }
2568
2569 private boolean shouldShowPublic() {
2570 return mSensitive && mHideSensitiveForIntrinsicHeight;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002571 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02002572
Ricky Waicd35def2016-05-03 11:07:07 +01002573 public void makeActionsVisibile() {
2574 setUserExpanded(true, true);
2575 if (isChildInGroup()) {
2576 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
2577 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07002578 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01002579 }
2580
Selim Cinekb5605e52015-02-20 18:21:41 +01002581 public void setChildrenExpanded(boolean expanded, boolean animate) {
2582 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07002583 if (mChildrenContainer != null) {
2584 mChildrenContainer.setChildrenExpanded(expanded);
2585 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07002586 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07002587 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01002588 }
2589
Selim Cinekb5605e52015-02-20 18:21:41 +01002590 public static void applyTint(View v, int color) {
2591 int alpha;
2592 if (color != 0) {
2593 alpha = COLORED_DIVIDER_ALPHA;
2594 } else {
2595 color = 0xff000000;
2596 alpha = DEFAULT_DIVIDER_ALPHA;
2597 }
2598 if (v.getBackground() instanceof ColorDrawable) {
2599 ColorDrawable background = (ColorDrawable) v.getBackground();
2600 background.mutate();
2601 background.setColor(color);
2602 background.setAlpha(alpha);
2603 }
2604 }
2605
Selim Cinek1685e632014-04-08 02:27:49 +02002606 public int getMaxExpandHeight() {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002607 return mPrivateLayout.getExpandHeight();
2608 }
2609
2610
2611 private int getHeadsUpHeight() {
2612 return mPrivateLayout.getHeadsUpHeight();
Chris Wren51c75102013-07-16 20:49:17 -04002613 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02002614
Mady Mellor34958fa2016-02-23 09:52:17 -08002615 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002616 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08002617 }
2618
Jorim Jaggibe565df2014-04-28 17:51:23 +02002619 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002620 public boolean isContentExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002621 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002622 return true;
2623 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002624 NotificationContentView showingLayout = getShowingLayout();
2625 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002626 }
2627
2628 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07002629 protected View getContentView() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002630 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cineka5703182016-05-11 21:23:16 -04002631 return mChildrenContainer;
2632 }
Selim Cinek560e64d2015-06-09 19:58:11 -07002633 return getShowingLayout();
2634 }
2635
2636 @Override
Gus Prevas211181532018-12-13 14:49:33 -05002637 public long performRemoveAnimation(long duration, long delay, float translationDirection,
2638 boolean isHeadsUpAnimation, float endLocation, Runnable onFinishedRunnable,
2639 AnimatorListenerAdapter animationListener) {
2640 if (mMenuRow.isMenuVisible()) {
2641 Animator anim = getTranslateViewAnimator(0f, null /* listener */);
2642 if (anim != null) {
2643 anim.addListener(new AnimatorListenerAdapter() {
2644 @Override
2645 public void onAnimationEnd(Animator animation) {
2646 ExpandableNotificationRow.super.performRemoveAnimation(
2647 duration, delay, translationDirection, isHeadsUpAnimation,
2648 endLocation, onFinishedRunnable, animationListener);
2649 }
2650 });
2651 anim.start();
2652 return anim.getDuration();
2653 }
2654 }
2655 return super.performRemoveAnimation(duration, delay, translationDirection,
2656 isHeadsUpAnimation, endLocation, onFinishedRunnable, animationListener);
2657 }
2658
2659 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07002660 protected void onAppearAnimationFinished(boolean wasAppearing) {
2661 super.onAppearAnimationFinished(wasAppearing);
2662 if (wasAppearing) {
2663 // During the animation the visible view might have changed, so let's make sure all
2664 // alphas are reset
2665 if (mChildrenContainer != null) {
2666 mChildrenContainer.setAlpha(1.0f);
2667 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
2668 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08002669 for (NotificationContentView l : mLayouts) {
2670 l.setAlpha(1.0f);
2671 l.setLayerType(LAYER_TYPE_NONE, null);
2672 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07002673 }
2674 }
2675
2676 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07002677 public int getExtraBottomPadding() {
2678 if (mIsSummaryWithChildren && isGroupExpanded()) {
2679 return mIncreasedPaddingBetweenElements;
2680 }
2681 return 0;
2682 }
2683
2684 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02002685 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinek4ca6c632017-02-23 18:03:37 -08002686 boolean changed = height != getActualHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +01002687 super.setActualHeight(height, notifyListeners);
Selim Cinek4ca6c632017-02-23 18:03:37 -08002688 if (changed && isRemoved()) {
2689 // TODO: remove this once we found the gfx bug for this.
2690 // This is a hack since a removed view sometimes would just stay blank. it occured
2691 // when sending yourself a message and then clicking on it.
2692 ViewGroup parent = (ViewGroup) getParent();
2693 if (parent != null) {
2694 parent.invalidate();
2695 }
2696 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002697 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08002698 mGuts.setActualHeight(height);
2699 return;
2700 }
Selim Cinekeef84282015-10-30 16:28:00 -07002701 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002702 for (NotificationContentView l : mLayouts) {
2703 l.setContentHeight(contentHeight);
2704 }
Selim Cinek42357e02016-02-24 18:48:01 -08002705 if (mIsSummaryWithChildren) {
2706 mChildrenContainer.setActualHeight(height);
2707 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002708 if (mGuts != null) {
2709 mGuts.setActualHeight(height);
2710 }
Mady Mellor54540972017-06-07 11:55:36 -07002711 if (mMenuRow.getMenuView() != null) {
Aaron Heuckroth266cb342018-09-07 14:52:04 -04002712 mMenuRow.onParentHeightUpdate();
Mady Mellor54540972017-06-07 11:55:36 -07002713 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002714 }
2715
2716 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01002717 public int getMaxContentHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002718 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002719 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002720 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002721 NotificationContentView showingLayout = getShowingLayout();
2722 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02002723 }
2724
2725 @Override
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002726 public int getMinHeight(boolean ignoreTemporaryStates) {
2727 if (!ignoreTemporaryStates && mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07002728 return mGuts.getIntrinsicHeight();
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002729 } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp
2730 && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08002731 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
Selim Cinek0b9cf462017-12-07 16:31:03 -08002732 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !shouldShowPublic()) {
Selim Cinekb55386d2015-12-16 17:26:49 -08002733 return mChildrenContainer.getMinHeight();
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002734 } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002735 return getHeadsUpHeight();
Selim Cinekb55386d2015-12-16 17:26:49 -08002736 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002737 NotificationContentView showingLayout = getShowingLayout();
2738 return showingLayout.getMinHeight();
2739 }
2740
2741 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07002742 public int getCollapsedHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002743 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek567e8452016-03-24 10:54:56 -07002744 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002745 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002746 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002747 }
2748
2749 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02002750 public void setClipTopAmount(int clipTopAmount) {
2751 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002752 for (NotificationContentView l : mLayouts) {
2753 l.setClipTopAmount(clipTopAmount);
2754 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002755 if (mGuts != null) {
2756 mGuts.setClipTopAmount(clipTopAmount);
2757 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002758 }
2759
Selim Cineka686b2c2016-10-26 13:58:27 -07002760 @Override
2761 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek2627d722018-01-19 12:16:49 -08002762 if (mExpandAnimationRunning) {
2763 return;
2764 }
Selim Cinek65d418e2016-11-29 15:42:34 -08002765 if (clipBottomAmount != mClipBottomAmount) {
2766 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002767 for (NotificationContentView l : mLayouts) {
2768 l.setClipBottomAmount(clipBottomAmount);
2769 }
Selim Cinek65d418e2016-11-29 15:42:34 -08002770 if (mGuts != null) {
2771 mGuts.setClipBottomAmount(clipBottomAmount);
2772 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002773 }
Selim Cinekc25989e2018-02-16 16:42:14 -08002774 if (mChildrenContainer != null && !mChildIsExpanding) {
Selim Cinek65d418e2016-11-29 15:42:34 -08002775 // We have to update this even if it hasn't changed, since the children locations can
2776 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08002777 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
2778 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002779 }
2780
Selim Cinek42357e02016-02-24 18:48:01 -08002781 public NotificationContentView getShowingLayout() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002782 return shouldShowPublic() ? mPublicLayout : mPrivateLayout;
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002783 }
Chris Wren78403d72014-07-28 10:23:24 +01002784
Kevind4660b22018-09-27 10:57:35 -07002785 public View getExpandedContentView() {
2786 return getPrivateLayout().getExpandedChild();
2787 }
2788
Selim Cinek1a48bab2017-02-17 19:38:40 -08002789 public void setLegacy(boolean legacy) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08002790 for (NotificationContentView l : mLayouts) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08002791 l.setLegacy(legacy);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002792 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07002793 }
2794
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002795 @Override
2796 protected void updateBackgroundTint() {
2797 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07002798 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002799 if (mIsSummaryWithChildren) {
2800 List<ExpandableNotificationRow> notificationChildren =
2801 mChildrenContainer.getNotificationChildren();
2802 for (int i = 0; i < notificationChildren.size(); i++) {
2803 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07002804 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002805 }
2806 }
2807 }
2808
Mady Mellorb0a82462016-04-30 17:31:02 -07002809 /**
2810 * Called when a group has finished animating from collapsed or expanded state.
2811 */
2812 public void onFinishedExpansionChange() {
2813 mGroupExpansionChanging = false;
2814 updateBackgroundForGroupState();
2815 }
2816
2817 /**
2818 * Updates the parent and children backgrounds in a group based on the expansion state.
2819 */
2820 public void updateBackgroundForGroupState() {
2821 if (mIsSummaryWithChildren) {
2822 // Only when the group has finished expanding do we hide its background.
Anthony Chen6bf88a02017-04-10 14:41:44 -07002823 mShowNoBackground = !mShowGroupBackgroundWhenExpanded && isGroupExpanded()
2824 && !isGroupExpansionChanging() && !isUserLocked();
Mady Mellorb0a82462016-04-30 17:31:02 -07002825 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
2826 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
2827 for (int i = 0; i < children.size(); i++) {
2828 children.get(i).updateBackgroundForGroupState();
2829 }
2830 } else if (isChildInGroup()) {
2831 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
2832 // Only show a background if the group is expanded OR if it is expanding / collapsing
Anthony Chen6bf88a02017-04-10 14:41:44 -07002833 // and has a custom background color.
Mady Mellorb0a82462016-04-30 17:31:02 -07002834 final boolean showBackground = isGroupExpanded()
2835 || ((mNotificationParent.isGroupExpansionChanging()
Anthony Chen6bf88a02017-04-10 14:41:44 -07002836 || mNotificationParent.isUserLocked()) && childColor != 0);
Mady Mellorb0a82462016-04-30 17:31:02 -07002837 mShowNoBackground = !showBackground;
2838 } else {
2839 // Only children or parents ever need no background.
2840 mShowNoBackground = false;
2841 }
2842 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002843 updateBackground();
2844 }
2845
Adrian Roos4a579672016-05-24 16:54:37 -07002846 public int getPositionOfChild(ExpandableNotificationRow childRow) {
2847 if (mIsSummaryWithChildren) {
2848 return mChildrenContainer.getPositionInLinearLayout(childRow);
2849 }
2850 return 0;
2851 }
2852
Chris Wren78403d72014-07-28 10:23:24 +01002853 public void setExpansionLogger(ExpansionLogger logger, String key) {
2854 mLogger = logger;
2855 mLoggingKey = key;
2856 }
2857
Chris Wren6abeeb92016-05-26 14:44:38 -04002858 public void onExpandedByGesture(boolean userExpanded) {
2859 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
2860 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
2861 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
2862 }
2863 MetricsLogger.action(mContext, event, userExpanded);
2864 }
2865
Selim Cinek6183d122016-01-14 18:48:41 -08002866 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08002867 public float getIncreasedPaddingAmount() {
2868 if (mIsSummaryWithChildren) {
2869 if (isGroupExpanded()) {
2870 return 1.0f;
2871 } else if (isUserLocked()) {
Selim Cinek414ad332017-02-24 19:06:12 -08002872 return mChildrenContainer.getIncreasedPaddingAmount();
Selim Cinek42357e02016-02-24 18:48:01 -08002873 }
Selim Cinek99104832017-01-25 14:47:33 -08002874 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08002875 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08002876 }
2877 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08002878 }
2879
Selim Cineka7ed2c12017-01-23 20:47:24 -08002880 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08002881 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08002882 }
2883
Selim Cinek61633a82016-01-25 15:54:10 -08002884 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08002885 protected boolean disallowSingleClick(MotionEvent event) {
dongwan0605.kimc4ddef42018-05-06 17:40:23 +09002886 if (areGutsExposed()) {
2887 return false;
2888 }
Selim Cinek6183d122016-01-14 18:48:41 -08002889 float x = event.getX();
2890 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08002891 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002892 if (header != null && header.isInTouchRect(x - getTranslation(), y)) {
2893 return true;
2894 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002895 if ((!mIsSummaryWithChildren || shouldShowPublic())
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002896 && getShowingLayout().disallowSingleClick(x, y)) {
2897 return true;
Selim Cinek6183d122016-01-14 18:48:41 -08002898 }
2899 return super.disallowSingleClick(event);
2900 }
2901
Selim Cinek414ad332017-02-24 19:06:12 -08002902 private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04002903 boolean nowExpanded = isExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08002904 if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
Chris Wren698b1702016-05-23 11:16:32 -04002905 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
2906 }
Selim Cinek414ad332017-02-24 19:06:12 -08002907 if (nowExpanded != wasExpanded) {
2908 updateShelfIconColor();
2909 if (mLogger != null) {
2910 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded);
2911 }
2912 if (mIsSummaryWithChildren) {
2913 mChildrenContainer.onExpansionChanged();
2914 }
Chris Wren78403d72014-07-28 10:23:24 +01002915 }
2916 }
Selim Cinek570981d2015-12-01 11:37:01 -08002917
Selim Cineke9bad242016-06-15 11:46:37 -07002918 @Override
2919 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2920 super.onInitializeAccessibilityNodeInfoInternal(info);
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002921 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
Selim Cineke9bad242016-06-15 11:46:37 -07002922 if (canViewBeDismissed()) {
2923 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
2924 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002925 boolean expandable = shouldShowPublic();
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002926 boolean isExpanded = false;
2927 if (!expandable) {
2928 if (mIsSummaryWithChildren) {
2929 expandable = true;
2930 if (!mIsLowPriority || isExpanded()) {
2931 isExpanded = isGroupExpanded();
2932 }
2933 } else {
2934 expandable = mPrivateLayout.isContentExpandable();
2935 isExpanded = isExpanded();
2936 }
2937 }
2938 if (expandable) {
2939 if (isExpanded) {
2940 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
2941 } else {
2942 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
2943 }
2944 }
Mady Mellorb3a6aed2018-05-11 13:24:07 -07002945 NotificationMenuRowPlugin provider = getProvider();
2946 if (provider != null) {
2947 MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
2948 if (snoozeMenu != null) {
2949 AccessibilityAction action = new AccessibilityAction(R.id.action_snooze,
2950 getContext().getResources()
2951 .getString(R.string.notification_menu_snooze_action));
2952 info.addAction(action);
2953 }
2954 }
Selim Cineke9bad242016-06-15 11:46:37 -07002955 }
2956
2957 @Override
2958 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
2959 if (super.performAccessibilityActionInternal(action, arguments)) {
2960 return true;
2961 }
2962 switch (action) {
2963 case AccessibilityNodeInfo.ACTION_DISMISS:
Rohan Shah524cf7b2018-03-15 14:40:02 -07002964 performDismissWithBlockingHelper(true /* fromAccessibility */);
Selim Cineke9bad242016-06-15 11:46:37 -07002965 return true;
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002966 case AccessibilityNodeInfo.ACTION_COLLAPSE:
2967 case AccessibilityNodeInfo.ACTION_EXPAND:
2968 mExpandClickListener.onClick(this);
2969 return true;
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002970 case AccessibilityNodeInfo.ACTION_LONG_CLICK:
2971 doLongClickCallback();
2972 return true;
Jason Monk05dd5672018-08-09 09:38:21 -04002973 default:
2974 if (action == R.id.action_snooze) {
2975 NotificationMenuRowPlugin provider = getProvider();
2976 if (provider == null) {
2977 provider = createMenu();
2978 }
2979 MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
2980 if (snoozeMenu != null) {
2981 doLongClickCallback(getWidth() / 2, getHeight() / 2, snoozeMenu);
2982 }
2983 return true;
Mady Mellorb3a6aed2018-05-11 13:24:07 -07002984 }
Selim Cineke9bad242016-06-15 11:46:37 -07002985 }
2986 return false;
2987 }
2988
2989 public boolean shouldRefocusOnDismiss() {
2990 return mRefocusOnDismiss || isAccessibilityFocused();
2991 }
2992
Selim Cinek570981d2015-12-01 11:37:01 -08002993 public interface OnExpandClickListener {
Ned Burnsf81c4c42019-01-07 14:10:43 -05002994 void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08002995 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002996
2997 @Override
Dave Mankoffa4d195d2018-11-16 13:33:27 -05002998 public ExpandableViewState createExpandableViewState() {
2999 return new NotificationViewState();
Selim Cinekf93bf3e2018-05-08 14:43:21 -07003000 }
3001
Selim Cinekd127d792016-11-01 19:11:41 -07003002 @Override
3003 public boolean isAboveShelf() {
Selim Cinekc8007c52017-02-28 16:09:56 -08003004 return !isOnKeyguard()
Selim Cinek2627d722018-01-19 12:16:49 -08003005 && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf)
Selim Cinekc25989e2018-02-16 16:42:14 -08003006 || mExpandAnimationRunning || mChildIsExpanding);
Selim Cinekd127d792016-11-01 19:11:41 -07003007 }
3008
Kevina97ea052018-09-11 13:53:18 -07003009 public void setOnAmbient(boolean onAmbient) {
3010 if (onAmbient != mOnAmbient) {
3011 mOnAmbient = onAmbient;
Adrian Roos6f6e1592017-05-02 16:22:53 -07003012 if (mChildrenContainer != null) {
Kevina97ea052018-09-11 13:53:18 -07003013 mChildrenContainer.notifyDozingStateChanged();
Adrian Roos6f6e1592017-05-02 16:22:53 -07003014 }
Adrian Roos0aac04f2016-12-08 15:59:29 -08003015 notifyHeightChanged(false /* needsAnimation */);
3016 }
3017 }
3018
Selim Cinek0fe07392017-11-09 13:26:34 -08003019 @Override
Tony Huangc092c432018-05-18 17:38:54 +08003020 public boolean topAmountNeedsClipping() {
3021 if (isGroupExpanded()) {
3022 return true;
3023 }
3024 if (isGroupExpansionChanging()) {
3025 return true;
3026 }
3027 if (getShowingLayout().shouldClipToRounding(true /* topRounded */,
3028 false /* bottomRounded */)) {
3029 return true;
3030 }
3031 if (mGuts != null && mGuts.getAlpha() != 0.0f) {
3032 return true;
3033 }
3034 return false;
3035 }
3036
3037 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08003038 protected boolean childNeedsClipping(View child) {
3039 if (child instanceof NotificationContentView) {
3040 NotificationContentView contentView = (NotificationContentView) child;
3041 if (isClippingNeeded()) {
3042 return true;
Selim Cinek86bfcee2018-01-17 11:00:47 -08003043 } else if (!hasNoRounding()
3044 && contentView.shouldClipToRounding(getCurrentTopRoundness() != 0.0f,
3045 getCurrentBottomRoundness() != 0.0f)) {
Selim Cinek515b2032017-11-15 10:20:19 -08003046 return true;
3047 }
3048 } else if (child == mChildrenContainer) {
Selim Cinek6487ebf2018-11-28 18:57:40 -08003049 if (isClippingNeeded() || !hasNoRounding()) {
Selim Cinek515b2032017-11-15 10:20:19 -08003050 return true;
3051 }
3052 } else if (child instanceof NotificationGuts) {
Selim Cinekb95fd182017-12-21 13:03:32 -08003053 return !hasNoRounding();
Selim Cinek515b2032017-11-15 10:20:19 -08003054 }
3055 return super.childNeedsClipping(child);
3056 }
3057
3058 @Override
Selim Cinek2871bef2017-11-22 08:40:00 -08003059 protected void applyRoundness() {
3060 super.applyRoundness();
3061 applyChildrenRoundness();
3062 }
3063
3064 private void applyChildrenRoundness() {
3065 if (mIsSummaryWithChildren) {
3066 mChildrenContainer.setCurrentBottomRoundness(getCurrentBottomRoundness());
3067 }
3068 }
3069
3070 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08003071 public Path getCustomClipPath(View child) {
3072 if (child instanceof NotificationGuts) {
Selim Cinekdefd46f2018-05-30 11:47:08 -07003073 return getClipPath(true /* ignoreTranslation */);
Selim Cinek515b2032017-11-15 10:20:19 -08003074 }
3075 return super.getCustomClipPath(child);
3076 }
3077
Selim Cinekb95fd182017-12-21 13:03:32 -08003078 private boolean hasNoRounding() {
3079 return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f;
Selim Cinek0fe07392017-11-09 13:26:34 -08003080 }
3081
Kevina97ea052018-09-11 13:53:18 -07003082 public boolean isOnAmbient() {
3083 return mOnAmbient;
Adrian Roos6f6e1592017-05-02 16:22:53 -07003084 }
3085
Evan Laird94492852018-10-25 13:43:01 -04003086 //TODO: this logic can't depend on layout if we are recycling!
3087 public boolean isMediaRow() {
3088 return getExpandedContentView() != null
3089 && getExpandedContentView().findViewById(
3090 com.android.internal.R.id.media_actions) != null;
3091 }
3092
3093 public boolean isTopLevelChild() {
3094 return getParent() instanceof NotificationStackScrollLayout;
3095 }
3096
3097 public boolean isGroupNotFullyVisible() {
3098 return getClipTopAmount() > 0 || getTranslationY() < 0;
3099 }
3100
Selim Cinekd127d792016-11-01 19:11:41 -07003101 public void setAboveShelf(boolean aboveShelf) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07003102 boolean wasAboveShelf = isAboveShelf();
Selim Cinekd127d792016-11-01 19:11:41 -07003103 mAboveShelf = aboveShelf;
Selim Cinek5cf1d052017-06-01 17:36:46 -07003104 if (isAboveShelf() != wasAboveShelf) {
3105 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
3106 }
Selim Cinekd127d792016-11-01 19:11:41 -07003107 }
3108
Gus Prevasa18dc572019-01-14 16:11:22 -05003109 /** Sets whether dismiss gestures are right-to-left (instead of left-to-right). */
3110 public void setDismissRtl(boolean dismissRtl) {
3111 mMenuRow.setDismissRtl(dismissRtl);
3112 }
3113
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003114 private static class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08003115
3116 @Override
3117 public void applyToView(View view) {
Selim Cinekbbcebde2016-11-09 18:28:20 -08003118 if (view instanceof ExpandableNotificationRow) {
3119 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinek2627d722018-01-19 12:16:49 -08003120 if (row.isExpandAnimationRunning()) {
3121 return;
3122 }
Selim Cinekc25989e2018-02-16 16:42:14 -08003123 handleFixedTranslationZ(row);
Selim Cinek2627d722018-01-19 12:16:49 -08003124 super.applyToView(view);
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003125 row.applyChildrenState();
Selim Cinekbbcebde2016-11-09 18:28:20 -08003126 }
3127 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08003128
Selim Cinekc25989e2018-02-16 16:42:14 -08003129 private void handleFixedTranslationZ(ExpandableNotificationRow row) {
3130 if (row.hasExpandingChild()) {
3131 zTranslation = row.getTranslationZ();
3132 clipTopAmount = row.getClipTopAmount();
3133 }
3134 }
3135
Selim Cinek0cfbef42016-11-09 19:06:36 -08003136 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08003137 protected void onYTranslationAnimationFinished(View view) {
3138 super.onYTranslationAnimationFinished(view);
Selim Cinekd4776a52017-02-14 18:50:16 -08003139 if (view instanceof ExpandableNotificationRow) {
3140 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
3141 if (row.isHeadsUpAnimatingAway()) {
3142 row.setHeadsUpAnimatingAway(false);
3143 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08003144 }
3145 }
3146
3147 @Override
3148 public void animateTo(View child, AnimationProperties properties) {
Selim Cinek0cfbef42016-11-09 19:06:36 -08003149 if (child instanceof ExpandableNotificationRow) {
3150 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
Selim Cinek2627d722018-01-19 12:16:49 -08003151 if (row.isExpandAnimationRunning()) {
3152 return;
3153 }
Selim Cinekc25989e2018-02-16 16:42:14 -08003154 handleFixedTranslationZ(row);
Selim Cinek2627d722018-01-19 12:16:49 -08003155 super.animateTo(child, properties);
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003156 row.startChildAnimation(properties);
Selim Cinek0cfbef42016-11-09 19:06:36 -08003157 }
3158 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08003159 }
Selim Cinek817abe72017-05-24 11:08:55 -07003160
3161 @VisibleForTesting
3162 protected void setChildrenContainer(NotificationChildrenContainer childrenContainer) {
3163 mChildrenContainer = childrenContainer;
3164 }
Geoffrey Pitsch409db272017-08-28 14:51:52 +00003165
Julia Reynoldsfc640012018-02-21 12:25:27 -05003166 @VisibleForTesting
3167 protected void setPrivateLayout(NotificationContentView privateLayout) {
3168 mPrivateLayout = privateLayout;
3169 }
3170
3171 @VisibleForTesting
3172 protected void setPublicLayout(NotificationContentView publicLayout) {
3173 mPublicLayout = publicLayout;
3174 }
3175
Geoffrey Pitsch409db272017-08-28 14:51:52 +00003176 /**
3177 * Equivalent to View.OnLongClickListener with coordinates
3178 */
3179 public interface LongPressListener {
3180 /**
3181 * Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
3182 * @return whether the longpress was handled
3183 */
3184 boolean onLongPress(View v, int x, int y, MenuItem item);
3185 }
Julia Reynoldsb5867452018-02-28 16:31:35 -05003186
3187 /**
3188 * Equivalent to View.OnClickListener with coordinates
3189 */
3190 public interface OnAppOpsClickListener {
3191 /**
3192 * Equivalent to {@link View.OnClickListener#onClick(View)} with coordinates
3193 * @return whether the click was handled
3194 */
3195 boolean onClick(View v, int x, int y, MenuItem item);
3196 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07003197
Selim Cinek30887662018-10-15 17:37:21 -07003198 @Override
3199 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3200 super.dump(fd, pw, args);
3201 pw.println(" Notification: " + getStatusBarNotification().getKey());
3202 pw.print(" visibility: " + getVisibility());
3203 pw.print(", alpha: " + getAlpha());
3204 pw.print(", translation: " + getTranslation());
3205 pw.print(", removed: " + isRemoved());
Selim Cinek0db74592018-12-05 17:42:51 -08003206 pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
Selim Cinek85a8f9f2018-11-21 13:58:27 -08003207 NotificationContentView showingLayout = getShowingLayout();
3208 pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
Selim Cinek30887662018-10-15 17:37:21 -07003209 pw.println();
Selim Cinek85a8f9f2018-11-21 13:58:27 -08003210 showingLayout.dump(fd, pw, args);
Selim Cinek30887662018-10-15 17:37:21 -07003211 pw.print(" ");
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003212 if (getViewState() != null) {
3213 getViewState().dump(fd, pw, args);
Selim Cinek30887662018-10-15 17:37:21 -07003214 } else {
3215 pw.print("no viewState!!!");
3216 }
3217 pw.println();
3218 pw.println();
3219 if (mIsSummaryWithChildren) {
Selim Cinek0db74592018-12-05 17:42:51 -08003220 pw.print(" ChildrenContainer");
3221 pw.print(" visibility: " + mChildrenContainer.getVisibility());
3222 pw.print(", alpha: " + mChildrenContainer.getAlpha());
3223 pw.print(", translationY: " + mChildrenContainer.getTranslationY());
3224 pw.println();
Selim Cinek30887662018-10-15 17:37:21 -07003225 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
3226 pw.println(" Children: " + notificationChildren.size());
3227 pw.println(" {");
3228 for(ExpandableNotificationRow child : notificationChildren) {
3229 child.dump(fd, pw, args);
3230 }
3231 pw.println(" }");
3232 pw.println();
3233 }
3234 }
3235
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07003236 /**
3237 * Background task for executing IPCs to check if the notification is a system notification. The
3238 * output is used for both the blocking helper and the notification info.
3239 */
3240 private class SystemNotificationAsyncTask extends AsyncTask<Void, Void, Boolean> {
3241
3242 @Override
3243 protected Boolean doInBackground(Void... voids) {
3244 return isSystemNotification(mContext, mStatusBarNotification);
3245 }
3246
3247 @Override
3248 protected void onPostExecute(Boolean result) {
Julia Reynoldsaa96cf32018-04-17 09:09:04 -04003249 if (mEntry != null) {
3250 mEntry.mIsSystemNotification = result;
3251 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07003252 }
3253 }
Chris Wren51c75102013-07-16 20:49:17 -04003254}