blob: d625b318487d7c4ebaf0dd305cba6cf7ce68cba6 [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;
Dave Mankoffdde5ee62019-05-02 17:36:11 -040079import com.android.systemui.classifier.FalsingManagerFactory;
Dave Mankoff468d4f62019-05-08 14:56:29 -040080import com.android.systemui.plugins.FalsingManager;
Mady Mellor95d743c2017-01-10 12:05:27 -080081import com.android.systemui.plugins.PluginListener;
Mady Mellor95d743c2017-01-10 12:05:27 -080082import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
83import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
Kevin38ce6fa2018-10-17 16:00:14 -070084import com.android.systemui.shared.plugins.PluginManager;
Beth Thibodeaueab4dde2019-02-07 11:37:02 -050085import com.android.systemui.statusbar.NotificationMediaManager;
Rohan Shah20790b82018-07-02 17:21:04 -070086import com.android.systemui.statusbar.RemoteInputController;
87import com.android.systemui.statusbar.StatusBarIconView;
Selim Cinek5cf1d052017-06-01 17:36:46 -070088import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
Selim Cinek2627d722018-01-19 12:16:49 -080089import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
Selim Cinek6743c0b2017-01-18 18:24:01 -080090import com.android.systemui.statusbar.notification.NotificationUtils;
Kevin38ce6fa2018-10-17 16:00:14 -070091import com.android.systemui.statusbar.notification.VisualStabilityManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050092import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Kevin38ce6fa2018-10-17 16:00:14 -070093import com.android.systemui.statusbar.notification.logging.NotificationCounters;
Ned Burns1a5e22f2019-02-14 15:11:52 -050094import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
Rohan Shah20790b82018-07-02 17:21:04 -070095import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
Rohan Shah20790b82018-07-02 17:21:04 -070096import com.android.systemui.statusbar.notification.stack.AmbientState;
97import com.android.systemui.statusbar.notification.stack.AnimationProperties;
98import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
99import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
Evan Laird94492852018-10-25 13:43:01 -0400100import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
Kevin38ce6fa2018-10-17 16:00:14 -0700101import com.android.systemui.statusbar.phone.NotificationGroupManager;
102import com.android.systemui.statusbar.phone.StatusBar;
103import com.android.systemui.statusbar.policy.HeadsUpManager;
Gustav Sennton8a52dc32019-04-15 12:48:23 +0100104import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions;
Selim Cinekb5605e52015-02-20 18:21:41 +0100105
Selim Cinek30887662018-10-15 17:37:21 -0700106import java.io.FileDescriptor;
107import java.io.PrintWriter;
Mady Mellor4b80b102016-01-22 08:03:58 -0800108import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +0100109import java.util.List;
Ned Burns3da3c782019-01-08 21:14:39 -0500110import java.util.concurrent.TimeUnit;
Lucas Dupincecc7c22017-09-12 16:02:45 -0700111import java.util.function.BooleanSupplier;
Selim Cinek8875de12018-03-22 10:14:32 -0700112import java.util.function.Consumer;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500113
Rohan Shah63411fc2018-03-28 19:05:52 -0700114/**
115 * View representing a notification item - this can be either the individual child notification or
116 * the group summary (which contains 1 or more child notifications).
117 */
Mady Mellor95d743c2017-01-10 12:05:27 -0800118public class ExpandableNotificationRow extends ActivatableNotificationView
119 implements PluginListener<NotificationMenuRowPlugin> {
Selim Cinekb5605e52015-02-20 18:21:41 +0100120
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700121 private static final boolean DEBUG = false;
Selim Cinekb5605e52015-02-20 18:21:41 +0100122 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
123 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Mady Mellor95d743c2017-01-10 12:05:27 -0800124 private static final int MENU_VIEW_INDEX = 0;
Rohan Shah63411fc2018-03-28 19:05:52 -0700125 private static final String TAG = "ExpandableNotifRow";
felkachange6c03a02018-05-24 15:38:04 +0800126 public static final float DEFAULT_HEADER_VISIBLE_AMOUNT = 1.0f;
Ned Burns3da3c782019-01-08 21:14:39 -0500127 private static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
Selim Cinekab9c7b22018-12-11 18:15:47 -0800128 private boolean mUpdateBackgroundOnUpdate;
Nadia Benbernou7a18c812019-02-08 16:23:10 -0500129 private boolean mNotificationTranslationFinished = false;
Mady Mellor95d743c2017-01-10 12:05:27 -0800130
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700131 /**
132 * Listener for when {@link ExpandableNotificationRow} is laid out.
133 */
Mady Mellor035badd2017-04-04 18:45:30 -0700134 public interface LayoutListener {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700135 void onLayout();
Mady Mellor035badd2017-04-04 18:45:30 -0700136 }
137
138 private LayoutListener mLayoutListener;
Ned Burns1a5e22f2019-02-14 15:11:52 -0500139 private final NotificationContentInflater mNotificationInflater;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700140 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800141 private int mIconTransformContentShiftNoIcon;
Rohan Shahb9d500a2018-06-25 16:27:16 -0700142 private int mMaxHeadsUpHeightBeforeN;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800143 private int mMaxHeadsUpHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800144 private int mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800145 private int mMaxHeadsUpHeightIncreased;
Rohan Shahb9d500a2018-06-25 16:27:16 -0700146 private int mNotificationMinHeightBeforeN;
147 private int mNotificationMinHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800148 private int mNotificationMinHeight;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800149 private int mNotificationMinHeightLarge;
Beth Thibodeaucb395352019-01-25 15:39:54 -0500150 private int mNotificationMinHeightMedia;
Selim Cinek01af3342016-02-09 19:25:31 -0800151 private int mNotificationMaxHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -0700152 private int mIncreasedPaddingBetweenElements;
Selim Cinek2627d722018-01-19 12:16:49 -0800153 private int mNotificationLaunchHeight;
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100154 private boolean mMustStayOnScreen;
Chris Wren51c75102013-07-16 20:49:17 -0400155
Selim Cinek1685e632014-04-08 02:27:49 +0200156 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -0400157 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +0200158 /** Has the user actively changed the expansion state of this row */
159 private boolean mHasUserChangedExpansion;
160 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -0400161 private boolean mUserExpanded;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700162 /** Whether the blocking helper is showing on this notification (even if dismissed) */
163 private boolean mIsBlockingHelperShowing;
Selim Cinek31aada42015-12-18 17:51:15 -0800164
165 /**
166 * Has this notification been expanded while it was pinned
167 */
168 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +0200169 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -0400170 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +0200171 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -0500172 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +0200173 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -0800174 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +0200175 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700176 private boolean mHideSensitiveForIntrinsicHeight;
felkachange6c03a02018-05-24 15:38:04 +0800177 private float mHeaderVisibleAmount = DEFAULT_HEADER_VISIBLE_AMOUNT;
Chris Wren51c75102013-07-16 20:49:17 -0400178
Selim Cinek1685e632014-04-08 02:27:49 +0200179 /**
180 * Is this notification expanded by the system. The expansion state can be overridden by the
181 * user expansion.
182 */
183 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200184
185 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700186 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200187 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700188 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200189
Kevina97ea052018-09-11 13:53:18 -0700190 /**
191 * Whether or not the row is currently on the doze screen.
192 */
193 private boolean mOnAmbient;
194
Mady Mellorb0a82462016-04-30 17:31:02 -0700195 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800196 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200197 private NotificationContentView mPublicLayout;
198 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800199 private NotificationContentView[] mLayouts;
Selim Cinek4bb59342016-04-08 19:29:35 -0700200 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100201 private ExpansionLogger mLogger;
202 private String mLoggingKey;
Selim Cinek8d490d42015-04-10 00:05:50 -0700203 private NotificationGuts mGuts;
Ned Burnsf81c4c42019-01-07 14:10:43 -0500204 private NotificationEntry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200205 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700206 private String mAppName;
Kevina97ea052018-09-11 13:53:18 -0700207
208 /**
209 * Whether or not the notification is using the heads up view and should peek from the top.
210 */
Selim Cinek1a521f32014-11-03 17:39:29 +0100211 private boolean mIsHeadsUp;
Kevina97ea052018-09-11 13:53:18 -0700212
213 /**
214 * Whether or not the notification is using the ambient display view and is pulsing. This
215 * occurs when a high priority notification alerts while the phone is dozing or is on AOD.
216 */
217 private boolean mIsAmbientPulsing;
218
Kevin38ce6fa2018-10-17 16:00:14 -0700219 /**
Selim Cinek459aee32019-02-20 11:18:56 -0800220 * Happens when the notification was pulsing before and goes away to ensure smooth animations.
221 */
222 private boolean mAmbientGoingAway;
223
224 /**
Kevin38ce6fa2018-10-17 16:00:14 -0700225 * Whether or not the notification should be redacted on the lock screen, i.e has sensitive
226 * content which should be redacted on the lock screen.
227 */
228 private boolean mNeedsRedaction;
Selim Cinek98713a42015-09-21 15:47:20 +0200229 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100230 private ViewStub mChildrenContainerStub;
231 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100232 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700233 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100234 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor95d743c2017-01-10 12:05:27 -0800235 private NotificationMenuRowPlugin mMenuRow;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100236 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100237 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700238 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700239 private FalsingManager mFalsingManager;
Selim Cinek2627d722018-01-19 12:16:49 -0800240 private boolean mExpandAnimationRunning;
Selim Cinek5cf1d052017-06-01 17:36:46 -0700241 private AboveShelfChangedListener mAboveShelfChangedListener;
Selim Cinek31aada42015-12-18 17:51:15 -0800242 private HeadsUpManager mHeadsUpManager;
Selim Cinek8875de12018-03-22 10:14:32 -0700243 private Consumer<Boolean> mHeadsUpAnimatingAwayListener;
Selim Cinekc25989e2018-02-16 16:42:14 -0800244 private boolean mChildIsExpanding;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200245
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700246 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800247 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700248 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700249 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800250 private OnExpandClickListener mOnExpandClickListener;
Julia Reynoldsb5867452018-02-28 16:31:35 -0500251 private View.OnClickListener mOnAppOpsClickListener;
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000252
253 // Listener will be called when receiving a long click event.
254 // Use #setLongPressPosition to optionally assign positional data with the long press.
255 private LongPressListener mLongPressListener;
256
Mady Mellorb0a82462016-04-30 17:31:02 -0700257 private boolean mGroupExpansionChanging;
258
Anthony Chen6bf88a02017-04-10 14:41:44 -0700259 /**
Lucas Dupincecc7c22017-09-12 16:02:45 -0700260 * A supplier that returns true if keyguard is secure.
261 */
262 private BooleanSupplier mSecureStateProvider;
263
264 /**
Anthony Chen6bf88a02017-04-10 14:41:44 -0700265 * Whether or not a notification that is not part of a group of notifications can be manually
266 * expanded by the user.
267 */
268 private boolean mEnableNonGroupedNotificationExpand;
269
270 /**
271 * Whether or not to update the background of the header of the notification when its expanded.
272 * If {@code true}, the header background will disappear when expanded.
273 */
274 private boolean mShowGroupBackgroundWhenExpanded;
275
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800276 private OnClickListener mExpandClickListener = new OnClickListener() {
277 @Override
278 public void onClick(View v) {
Selim Cinek0b9cf462017-12-07 16:31:03 -0800279 if (!shouldShowPublic() && (!mIsLowPriority || isExpanded())
Selim Cinek414ad332017-02-24 19:06:12 -0800280 && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700281 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400282 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
283 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
284 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400285 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
286 nowExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -0800287 onExpansionChanged(true /* userAction */, wasExpanded);
Anthony Chen6bf88a02017-04-10 14:41:44 -0700288 } else if (mEnableNonGroupedNotificationExpand) {
Selim Cineke9bad242016-06-15 11:46:37 -0700289 if (v.isAccessibilityFocused()) {
290 mPrivateLayout.setFocusOnVisibilityChange();
291 }
Selim Cinek31aada42015-12-18 17:51:15 -0800292 boolean nowExpanded;
293 if (isPinned()) {
294 nowExpanded = !mExpandedWhenPinned;
295 mExpandedWhenPinned = nowExpanded;
296 } else {
297 nowExpanded = !isExpanded();
298 setUserExpanded(nowExpanded);
299 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800300 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800301 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400302 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
303 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800304 }
305 }
306 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700307 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700308 private boolean mDismissed;
309 private boolean mKeepInParent;
310 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700311 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
312 new FloatProperty<ExpandableNotificationRow>("translate") {
313 @Override
314 public void setValue(ExpandableNotificationRow object, float value) {
315 object.setTranslation(value);
316 }
317
318 @Override
319 public Float get(ExpandableNotificationRow object) {
320 return object.getTranslation();
321 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700322 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700323 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700324 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700325 private View mChildAfterViewWhenDismissed;
326 private View mGroupParentWhenDismissed;
327 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800328 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700329 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700330 private boolean mAboveShelf;
Selim Cinek875a3a12016-11-18 17:52:16 -0800331 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800332 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800333 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800334 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800335 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800336 private boolean mUseIncreasedHeadsUpHeight;
Selim Cinekef8c2252017-02-10 14:52:18 -0800337 private float mTranslationWhenRemoved;
338 private boolean mWasChildInGroupWhenRemoved;
Ahan Wude396fa2018-05-08 20:42:24 +0800339 private NotificationInlineImageResolver mImageResolver;
Beth Thibodeaueab4dde2019-02-07 11:37:02 -0500340 private NotificationMediaManager mMediaManager;
Mady Mellorb0a82462016-04-30 17:31:02 -0700341
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700342 private SystemNotificationAsyncTask mSystemNotificationAsyncTask =
343 new SystemNotificationAsyncTask();
Mady Mellorc3d6f7d2018-11-07 09:36:56 -0800344 private int mStatusBarState = -1;
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700345
346 /**
347 * Returns whether the given {@code statusBarNotification} is a system notification.
348 * <b>Note</b>, this should be run in the background thread if possible as it makes multiple IPC
349 * calls.
350 */
351 private static Boolean isSystemNotification(
352 Context context, StatusBarNotification statusBarNotification) {
353 PackageManager packageManager = StatusBar.getPackageManagerForUser(
354 context, statusBarNotification.getUser().getIdentifier());
355 Boolean isSystemNotification = null;
356
357 try {
358 PackageInfo packageInfo = packageManager.getPackageInfo(
359 statusBarNotification.getPackageName(), PackageManager.GET_SIGNATURES);
360
361 isSystemNotification =
362 com.android.settingslib.Utils.isSystemPackage(
363 context.getResources(), packageManager, packageInfo);
364 } catch (PackageManager.NameNotFoundException e) {
365 Log.e(TAG, "cacheIsSystemNotification: Could not find package info");
366 }
367 return isSystemNotification;
368 }
369
Mady Mellor43c2cd12016-12-12 21:05:13 -0800370 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700371 public boolean isGroupExpansionChanging() {
372 if (isChildInGroup()) {
373 return mNotificationParent.isGroupExpansionChanging();
374 }
375 return mGroupExpansionChanging;
376 }
377
378 public void setGroupExpansionChanging(boolean changing) {
379 mGroupExpansionChanging = changing;
380 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700381
Adrian Roos599be342016-06-13 14:54:39 -0700382 @Override
383 public void setActualHeightAnimating(boolean animating) {
384 if (mPrivateLayout != null) {
385 mPrivateLayout.setContentHeightAnimating(animating);
386 }
387 }
388
Selim Cinek8d490d42015-04-10 00:05:50 -0700389 public NotificationContentView getPrivateLayout() {
390 return mPrivateLayout;
391 }
392
393 public NotificationContentView getPublicLayout() {
394 return mPublicLayout;
395 }
396
Selim Cinekcab4a602014-09-03 14:47:57 +0200397 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800398 for (NotificationContentView l : mLayouts) {
399 setIconAnimationRunning(running, l);
400 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800401 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700402 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek414ad332017-02-24 19:06:12 -0800403 setIconAnimationRunningForChild(running, mChildrenContainer.getLowPriorityHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800404 List<ExpandableNotificationRow> notificationChildren =
405 mChildrenContainer.getNotificationChildren();
406 for (int i = 0; i < notificationChildren.size(); i++) {
407 ExpandableNotificationRow child = notificationChildren.get(i);
408 child.setIconAnimationRunning(running);
409 }
410 }
411 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200412 }
413
414 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
415 if (layout != null) {
416 View contractedChild = layout.getContractedChild();
417 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700418 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200419 setIconAnimationRunningForChild(running, contractedChild);
420 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700421 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200422 }
423 }
424
425 private void setIconAnimationRunningForChild(boolean running, View child) {
426 if (child != null) {
427 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
428 setIconRunning(icon, running);
429 ImageView rightIcon = (ImageView) child.findViewById(
430 com.android.internal.R.id.right_icon);
431 setIconRunning(rightIcon, running);
432 }
433 }
434
435 private void setIconRunning(ImageView imageView, boolean running) {
436 if (imageView != null) {
437 Drawable drawable = imageView.getDrawable();
438 if (drawable instanceof AnimationDrawable) {
439 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
440 if (running) {
441 animationDrawable.start();
442 } else {
443 animationDrawable.stop();
444 }
445 } else if (drawable instanceof AnimatedVectorDrawable) {
446 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
447 if (running) {
448 animationDrawable.start();
449 } else {
450 animationDrawable.stop();
451 }
452 }
453 }
454 }
455
Kevind4660b22018-09-27 10:57:35 -0700456 /**
457 * Set the entry for the row.
458 *
459 * @param entry the entry this row is tied to
460 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500461 public void setEntry(@NonNull NotificationEntry entry) {
Selim Cinekda42d652015-12-04 15:51:16 -0800462 mEntry = entry;
463 mStatusBarNotification = entry.notification;
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700464 cacheIsSystemNotification();
Rohan Shah63411fc2018-03-28 19:05:52 -0700465 }
466
467 /**
Kevin01a53cb2018-11-09 18:19:54 -0800468 * Inflate views based off the inflation flags set. Inflation happens asynchronously.
Kevind4660b22018-09-27 10:57:35 -0700469 */
470 public void inflateViews() {
471 mNotificationInflater.inflateNotificationViews();
472 }
473
474 /**
Kevind5022f92018-10-08 18:30:26 -0700475 * Marks a content view as freeable, setting it so that future inflations do not reinflate
476 * and ensuring that the view is freed when it is safe to remove.
477 *
478 * @param inflationFlag flag corresponding to the content view to be freed
479 */
480 public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) {
481 // View should not be reinflated in the future
482 updateInflationFlag(inflationFlag, false);
483 Runnable freeViewRunnable = () ->
484 mNotificationInflater.freeNotificationView(inflationFlag);
485 switch (inflationFlag) {
486 case FLAG_CONTENT_VIEW_HEADS_UP:
487 getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_HEADSUP,
488 freeViewRunnable);
489 break;
490 case FLAG_CONTENT_VIEW_AMBIENT:
491 getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT,
492 freeViewRunnable);
493 getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT,
494 freeViewRunnable);
495 break;
Kevin38ce6fa2018-10-17 16:00:14 -0700496 case FLAG_CONTENT_VIEW_PUBLIC:
497 getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_CONTRACTED,
498 freeViewRunnable);
Kevind5022f92018-10-08 18:30:26 -0700499 default:
500 break;
501 }
502 }
503
504 /**
Kevind4660b22018-09-27 10:57:35 -0700505 * Update whether or not a content view should be inflated.
506 *
507 * @param flag the flag corresponding to the content view
508 * @param shouldInflate true if it should be inflated, false if it should not
509 */
510 public void updateInflationFlag(@InflationFlag int flag, boolean shouldInflate) {
511 mNotificationInflater.updateInflationFlag(flag, shouldInflate);
512 }
513
514 /**
Kevin01a53cb2018-11-09 18:19:54 -0800515 * Whether or not a content view should be inflated.
516 *
517 * @param flag the flag corresponding to the content view
518 * @return true if the flag is set, false otherwise
519 */
520 public boolean isInflationFlagSet(@InflationFlag int flag) {
521 return mNotificationInflater.isInflationFlagSet(flag);
522 }
523
524 /**
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700525 * Caches whether or not this row contains a system notification. Note, this is only cached
526 * once per notification as the packageInfo can't technically change for a notification row.
Rohan Shah63411fc2018-03-28 19:05:52 -0700527 */
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700528 private void cacheIsSystemNotification() {
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400529 if (mEntry != null && mEntry.mIsSystemNotification == null) {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700530 if (mSystemNotificationAsyncTask.getStatus() == AsyncTask.Status.PENDING) {
531 // Run async task once, only if it hasn't already been executed. Note this is
532 // executed in serial - no need to parallelize this small task.
533 mSystemNotificationAsyncTask.execute();
Rohan Shah63411fc2018-03-28 19:05:52 -0700534 }
535 }
536 }
537
538 /**
Rohan Shahca0447e2018-03-30 15:18:27 -0700539 * Returns whether this row is considered non-blockable (i.e. it's a non-blockable system notif
540 * or is in a whitelist).
Rohan Shah63411fc2018-03-28 19:05:52 -0700541 */
542 public boolean getIsNonblockable() {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700543 boolean isNonblockable = Dependency.get(NotificationBlockingHelperManager.class)
Julia Reynolds0abae112018-06-08 10:36:57 -0400544 .isNonblockable(mStatusBarNotification.getPackageName(),
545 mEntry.channel.getId());
Rohan Shah63411fc2018-03-28 19:05:52 -0700546
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700547 // If the SystemNotifAsyncTask hasn't finished running or retrieved a value, we'll try once
548 // again, but in-place on the main thread this time. This should rarely ever get called.
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400549 if (mEntry != null && mEntry.mIsSystemNotification == null) {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700550 if (DEBUG) {
551 Log.d(TAG, "Retrieving isSystemNotification on main thread");
552 }
553 mSystemNotificationAsyncTask.cancel(true /* mayInterruptIfRunning */);
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400554 mEntry.mIsSystemNotification = isSystemNotification(mContext, mStatusBarNotification);
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700555 }
556
Julia Reynolds0c245002019-03-27 16:10:11 -0400557 isNonblockable |= mEntry.channel.isImportanceLockedByOEM();
558 isNonblockable |= mEntry.channel.isImportanceLockedByCriticalDeviceFunction();
559
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400560 if (!isNonblockable && mEntry != null && mEntry.mIsSystemNotification != null) {
561 if (mEntry.mIsSystemNotification) {
Rohan Shah63411fc2018-03-28 19:05:52 -0700562 if (mEntry.channel != null
563 && !mEntry.channel.isBlockableSystem()) {
564 isNonblockable = true;
565 }
566 }
567 }
568 return isNonblockable;
Selim Cinekc478f902017-02-22 20:55:44 -0800569 }
570
Selim Cinek5ba22542017-04-20 15:16:10 -0700571 public void onNotificationUpdated() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800572 for (NotificationContentView l : mLayouts) {
Selim Cinekc478f902017-02-22 20:55:44 -0800573 l.onNotificationUpdated(mEntry);
Adrian Rooseb434ff2017-01-11 11:18:48 -0800574 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800575 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800576 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700577 updateNotificationColor();
Mady Mellor4c197602017-04-10 17:57:52 -0700578 if (mMenuRow != null) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700579 mMenuRow.onNotificationUpdated(mStatusBarNotification);
Beverly3f56f052018-05-08 14:56:03 -0400580 mMenuRow.setAppName(mAppName);
Mady Mellor4c197602017-04-10 17:57:52 -0700581 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800582 if (mIsSummaryWithChildren) {
Selim Cinek414ad332017-02-24 19:06:12 -0800583 mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
Selim Cinekc897bd32016-03-18 17:32:31 -0700584 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800585 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800586 if (mIconAnimationRunning) {
587 setIconAnimationRunning(true);
588 }
Kevin38ce6fa2018-10-17 16:00:14 -0700589 if (mLastChronometerRunning) {
590 setChronometerRunning(true);
591 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800592 if (mNotificationParent != null) {
593 mNotificationParent.updateChildrenHeaderAppearance();
594 }
Selim Cinek263398f2015-10-21 17:40:23 -0700595 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800596 // The public layouts expand button is always visible
597 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800598 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700599 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800600 updateShelfIconColor();
Selim Cinekfe24fb72018-02-13 14:34:55 -0800601 updateRippleAllowed();
Selim Cinekab9c7b22018-12-11 18:15:47 -0800602 if (mUpdateBackgroundOnUpdate) {
603 mUpdateBackgroundOnUpdate = false;
604 updateBackgroundColors();
605 }
Selim Cinek6743c0b2017-01-18 18:24:01 -0800606 }
607
Gus Prevas33fbc152018-12-04 13:17:32 -0500608 /** Called when the notification's ranking was changed (but nothing else changed). */
609 public void onNotificationRankingUpdated() {
610 if (mMenuRow != null) {
611 mMenuRow.onNotificationUpdated(mStatusBarNotification);
612 }
613 }
614
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700615 @VisibleForTesting
616 void updateShelfIconColor() {
Selim Cinek6743c0b2017-01-18 18:24:01 -0800617 StatusBarIconView expandedIcon = mEntry.expandedIcon;
618 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
619 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
Lucas Dupina291d192018-06-07 13:59:42 -0700620 ContrastColorUtil.getInstance(mContext));
Selim Cinek875ba9b2017-02-13 16:20:17 -0800621 int color = StatusBarIconView.NO_COLOR;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800622 if (colorize) {
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700623 NotificationHeaderView header = getVisibleNotificationHeader();
624 if (header != null) {
625 color = header.getOriginalIconColor();
626 } else {
627 color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
628 getBackgroundColorWithoutTint());
629 }
Selim Cinek6743c0b2017-01-18 18:24:01 -0800630 }
Selim Cinek875ba9b2017-02-13 16:20:17 -0800631 expandedIcon.setStaticDrawableColor(color);
Selim Cinekda42d652015-12-04 15:51:16 -0800632 }
633
Selim Cinek5cf1d052017-06-01 17:36:46 -0700634 public void setAboveShelfChangedListener(AboveShelfChangedListener aboveShelfChangedListener) {
635 mAboveShelfChangedListener = aboveShelfChangedListener;
636 }
637
Lucas Dupincecc7c22017-09-12 16:02:45 -0700638 /**
639 * Sets a supplier that can determine whether the keyguard is secure or not.
640 * @param secureStateProvider A function that returns true if keyguard is secure.
641 */
642 public void setSecureStateProvider(BooleanSupplier secureStateProvider) {
643 mSecureStateProvider = secureStateProvider;
644 }
645
Selim Cinek4705f292017-04-24 22:18:48 -0700646 @Override
647 public boolean isDimmable() {
648 if (!getShowingLayout().isDimmable()) {
649 return false;
650 }
Selim Cinekf434a742019-05-28 17:39:49 -0700651 if (showingAmbientPulsing()) {
652 return false;
653 }
Selim Cinek4705f292017-04-24 22:18:48 -0700654 return super.isDimmable();
655 }
656
Selim Cinekda42d652015-12-04 15:51:16 -0800657 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800658 for (NotificationContentView l : mLayouts) {
659 updateLimitsForView(l);
660 }
Selim Cineka1744872016-03-11 15:36:06 -0800661 }
662
663 private void updateLimitsForView(NotificationContentView layout) {
Kevin38ce6fa2018-10-17 16:00:14 -0700664 boolean customView = layout.getContractedChild() != null
665 && layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800666 != com.android.internal.R.id.status_bar_latest_event_content;
667 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800668 boolean beforeP = mEntry.targetSdk < Build.VERSION_CODES.P;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800669 int minHeight;
Beth Thibodeaucb395352019-01-25 15:39:54 -0500670
671 View expandedView = layout.getExpandedChild();
672 boolean isMediaLayout = expandedView != null
673 && expandedView.findViewById(com.android.internal.R.id.media_actions) != null;
Beth Thibodeaueab4dde2019-02-07 11:37:02 -0500674 boolean showCompactMediaSeekbar = mMediaManager.getShowCompactMediaSeekbar();
Beth Thibodeaucb395352019-01-25 15:39:54 -0500675
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800676 if (customView && beforeP && !mIsSummaryWithChildren) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700677 minHeight = beforeN ? mNotificationMinHeightBeforeN : mNotificationMinHeightBeforeP;
Beth Thibodeaueab4dde2019-02-07 11:37:02 -0500678 } else if (isMediaLayout && showCompactMediaSeekbar) {
Beth Thibodeaucb395352019-01-25 15:39:54 -0500679 minHeight = mNotificationMinHeightMedia;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800680 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
681 minHeight = mNotificationMinHeightLarge;
682 } else {
683 minHeight = mNotificationMinHeight;
684 }
Selim Cineka1744872016-03-11 15:36:06 -0800685 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
686 layout.getHeadsUpChild().getId()
687 != com.android.internal.R.id.status_bar_latest_event_content;
Rohan Shahb9d500a2018-06-25 16:27:16 -0700688 int headsUpHeight;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800689 if (headsUpCustom && beforeP) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700690 headsUpHeight = beforeN ? mMaxHeadsUpHeightBeforeN : mMaxHeadsUpHeightBeforeP;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800691 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700692 headsUpHeight = mMaxHeadsUpHeightIncreased;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800693 } else {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700694 headsUpHeight = mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800695 }
Selim Cineke62255c2017-09-28 18:23:23 -0700696 NotificationViewWrapper headsUpWrapper = layout.getVisibleWrapper(
Kevind5022f92018-10-08 18:30:26 -0700697 VISIBLE_TYPE_HEADSUP);
Selim Cineke62255c2017-09-28 18:23:23 -0700698 if (headsUpWrapper != null) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700699 headsUpHeight = Math.max(headsUpHeight, headsUpWrapper.getMinLayoutHeight());
Selim Cineke62255c2017-09-28 18:23:23 -0700700 }
Lucas Dupin00be88f2019-01-03 17:50:52 -0800701 layout.setHeights(minHeight, headsUpHeight, mNotificationMaxHeight, headsUpHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200702 }
703
704 public StatusBarNotification getStatusBarNotification() {
705 return mStatusBarNotification;
706 }
707
Ned Burnsf81c4c42019-01-07 14:10:43 -0500708 public NotificationEntry getEntry() {
Selim Cinek281c2022016-10-13 19:14:43 -0700709 return mEntry;
710 }
711
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700712 public boolean isHeadsUp() {
713 return mIsHeadsUp;
714 }
715
Selim Cinek1a521f32014-11-03 17:39:29 +0100716 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinek5cf1d052017-06-01 17:36:46 -0700717 boolean wasAboveShelf = isAboveShelf();
Selim Cinekc80fdb12015-04-13 15:09:08 -0700718 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100719 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700720 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700721 if (mIsSummaryWithChildren) {
722 // The overflow might change since we allow more lines as HUN.
723 mChildrenContainer.updateGroupOverflow();
724 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700725 if (intrinsicBefore != getIntrinsicHeight()) {
726 notifyHeightChanged(false /* needsAnimation */);
727 }
Selim Cinekd127d792016-11-01 19:11:41 -0700728 if (isHeadsUp) {
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100729 mMustStayOnScreen = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700730 setAboveShelf(true);
Kevind5022f92018-10-08 18:30:26 -0700731 } else if (isAboveShelf() != wasAboveShelf) {
732 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
Selim Cinekd127d792016-11-01 19:11:41 -0700733 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100734 }
735
Selim Cinek5040f2e2019-02-14 18:22:42 -0800736 @Override
Selim Cinek459aee32019-02-20 11:18:56 -0800737 public boolean showingAmbientPulsing() {
738 return mIsAmbientPulsing || mAmbientGoingAway;
Kevina97ea052018-09-11 13:53:18 -0700739 }
740
741 public void setAmbientPulsing(boolean isAmbientPulsing) {
742 mIsAmbientPulsing = isAmbientPulsing;
743 }
744
Selim Cinekb5605e52015-02-20 18:21:41 +0100745 public void setGroupManager(NotificationGroupManager groupManager) {
746 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700747 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100748 }
749
Adrian Roosb88b1a12015-12-09 18:51:05 -0800750 public void setRemoteInputController(RemoteInputController r) {
751 mPrivateLayout.setRemoteInputController(r);
752 }
753
Mady Mellor3fd273e2016-03-15 21:08:14 -0700754 public void setAppName(String appName) {
755 mAppName = appName;
Mady Mellor95d743c2017-01-10 12:05:27 -0800756 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800757 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700758 }
759 }
760
Selim Cinekb5605e52015-02-20 18:21:41 +0100761 public void addChildNotification(ExpandableNotificationRow row) {
762 addChildNotification(row, -1);
763 }
764
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800765 /**
766 * Set the how much the header should be visible. A value of 0 will make the header fully gone
767 * and a value of 1 will make the notification look just like normal.
768 * This is being used for heads up notifications, when they are pinned to the top of the screen
769 * and the header content is extracted to the statusbar.
770 *
771 * @param headerVisibleAmount the amount the header should be visible.
772 */
773 public void setHeaderVisibleAmount(float headerVisibleAmount) {
774 if (mHeaderVisibleAmount != headerVisibleAmount) {
775 mHeaderVisibleAmount = headerVisibleAmount;
Selim Cinek4b259a12019-05-09 19:10:51 -0700776 for (NotificationContentView l : mLayouts) {
777 l.setHeaderVisibleAmount(headerVisibleAmount);
778 }
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800779 if (mChildrenContainer != null) {
780 mChildrenContainer.setHeaderVisibleAmount(headerVisibleAmount);
781 }
782 notifyHeightChanged(false /* needsAnimation */);
783 }
784 }
785
Selim Cinek99e9adf2018-03-15 09:17:47 -0700786 @Override
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800787 public float getHeaderVisibleAmount() {
788 return mHeaderVisibleAmount;
789 }
790
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100791 @Override
792 public void setHeadsUpIsVisible() {
793 super.setHeadsUpIsVisible();
794 mMustStayOnScreen = false;
795 }
796
Selim Cinekb5605e52015-02-20 18:21:41 +0100797 /**
798 * Add a child notification to this view.
799 *
800 * @param row the row to add
801 * @param childIndex the index to add it at, if -1 it will be added at the end
802 */
803 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
804 if (mChildrenContainer == null) {
805 mChildrenContainerStub.inflate();
806 }
807 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700808 onChildrenCountChanged();
809 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100810 }
811
812 public void removeChildNotification(ExpandableNotificationRow row) {
813 if (mChildrenContainer != null) {
814 mChildrenContainer.removeNotification(row);
815 }
Selim Cinek263398f2015-10-21 17:40:23 -0700816 onChildrenCountChanged();
817 row.setIsChildInGroup(false, null);
Selim Cinek2871bef2017-11-22 08:40:00 -0800818 row.setBottomRoundness(0.0f, false /* animate */);
Selim Cinek263398f2015-10-21 17:40:23 -0700819 }
820
Mady Mellor43c2cd12016-12-12 21:05:13 -0800821 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700822 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700823 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700824 }
825
Rohan Shah524cf7b2018-03-15 14:40:02 -0700826 /**
827 * @return whether this notification is the only child in the group summary
828 */
829 public boolean isOnlyChildInGroup() {
830 return mGroupManager.isOnlyChildInGroup(getStatusBarNotification());
831 }
832
Selim Cinek388df6d2015-10-22 13:25:11 -0700833 public ExpandableNotificationRow getNotificationParent() {
834 return mNotificationParent;
835 }
836
Selim Cinek263398f2015-10-21 17:40:23 -0700837 /**
838 * @param isChildInGroup Is this notification now in a group
839 * @param parent the new parent notification
840 */
Selim Cinekc25989e2018-02-16 16:42:14 -0800841 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500842 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cinekc25989e2018-02-16 16:42:14 -0800843 if (mExpandAnimationRunning && !isChildInGroup && mNotificationParent != null) {
844 mNotificationParent.setChildIsExpanding(false);
845 mNotificationParent.setExtraWidthForClipping(0.0f);
846 mNotificationParent.setMinimumHeightForClipping(0);
847 }
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700848 mNotificationParent = childInGroup ? parent : null;
849 mPrivateLayout.setIsChildInGroup(childInGroup);
Selim Cinek5ba22542017-04-20 15:16:10 -0700850 mNotificationInflater.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400851 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700852 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700853 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700854 if (mNotificationParent != null) {
Selim Cinek9ce32852017-02-15 16:21:10 -0800855 setOverrideTintColor(NO_COLOR, 0.0f);
Selim Cinekeccf4942018-05-30 09:55:36 -0700856 // Let's reset the distance to top roundness, as this isn't applied to group children
857 setDistanceToTopRoundness(NO_ROUNDNESS);
Mady Mellorb0a82462016-04-30 17:31:02 -0700858 mNotificationParent.updateBackgroundForGroupState();
859 }
Selim Cinekdb167372016-11-17 15:41:17 -0800860 updateIconVisibilities();
Selim Cinek2871bef2017-11-22 08:40:00 -0800861 updateBackgroundClipping();
Selim Cinek34d93b02015-10-22 12:30:38 -0700862 }
863
864 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800865 public boolean onTouchEvent(MotionEvent event) {
866 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
867 || !isChildInGroup() || isGroupExpanded()) {
868 return super.onTouchEvent(event);
869 } else {
870 return false;
871 }
872 }
873
874 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800875 protected boolean handleSlideBack() {
Mady Mellor95d743c2017-01-10 12:05:27 -0800876 if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800877 animateTranslateNotification(0 /* targetLeft */);
878 return true;
879 }
880 return false;
881 }
882
883 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700884 protected boolean shouldHideBackground() {
885 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700886 }
887
888 @Override
889 public boolean isSummaryWithChildren() {
890 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100891 }
892
893 @Override
894 public boolean areChildrenExpanded() {
895 return mChildrenExpanded;
896 }
897
898 public List<ExpandableNotificationRow> getNotificationChildren() {
899 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
900 }
901
Selim Cinekeef84282015-10-30 16:28:00 -0700902 public int getNumberOfNotificationChildren() {
903 if (mChildrenContainer == null) {
904 return 0;
905 }
906 return mChildrenContainer.getNotificationChildren().size();
907 }
908
Selim Cinekb5605e52015-02-20 18:21:41 +0100909 /**
910 * Apply the order given in the list to the children.
911 *
912 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800913 * @param visualStabilityManager
914 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100915 * @return whether the list order has changed
916 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800917 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
918 VisualStabilityManager visualStabilityManager,
919 VisualStabilityManager.Callback callback) {
920 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
921 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100922 }
923
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500924 /** Updates states of all children. */
925 public void updateChildrenStates(AmbientState ambientState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700926 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500927 ExpandableViewState parentState = getViewState();
928 mChildrenContainer.updateState(parentState, ambientState);
Selim Cinekb5605e52015-02-20 18:21:41 +0100929 }
930 }
931
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500932 /** Applies children states. */
933 public void applyChildrenState() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700934 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500935 mChildrenContainer.applyState();
Selim Cinekb5605e52015-02-20 18:21:41 +0100936 }
937 }
938
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500939 /** Prepares expansion changed. */
940 public void prepareExpansionChanged() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700941 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500942 mChildrenContainer.prepareExpansionChanged();
Selim Cinekb5605e52015-02-20 18:21:41 +0100943 }
944 }
945
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500946 /** Starts child animations. */
947 public void startChildAnimation(AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700948 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500949 mChildrenContainer.startAnimationToState(properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100950 }
951 }
952
953 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800954 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100955 return this;
956 } else {
957 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
958 return view == null ? this : view;
959 }
960 }
961
Selim Cinekab29aeb2015-02-20 18:18:32 +0100962 public NotificationGuts getGuts() {
963 return mGuts;
964 }
965
Selim Cinek684a4422015-04-15 16:18:39 -0700966 /**
967 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
968 * the notification will be rendered on top of the screen.
969 *
970 * @param pinned whether it is pinned
971 */
972 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700973 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek5cf1d052017-06-01 17:36:46 -0700974 boolean wasAboveShelf = isAboveShelf();
Selim Cinek684a4422015-04-15 16:18:39 -0700975 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700976 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700977 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700978 }
Selim Cinek31aada42015-12-18 17:51:15 -0800979 if (pinned) {
980 setIconAnimationRunning(true);
981 mExpandedWhenPinned = false;
982 } else if (mExpandedWhenPinned) {
983 setUserExpanded(true);
984 }
Selim Cinek98713a42015-09-21 15:47:20 +0200985 setChronometerRunning(mLastChronometerRunning);
Selim Cinek5cf1d052017-06-01 17:36:46 -0700986 if (isAboveShelf() != wasAboveShelf) {
987 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
988 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700989 }
990
Selim Cinek29aab962018-02-27 17:05:45 -0800991 @Override
Selim Cinek684a4422015-04-15 16:18:39 -0700992 public boolean isPinned() {
993 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700994 }
995
Selim Cinekd127d792016-11-01 19:11:41 -0700996 @Override
997 public int getPinnedHeadsUpHeight() {
998 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
999 }
1000
Selim Cinek31aada42015-12-18 17:51:15 -08001001 /**
1002 * @param atLeastMinHeight should the value returned be at least the minimum height.
1003 * Used to avoid cyclic calls
1004 * @return the height of the heads up notification when pinned
1005 */
Selim Cinekd127d792016-11-01 19:11:41 -07001006 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -08001007 if (mIsSummaryWithChildren) {
1008 return mChildrenContainer.getIntrinsicHeight();
1009 }
Selim Cinek31aada42015-12-18 17:51:15 -08001010 if(mExpandedWhenPinned) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08001011 return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
Selim Cinek31aada42015-12-18 17:51:15 -08001012 } else if (atLeastMinHeight) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08001013 return Math.max(getCollapsedHeight(), getHeadsUpHeight());
Selim Cinek31aada42015-12-18 17:51:15 -08001014 } else {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08001015 return getHeadsUpHeight();
Selim Cinek31aada42015-12-18 17:51:15 -08001016 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001017 }
1018
Jorim Jaggi5eb67c22015-08-19 19:50:49 -07001019 /**
1020 * Mark whether this notification was just clicked, i.e. the user has just clicked this
1021 * notification in this frame.
1022 */
1023 public void setJustClicked(boolean justClicked) {
1024 mJustClicked = justClicked;
1025 }
1026
1027 /**
1028 * @return true if this notification has been clicked in this frame, false otherwise
1029 */
1030 public boolean wasJustClicked() {
1031 return mJustClicked;
1032 }
1033
Selim Cinek98713a42015-09-21 15:47:20 +02001034 public void setChronometerRunning(boolean running) {
1035 mLastChronometerRunning = running;
1036 setChronometerRunning(running, mPrivateLayout);
1037 setChronometerRunning(running, mPublicLayout);
1038 if (mChildrenContainer != null) {
1039 List<ExpandableNotificationRow> notificationChildren =
1040 mChildrenContainer.getNotificationChildren();
1041 for (int i = 0; i < notificationChildren.size(); i++) {
1042 ExpandableNotificationRow child = notificationChildren.get(i);
1043 child.setChronometerRunning(running);
1044 }
1045 }
1046 }
1047
1048 private void setChronometerRunning(boolean running, NotificationContentView layout) {
1049 if (layout != null) {
1050 running = running || isPinned();
1051 View contractedChild = layout.getContractedChild();
1052 View expandedChild = layout.getExpandedChild();
1053 View headsUpChild = layout.getHeadsUpChild();
1054 setChronometerRunningForChild(running, contractedChild);
1055 setChronometerRunningForChild(running, expandedChild);
1056 setChronometerRunningForChild(running, headsUpChild);
1057 }
1058 }
1059
1060 private void setChronometerRunningForChild(boolean running, View child) {
1061 if (child != null) {
1062 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
1063 if (chronometer instanceof Chronometer) {
1064 ((Chronometer) chronometer).setStarted(running);
1065 }
1066 }
1067 }
1068
Selim Cinekea4bef72015-12-02 15:51:10 -08001069 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -07001070 if (mIsSummaryWithChildren) {
1071 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -07001072 }
Selim Cinekea4bef72015-12-02 15:51:10 -08001073 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -07001074 }
1075
Selim Cinek414ad332017-02-24 19:06:12 -08001076 /**
1077 * @return the currently visible notification header. This can be different from
1078 * {@link #getNotificationHeader()} in case it is a low-priority group.
1079 */
1080 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08001081 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek414ad332017-02-24 19:06:12 -08001082 return mChildrenContainer.getVisibleHeader();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001083 }
1084 return getShowingLayout().getVisibleNotificationHeader();
1085 }
1086
Selim Cinekb26afa32017-06-29 10:28:17 +02001087
1088 /**
1089 * @return the contracted notification header. This can be different from
1090 * {@link #getNotificationHeader()} and also {@link #getVisibleNotificationHeader()} and only
1091 * returns the contracted version.
1092 */
1093 public NotificationHeaderView getContractedNotificationHeader() {
1094 if (mIsSummaryWithChildren) {
1095 return mChildrenContainer.getHeaderView();
1096 }
1097 return mPrivateLayout.getContractedNotificationHeader();
1098 }
1099
Selim Cinek570981d2015-12-01 11:37:01 -08001100 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
1101 mOnExpandClickListener = onExpandClickListener;
1102 }
1103
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001104 public void setLongPressListener(LongPressListener longPressListener) {
1105 mLongPressListener = longPressListener;
1106 }
1107
Selim Cinekddf1b392016-05-27 16:33:10 -07001108 @Override
1109 public void setOnClickListener(@Nullable OnClickListener l) {
1110 super.setOnClickListener(l);
1111 mOnClickListener = l;
1112 updateClickAndFocus();
1113 }
1114
1115 private void updateClickAndFocus() {
1116 boolean normalChild = !isChildInGroup() || isGroupExpanded();
1117 boolean clickable = mOnClickListener != null && normalChild;
1118 if (isFocusable() != normalChild) {
1119 setFocusable(normalChild);
1120 }
1121 if (isClickable() != clickable) {
1122 setClickable(clickable);
1123 }
1124 }
1125
Selim Cinek31aada42015-12-18 17:51:15 -08001126 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
1127 mHeadsUpManager = headsUpManager;
1128 }
1129
Gustav Senntond0e84532018-12-03 16:48:36 +00001130 public HeadsUpManager getHeadsUpManager() {
1131 return mHeadsUpManager;
1132 }
1133
Mady Mellor87d79452017-01-10 11:52:52 -08001134 public void setGutsView(MenuItem item) {
Rohan Shah20790b82018-07-02 17:21:04 -07001135 if (mGuts != null && item.getGutsView() instanceof NotificationGuts.GutsContent) {
1136 ((NotificationGuts.GutsContent) item.getGutsView()).setGutsParent(mGuts);
1137 mGuts.setGutsContent((NotificationGuts.GutsContent) item.getGutsView());
Mady Mellor87d79452017-01-10 11:52:52 -08001138 }
1139 }
1140
Mady Mellor95d743c2017-01-10 12:05:27 -08001141 @Override
1142 protected void onAttachedToWindow() {
1143 super.onAttachedToWindow();
Aaron Heuckroth1dd67cb2018-06-14 14:28:08 -04001144 mEntry.setInitializationTime(SystemClock.elapsedRealtime());
Mady Mellor95d743c2017-01-10 12:05:27 -08001145 Dependency.get(PluginManager.class).addPluginListener(this,
1146 NotificationMenuRowPlugin.class, false /* Allow multiple */);
1147 }
1148
1149 @Override
1150 protected void onDetachedFromWindow() {
1151 super.onDetachedFromWindow();
1152 Dependency.get(PluginManager.class).removePluginListener(this);
1153 }
1154
1155 @Override
1156 public void onPluginConnected(NotificationMenuRowPlugin plugin, Context pluginContext) {
Evan Lairde55c6012019-03-13 12:54:37 -04001157 boolean existed = mMenuRow != null && mMenuRow.getMenuView() != null;
Mady Mellor95d743c2017-01-10 12:05:27 -08001158 if (existed) {
1159 removeView(mMenuRow.getMenuView());
1160 }
Evan Lairde55c6012019-03-13 12:54:37 -04001161 if (plugin == null) {
1162 return;
1163 }
Mady Mellor95d743c2017-01-10 12:05:27 -08001164 mMenuRow = plugin;
Aaron Heuckroth266cb342018-09-07 14:52:04 -04001165 if (mMenuRow.shouldUseDefaultMenuItems()) {
Mady Mellor4c197602017-04-10 17:57:52 -07001166 ArrayList<MenuItem> items = new ArrayList<>();
1167 items.add(NotificationMenuRow.createInfoItem(mContext));
1168 items.add(NotificationMenuRow.createSnoozeItem(mContext));
Julia Reynoldsb5867452018-02-28 16:31:35 -05001169 items.add(NotificationMenuRow.createAppOpsItem(mContext));
Mady Mellor4c197602017-04-10 17:57:52 -07001170 mMenuRow.setMenuItems(items);
Mady Mellor95d743c2017-01-10 12:05:27 -08001171 }
1172 if (existed) {
1173 createMenu();
1174 }
1175 }
1176
1177 @Override
1178 public void onPluginDisconnected(NotificationMenuRowPlugin plugin) {
1179 boolean existed = mMenuRow.getMenuView() != null;
1180 mMenuRow = new NotificationMenuRow(mContext); // Back to default
1181 if (existed) {
1182 createMenu();
1183 }
1184 }
1185
Evan Lairde55c6012019-03-13 12:54:37 -04001186 /**
1187 * Get a handle to a NotificationMenuRowPlugin whose menu view has been added to our hierarchy,
1188 * or null if there is no menu row
1189 *
1190 * @return a {@link NotificationMenuRowPlugin}, or null
1191 */
1192 @Nullable
Mady Mellor95d743c2017-01-10 12:05:27 -08001193 public NotificationMenuRowPlugin createMenu() {
Evan Lairde55c6012019-03-13 12:54:37 -04001194 if (mMenuRow == null) {
1195 return null;
1196 }
1197
Mady Mellor95d743c2017-01-10 12:05:27 -08001198 if (mMenuRow.getMenuView() == null) {
Mady Mellor4ab28202017-06-06 11:42:50 -07001199 mMenuRow.createMenu(this, mStatusBarNotification);
Mady Mellor95d743c2017-01-10 12:05:27 -08001200 mMenuRow.setAppName(mAppName);
1201 FrameLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
1202 LayoutParams.MATCH_PARENT);
1203 addView(mMenuRow.getMenuView(), MENU_VIEW_INDEX, lp);
1204 }
1205 return mMenuRow;
1206 }
1207
Evan Lairde55c6012019-03-13 12:54:37 -04001208 @Nullable
Mady Mellor95d743c2017-01-10 12:05:27 -08001209 public NotificationMenuRowPlugin getProvider() {
1210 return mMenuRow;
1211 }
1212
Anthony Chen9fe1ee72017-04-07 13:53:37 -07001213 @Override
Selim Cinek1a48bab2017-02-17 19:38:40 -08001214 public void onDensityOrFontScaleChanged() {
Anthony Chen9fe1ee72017-04-07 13:53:37 -07001215 super.onDensityOrFontScaleChanged();
Selim Cinek01af3342016-02-09 19:25:31 -08001216 initDimens();
Anthony Chenad4d1582017-04-10 16:07:58 -07001217 initBackground();
Lucas Dupinf03e7522018-06-25 16:21:13 -07001218 reInflateViews();
1219 }
1220
1221 private void reInflateViews() {
Selim Cinek817abe72017-05-24 11:08:55 -07001222 // Let's update our childrencontainer. This is intentionally not guarded with
1223 // mIsSummaryWithChildren since we might have had children but not anymore.
1224 if (mChildrenContainer != null) {
1225 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -08001226 }
1227 if (mGuts != null) {
1228 View oldGuts = mGuts;
1229 int index = indexOfChild(oldGuts);
1230 removeView(oldGuts);
1231 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
1232 R.layout.notification_guts, this, false);
1233 mGuts.setVisibility(oldGuts.getVisibility());
1234 addView(mGuts, index);
1235 }
Evan Lairde55c6012019-03-13 12:54:37 -04001236 View oldMenu = mMenuRow == null ? null : mMenuRow.getMenuView();
Mady Mellor95d743c2017-01-10 12:05:27 -08001237 if (oldMenu != null) {
Mady Mellor761cde12017-01-10 11:36:39 -08001238 int menuIndex = indexOfChild(oldMenu);
1239 removeView(oldMenu);
Mady Mellor4ab28202017-06-06 11:42:50 -07001240 mMenuRow.createMenu(ExpandableNotificationRow.this, mStatusBarNotification);
Mady Mellor761cde12017-01-10 11:36:39 -08001241 mMenuRow.setAppName(mAppName);
Mady Mellor95d743c2017-01-10 12:05:27 -08001242 addView(mMenuRow.getMenuView(), menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -08001243 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001244 for (NotificationContentView l : mLayouts) {
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001245 l.initView();
Adrian Rooseb434ff2017-01-11 11:18:48 -08001246 l.reInflateViews();
1247 }
Amin Shaikhc3f0b062019-02-12 19:00:17 -05001248 mStatusBarNotification.clearPackageContext();
Lucas Dupinf03e7522018-06-25 16:21:13 -07001249 mNotificationInflater.clearCachesAndReInflate();
Selim Cinek01af3342016-02-09 19:25:31 -08001250 }
1251
Mady Mellor9d03a522017-04-04 18:45:30 -07001252 @Override
1253 public void onConfigurationChanged(Configuration newConfig) {
Evan Lairde55c6012019-03-13 12:54:37 -04001254 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Mady Mellor9d03a522017-04-04 18:45:30 -07001255 mMenuRow.onConfigurationChanged();
1256 }
1257 }
1258
Lucas Dupinf03e7522018-06-25 16:21:13 -07001259 public void onUiModeChanged() {
Selim Cinekab9c7b22018-12-11 18:15:47 -08001260 mUpdateBackgroundOnUpdate = true;
Lucas Dupinf03e7522018-06-25 16:21:13 -07001261 reInflateViews();
1262 if (mChildrenContainer != null) {
1263 for (ExpandableNotificationRow child : mChildrenContainer.getNotificationChildren()) {
1264 child.onUiModeChanged();
1265 }
1266 }
1267 }
1268
Selim Cinekc3179332016-03-04 14:44:56 -08001269 public void setContentBackground(int customBackgroundColor, boolean animate,
1270 NotificationContentView notificationContentView) {
1271 if (getShowingLayout() == notificationContentView) {
1272 setTintColor(customBackgroundColor, animate);
1273 }
1274 }
1275
Kenny Guy14d035c2018-05-02 19:10:36 +01001276 @Override
1277 protected void setBackgroundTintColor(int color) {
1278 super.setBackgroundTintColor(color);
1279 NotificationContentView view = getShowingLayout();
1280 if (view != null) {
1281 view.setBackgroundTintColor(color);
1282 }
1283 }
1284
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001285 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -08001286 for (NotificationContentView l : mLayouts) {
1287 l.closeRemoteInput();
1288 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001289 }
1290
Selim Cinekc897bd32016-03-18 17:32:31 -07001291 /**
1292 * Set by how much the single line view should be indented.
1293 */
1294 public void setSingleLineWidthIndention(int indention) {
1295 mPrivateLayout.setSingleLineWidthIndention(indention);
1296 }
1297
1298 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -07001299 return mNotificationColor;
1300 }
1301
1302 private void updateNotificationColor() {
Lucas Dupind26facc2018-09-10 18:07:30 -07001303 Configuration currentConfig = getResources().getConfiguration();
1304 boolean nightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
1305 == Configuration.UI_MODE_NIGHT_YES;
1306
Lucas Dupina291d192018-06-07 13:59:42 -07001307 mNotificationColor = ContrastColorUtil.resolveContrastColor(mContext,
Selim Cinekac5f0272017-05-02 16:05:41 -07001308 getStatusBarNotification().getNotification().color,
Lucas Dupind26facc2018-09-10 18:07:30 -07001309 getBackgroundColorWithoutTint(), nightMode);
Selim Cinekc897bd32016-03-18 17:32:31 -07001310 }
1311
1312 public HybridNotificationView getSingleLineView() {
1313 return mPrivateLayout.getSingleLineView();
1314 }
1315
Selim Cinekf07d0622016-03-21 19:52:52 -07001316 public boolean isOnKeyguard() {
1317 return mOnKeyguard;
1318 }
1319
Selim Cinekc1e389d2016-04-07 11:02:57 -07001320 public void removeAllChildren() {
1321 List<ExpandableNotificationRow> notificationChildren
1322 = mChildrenContainer.getNotificationChildren();
1323 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
1324 for (int i = 0; i < clonedList.size(); i++) {
1325 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -07001326 if (row.keepInParent()) {
1327 continue;
1328 }
Selim Cinekc1e389d2016-04-07 11:02:57 -07001329 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -07001330 row.setIsChildInGroup(false, null);
1331 }
1332 onChildrenCountChanged();
1333 }
1334
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001335 public void setForceUnlocked(boolean forceUnlocked) {
1336 mForceUnlocked = forceUnlocked;
1337 if (mIsSummaryWithChildren) {
1338 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
1339 for (ExpandableNotificationRow child : notificationChildren) {
1340 child.setForceUnlocked(forceUnlocked);
1341 }
1342 }
1343 }
1344
Selim Cinekd03518c2018-03-15 12:13:51 -07001345 public void setDismissed(boolean fromAccessibility) {
Rohan Shahc6990a02018-03-23 17:24:17 -07001346 setLongPressListener(null);
Selim Cinekd03518c2018-03-15 12:13:51 -07001347 mDismissed = true;
Selim Cineke9bad242016-06-15 11:46:37 -07001348 mGroupParentWhenDismissed = mNotificationParent;
1349 mRefocusOnDismiss = fromAccessibility;
1350 mChildAfterViewWhenDismissed = null;
Selim Cinekd03518c2018-03-15 12:13:51 -07001351 mEntry.icon.setDismissed();
Selim Cineke9bad242016-06-15 11:46:37 -07001352 if (isChildInGroup()) {
1353 List<ExpandableNotificationRow> notificationChildren =
1354 mNotificationParent.getNotificationChildren();
1355 int i = notificationChildren.indexOf(this);
1356 if (i != -1 && i < notificationChildren.size() - 1) {
1357 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
1358 }
1359 }
Selim Cinek3f19f602016-05-02 18:01:56 -07001360 }
1361
1362 public boolean isDismissed() {
1363 return mDismissed;
1364 }
1365
1366 public boolean keepInParent() {
1367 return mKeepInParent;
1368 }
1369
1370 public void setKeepInParent(boolean keepInParent) {
1371 mKeepInParent = keepInParent;
1372 }
1373
Selim Cinekd9b7dd42017-11-10 17:53:47 -08001374 @Override
Selim Cinek3f19f602016-05-02 18:01:56 -07001375 public boolean isRemoved() {
1376 return mRemoved;
1377 }
1378
Adrian Roosd009ab12016-05-20 17:58:53 -07001379 public void setRemoved() {
1380 mRemoved = true;
Selim Cinekef8c2252017-02-10 14:52:18 -08001381 mTranslationWhenRemoved = getTranslationY();
1382 mWasChildInGroupWhenRemoved = isChildInGroup();
1383 if (isChildInGroup()) {
1384 mTranslationWhenRemoved += getNotificationParent().getTranslationY();
1385 }
Adrian Roosd009ab12016-05-20 17:58:53 -07001386 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -07001387 }
1388
Selim Cinekef8c2252017-02-10 14:52:18 -08001389 public boolean wasChildInGroupWhenRemoved() {
1390 return mWasChildInGroupWhenRemoved;
1391 }
1392
1393 public float getTranslationWhenRemoved() {
1394 return mTranslationWhenRemoved;
1395 }
1396
Selim Cinekd1395642016-04-28 12:22:42 -07001397 public NotificationChildrenContainer getChildrenContainer() {
1398 return mChildrenContainer;
1399 }
1400
Selim Cinekcafa87f2016-10-26 17:00:17 -07001401 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07001402 boolean wasAboveShelf = isAboveShelf();
Selim Cinek8875de12018-03-22 10:14:32 -07001403 boolean changed = headsUpAnimatingAway != mHeadsupDisappearRunning;
Selim Cinekcafa87f2016-10-26 17:00:17 -07001404 mHeadsupDisappearRunning = headsUpAnimatingAway;
1405 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
Selim Cinek8875de12018-03-22 10:14:32 -07001406 if (changed && mHeadsUpAnimatingAwayListener != null) {
1407 mHeadsUpAnimatingAwayListener.accept(headsUpAnimatingAway);
1408 }
Selim Cinek5cf1d052017-06-01 17:36:46 -07001409 if (isAboveShelf() != wasAboveShelf) {
1410 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
1411 }
Selim Cinekcafa87f2016-10-26 17:00:17 -07001412 }
1413
Selim Cinek8875de12018-03-22 10:14:32 -07001414 public void setHeadsUpAnimatingAwayListener(Consumer<Boolean> listener) {
1415 mHeadsUpAnimatingAwayListener = listener;
1416 }
1417
Selim Cinekcafa87f2016-10-26 17:00:17 -07001418 /**
1419 * @return if the view was just heads upped and is now animating away. During such a time the
1420 * layout needs to be kept consistent
1421 */
Selim Cinek29aab962018-02-27 17:05:45 -08001422 @Override
Selim Cinekcafa87f2016-10-26 17:00:17 -07001423 public boolean isHeadsUpAnimatingAway() {
1424 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -07001425 }
1426
Selim Cineke9bad242016-06-15 11:46:37 -07001427 public View getChildAfterViewWhenDismissed() {
1428 return mChildAfterViewWhenDismissed;
1429 }
1430
1431 public View getGroupParentWhenDismissed() {
1432 return mGroupParentWhenDismissed;
1433 }
1434
Rohan Shah524cf7b2018-03-15 14:40:02 -07001435 /**
1436 * Dismisses the notification with the option of showing the blocking helper in-place if we have
1437 * a negative user sentiment.
1438 *
1439 * @param fromAccessibility whether this dismiss is coming from an accessibility action
1440 * @return whether a blocking helper is shown in this row
1441 */
1442 public boolean performDismissWithBlockingHelper(boolean fromAccessibility) {
1443 NotificationBlockingHelperManager manager =
1444 Dependency.get(NotificationBlockingHelperManager.class);
1445 boolean isBlockingHelperShown = manager.perhapsShowBlockingHelper(this, mMenuRow);
1446
Rohan Shahda5dcdd2018-04-27 17:21:50 -07001447 Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
1448
Rohan Shah524cf7b2018-03-15 14:40:02 -07001449 // Continue with dismiss since we don't want the blocking helper to be directly associated
1450 // with a certain notification.
1451 performDismiss(fromAccessibility);
1452 return isBlockingHelperShown;
1453 }
1454
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001455 public void performDismiss(boolean fromAccessibility) {
Rohan Shah524cf7b2018-03-15 14:40:02 -07001456 if (isOnlyChildInGroup()) {
Ned Burnsf81c4c42019-01-07 14:10:43 -05001457 NotificationEntry groupSummary =
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001458 mGroupManager.getLogicalGroupSummary(getStatusBarNotification());
1459 if (groupSummary.isClearable()) {
Rohan Shah524cf7b2018-03-15 14:40:02 -07001460 // If this is the only child in the group, dismiss the group, but don't try to show
1461 // the blocking helper affordance!
Evan Laird94492852018-10-25 13:43:01 -04001462 groupSummary.getRow().performDismiss(fromAccessibility);
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001463 }
1464 }
Selim Cinekd03518c2018-03-15 12:13:51 -07001465 setDismissed(fromAccessibility);
Evan Laird94492852018-10-25 13:43:01 -04001466 if (mEntry.isClearable()) {
Julia Reynoldsfd4099d2018-08-21 11:06:06 -04001467 // TODO: track dismiss sentiment
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001468 if (mOnDismissRunnable != null) {
1469 mOnDismissRunnable.run();
1470 }
Selim Cineke9079112016-12-14 14:41:01 -08001471 }
Selim Cinek9e624e72016-07-20 13:46:49 -07001472 }
1473
Rohan Shah524cf7b2018-03-15 14:40:02 -07001474 public void setBlockingHelperShowing(boolean isBlockingHelperShowing) {
1475 mIsBlockingHelperShowing = isBlockingHelperShowing;
1476 }
1477
1478 public boolean isBlockingHelperShowing() {
1479 return mIsBlockingHelperShowing;
1480 }
1481
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001482 public boolean isBlockingHelperShowingAndTranslationFinished() {
1483 return mIsBlockingHelperShowing && mNotificationTranslationFinished;
1484 }
1485
Selim Cineke9079112016-12-14 14:41:01 -08001486 public void setOnDismissRunnable(Runnable onDismissRunnable) {
1487 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -07001488 }
1489
Selim Cinek281c2022016-10-13 19:14:43 -07001490 public View getNotificationIcon() {
Selim Cinek414ad332017-02-24 19:06:12 -08001491 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek281c2022016-10-13 19:14:43 -07001492 if (notificationHeader != null) {
1493 return notificationHeader.getIcon();
1494 }
1495 return null;
1496 }
1497
1498 /**
1499 * @return whether the notification is currently showing a view with an icon.
1500 */
1501 public boolean isShowingIcon() {
Mady Mellor434180c2017-02-13 11:29:42 -08001502 if (areGutsExposed()) {
1503 return false;
1504 }
Selim Cinek2ffa02f2017-03-06 15:56:37 -08001505 return getVisibleNotificationHeader() != null;
Selim Cinek281c2022016-10-13 19:14:43 -07001506 }
1507
Selim Cinek0242fbb2016-10-19 13:38:32 -07001508 /**
1509 * Set how much this notification is transformed into an icon.
1510 *
Selim Cinek2b549f42016-11-22 16:38:51 -08001511 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
1512 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -08001513 * @param isLastChild is this the last child in the list. If true, then the transformation is
1514 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -07001515 */
Selim Cinek2b549f42016-11-22 16:38:51 -08001516 public void setContentTransformationAmount(float contentTransformationAmount,
1517 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -08001518 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001519 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001520 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001521 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001522 if (changeTransformation) {
1523 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -08001524 }
1525 }
1526
1527 /**
1528 * Set the icons to be visible of this notification.
1529 */
1530 public void setIconsVisible(boolean iconsVisible) {
1531 if (iconsVisible != mIconsVisible) {
1532 mIconsVisible = iconsVisible;
1533 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -07001534 }
1535 }
1536
Selim Cinekdb167372016-11-17 15:41:17 -08001537 @Override
1538 protected void onBelowSpeedBumpChanged() {
1539 updateIconVisibilities();
1540 }
1541
Selim Cinek875a3a12016-11-18 17:52:16 -08001542 private void updateContentTransformation() {
Selim Cinek2627d722018-01-19 12:16:49 -08001543 if (mExpandAnimationRunning) {
1544 return;
1545 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001546 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -08001547 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -08001548 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -08001549 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001550 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001551 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -08001552 translationY *= 0.4f;
1553 } else {
1554 contentAlpha = 1.0f;
1555 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001556 for (NotificationContentView l : mLayouts) {
1557 l.setAlpha(contentAlpha);
1558 l.setTranslationY(translationY);
1559 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001560 if (mChildrenContainer != null) {
1561 mChildrenContainer.setAlpha(contentAlpha);
1562 mChildrenContainer.setTranslationY(translationY);
1563 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -07001564 }
1565 }
1566
1567 private void updateIconVisibilities() {
Gus Prevas4b3c0ff22018-11-02 13:15:23 -04001568 boolean visible = isChildInGroup() || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -08001569 for (NotificationContentView l : mLayouts) {
1570 l.setIconsVisible(visible);
1571 }
Selim Cinekdb167372016-11-17 15:41:17 -08001572 if (mChildrenContainer != null) {
1573 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001574 }
1575 }
1576
Selim Cinek875a3a12016-11-18 17:52:16 -08001577 /**
1578 * Get the relative top padding of a view relative to this view. This recursively walks up the
1579 * hierarchy and does the corresponding measuring.
1580 *
1581 * @param view the view to the the padding for. The requested view has to be a child of this
1582 * notification.
1583 * @return the toppadding
1584 */
1585 public int getRelativeTopPadding(View view) {
1586 int topPadding = 0;
1587 while (view.getParent() instanceof ViewGroup) {
1588 topPadding += view.getTop();
1589 view = (View) view.getParent();
1590 if (view instanceof ExpandableNotificationRow) {
1591 return topPadding;
1592 }
1593 }
1594 return topPadding;
1595 }
1596
Selim Cineka1d97902016-12-14 16:31:40 -08001597 public float getContentTranslation() {
1598 return mPrivateLayout.getTranslationY();
1599 }
1600
Selim Cinek6743c0b2017-01-18 18:24:01 -08001601 public void setIsLowPriority(boolean isLowPriority) {
1602 mIsLowPriority = isLowPriority;
1603 mPrivateLayout.setIsLowPriority(isLowPriority);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001604 mNotificationInflater.setIsLowPriority(mIsLowPriority);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001605 if (mChildrenContainer != null) {
1606 mChildrenContainer.setIsLowPriority(isLowPriority);
1607 }
1608 }
1609
Selim Cinek414ad332017-02-24 19:06:12 -08001610 public boolean isLowPriority() {
1611 return mIsLowPriority;
1612 }
1613
Selim Cinek7d1009b2017-01-25 15:28:28 -08001614 public void setUseIncreasedCollapsedHeight(boolean use) {
1615 mUseIncreasedCollapsedHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001616 mNotificationInflater.setUsesIncreasedHeight(use);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001617 }
1618
Selim Cinek87ed69b2017-02-09 15:59:43 -08001619 public void setUseIncreasedHeadsUpHeight(boolean use) {
1620 mUseIncreasedHeadsUpHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001621 mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
1622 }
1623
1624 public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
1625 mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001626 }
1627
Selim Cinek5ba22542017-04-20 15:16:10 -07001628 public void setInflationCallback(InflationCallback callback) {
1629 mNotificationInflater.setInflationCallback(callback);
Selim Cinekc478f902017-02-22 20:55:44 -08001630 }
1631
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001632 public void setNeedsRedaction(boolean needsRedaction) {
Kevin38ce6fa2018-10-17 16:00:14 -07001633 if (mNeedsRedaction != needsRedaction) {
1634 mNeedsRedaction = needsRedaction;
1635 updateInflationFlag(FLAG_CONTENT_VIEW_PUBLIC, needsRedaction /* shouldInflate */);
1636 mNotificationInflater.updateNeedsRedaction(needsRedaction);
1637 if (!needsRedaction) {
1638 freeContentViewWhenSafe(FLAG_CONTENT_VIEW_PUBLIC);
1639 }
1640 }
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001641 }
1642
Selim Cinek5ba22542017-04-20 15:16:10 -07001643 @VisibleForTesting
Ned Burns1a5e22f2019-02-14 15:11:52 -05001644 public NotificationContentInflater getNotificationInflater() {
Selim Cinek5ba22542017-04-20 15:16:10 -07001645 return mNotificationInflater;
1646 }
1647
Chris Wren78403d72014-07-28 10:23:24 +01001648 public interface ExpansionLogger {
Anthony Chen6bf88a02017-04-10 14:41:44 -07001649 void logNotificationExpansion(String key, boolean userAction, boolean expanded);
Chris Wren78403d72014-07-28 10:23:24 +01001650 }
Selim Cinek1685e632014-04-08 02:27:49 +02001651
Chris Wren51c75102013-07-16 20:49:17 -04001652 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1653 super(context, attrs);
Dave Mankoffdde5ee62019-05-02 17:36:11 -04001654 mFalsingManager = FalsingManagerFactory.getInstance(context);
Ned Burns1a5e22f2019-02-14 15:11:52 -05001655 mNotificationInflater = new NotificationContentInflater(this);
Mady Mellor95d743c2017-01-10 12:05:27 -08001656 mMenuRow = new NotificationMenuRow(mContext);
Ahan Wude396fa2018-05-08 20:42:24 +08001657 mImageResolver = new NotificationInlineImageResolver(context,
1658 new NotificationInlineImageCache());
Beth Thibodeaueab4dde2019-02-07 11:37:02 -05001659 mMediaManager = Dependency.get(NotificationMediaManager.class);
Selim Cinek01af3342016-02-09 19:25:31 -08001660 initDimens();
1661 }
1662
1663 private void initDimens() {
Rohan Shahb9d500a2018-06-25 16:27:16 -07001664 mNotificationMinHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
Selim Cineke62255c2017-09-28 18:23:23 -07001665 R.dimen.notification_min_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001666 mNotificationMinHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1667 R.dimen.notification_min_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001668 mNotificationMinHeight = NotificationUtils.getFontScaledHeight(mContext,
1669 R.dimen.notification_min_height);
1670 mNotificationMinHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001671 R.dimen.notification_min_height_increased);
Beth Thibodeaucb395352019-01-25 15:39:54 -05001672 mNotificationMinHeightMedia = NotificationUtils.getFontScaledHeight(mContext,
1673 R.dimen.notification_min_height_media);
Selim Cineke62255c2017-09-28 18:23:23 -07001674 mNotificationMaxHeight = NotificationUtils.getFontScaledHeight(mContext,
1675 R.dimen.notification_max_height);
Rohan Shahb9d500a2018-06-25 16:27:16 -07001676 mMaxHeadsUpHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek77019c72015-12-09 10:18:02 -08001677 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001678 mMaxHeadsUpHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1679 R.dimen.notification_max_heads_up_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001680 mMaxHeadsUpHeight = NotificationUtils.getFontScaledHeight(mContext,
1681 R.dimen.notification_max_heads_up_height);
1682 mMaxHeadsUpHeightIncreased = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001683 R.dimen.notification_max_heads_up_height_increased);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001684
Anthony Chen7acbb772017-04-07 16:45:25 -07001685 Resources res = getResources();
1686 mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
1687 R.dimen.notification_divider_height_increased);
1688 mIconTransformContentShiftNoIcon = res.getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001689 R.dimen.notification_icon_transform_content_shift);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001690 mEnableNonGroupedNotificationExpand =
1691 res.getBoolean(R.bool.config_enableNonGroupedNotificationExpand);
1692 mShowGroupBackgroundWhenExpanded =
1693 res.getBoolean(R.bool.config_showGroupNotificationBgWhenExpanded);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001694 }
1695
Ahan Wude396fa2018-05-08 20:42:24 +08001696 NotificationInlineImageResolver getImageResolver() {
1697 return mImageResolver;
1698 }
1699
Selim Cinekf619ffc2016-02-17 14:53:05 -08001700 /**
Christoph Studera7fe6312014-06-27 19:32:44 +02001701 * Resets this view so it can be re-used for an updated notification.
1702 */
1703 public void reset() {
Jorim Jaggiae441282014-08-01 02:45:18 +02001704 mShowingPublicInitialized = false;
Selim Cinek31094df2014-08-14 19:28:15 +02001705 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001706 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001707 }
1708
Julia Reynoldsfc640012018-02-21 12:25:27 -05001709 public void showAppOpsIcons(ArraySet<Integer> activeOps) {
1710 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
1711 mChildrenContainer.getHeaderView().showAppOpsIcons(activeOps);
1712 }
1713 mPrivateLayout.showAppOpsIcons(activeOps);
1714 mPublicLayout.showAppOpsIcons(activeOps);
1715 }
1716
Gus Prevas7306b902018-12-11 10:57:06 -05001717 /** Sets the last time the notification being displayed audibly alerted the user. */
1718 public void setLastAudiblyAlertedMs(long lastAudiblyAlertedMs) {
Gus Prevasa3226492018-10-23 11:10:09 -04001719 if (NotificationUtils.useNewInterruptionModel(mContext)) {
Ned Burns3da3c782019-01-08 21:14:39 -05001720 long timeSinceAlertedAudibly = System.currentTimeMillis() - lastAudiblyAlertedMs;
1721 boolean alertedRecently =
1722 timeSinceAlertedAudibly < RECENTLY_ALERTED_THRESHOLD_MS;
1723
1724 applyAudiblyAlertedRecently(alertedRecently);
1725
1726 removeCallbacks(mExpireRecentlyAlertedFlag);
1727 if (alertedRecently) {
1728 long timeUntilNoLongerRecent =
1729 RECENTLY_ALERTED_THRESHOLD_MS - timeSinceAlertedAudibly;
1730 postDelayed(mExpireRecentlyAlertedFlag, timeUntilNoLongerRecent);
Gus Prevasa3226492018-10-23 11:10:09 -04001731 }
Gus Prevasa3226492018-10-23 11:10:09 -04001732 }
1733 }
1734
Ned Burns3da3c782019-01-08 21:14:39 -05001735 private final Runnable mExpireRecentlyAlertedFlag = () -> applyAudiblyAlertedRecently(false);
1736
1737 private void applyAudiblyAlertedRecently(boolean audiblyAlertedRecently) {
1738 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
1739 mChildrenContainer.getHeaderView().setRecentlyAudiblyAlerted(audiblyAlertedRecently);
1740 }
1741 mPrivateLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
1742 mPublicLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
1743 }
1744
Julia Reynoldsb5867452018-02-28 16:31:35 -05001745 public View.OnClickListener getAppOpsOnClickListener() {
1746 return mOnAppOpsClickListener;
1747 }
1748
Rohan Shah20790b82018-07-02 17:21:04 -07001749 public void setAppOpsOnClickListener(ExpandableNotificationRow.OnAppOpsClickListener l) {
Julia Reynoldsb5867452018-02-28 16:31:35 -05001750 mOnAppOpsClickListener = v -> {
1751 createMenu();
Evan Lairde55c6012019-03-13 12:54:37 -04001752 NotificationMenuRowPlugin provider = getProvider();
1753 if (provider == null) {
1754 return;
1755 }
1756 MenuItem menuItem = provider.getAppOpsMenuItem(mContext);
Julia Reynoldsb5867452018-02-28 16:31:35 -05001757 if (menuItem != null) {
1758 l.onClick(this, v.getWidth() / 2, v.getHeight() / 2, menuItem);
1759 }
1760 };
1761 }
1762
Jorim Jaggi251957d2014-04-09 04:24:09 +02001763 @Override
1764 protected void onFinishInflate() {
1765 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001766 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1767 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001768 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1769
1770 for (NotificationContentView l : mLayouts) {
1771 l.setExpandClickListener(mExpandClickListener);
1772 l.setContainingNotification(this);
1773 }
Selim Cinekab29aeb2015-02-20 18:18:32 +01001774 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1775 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001776 @Override
1777 public void onInflate(ViewStub stub, View inflated) {
1778 mGuts = (NotificationGuts) inflated;
1779 mGuts.setClipTopAmount(getClipTopAmount());
1780 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001781 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001782 }
1783 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001784 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1785 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1786
1787 @Override
1788 public void onInflate(ViewStub stub, View inflated) {
1789 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001790 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek414ad332017-02-24 19:06:12 -08001791 mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001792 mChildrenContainer.onNotificationUpdated();
Anthony Chen7acbb772017-04-07 16:45:25 -07001793
1794 if (mShouldTranslateContents) {
1795 mTranslateableViews.add(mChildrenContainer);
1796 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001797 }
1798 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001799
Anthony Chen7acbb772017-04-07 16:45:25 -07001800 if (mShouldTranslateContents) {
1801 // Add the views that we translate to reveal the menu
1802 mTranslateableViews = new ArrayList<>();
1803 for (int i = 0; i < getChildCount(); i++) {
1804 mTranslateableViews.add(getChildAt(i));
1805 }
1806 // Remove views that don't translate
1807 mTranslateableViews.remove(mChildrenContainerStub);
1808 mTranslateableViews.remove(mGutsStub);
Mady Mellor4b80b102016-01-22 08:03:58 -08001809 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001810 }
1811
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001812 private void doLongClickCallback() {
1813 doLongClickCallback(getWidth() / 2, getHeight() / 2);
1814 }
1815
1816 public void doLongClickCallback(int x, int y) {
1817 createMenu();
Evan Lairde55c6012019-03-13 12:54:37 -04001818 NotificationMenuRowPlugin provider = getProvider();
1819 MenuItem menuItem = null;
1820 if (provider != null) {
1821 menuItem = provider.getLongpressMenuItem(mContext);
1822 }
Mady Mellorb3a6aed2018-05-11 13:24:07 -07001823 doLongClickCallback(x, y, menuItem);
1824 }
1825
1826 private void doLongClickCallback(int x, int y, MenuItem menuItem) {
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001827 if (mLongPressListener != null && menuItem != null) {
1828 mLongPressListener.onLongPress(this, x, y, menuItem);
1829 }
1830 }
1831
1832 @Override
1833 public boolean onKeyDown(int keyCode, KeyEvent event) {
1834 if (KeyEvent.isConfirmKey(keyCode)) {
1835 event.startTracking();
1836 return true;
1837 }
1838 return super.onKeyDown(keyCode, event);
1839 }
1840
1841 @Override
1842 public boolean onKeyUp(int keyCode, KeyEvent event) {
1843 if (KeyEvent.isConfirmKey(keyCode)) {
1844 if (!event.isCanceled()) {
1845 performClick();
1846 }
1847 return true;
1848 }
1849 return super.onKeyUp(keyCode, event);
1850 }
1851
1852 @Override
1853 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
1854 if (KeyEvent.isConfirmKey(keyCode)) {
1855 doLongClickCallback();
1856 return true;
1857 }
1858 return false;
1859 }
1860
Mady Mellor4b80b102016-01-22 08:03:58 -08001861 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001862 if (mTranslateAnim != null) {
1863 mTranslateAnim.cancel();
1864 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001865
1866 if (!mShouldTranslateContents) {
1867 setTranslationX(0);
1868 } else if (mTranslateableViews != null) {
Mady Mellor4b80b102016-01-22 08:03:58 -08001869 for (int i = 0; i < mTranslateableViews.size(); i++) {
1870 mTranslateableViews.get(i).setTranslationX(0);
1871 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001872 invalidateOutline();
shawnlin4fbeac42018-04-30 20:32:40 +08001873 getEntry().expandedIcon.setScrollX(0);
Mady Mellor4b80b102016-01-22 08:03:58 -08001874 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001875
Evan Lairde55c6012019-03-13 12:54:37 -04001876 if (mMenuRow != null) {
1877 mMenuRow.resetMenu();
1878 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001879 }
1880
Rohan Shah56eb0912018-05-10 21:49:04 -07001881 void onGutsOpened() {
Evan Lairdab1faee2019-05-23 16:53:10 -04001882 resetTranslation();
Rohan Shah56eb0912018-05-10 21:49:04 -07001883 updateContentAccessibilityImportanceForGuts(false /* isEnabled */);
1884 }
1885
1886 void onGutsClosed() {
1887 updateContentAccessibilityImportanceForGuts(true /* isEnabled */);
1888 }
1889
1890 /**
1891 * Updates whether all the non-guts content inside this row is important for accessibility.
1892 *
1893 * @param isEnabled whether the content views should be enabled for accessibility
1894 */
1895 private void updateContentAccessibilityImportanceForGuts(boolean isEnabled) {
1896 if (mChildrenContainer != null) {
1897 updateChildAccessibilityImportance(mChildrenContainer, isEnabled);
1898 }
1899 if (mLayouts != null) {
1900 for (View view : mLayouts) {
1901 updateChildAccessibilityImportance(view, isEnabled);
1902 }
1903 }
1904
1905 if (isEnabled) {
1906 this.requestAccessibilityFocus();
1907 }
1908 }
1909
1910 /**
1911 * Updates whether the given childView is important for accessibility based on
1912 * {@code isEnabled}.
1913 */
1914 private void updateChildAccessibilityImportance(View childView, boolean isEnabled) {
1915 childView.setImportantForAccessibility(isEnabled
1916 ? View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
1917 : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
1918 }
1919
Selim Cinekde4de0e2018-01-24 16:21:07 -08001920 public CharSequence getActiveRemoteInputText() {
1921 return mPrivateLayout.getActiveRemoteInputText();
1922 }
1923
Mady Mellor4b80b102016-01-22 08:03:58 -08001924 public void animateTranslateNotification(final float leftTarget) {
1925 if (mTranslateAnim != null) {
1926 mTranslateAnim.cancel();
1927 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001928 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001929 if (mTranslateAnim != null) {
1930 mTranslateAnim.start();
1931 }
1932 }
1933
1934 @Override
1935 public void setTranslation(float translationX) {
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001936 if (isBlockingHelperShowingAndTranslationFinished()) {
1937 mGuts.setTranslationX(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001938 return;
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001939 } else if (!mShouldTranslateContents) {
Anthony Chen7acbb772017-04-07 16:45:25 -07001940 setTranslationX(translationX);
1941 } else if (mTranslateableViews != null) {
1942 // Translate the group of views
1943 for (int i = 0; i < mTranslateableViews.size(); i++) {
1944 if (mTranslateableViews.get(i) != null) {
1945 mTranslateableViews.get(i).setTranslationX(translationX);
1946 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001947 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001948 invalidateOutline();
Selim Cinek143672c2018-03-23 20:04:32 -07001949
1950 // In order to keep the shelf in sync with this swiping, we're simply translating
1951 // it's icon by the same amount. The translation is already being used for the normal
1952 // positioning, so we can use the scrollX instead.
1953 getEntry().expandedIcon.setScrollX((int) -translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001954 }
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001955
Evan Lairde55c6012019-03-13 12:54:37 -04001956 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Aaron Heuckroth266cb342018-09-07 14:52:04 -04001957 mMenuRow.onParentTranslationUpdate(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001958 }
1959 }
1960
1961 @Override
1962 public float getTranslation() {
Anthony Chene04afcb2017-04-21 13:51:32 -07001963 if (!mShouldTranslateContents) {
Anthony Chen7acbb772017-04-07 16:45:25 -07001964 return getTranslationX();
1965 }
1966
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001967 if (isBlockingHelperShowingAndCanTranslate()) {
1968 return mGuts.getTranslationX();
1969 }
1970
Mady Mellor34958fa2016-02-23 09:52:17 -08001971 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1972 // All of the views in the list should have same translation, just use first one.
1973 return mTranslateableViews.get(0).getTranslationX();
1974 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001975
Mady Mellor34958fa2016-02-23 09:52:17 -08001976 return 0;
1977 }
1978
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001979 private boolean isBlockingHelperShowingAndCanTranslate() {
1980 return areGutsExposed() && mIsBlockingHelperShowing && mNotificationTranslationFinished;
1981 }
1982
Mady Mellor34958fa2016-02-23 09:52:17 -08001983 public Animator getTranslateViewAnimator(final float leftTarget,
1984 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001985 if (mTranslateAnim != null) {
1986 mTranslateAnim.cancel();
1987 }
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001988
Mady Mellorb0a82462016-04-30 17:31:02 -07001989 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1990 leftTarget);
1991 if (listener != null) {
1992 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001993 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001994 translateAnim.addListener(new AnimatorListenerAdapter() {
1995 boolean cancelled = false;
1996
1997 @Override
1998 public void onAnimationCancel(Animator anim) {
1999 cancelled = true;
2000 }
2001
2002 @Override
2003 public void onAnimationEnd(Animator anim) {
Nadia Benbernou7a18c812019-02-08 16:23:10 -05002004 if (mIsBlockingHelperShowing) {
2005 mNotificationTranslationFinished = true;
2006 }
Mady Mellor95d743c2017-01-10 12:05:27 -08002007 if (!cancelled && leftTarget == 0) {
Evan Lairde55c6012019-03-13 12:54:37 -04002008 if (mMenuRow != null) {
2009 mMenuRow.resetMenu();
2010 }
Mady Mellorb0a82462016-04-30 17:31:02 -07002011 mTranslateAnim = null;
2012 }
2013 }
2014 });
2015 mTranslateAnim = translateAnim;
2016 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08002017 }
2018
Evan Lairde55c6012019-03-13 12:54:37 -04002019 void ensureGutsInflated() {
Selim Cinekab29aeb2015-02-20 18:18:32 +01002020 if (mGuts == null) {
2021 mGutsStub.inflate();
2022 }
2023 }
2024
Selim Cinekda42d652015-12-04 15:51:16 -08002025 private void updateChildrenVisibility() {
Selim Cinek7fa385a2018-01-24 08:35:28 -08002026 boolean hideContentWhileLaunching = mExpandAnimationRunning && mGuts != null
2027 && mGuts.isExposed();
Selim Cinek01497392019-05-23 11:22:23 -07002028 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren
Selim Cinek7fa385a2018-01-24 08:35:28 -08002029 && !hideContentWhileLaunching ? VISIBLE : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08002030 if (mChildrenContainer != null) {
Selim Cinek01497392019-05-23 11:22:23 -07002031 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren
Selim Cinek7fa385a2018-01-24 08:35:28 -08002032 && !hideContentWhileLaunching ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08002033 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08002034 }
Selim Cinekda42d652015-12-04 15:51:16 -08002035 // The limits might have changed if the view suddenly became a group or vice versa
2036 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01002037 }
2038
Jorim Jaggife40f7d2014-04-28 15:20:04 +02002039 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08002040 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
2041 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02002042 // Add a record for the entire layout since its content is somehow small.
2043 // The event comes from a leaf view that is interacted with.
2044 AccessibilityEvent record = AccessibilityEvent.obtain();
2045 onInitializeAccessibilityEvent(record);
2046 dispatchPopulateAccessibilityEvent(record);
2047 event.appendRecord(record);
2048 return true;
2049 }
2050 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02002051 }
Chris Wren51c75102013-07-16 20:49:17 -04002052
John Spurlocke15452b2014-08-21 09:44:39 -04002053 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01002054 public void setDark(boolean dark, boolean fade, long delay) {
Lucas Dupin00be88f2019-01-03 17:50:52 -08002055 if (mDark == dark) {
2056 return;
2057 }
Jorim Jaggi4e857f42014-11-17 19:14:04 +01002058 super.setDark(dark, fade, delay);
Kevina97ea052018-09-11 13:53:18 -07002059 if (!mIsAmbientPulsing) {
Adrian Roos28f90c72017-05-08 17:24:26 -07002060 // Only fade the showing view of the pulsing notification.
2061 fade = false;
2062 }
John Spurlocke15452b2014-08-21 09:44:39 -04002063 final NotificationContentView showing = getShowingLayout();
2064 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01002065 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04002066 }
Selim Cineka7c69632017-06-07 15:51:29 -07002067 updateShelfIconColor();
John Spurlocke15452b2014-08-21 09:44:39 -04002068 }
2069
Selim Cinek2627d722018-01-19 12:16:49 -08002070 public void applyExpandAnimationParams(ExpandAnimationParameters params) {
2071 if (params == null) {
2072 return;
2073 }
Selim Cinek2627d722018-01-19 12:16:49 -08002074 float zProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
2075 params.getProgress(0, 50));
2076 float translationZ = MathUtils.lerp(params.getStartTranslationZ(),
2077 mNotificationLaunchHeight,
2078 zProgress);
2079 setTranslationZ(translationZ);
Selim Cinekc25989e2018-02-16 16:42:14 -08002080 float extraWidthForClipping = params.getWidth() - getWidth()
2081 + MathUtils.lerp(0, mOutlineRadius * 2, params.getProgress());
2082 setExtraWidthForClipping(extraWidthForClipping);
2083 int top = params.getTop();
2084 float interpolation = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(params.getProgress());
2085 int startClipTopAmount = params.getStartClipTopAmount();
2086 if (mNotificationParent != null) {
Selim Cinekc42db8d2018-12-04 13:29:25 -08002087 float parentY = mNotificationParent.getTranslationY();
2088 top -= parentY;
Selim Cinekc25989e2018-02-16 16:42:14 -08002089 mNotificationParent.setTranslationZ(translationZ);
2090 int parentStartClipTopAmount = params.getParentStartClipTopAmount();
2091 if (startClipTopAmount != 0) {
2092 int clipTopAmount = (int) MathUtils.lerp(parentStartClipTopAmount,
2093 parentStartClipTopAmount - startClipTopAmount,
2094 interpolation);
2095 mNotificationParent.setClipTopAmount(clipTopAmount);
2096 }
2097 mNotificationParent.setExtraWidthForClipping(extraWidthForClipping);
Selim Cinekc42db8d2018-12-04 13:29:25 -08002098 float clipBottom = Math.max(params.getBottom(),
2099 parentY + mNotificationParent.getActualHeight()
2100 - mNotificationParent.getClipBottomAmount());
2101 float clipTop = Math.min(params.getTop(), parentY);
2102 int minimumHeightForClipping = (int) (clipBottom - clipTop);
2103 mNotificationParent.setMinimumHeightForClipping(minimumHeightForClipping);
Selim Cinekc25989e2018-02-16 16:42:14 -08002104 } else if (startClipTopAmount != 0) {
2105 int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, interpolation);
2106 setClipTopAmount(clipTopAmount);
2107 }
2108 setTranslationY(top);
Selim Cinek2627d722018-01-19 12:16:49 -08002109 setActualHeight(params.getHeight());
Selim Cinekc25989e2018-02-16 16:42:14 -08002110
Selim Cinek2627d722018-01-19 12:16:49 -08002111 mBackgroundNormal.setExpandAnimationParams(params);
2112 }
2113
2114 public void setExpandAnimationRunning(boolean expandAnimationRunning) {
Selim Cinekc25989e2018-02-16 16:42:14 -08002115 View contentView;
2116 if (mIsSummaryWithChildren) {
2117 contentView = mChildrenContainer;
2118 } else {
2119 contentView = getShowingLayout();
2120 }
2121 if (mGuts != null && mGuts.isExposed()) {
2122 contentView = mGuts;
2123 }
Selim Cinek2627d722018-01-19 12:16:49 -08002124 if (expandAnimationRunning) {
Selim Cinek2627d722018-01-19 12:16:49 -08002125 contentView.animate()
2126 .alpha(0f)
2127 .setDuration(ActivityLaunchAnimator.ANIMATION_DURATION_FADE_CONTENT)
2128 .setInterpolator(Interpolators.ALPHA_OUT);
2129 setAboveShelf(true);
2130 mExpandAnimationRunning = true;
Dave Mankoffa4d195d2018-11-16 13:33:27 -05002131 getViewState().cancelAnimations(this);
Selim Cinek2627d722018-01-19 12:16:49 -08002132 mNotificationLaunchHeight = AmbientState.getNotificationLaunchHeight(getContext());
2133 } else {
2134 mExpandAnimationRunning = false;
2135 setAboveShelf(isAboveShelf());
Selim Cinek7fa385a2018-01-24 08:35:28 -08002136 if (mGuts != null) {
2137 mGuts.setAlpha(1.0f);
2138 }
Selim Cinekc25989e2018-02-16 16:42:14 -08002139 if (contentView != null) {
2140 contentView.setAlpha(1.0f);
2141 }
2142 setExtraWidthForClipping(0.0f);
2143 if (mNotificationParent != null) {
2144 mNotificationParent.setExtraWidthForClipping(0.0f);
2145 mNotificationParent.setMinimumHeightForClipping(0);
2146 }
2147 }
2148 if (mNotificationParent != null) {
2149 mNotificationParent.setChildIsExpanding(mExpandAnimationRunning);
Selim Cinek2627d722018-01-19 12:16:49 -08002150 }
Selim Cinek7fa385a2018-01-24 08:35:28 -08002151 updateChildrenVisibility();
Selim Cinek2627d722018-01-19 12:16:49 -08002152 updateClipping();
2153 mBackgroundNormal.setExpandAnimationRunning(expandAnimationRunning);
2154 }
2155
Selim Cinekc25989e2018-02-16 16:42:14 -08002156 private void setChildIsExpanding(boolean isExpanding) {
2157 mChildIsExpanding = isExpanding;
Selim Cinek6487ebf2018-11-28 18:57:40 -08002158 updateClipping();
2159 invalidate();
Selim Cinekc25989e2018-02-16 16:42:14 -08002160 }
2161
2162 @Override
2163 public boolean hasExpandingChild() {
2164 return mChildIsExpanding;
2165 }
2166
Selim Cinek2627d722018-01-19 12:16:49 -08002167 @Override
2168 protected boolean shouldClipToActualHeight() {
Selim Cinek53328492018-12-05 14:58:44 -08002169 return super.shouldClipToActualHeight() && !mExpandAnimationRunning;
Selim Cinek2627d722018-01-19 12:16:49 -08002170 }
2171
2172 @Override
2173 public boolean isExpandAnimationRunning() {
2174 return mExpandAnimationRunning;
2175 }
2176
Lucas Dupincecc7c22017-09-12 16:02:45 -07002177 /**
2178 * Tap sounds should not be played when we're unlocking.
2179 * Doing so would cause audio collision and the system would feel unpolished.
2180 */
2181 @Override
2182 public boolean isSoundEffectsEnabled() {
2183 final boolean mute = mDark && mSecureStateProvider != null &&
2184 !mSecureStateProvider.getAsBoolean();
2185 return !mute && super.isSoundEffectsEnabled();
2186 }
2187
Chris Wren51c75102013-07-16 20:49:17 -04002188 public boolean isExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002189 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek388df6d2015-10-22 13:25:11 -07002190 return !mChildrenExpanded;
2191 }
Anthony Chen6bf88a02017-04-10 14:41:44 -07002192 return mEnableNonGroupedNotificationExpand && mExpandable;
Chris Wren51c75102013-07-16 20:49:17 -04002193 }
2194
2195 public void setExpandable(boolean expandable) {
2196 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002197 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04002198 }
2199
Selim Cinek4ffd6362015-12-29 15:12:23 +01002200 @Override
2201 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08002202 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
2203 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01002204 }
2205
Selim Cinek1685e632014-04-08 02:27:49 +02002206 /**
2207 * @return whether the user has changed the expansion state
2208 */
2209 public boolean hasUserChangedExpansion() {
2210 return mHasUserChangedExpansion;
2211 }
2212
Chris Wren51c75102013-07-16 20:49:17 -04002213 public boolean isUserExpanded() {
2214 return mUserExpanded;
2215 }
2216
Selim Cinek1685e632014-04-08 02:27:49 +02002217 /**
2218 * Set this notification to be expanded by the user
2219 *
2220 * @param userExpanded whether the user wants this notification to be expanded
2221 */
Chris Wren51c75102013-07-16 20:49:17 -04002222 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07002223 setUserExpanded(userExpanded, false /* allowChildExpansion */);
2224 }
2225
2226 /**
2227 * Set this notification to be expanded by the user
2228 *
2229 * @param userExpanded whether the user wants this notification to be expanded
2230 * @param allowChildExpansion whether a call to this method allows expanding children
2231 */
2232 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07002233 mFalsingManager.setNotificationExpanded();
Selim Cinek0b9cf462017-12-07 16:31:03 -08002234 if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
Selim Cinek414ad332017-02-24 19:06:12 -08002235 && !mChildrenContainer.showingAsLowPriority()) {
Chris Wren698b1702016-05-23 11:16:32 -04002236 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07002237 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -08002238 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07002239 return;
2240 }
Christoph Studera7fe6312014-06-27 19:32:44 +02002241 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01002242 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02002243 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04002244 mUserExpanded = userExpanded;
Selim Cinek414ad332017-02-24 19:06:12 -08002245 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002246 if (!wasExpanded && isExpanded()
2247 && getActualHeight() != getIntrinsicHeight()) {
2248 notifyHeightChanged(true /* needsAnimation */);
2249 }
Chris Wren51c75102013-07-16 20:49:17 -04002250 }
2251
Selim Cinekccd14fb2014-08-12 18:53:24 +02002252 public void resetUserExpansion() {
Selim Cinekf2495a72019-03-11 19:58:15 -07002253 boolean wasExpanded = isExpanded();
Selim Cinekccd14fb2014-08-12 18:53:24 +02002254 mHasUserChangedExpansion = false;
2255 mUserExpanded = false;
Selim Cinekf2495a72019-03-11 19:58:15 -07002256 if (wasExpanded != isExpanded()) {
2257 if (mIsSummaryWithChildren) {
2258 mChildrenContainer.onExpansionChanged();
2259 }
2260 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek414ad332017-02-24 19:06:12 -08002261 }
2262 updateShelfIconColor();
Selim Cinekccd14fb2014-08-12 18:53:24 +02002263 }
2264
Chris Wren51c75102013-07-16 20:49:17 -04002265 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07002266 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04002267 }
2268
2269 public void setUserLocked(boolean userLocked) {
2270 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08002271 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07002272 // This is intentionally not guarded with mIsSummaryWithChildren since we might have had
2273 // children but not anymore.
2274 if (mChildrenContainer != null) {
Selim Cinek42357e02016-02-24 18:48:01 -08002275 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07002276 if (mIsSummaryWithChildren && (userLocked || !isGroupExpanded())) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002277 updateBackgroundForGroupState();
2278 }
Selim Cinek42357e02016-02-24 18:48:01 -08002279 }
Chris Wren51c75102013-07-16 20:49:17 -04002280 }
2281
Selim Cinek1685e632014-04-08 02:27:49 +02002282 /**
2283 * @return has the system set this notification to be expanded
2284 */
2285 public boolean isSystemExpanded() {
2286 return mIsSystemExpanded;
2287 }
2288
2289 /**
2290 * Set this notification to be expanded by the system.
2291 *
2292 * @param expand whether the system wants this notification to be expanded.
2293 */
2294 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02002295 if (expand != mIsSystemExpanded) {
2296 final boolean wasExpanded = isExpanded();
2297 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01002298 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek414ad332017-02-24 19:06:12 -08002299 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07002300 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07002301 mChildrenContainer.updateGroupOverflow();
2302 }
Selim Cinek31094df2014-08-14 19:28:15 +02002303 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02002304 }
2305
2306 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07002307 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02002308 */
Selim Cinek83bc7832015-10-22 13:26:54 -07002309 public void setOnKeyguard(boolean onKeyguard) {
2310 if (onKeyguard != mOnKeyguard) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07002311 boolean wasAboveShelf = isAboveShelf();
Selim Cinek31094df2014-08-14 19:28:15 +02002312 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07002313 mOnKeyguard = onKeyguard;
Selim Cinek414ad332017-02-24 19:06:12 -08002314 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cinek31094df2014-08-14 19:28:15 +02002315 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07002316 if (mIsSummaryWithChildren) {
2317 mChildrenContainer.updateGroupOverflow();
2318 }
Mady Mellor4b80b102016-01-22 08:03:58 -08002319 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02002320 }
Selim Cinek5cf1d052017-06-01 17:36:46 -07002321 if (isAboveShelf() != wasAboveShelf) {
2322 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
2323 }
Selim Cinek31094df2014-08-14 19:28:15 +02002324 }
Selim Cinekfe24fb72018-02-13 14:34:55 -08002325 updateRippleAllowed();
2326 }
2327
2328 private void updateRippleAllowed() {
2329 boolean allowed = isOnKeyguard()
2330 || mEntry.notification.getNotification().contentIntent == null;
2331 setRippleAllowed(allowed);
Selim Cinek1685e632014-04-08 02:27:49 +02002332 }
2333
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02002334 @Override
2335 public int getIntrinsicHeight() {
Mady Mellorc3d6f7d2018-11-07 09:36:56 -08002336 if (isShownAsBubble()) {
2337 return getMaxExpandHeight();
2338 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002339 if (isUserLocked()) {
2340 return getActualHeight();
2341 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002342 if (mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07002343 return mGuts.getIntrinsicHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08002344 } else if ((isChildInGroup() && !isGroupExpanded())) {
2345 return mPrivateLayout.getMinHeight();
2346 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
2347 return getMinHeight();
Selim Cinek7927c732019-03-06 15:21:39 -08002348 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002349 return mChildrenContainer.getIntrinsicHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07002350 } else if (isHeadsUpAllowed() && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07002351 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08002352 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
2353 } else if (isExpanded()) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002354 return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
Selim Cinek8d490d42015-04-10 00:05:50 -07002355 } else {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002356 return Math.max(getCollapsedHeight(), getHeadsUpHeight());
Selim Cinek8d490d42015-04-10 00:05:50 -07002357 }
Selim Cinek31aada42015-12-18 17:51:15 -08002358 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07002359 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08002360 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07002361 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02002362 }
Selim Cinekb5605e52015-02-20 18:21:41 +01002363 }
Selim Cinek1685e632014-04-08 02:27:49 +02002364
Adrian Roos6f6e1592017-05-02 16:22:53 -07002365 private boolean isHeadsUpAllowed() {
Kevina97ea052018-09-11 13:53:18 -07002366 return !mOnKeyguard && !mOnAmbient;
Adrian Roos6f6e1592017-05-02 16:22:53 -07002367 }
2368
Mady Mellorc3d6f7d2018-11-07 09:36:56 -08002369 private boolean isShownAsBubble() {
Mady Mellor3f2efdb2018-11-21 11:30:45 -08002370 return mEntry.isBubble() && !mEntry.showInShadeWhenBubble() && !mEntry.isBubbleDismissed();
Mady Mellorc3d6f7d2018-11-07 09:36:56 -08002371 }
2372
2373 /**
2374 * Set the current status bar state.
2375 * @param state should be from {@link com.android.systemui.statusbar.StatusBarState}.
2376 */
2377 public void setStatusBarState(int state) {
2378 if (mStatusBarState != state) {
2379 mStatusBarState = state;
2380 }
2381 }
2382
Mady Mellor43c2cd12016-12-12 21:05:13 -08002383 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07002384 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07002385 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01002386 }
2387
Selim Cinek263398f2015-10-21 17:40:23 -07002388 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05002389 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07002390 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
2391 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
Selim Cinek414ad332017-02-24 19:06:12 -08002392 mChildrenContainer.recreateNotificationHeader(mExpandClickListener
2393 );
Selim Cinek263398f2015-10-21 17:40:23 -07002394 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07002395 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002396 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08002397 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08002398 updateChildrenVisibility();
Selim Cinek2871bef2017-11-22 08:40:00 -08002399 applyChildrenRoundness();
Selim Cinek263398f2015-10-21 17:40:23 -07002400 }
Rohan Shah63411fc2018-03-28 19:05:52 -07002401 /**
2402 * Returns the number of channels covered by the notification row (including its children if
2403 * it's a summary notification).
2404 */
2405 public int getNumUniqueChannels() {
Evan Laird47dc4542019-04-24 15:10:52 -04002406 return getUniqueChannels().size();
2407 }
2408
2409 /**
2410 * Returns the channels covered by the notification row (including its children if
2411 * it's a summary notification).
2412 */
2413 public ArraySet<NotificationChannel> getUniqueChannels() {
Rohan Shah63411fc2018-03-28 19:05:52 -07002414 ArraySet<NotificationChannel> channels = new ArraySet<>();
2415
2416 channels.add(mEntry.channel);
2417
2418 // If this is a summary, then add in the children notification channels for the
2419 // same user and pkg.
2420 if (mIsSummaryWithChildren) {
2421 final List<ExpandableNotificationRow> childrenRows = getNotificationChildren();
2422 final int numChildren = childrenRows.size();
2423 for (int i = 0; i < numChildren; i++) {
2424 final ExpandableNotificationRow childRow = childrenRows.get(i);
2425 final NotificationChannel childChannel = childRow.getEntry().channel;
2426 final StatusBarNotification childSbn = childRow.getStatusBarNotification();
2427 if (childSbn.getUser().equals(mStatusBarNotification.getUser()) &&
2428 childSbn.getPackageName().equals(mStatusBarNotification.getPackageName())) {
2429 channels.add(childChannel);
2430 }
2431 }
2432 }
Evan Laird47dc4542019-04-24 15:10:52 -04002433
2434 return channels;
Rohan Shah63411fc2018-03-28 19:05:52 -07002435 }
Selim Cinek263398f2015-10-21 17:40:23 -07002436
Mady Mellorb0a82462016-04-30 17:31:02 -07002437 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07002438 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002439 mChildrenContainer.updateChildrenHeaderAppearance();
2440 }
2441 }
2442
Selim Cinek1685e632014-04-08 02:27:49 +02002443 /**
2444 * Check whether the view state is currently expanded. This is given by the system in {@link
2445 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
2446 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
2447 * view can differ from this state, if layout params are modified from outside.
2448 *
2449 * @return whether the view state is currently expanded.
2450 */
Selim Cinek83bc7832015-10-22 13:26:54 -07002451 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08002452 return isExpanded(false /* allowOnKeyguard */);
2453 }
2454
2455 public boolean isExpanded(boolean allowOnKeyguard) {
2456 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01002457 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
2458 || isUserExpanded());
2459 }
2460
2461 private boolean isSystemChildExpanded() {
2462 return mIsSystemChildExpanded;
2463 }
2464
2465 public void setSystemChildExpanded(boolean expanded) {
2466 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02002467 }
2468
Mady Mellor035badd2017-04-04 18:45:30 -07002469 public void setLayoutListener(LayoutListener listener) {
2470 mLayoutListener = listener;
2471 }
2472
2473 public void removeListener() {
2474 mLayoutListener = null;
2475 }
2476
Selim Cinek1685e632014-04-08 02:27:49 +02002477 @Override
2478 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002479 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02002480 super.onLayout(changed, left, top, right, bottom);
Selim Cinek15af9762019-03-19 18:32:37 -07002481 if (intrinsicBefore != getIntrinsicHeight() && intrinsicBefore != 0) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002482 notifyHeightChanged(true /* needsAnimation */);
2483 }
Evan Lairde55c6012019-03-13 12:54:37 -04002484 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Aaron Heuckroth266cb342018-09-07 14:52:04 -04002485 mMenuRow.onParentHeightUpdate();
Mady Mellora6edc872016-04-26 11:01:03 -07002486 }
Selim Cinek875a3a12016-11-18 17:52:16 -08002487 updateContentShiftHeight();
Mady Mellor035badd2017-04-04 18:45:30 -07002488 if (mLayoutListener != null) {
2489 mLayoutListener.onLayout();
2490 }
Selim Cinek875a3a12016-11-18 17:52:16 -08002491 }
2492
2493 /**
2494 * Updates the content shift height such that the header is completely hidden when coming from
2495 * the top.
2496 */
2497 private void updateContentShiftHeight() {
Selim Cinek414ad332017-02-24 19:06:12 -08002498 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek875a3a12016-11-18 17:52:16 -08002499 if (notificationHeader != null) {
2500 CachingIconView icon = notificationHeader.getIcon();
2501 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
2502 } else {
2503 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
2504 }
Selim Cinek1685e632014-04-08 02:27:49 +02002505 }
2506
Selim Cinekfa0a2d32016-01-14 13:02:21 -08002507 @Override
2508 public void notifyHeightChanged(boolean needsAnimation) {
2509 super.notifyHeightChanged(needsAnimation);
2510 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
2511 }
2512
Selim Cinek3c76d502016-02-19 15:16:33 -08002513 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02002514 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08002515 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02002516 }
2517
Mady Mellor43c2cd12016-12-12 21:05:13 -08002518 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02002519 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07002520 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08002521 if (mIsSummaryWithChildren) {
2522 List<ExpandableNotificationRow> notificationChildren =
2523 mChildrenContainer.getNotificationChildren();
2524 for (int i = 0; i < notificationChildren.size(); i++) {
2525 ExpandableNotificationRow child = notificationChildren.get(i);
2526 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
2527 }
2528 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002529 }
2530
Mady Mellor43c2cd12016-12-12 21:05:13 -08002531 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02002532 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
2533 long duration) {
Selim Cinek69594fb2018-05-18 12:06:10 -07002534 if (getVisibility() == GONE) {
2535 // If we are GONE, the hideSensitive parameter will not be calculated and always be
2536 // false, which is incorrect, let's wait until a real call comes in later.
2537 return;
2538 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002539 boolean oldShowingPublic = mShowingPublic;
2540 mShowingPublic = mSensitive && hideSensitive;
2541 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
2542 return;
2543 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05002544
2545 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02002546 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002547
Jorim Jaggiae441282014-08-01 02:45:18 +02002548 if (!animated) {
2549 mPublicLayout.animate().cancel();
2550 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07002551 if (mChildrenContainer != null) {
2552 mChildrenContainer.animate().cancel();
2553 mChildrenContainer.setAlpha(1f);
2554 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002555 mPublicLayout.setAlpha(1f);
2556 mPrivateLayout.setAlpha(1f);
2557 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08002558 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02002559 } else {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002560 animateShowingPublic(delay, duration, mShowingPublic);
Jorim Jaggiae441282014-08-01 02:45:18 +02002561 }
Selim Cinekc3179332016-03-04 14:44:56 -08002562 NotificationContentView showingLayout = getShowingLayout();
2563 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002564 mPrivateLayout.updateExpandButtons(isExpandable());
Lucas Dupinb6ed63b2017-05-30 16:17:42 -07002565 updateShelfIconColor();
Adrian Roose5726a22016-12-19 14:26:51 -08002566 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02002567 mShowingPublicInitialized = true;
2568 }
2569
Selim Cinek0b9cf462017-12-07 16:31:03 -08002570 private void animateShowingPublic(long delay, long duration, boolean showingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002571 View[] privateViews = mIsSummaryWithChildren
2572 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08002573 : new View[] {mPrivateLayout};
2574 View[] publicViews = new View[] {mPublicLayout};
Selim Cinek0b9cf462017-12-07 16:31:03 -08002575 View[] hiddenChildren = showingPublic ? privateViews : publicViews;
2576 View[] shownChildren = showingPublic ? publicViews : privateViews;
Selim Cinekd84a5932015-12-15 11:45:36 -08002577 for (final View hiddenView : hiddenChildren) {
2578 hiddenView.setVisibility(View.VISIBLE);
2579 hiddenView.animate().cancel();
2580 hiddenView.animate()
2581 .alpha(0f)
2582 .setStartDelay(delay)
2583 .setDuration(duration)
2584 .withEndAction(new Runnable() {
2585 @Override
2586 public void run() {
2587 hiddenView.setVisibility(View.INVISIBLE);
2588 }
2589 });
2590 }
2591 for (View showView : shownChildren) {
2592 showView.setVisibility(View.VISIBLE);
2593 showView.setAlpha(0f);
2594 showView.animate().cancel();
2595 showView.animate()
2596 .alpha(1f)
2597 .setStartDelay(delay)
2598 .setDuration(duration);
2599 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04002600 }
2601
Mady Mellor43c2cd12016-12-12 21:05:13 -08002602 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08002603 public boolean mustStayOnScreen() {
Selim Cinek9b9d6e12017-11-30 12:29:47 +01002604 return mIsHeadsUp && mMustStayOnScreen;
Selim Cinek3776fe02016-02-04 13:32:43 -08002605 }
2606
Selim Cinek9e624e72016-07-20 13:46:49 -07002607 /**
2608 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
2609 * otherwise some state might not be updated. To request about the general clearability
Ned Burnsf81c4c42019-01-07 14:10:43 -05002610 * see {@link NotificationEntry#isClearable()}.
Selim Cinek9e624e72016-07-20 13:46:49 -07002611 */
2612 public boolean canViewBeDismissed() {
Evan Laird94492852018-10-25 13:43:01 -04002613 return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
Selim Cinek0b9cf462017-12-07 16:31:03 -08002614 }
2615
2616 private boolean shouldShowPublic() {
2617 return mSensitive && mHideSensitiveForIntrinsicHeight;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002618 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02002619
Ricky Waicd35def2016-05-03 11:07:07 +01002620 public void makeActionsVisibile() {
2621 setUserExpanded(true, true);
2622 if (isChildInGroup()) {
2623 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
2624 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07002625 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01002626 }
2627
Selim Cinekb5605e52015-02-20 18:21:41 +01002628 public void setChildrenExpanded(boolean expanded, boolean animate) {
2629 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07002630 if (mChildrenContainer != null) {
2631 mChildrenContainer.setChildrenExpanded(expanded);
2632 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07002633 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07002634 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01002635 }
2636
Selim Cinekb5605e52015-02-20 18:21:41 +01002637 public static void applyTint(View v, int color) {
2638 int alpha;
2639 if (color != 0) {
2640 alpha = COLORED_DIVIDER_ALPHA;
2641 } else {
2642 color = 0xff000000;
2643 alpha = DEFAULT_DIVIDER_ALPHA;
2644 }
2645 if (v.getBackground() instanceof ColorDrawable) {
2646 ColorDrawable background = (ColorDrawable) v.getBackground();
2647 background.mutate();
2648 background.setColor(color);
2649 background.setAlpha(alpha);
2650 }
2651 }
2652
Selim Cinek1685e632014-04-08 02:27:49 +02002653 public int getMaxExpandHeight() {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002654 return mPrivateLayout.getExpandHeight();
2655 }
2656
2657
2658 private int getHeadsUpHeight() {
Gustav Sennton8a1869f2019-04-23 17:30:18 +01002659 return getShowingLayout().getHeadsUpHeight();
Chris Wren51c75102013-07-16 20:49:17 -04002660 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02002661
Mady Mellor34958fa2016-02-23 09:52:17 -08002662 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002663 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08002664 }
2665
Jorim Jaggibe565df2014-04-28 17:51:23 +02002666 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002667 public boolean isContentExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002668 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002669 return true;
2670 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002671 NotificationContentView showingLayout = getShowingLayout();
2672 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002673 }
2674
2675 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07002676 protected View getContentView() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002677 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cineka5703182016-05-11 21:23:16 -04002678 return mChildrenContainer;
2679 }
Selim Cinek560e64d2015-06-09 19:58:11 -07002680 return getShowingLayout();
2681 }
2682
2683 @Override
Gus Prevas211181532018-12-13 14:49:33 -05002684 public long performRemoveAnimation(long duration, long delay, float translationDirection,
2685 boolean isHeadsUpAnimation, float endLocation, Runnable onFinishedRunnable,
2686 AnimatorListenerAdapter animationListener) {
Evan Lairde55c6012019-03-13 12:54:37 -04002687 if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Gus Prevas211181532018-12-13 14:49:33 -05002688 Animator anim = getTranslateViewAnimator(0f, null /* listener */);
2689 if (anim != null) {
2690 anim.addListener(new AnimatorListenerAdapter() {
2691 @Override
2692 public void onAnimationEnd(Animator animation) {
2693 ExpandableNotificationRow.super.performRemoveAnimation(
2694 duration, delay, translationDirection, isHeadsUpAnimation,
2695 endLocation, onFinishedRunnable, animationListener);
2696 }
2697 });
2698 anim.start();
2699 return anim.getDuration();
2700 }
2701 }
2702 return super.performRemoveAnimation(duration, delay, translationDirection,
2703 isHeadsUpAnimation, endLocation, onFinishedRunnable, animationListener);
2704 }
2705
2706 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07002707 protected void onAppearAnimationFinished(boolean wasAppearing) {
2708 super.onAppearAnimationFinished(wasAppearing);
2709 if (wasAppearing) {
2710 // During the animation the visible view might have changed, so let's make sure all
2711 // alphas are reset
2712 if (mChildrenContainer != null) {
2713 mChildrenContainer.setAlpha(1.0f);
2714 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
2715 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08002716 for (NotificationContentView l : mLayouts) {
2717 l.setAlpha(1.0f);
2718 l.setLayerType(LAYER_TYPE_NONE, null);
2719 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07002720 }
2721 }
2722
2723 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07002724 public int getExtraBottomPadding() {
2725 if (mIsSummaryWithChildren && isGroupExpanded()) {
2726 return mIncreasedPaddingBetweenElements;
2727 }
2728 return 0;
2729 }
2730
2731 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02002732 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinek4ca6c632017-02-23 18:03:37 -08002733 boolean changed = height != getActualHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +01002734 super.setActualHeight(height, notifyListeners);
Selim Cinek4ca6c632017-02-23 18:03:37 -08002735 if (changed && isRemoved()) {
2736 // TODO: remove this once we found the gfx bug for this.
2737 // This is a hack since a removed view sometimes would just stay blank. it occured
2738 // when sending yourself a message and then clicking on it.
2739 ViewGroup parent = (ViewGroup) getParent();
2740 if (parent != null) {
2741 parent.invalidate();
2742 }
2743 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002744 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08002745 mGuts.setActualHeight(height);
2746 return;
2747 }
Selim Cinekeef84282015-10-30 16:28:00 -07002748 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002749 for (NotificationContentView l : mLayouts) {
2750 l.setContentHeight(contentHeight);
2751 }
Selim Cinek42357e02016-02-24 18:48:01 -08002752 if (mIsSummaryWithChildren) {
2753 mChildrenContainer.setActualHeight(height);
2754 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002755 if (mGuts != null) {
2756 mGuts.setActualHeight(height);
2757 }
Evan Lairde55c6012019-03-13 12:54:37 -04002758 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Aaron Heuckroth266cb342018-09-07 14:52:04 -04002759 mMenuRow.onParentHeightUpdate();
Mady Mellor54540972017-06-07 11:55:36 -07002760 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002761 }
2762
2763 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01002764 public int getMaxContentHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002765 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002766 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002767 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002768 NotificationContentView showingLayout = getShowingLayout();
2769 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02002770 }
2771
2772 @Override
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002773 public int getMinHeight(boolean ignoreTemporaryStates) {
2774 if (!ignoreTemporaryStates && mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07002775 return mGuts.getIntrinsicHeight();
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002776 } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp
2777 && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08002778 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
Selim Cinek0b9cf462017-12-07 16:31:03 -08002779 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !shouldShowPublic()) {
Selim Cinekb55386d2015-12-16 17:26:49 -08002780 return mChildrenContainer.getMinHeight();
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002781 } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002782 return getHeadsUpHeight();
Selim Cinekb55386d2015-12-16 17:26:49 -08002783 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002784 NotificationContentView showingLayout = getShowingLayout();
2785 return showingLayout.getMinHeight();
2786 }
2787
2788 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07002789 public int getCollapsedHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002790 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek567e8452016-03-24 10:54:56 -07002791 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002792 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002793 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002794 }
2795
2796 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02002797 public void setClipTopAmount(int clipTopAmount) {
2798 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002799 for (NotificationContentView l : mLayouts) {
2800 l.setClipTopAmount(clipTopAmount);
2801 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002802 if (mGuts != null) {
2803 mGuts.setClipTopAmount(clipTopAmount);
2804 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002805 }
2806
Selim Cineka686b2c2016-10-26 13:58:27 -07002807 @Override
2808 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek2627d722018-01-19 12:16:49 -08002809 if (mExpandAnimationRunning) {
2810 return;
2811 }
Selim Cinek65d418e2016-11-29 15:42:34 -08002812 if (clipBottomAmount != mClipBottomAmount) {
2813 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002814 for (NotificationContentView l : mLayouts) {
2815 l.setClipBottomAmount(clipBottomAmount);
2816 }
Selim Cinek65d418e2016-11-29 15:42:34 -08002817 if (mGuts != null) {
2818 mGuts.setClipBottomAmount(clipBottomAmount);
2819 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002820 }
Selim Cinekc25989e2018-02-16 16:42:14 -08002821 if (mChildrenContainer != null && !mChildIsExpanding) {
Selim Cinek65d418e2016-11-29 15:42:34 -08002822 // We have to update this even if it hasn't changed, since the children locations can
2823 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08002824 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
2825 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002826 }
2827
Selim Cinek42357e02016-02-24 18:48:01 -08002828 public NotificationContentView getShowingLayout() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002829 return shouldShowPublic() ? mPublicLayout : mPrivateLayout;
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002830 }
Chris Wren78403d72014-07-28 10:23:24 +01002831
Kevind4660b22018-09-27 10:57:35 -07002832 public View getExpandedContentView() {
2833 return getPrivateLayout().getExpandedChild();
2834 }
2835
Selim Cinek1a48bab2017-02-17 19:38:40 -08002836 public void setLegacy(boolean legacy) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08002837 for (NotificationContentView l : mLayouts) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08002838 l.setLegacy(legacy);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002839 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07002840 }
2841
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002842 @Override
2843 protected void updateBackgroundTint() {
2844 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07002845 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002846 if (mIsSummaryWithChildren) {
2847 List<ExpandableNotificationRow> notificationChildren =
2848 mChildrenContainer.getNotificationChildren();
2849 for (int i = 0; i < notificationChildren.size(); i++) {
2850 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07002851 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002852 }
2853 }
2854 }
2855
Mady Mellorb0a82462016-04-30 17:31:02 -07002856 /**
2857 * Called when a group has finished animating from collapsed or expanded state.
2858 */
2859 public void onFinishedExpansionChange() {
2860 mGroupExpansionChanging = false;
2861 updateBackgroundForGroupState();
2862 }
2863
2864 /**
2865 * Updates the parent and children backgrounds in a group based on the expansion state.
2866 */
2867 public void updateBackgroundForGroupState() {
2868 if (mIsSummaryWithChildren) {
2869 // Only when the group has finished expanding do we hide its background.
Anthony Chen6bf88a02017-04-10 14:41:44 -07002870 mShowNoBackground = !mShowGroupBackgroundWhenExpanded && isGroupExpanded()
2871 && !isGroupExpansionChanging() && !isUserLocked();
Mady Mellorb0a82462016-04-30 17:31:02 -07002872 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
2873 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
2874 for (int i = 0; i < children.size(); i++) {
2875 children.get(i).updateBackgroundForGroupState();
2876 }
2877 } else if (isChildInGroup()) {
2878 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
2879 // Only show a background if the group is expanded OR if it is expanding / collapsing
Anthony Chen6bf88a02017-04-10 14:41:44 -07002880 // and has a custom background color.
Mady Mellorb0a82462016-04-30 17:31:02 -07002881 final boolean showBackground = isGroupExpanded()
2882 || ((mNotificationParent.isGroupExpansionChanging()
Anthony Chen6bf88a02017-04-10 14:41:44 -07002883 || mNotificationParent.isUserLocked()) && childColor != 0);
Mady Mellorb0a82462016-04-30 17:31:02 -07002884 mShowNoBackground = !showBackground;
2885 } else {
2886 // Only children or parents ever need no background.
2887 mShowNoBackground = false;
2888 }
2889 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002890 updateBackground();
2891 }
2892
Adrian Roos4a579672016-05-24 16:54:37 -07002893 public int getPositionOfChild(ExpandableNotificationRow childRow) {
2894 if (mIsSummaryWithChildren) {
2895 return mChildrenContainer.getPositionInLinearLayout(childRow);
2896 }
2897 return 0;
2898 }
2899
Chris Wren78403d72014-07-28 10:23:24 +01002900 public void setExpansionLogger(ExpansionLogger logger, String key) {
2901 mLogger = logger;
2902 mLoggingKey = key;
2903 }
2904
Chris Wren6abeeb92016-05-26 14:44:38 -04002905 public void onExpandedByGesture(boolean userExpanded) {
2906 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
2907 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
2908 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
2909 }
2910 MetricsLogger.action(mContext, event, userExpanded);
2911 }
2912
Selim Cinek6183d122016-01-14 18:48:41 -08002913 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08002914 public float getIncreasedPaddingAmount() {
2915 if (mIsSummaryWithChildren) {
2916 if (isGroupExpanded()) {
2917 return 1.0f;
2918 } else if (isUserLocked()) {
Selim Cinek414ad332017-02-24 19:06:12 -08002919 return mChildrenContainer.getIncreasedPaddingAmount();
Selim Cinek42357e02016-02-24 18:48:01 -08002920 }
Selim Cinek99104832017-01-25 14:47:33 -08002921 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08002922 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08002923 }
2924 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08002925 }
2926
Selim Cineka7ed2c12017-01-23 20:47:24 -08002927 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08002928 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08002929 }
2930
Selim Cinek61633a82016-01-25 15:54:10 -08002931 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08002932 protected boolean disallowSingleClick(MotionEvent event) {
dongwan0605.kimc4ddef42018-05-06 17:40:23 +09002933 if (areGutsExposed()) {
2934 return false;
2935 }
Selim Cinek6183d122016-01-14 18:48:41 -08002936 float x = event.getX();
2937 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08002938 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002939 if (header != null && header.isInTouchRect(x - getTranslation(), y)) {
2940 return true;
2941 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002942 if ((!mIsSummaryWithChildren || shouldShowPublic())
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002943 && getShowingLayout().disallowSingleClick(x, y)) {
2944 return true;
Selim Cinek6183d122016-01-14 18:48:41 -08002945 }
2946 return super.disallowSingleClick(event);
2947 }
2948
Selim Cinek414ad332017-02-24 19:06:12 -08002949 private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04002950 boolean nowExpanded = isExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08002951 if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
Chris Wren698b1702016-05-23 11:16:32 -04002952 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
2953 }
Selim Cinek414ad332017-02-24 19:06:12 -08002954 if (nowExpanded != wasExpanded) {
2955 updateShelfIconColor();
2956 if (mLogger != null) {
2957 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded);
2958 }
2959 if (mIsSummaryWithChildren) {
2960 mChildrenContainer.onExpansionChanged();
2961 }
Chris Wren78403d72014-07-28 10:23:24 +01002962 }
2963 }
Selim Cinek570981d2015-12-01 11:37:01 -08002964
Selim Cineke9bad242016-06-15 11:46:37 -07002965 @Override
2966 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2967 super.onInitializeAccessibilityNodeInfoInternal(info);
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002968 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
Selim Cineke9bad242016-06-15 11:46:37 -07002969 if (canViewBeDismissed()) {
2970 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
2971 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002972 boolean expandable = shouldShowPublic();
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002973 boolean isExpanded = false;
2974 if (!expandable) {
2975 if (mIsSummaryWithChildren) {
2976 expandable = true;
2977 if (!mIsLowPriority || isExpanded()) {
2978 isExpanded = isGroupExpanded();
2979 }
2980 } else {
2981 expandable = mPrivateLayout.isContentExpandable();
2982 isExpanded = isExpanded();
2983 }
2984 }
2985 if (expandable) {
2986 if (isExpanded) {
2987 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
2988 } else {
2989 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
2990 }
2991 }
Mady Mellorb3a6aed2018-05-11 13:24:07 -07002992 NotificationMenuRowPlugin provider = getProvider();
2993 if (provider != null) {
2994 MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
2995 if (snoozeMenu != null) {
2996 AccessibilityAction action = new AccessibilityAction(R.id.action_snooze,
2997 getContext().getResources()
2998 .getString(R.string.notification_menu_snooze_action));
2999 info.addAction(action);
3000 }
3001 }
Selim Cineke9bad242016-06-15 11:46:37 -07003002 }
3003
3004 @Override
3005 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
3006 if (super.performAccessibilityActionInternal(action, arguments)) {
3007 return true;
3008 }
3009 switch (action) {
3010 case AccessibilityNodeInfo.ACTION_DISMISS:
Rohan Shah524cf7b2018-03-15 14:40:02 -07003011 performDismissWithBlockingHelper(true /* fromAccessibility */);
Selim Cineke9bad242016-06-15 11:46:37 -07003012 return true;
Selim Cinekc0ac4af2017-03-03 15:13:48 -08003013 case AccessibilityNodeInfo.ACTION_COLLAPSE:
3014 case AccessibilityNodeInfo.ACTION_EXPAND:
3015 mExpandClickListener.onClick(this);
3016 return true;
Geoffrey Pitsch409db272017-08-28 14:51:52 +00003017 case AccessibilityNodeInfo.ACTION_LONG_CLICK:
3018 doLongClickCallback();
3019 return true;
Jason Monk05dd5672018-08-09 09:38:21 -04003020 default:
3021 if (action == R.id.action_snooze) {
3022 NotificationMenuRowPlugin provider = getProvider();
Evan Lairde55c6012019-03-13 12:54:37 -04003023 if (provider == null && mMenuRow != null) {
Jason Monk05dd5672018-08-09 09:38:21 -04003024 provider = createMenu();
Evan Lairde55c6012019-03-13 12:54:37 -04003025 } else {
3026 return false;
Jason Monk05dd5672018-08-09 09:38:21 -04003027 }
3028 MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
3029 if (snoozeMenu != null) {
3030 doLongClickCallback(getWidth() / 2, getHeight() / 2, snoozeMenu);
3031 }
3032 return true;
Mady Mellorb3a6aed2018-05-11 13:24:07 -07003033 }
Selim Cineke9bad242016-06-15 11:46:37 -07003034 }
3035 return false;
3036 }
3037
3038 public boolean shouldRefocusOnDismiss() {
3039 return mRefocusOnDismiss || isAccessibilityFocused();
3040 }
3041
Selim Cinek570981d2015-12-01 11:37:01 -08003042 public interface OnExpandClickListener {
Ned Burnsf81c4c42019-01-07 14:10:43 -05003043 void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08003044 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08003045
3046 @Override
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003047 public ExpandableViewState createExpandableViewState() {
3048 return new NotificationViewState();
Selim Cinekf93bf3e2018-05-08 14:43:21 -07003049 }
3050
Selim Cinekd127d792016-11-01 19:11:41 -07003051 @Override
3052 public boolean isAboveShelf() {
Selim Cinek459aee32019-02-20 11:18:56 -08003053 return showingAmbientPulsing() || (!isOnKeyguard()
Selim Cinek2627d722018-01-19 12:16:49 -08003054 && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf)
Selim Cinek5040f2e2019-02-14 18:22:42 -08003055 || mExpandAnimationRunning || mChildIsExpanding));
Selim Cinekd127d792016-11-01 19:11:41 -07003056 }
3057
Kevina97ea052018-09-11 13:53:18 -07003058 public void setOnAmbient(boolean onAmbient) {
3059 if (onAmbient != mOnAmbient) {
3060 mOnAmbient = onAmbient;
Adrian Roos0aac04f2016-12-08 15:59:29 -08003061 notifyHeightChanged(false /* needsAnimation */);
3062 }
3063 }
3064
Selim Cinek0fe07392017-11-09 13:26:34 -08003065 @Override
Tony Huangc092c432018-05-18 17:38:54 +08003066 public boolean topAmountNeedsClipping() {
3067 if (isGroupExpanded()) {
3068 return true;
3069 }
3070 if (isGroupExpansionChanging()) {
3071 return true;
3072 }
3073 if (getShowingLayout().shouldClipToRounding(true /* topRounded */,
3074 false /* bottomRounded */)) {
3075 return true;
3076 }
3077 if (mGuts != null && mGuts.getAlpha() != 0.0f) {
3078 return true;
3079 }
3080 return false;
3081 }
3082
3083 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08003084 protected boolean childNeedsClipping(View child) {
3085 if (child instanceof NotificationContentView) {
3086 NotificationContentView contentView = (NotificationContentView) child;
3087 if (isClippingNeeded()) {
3088 return true;
Selim Cinek86bfcee2018-01-17 11:00:47 -08003089 } else if (!hasNoRounding()
3090 && contentView.shouldClipToRounding(getCurrentTopRoundness() != 0.0f,
3091 getCurrentBottomRoundness() != 0.0f)) {
Selim Cinek515b2032017-11-15 10:20:19 -08003092 return true;
3093 }
3094 } else if (child == mChildrenContainer) {
Selim Cinek6487ebf2018-11-28 18:57:40 -08003095 if (isClippingNeeded() || !hasNoRounding()) {
Selim Cinek515b2032017-11-15 10:20:19 -08003096 return true;
3097 }
3098 } else if (child instanceof NotificationGuts) {
Selim Cinekb95fd182017-12-21 13:03:32 -08003099 return !hasNoRounding();
Selim Cinek515b2032017-11-15 10:20:19 -08003100 }
3101 return super.childNeedsClipping(child);
3102 }
3103
3104 @Override
Selim Cinek2871bef2017-11-22 08:40:00 -08003105 protected void applyRoundness() {
3106 super.applyRoundness();
3107 applyChildrenRoundness();
3108 }
3109
3110 private void applyChildrenRoundness() {
3111 if (mIsSummaryWithChildren) {
3112 mChildrenContainer.setCurrentBottomRoundness(getCurrentBottomRoundness());
3113 }
3114 }
3115
3116 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08003117 public Path getCustomClipPath(View child) {
3118 if (child instanceof NotificationGuts) {
Selim Cinekdefd46f2018-05-30 11:47:08 -07003119 return getClipPath(true /* ignoreTranslation */);
Selim Cinek515b2032017-11-15 10:20:19 -08003120 }
3121 return super.getCustomClipPath(child);
3122 }
3123
Selim Cinekb95fd182017-12-21 13:03:32 -08003124 private boolean hasNoRounding() {
3125 return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f;
Selim Cinek0fe07392017-11-09 13:26:34 -08003126 }
3127
Kevina97ea052018-09-11 13:53:18 -07003128 public boolean isOnAmbient() {
3129 return mOnAmbient;
Adrian Roos6f6e1592017-05-02 16:22:53 -07003130 }
3131
Evan Laird94492852018-10-25 13:43:01 -04003132 //TODO: this logic can't depend on layout if we are recycling!
3133 public boolean isMediaRow() {
3134 return getExpandedContentView() != null
3135 && getExpandedContentView().findViewById(
3136 com.android.internal.R.id.media_actions) != null;
3137 }
3138
3139 public boolean isTopLevelChild() {
3140 return getParent() instanceof NotificationStackScrollLayout;
3141 }
3142
3143 public boolean isGroupNotFullyVisible() {
3144 return getClipTopAmount() > 0 || getTranslationY() < 0;
3145 }
3146
Selim Cinekd127d792016-11-01 19:11:41 -07003147 public void setAboveShelf(boolean aboveShelf) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07003148 boolean wasAboveShelf = isAboveShelf();
Selim Cinekd127d792016-11-01 19:11:41 -07003149 mAboveShelf = aboveShelf;
Selim Cinek5cf1d052017-06-01 17:36:46 -07003150 if (isAboveShelf() != wasAboveShelf) {
3151 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
3152 }
Selim Cinekd127d792016-11-01 19:11:41 -07003153 }
3154
Gus Prevasa18dc572019-01-14 16:11:22 -05003155 /** Sets whether dismiss gestures are right-to-left (instead of left-to-right). */
3156 public void setDismissRtl(boolean dismissRtl) {
Evan Lairde55c6012019-03-13 12:54:37 -04003157 if (mMenuRow != null) {
3158 mMenuRow.setDismissRtl(dismissRtl);
3159 }
Gus Prevasa18dc572019-01-14 16:11:22 -05003160 }
3161
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003162 private static class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08003163
3164 @Override
3165 public void applyToView(View view) {
Selim Cinekbbcebde2016-11-09 18:28:20 -08003166 if (view instanceof ExpandableNotificationRow) {
3167 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinek2627d722018-01-19 12:16:49 -08003168 if (row.isExpandAnimationRunning()) {
3169 return;
3170 }
Selim Cinekc25989e2018-02-16 16:42:14 -08003171 handleFixedTranslationZ(row);
Selim Cinek2627d722018-01-19 12:16:49 -08003172 super.applyToView(view);
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003173 row.applyChildrenState();
Selim Cinekbbcebde2016-11-09 18:28:20 -08003174 }
3175 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08003176
Selim Cinekc25989e2018-02-16 16:42:14 -08003177 private void handleFixedTranslationZ(ExpandableNotificationRow row) {
3178 if (row.hasExpandingChild()) {
3179 zTranslation = row.getTranslationZ();
3180 clipTopAmount = row.getClipTopAmount();
3181 }
3182 }
3183
Selim Cinek0cfbef42016-11-09 19:06:36 -08003184 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08003185 protected void onYTranslationAnimationFinished(View view) {
3186 super.onYTranslationAnimationFinished(view);
Selim Cinekd4776a52017-02-14 18:50:16 -08003187 if (view instanceof ExpandableNotificationRow) {
3188 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
3189 if (row.isHeadsUpAnimatingAway()) {
3190 row.setHeadsUpAnimatingAway(false);
3191 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08003192 }
3193 }
3194
3195 @Override
3196 public void animateTo(View child, AnimationProperties properties) {
Selim Cinek0cfbef42016-11-09 19:06:36 -08003197 if (child instanceof ExpandableNotificationRow) {
3198 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
Selim Cinek2627d722018-01-19 12:16:49 -08003199 if (row.isExpandAnimationRunning()) {
3200 return;
3201 }
Selim Cinekc25989e2018-02-16 16:42:14 -08003202 handleFixedTranslationZ(row);
Selim Cinek2627d722018-01-19 12:16:49 -08003203 super.animateTo(child, properties);
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003204 row.startChildAnimation(properties);
Selim Cinek0cfbef42016-11-09 19:06:36 -08003205 }
3206 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08003207 }
Selim Cinek817abe72017-05-24 11:08:55 -07003208
Selim Cinek459aee32019-02-20 11:18:56 -08003209 public void setAmbientGoingAway(boolean goingAway) {
3210 mAmbientGoingAway = goingAway;
3211 }
3212
Gustav Sennton8a52dc32019-04-15 12:48:23 +01003213 /**
3214 * Returns the Smart Suggestions backing the smart suggestion buttons in the notification.
3215 */
3216 public SmartRepliesAndActions getExistingSmartRepliesAndActions() {
3217 return mPrivateLayout.getCurrentSmartRepliesAndActions();
3218 }
3219
Selim Cinek817abe72017-05-24 11:08:55 -07003220 @VisibleForTesting
3221 protected void setChildrenContainer(NotificationChildrenContainer childrenContainer) {
3222 mChildrenContainer = childrenContainer;
3223 }
Geoffrey Pitsch409db272017-08-28 14:51:52 +00003224
Julia Reynoldsfc640012018-02-21 12:25:27 -05003225 @VisibleForTesting
3226 protected void setPrivateLayout(NotificationContentView privateLayout) {
3227 mPrivateLayout = privateLayout;
3228 }
3229
3230 @VisibleForTesting
3231 protected void setPublicLayout(NotificationContentView publicLayout) {
3232 mPublicLayout = publicLayout;
3233 }
3234
Geoffrey Pitsch409db272017-08-28 14:51:52 +00003235 /**
3236 * Equivalent to View.OnLongClickListener with coordinates
3237 */
3238 public interface LongPressListener {
3239 /**
3240 * Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
3241 * @return whether the longpress was handled
3242 */
3243 boolean onLongPress(View v, int x, int y, MenuItem item);
3244 }
Julia Reynoldsb5867452018-02-28 16:31:35 -05003245
3246 /**
3247 * Equivalent to View.OnClickListener with coordinates
3248 */
3249 public interface OnAppOpsClickListener {
3250 /**
3251 * Equivalent to {@link View.OnClickListener#onClick(View)} with coordinates
3252 * @return whether the click was handled
3253 */
3254 boolean onClick(View v, int x, int y, MenuItem item);
3255 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07003256
Selim Cinek30887662018-10-15 17:37:21 -07003257 @Override
3258 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3259 super.dump(fd, pw, args);
3260 pw.println(" Notification: " + getStatusBarNotification().getKey());
3261 pw.print(" visibility: " + getVisibility());
3262 pw.print(", alpha: " + getAlpha());
3263 pw.print(", translation: " + getTranslation());
3264 pw.print(", removed: " + isRemoved());
Selim Cinek0db74592018-12-05 17:42:51 -08003265 pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
Selim Cinek85a8f9f2018-11-21 13:58:27 -08003266 NotificationContentView showingLayout = getShowingLayout();
3267 pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
Selim Cinek30887662018-10-15 17:37:21 -07003268 pw.println();
Selim Cinek85a8f9f2018-11-21 13:58:27 -08003269 showingLayout.dump(fd, pw, args);
Selim Cinek30887662018-10-15 17:37:21 -07003270 pw.print(" ");
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003271 if (getViewState() != null) {
3272 getViewState().dump(fd, pw, args);
Selim Cinek30887662018-10-15 17:37:21 -07003273 } else {
3274 pw.print("no viewState!!!");
3275 }
3276 pw.println();
3277 pw.println();
3278 if (mIsSummaryWithChildren) {
Selim Cinek0db74592018-12-05 17:42:51 -08003279 pw.print(" ChildrenContainer");
3280 pw.print(" visibility: " + mChildrenContainer.getVisibility());
3281 pw.print(", alpha: " + mChildrenContainer.getAlpha());
3282 pw.print(", translationY: " + mChildrenContainer.getTranslationY());
3283 pw.println();
Selim Cinek30887662018-10-15 17:37:21 -07003284 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
3285 pw.println(" Children: " + notificationChildren.size());
3286 pw.println(" {");
3287 for(ExpandableNotificationRow child : notificationChildren) {
3288 child.dump(fd, pw, args);
3289 }
3290 pw.println(" }");
3291 pw.println();
3292 }
3293 }
3294
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07003295 /**
3296 * Background task for executing IPCs to check if the notification is a system notification. The
3297 * output is used for both the blocking helper and the notification info.
3298 */
3299 private class SystemNotificationAsyncTask extends AsyncTask<Void, Void, Boolean> {
3300
3301 @Override
3302 protected Boolean doInBackground(Void... voids) {
3303 return isSystemNotification(mContext, mStatusBarNotification);
3304 }
3305
3306 @Override
3307 protected void onPostExecute(Boolean result) {
Julia Reynoldsaa96cf32018-04-17 09:09:04 -04003308 if (mEntry != null) {
3309 mEntry.mIsSystemNotification = result;
3310 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07003311 }
3312 }
Chris Wren51c75102013-07-16 20:49:17 -04003313}