blob: c769daa735198855123fec05774d9fcbccb21ee8 [file] [log] [blame]
Chris Wren51c75102013-07-16 20:49:17 -04001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
Rohan Shah20790b82018-07-02 17:21:04 -070014 * limitations under the License
Chris Wren51c75102013-07-16 20:49:17 -040015 */
16
Rohan Shah20790b82018-07-02 17:21:04 -070017package com.android.systemui.statusbar.notification.row;
Chris Wren51c75102013-07-16 20:49:17 -040018
Dave Mankoffa4d195d2018-11-16 13:33:27 -050019import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
Ned Burns1a5e22f2019-02-14 15:11:52 -050020import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT;
21import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP;
22import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_PUBLIC;
23import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationCallback;
Dave Mankoffa4d195d2018-11-16 13:33:27 -050024import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
25import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
26import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
Selim Cinekc478f902017-02-22 20:55:44 -080027
Mady Mellor4b80b102016-01-22 08:03:58 -080028import android.animation.Animator;
29import android.animation.AnimatorListenerAdapter;
Mady Mellor4b80b102016-01-22 08:03:58 -080030import android.animation.ObjectAnimator;
Mady Mellor4b80b102016-01-22 08:03:58 -080031import android.animation.ValueAnimator.AnimatorUpdateListener;
Kevind4660b22018-09-27 10:57:35 -070032import android.annotation.NonNull;
Selim Cinekddf1b392016-05-27 16:33:10 -070033import android.annotation.Nullable;
Rohan Shah63411fc2018-03-28 19:05:52 -070034import android.app.NotificationChannel;
Chris Wren51c75102013-07-16 20:49:17 -040035import android.content.Context;
Rohan Shah63411fc2018-03-28 19:05:52 -070036import android.content.pm.PackageInfo;
37import android.content.pm.PackageManager;
Mady Mellor9d03a522017-04-04 18:45:30 -070038import android.content.res.Configuration;
Julia Reynoldsb5867452018-02-28 16:31:35 -050039import android.content.res.Resources;
Selim Cinek515b2032017-11-15 10:20:19 -080040import android.graphics.Path;
Selim Cinekcab4a602014-09-03 14:47:57 +020041import android.graphics.drawable.AnimatedVectorDrawable;
42import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010043import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020044import android.graphics.drawable.Drawable;
Rohan Shah4ed1b2a2018-03-30 13:26:01 -070045import android.os.AsyncTask;
Selim Cinekda42d652015-12-04 15:51:16 -080046import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070047import android.os.Bundle;
Kevin38ce6fa2018-10-17 16:00:14 -070048import android.os.SystemClock;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020049import android.service.notification.StatusBarNotification;
Julia Reynoldsfc640012018-02-21 12:25:27 -050050import android.util.ArraySet;
Chris Wren51c75102013-07-16 20:49:17 -040051import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070052import android.util.FloatProperty;
Rohan Shah63411fc2018-03-28 19:05:52 -070053import android.util.Log;
Selim Cinek2627d722018-01-19 12:16:49 -080054import android.util.MathUtils;
Mady Mellorb0a82462016-04-30 17:31:02 -070055import android.util.Property;
Geoffrey Pitsch409db272017-08-28 14:51:52 +000056import android.view.KeyEvent;
Selim Cinek01af3342016-02-09 19:25:31 -080057import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080058import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080059import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050060import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080061import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020062import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020063import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070064import android.view.accessibility.AccessibilityNodeInfo;
Mady Mellorb3a6aed2018-05-11 13:24:07 -070065import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Selim Cinek98713a42015-09-21 15:47:20 +020066import android.widget.Chronometer;
Mady Mellor95d743c2017-01-10 12:05:27 -080067import android.widget.FrameLayout;
Selim Cinekcab4a602014-09-03 14:47:57 +020068import android.widget.ImageView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080069import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010070
Selim Cinek5ba22542017-04-20 15:16:10 -070071import com.android.internal.annotations.VisibleForTesting;
Chris Wren698b1702016-05-23 11:16:32 -040072import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010073import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Lucas Dupina291d192018-06-07 13:59:42 -070074import com.android.internal.util.ContrastColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080075import com.android.internal.widget.CachingIconView;
Mady Mellor95d743c2017-01-10 12:05:27 -080076import com.android.systemui.Dependency;
Selim Cinek0242fbb2016-10-19 13:38:32 -070077import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050078import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070079import com.android.systemui.classifier.FalsingManager;
Mady Mellor95d743c2017-01-10 12:05:27 -080080import com.android.systemui.plugins.PluginListener;
Mady Mellor95d743c2017-01-10 12:05:27 -080081import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
82import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
Kevin38ce6fa2018-10-17 16:00:14 -070083import com.android.systemui.shared.plugins.PluginManager;
Beth Thibodeaueab4dde2019-02-07 11:37:02 -050084import com.android.systemui.statusbar.NotificationMediaManager;
Rohan Shah20790b82018-07-02 17:21:04 -070085import com.android.systemui.statusbar.RemoteInputController;
86import com.android.systemui.statusbar.StatusBarIconView;
Selim Cinek5cf1d052017-06-01 17:36:46 -070087import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
Selim Cinek2627d722018-01-19 12:16:49 -080088import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
Selim Cinek6743c0b2017-01-18 18:24:01 -080089import com.android.systemui.statusbar.notification.NotificationUtils;
Kevin38ce6fa2018-10-17 16:00:14 -070090import com.android.systemui.statusbar.notification.VisualStabilityManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050091import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Kevin38ce6fa2018-10-17 16:00:14 -070092import com.android.systemui.statusbar.notification.logging.NotificationCounters;
Ned Burns1a5e22f2019-02-14 15:11:52 -050093import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
Rohan Shah20790b82018-07-02 17:21:04 -070094import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
Rohan Shah20790b82018-07-02 17:21:04 -070095import com.android.systemui.statusbar.notification.stack.AmbientState;
96import com.android.systemui.statusbar.notification.stack.AnimationProperties;
97import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
98import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
Evan Laird94492852018-10-25 13:43:01 -040099import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
Kevin38ce6fa2018-10-17 16:00:14 -0700100import com.android.systemui.statusbar.phone.NotificationGroupManager;
101import com.android.systemui.statusbar.phone.StatusBar;
102import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100103
Selim Cinek30887662018-10-15 17:37:21 -0700104import java.io.FileDescriptor;
105import java.io.PrintWriter;
Mady Mellor4b80b102016-01-22 08:03:58 -0800106import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +0100107import java.util.List;
Ned Burns3da3c782019-01-08 21:14:39 -0500108import java.util.concurrent.TimeUnit;
Lucas Dupincecc7c22017-09-12 16:02:45 -0700109import java.util.function.BooleanSupplier;
Selim Cinek8875de12018-03-22 10:14:32 -0700110import java.util.function.Consumer;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500111
Rohan Shah63411fc2018-03-28 19:05:52 -0700112/**
113 * View representing a notification item - this can be either the individual child notification or
114 * the group summary (which contains 1 or more child notifications).
115 */
Mady Mellor95d743c2017-01-10 12:05:27 -0800116public class ExpandableNotificationRow extends ActivatableNotificationView
117 implements PluginListener<NotificationMenuRowPlugin> {
Selim Cinekb5605e52015-02-20 18:21:41 +0100118
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700119 private static final boolean DEBUG = false;
Selim Cinekb5605e52015-02-20 18:21:41 +0100120 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
121 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Mady Mellor95d743c2017-01-10 12:05:27 -0800122 private static final int MENU_VIEW_INDEX = 0;
Rohan Shah63411fc2018-03-28 19:05:52 -0700123 private static final String TAG = "ExpandableNotifRow";
felkachange6c03a02018-05-24 15:38:04 +0800124 public static final float DEFAULT_HEADER_VISIBLE_AMOUNT = 1.0f;
Ned Burns3da3c782019-01-08 21:14:39 -0500125 private static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
Selim Cinekab9c7b22018-12-11 18:15:47 -0800126 private boolean mUpdateBackgroundOnUpdate;
Nadia Benbernou7a18c812019-02-08 16:23:10 -0500127 private boolean mNotificationTranslationFinished = false;
Mady Mellor95d743c2017-01-10 12:05:27 -0800128
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700129 /**
130 * Listener for when {@link ExpandableNotificationRow} is laid out.
131 */
Mady Mellor035badd2017-04-04 18:45:30 -0700132 public interface LayoutListener {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700133 void onLayout();
Mady Mellor035badd2017-04-04 18:45:30 -0700134 }
135
136 private LayoutListener mLayoutListener;
Ned Burns1a5e22f2019-02-14 15:11:52 -0500137 private final NotificationContentInflater mNotificationInflater;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700138 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800139 private int mIconTransformContentShiftNoIcon;
Rohan Shahb9d500a2018-06-25 16:27:16 -0700140 private int mMaxHeadsUpHeightBeforeN;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800141 private int mMaxHeadsUpHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800142 private int mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800143 private int mMaxHeadsUpHeightIncreased;
Rohan Shahb9d500a2018-06-25 16:27:16 -0700144 private int mNotificationMinHeightBeforeN;
145 private int mNotificationMinHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800146 private int mNotificationMinHeight;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800147 private int mNotificationMinHeightLarge;
Beth Thibodeaucb395352019-01-25 15:39:54 -0500148 private int mNotificationMinHeightMedia;
Selim Cinek01af3342016-02-09 19:25:31 -0800149 private int mNotificationMaxHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -0700150 private int mIncreasedPaddingBetweenElements;
Selim Cinek2627d722018-01-19 12:16:49 -0800151 private int mNotificationLaunchHeight;
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100152 private boolean mMustStayOnScreen;
Chris Wren51c75102013-07-16 20:49:17 -0400153
Selim Cinek1685e632014-04-08 02:27:49 +0200154 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -0400155 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +0200156 /** Has the user actively changed the expansion state of this row */
157 private boolean mHasUserChangedExpansion;
158 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -0400159 private boolean mUserExpanded;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700160 /** Whether the blocking helper is showing on this notification (even if dismissed) */
161 private boolean mIsBlockingHelperShowing;
Selim Cinek31aada42015-12-18 17:51:15 -0800162
163 /**
164 * Has this notification been expanded while it was pinned
165 */
166 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +0200167 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -0400168 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +0200169 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -0500170 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +0200171 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -0800172 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +0200173 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700174 private boolean mHideSensitiveForIntrinsicHeight;
felkachange6c03a02018-05-24 15:38:04 +0800175 private float mHeaderVisibleAmount = DEFAULT_HEADER_VISIBLE_AMOUNT;
Chris Wren51c75102013-07-16 20:49:17 -0400176
Selim Cinek1685e632014-04-08 02:27:49 +0200177 /**
178 * Is this notification expanded by the system. The expansion state can be overridden by the
179 * user expansion.
180 */
181 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200182
183 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700184 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200185 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700186 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200187
Kevina97ea052018-09-11 13:53:18 -0700188 /**
189 * Whether or not the row is currently on the doze screen.
190 */
191 private boolean mOnAmbient;
192
Mady Mellorb0a82462016-04-30 17:31:02 -0700193 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800194 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200195 private NotificationContentView mPublicLayout;
196 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800197 private NotificationContentView[] mLayouts;
Selim Cinek4bb59342016-04-08 19:29:35 -0700198 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100199 private ExpansionLogger mLogger;
200 private String mLoggingKey;
Selim Cinek8d490d42015-04-10 00:05:50 -0700201 private NotificationGuts mGuts;
Ned Burnsf81c4c42019-01-07 14:10:43 -0500202 private NotificationEntry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200203 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700204 private String mAppName;
Kevina97ea052018-09-11 13:53:18 -0700205
206 /**
207 * Whether or not the notification is using the heads up view and should peek from the top.
208 */
Selim Cinek1a521f32014-11-03 17:39:29 +0100209 private boolean mIsHeadsUp;
Kevina97ea052018-09-11 13:53:18 -0700210
211 /**
212 * Whether or not the notification is using the ambient display view and is pulsing. This
213 * occurs when a high priority notification alerts while the phone is dozing or is on AOD.
214 */
215 private boolean mIsAmbientPulsing;
216
Kevin38ce6fa2018-10-17 16:00:14 -0700217 /**
Selim Cinek459aee32019-02-20 11:18:56 -0800218 * Happens when the notification was pulsing before and goes away to ensure smooth animations.
219 */
220 private boolean mAmbientGoingAway;
221
222 /**
Kevin38ce6fa2018-10-17 16:00:14 -0700223 * Whether or not the notification should be redacted on the lock screen, i.e has sensitive
224 * content which should be redacted on the lock screen.
225 */
226 private boolean mNeedsRedaction;
Selim Cinek98713a42015-09-21 15:47:20 +0200227 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100228 private ViewStub mChildrenContainerStub;
229 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100230 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700231 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100232 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor95d743c2017-01-10 12:05:27 -0800233 private NotificationMenuRowPlugin mMenuRow;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100234 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100235 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700236 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700237 private FalsingManager mFalsingManager;
Selim Cinek2627d722018-01-19 12:16:49 -0800238 private boolean mExpandAnimationRunning;
Selim Cinek5cf1d052017-06-01 17:36:46 -0700239 private AboveShelfChangedListener mAboveShelfChangedListener;
Selim Cinek31aada42015-12-18 17:51:15 -0800240 private HeadsUpManager mHeadsUpManager;
Selim Cinek8875de12018-03-22 10:14:32 -0700241 private Consumer<Boolean> mHeadsUpAnimatingAwayListener;
Selim Cinekc25989e2018-02-16 16:42:14 -0800242 private boolean mChildIsExpanding;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200243
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700244 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800245 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700246 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700247 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800248 private OnExpandClickListener mOnExpandClickListener;
Julia Reynoldsb5867452018-02-28 16:31:35 -0500249 private View.OnClickListener mOnAppOpsClickListener;
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000250
251 // Listener will be called when receiving a long click event.
252 // Use #setLongPressPosition to optionally assign positional data with the long press.
253 private LongPressListener mLongPressListener;
254
Mady Mellorb0a82462016-04-30 17:31:02 -0700255 private boolean mGroupExpansionChanging;
256
Anthony Chen6bf88a02017-04-10 14:41:44 -0700257 /**
Lucas Dupincecc7c22017-09-12 16:02:45 -0700258 * A supplier that returns true if keyguard is secure.
259 */
260 private BooleanSupplier mSecureStateProvider;
261
262 /**
Anthony Chen6bf88a02017-04-10 14:41:44 -0700263 * Whether or not a notification that is not part of a group of notifications can be manually
264 * expanded by the user.
265 */
266 private boolean mEnableNonGroupedNotificationExpand;
267
268 /**
269 * Whether or not to update the background of the header of the notification when its expanded.
270 * If {@code true}, the header background will disappear when expanded.
271 */
272 private boolean mShowGroupBackgroundWhenExpanded;
273
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800274 private OnClickListener mExpandClickListener = new OnClickListener() {
275 @Override
276 public void onClick(View v) {
Selim Cinek0b9cf462017-12-07 16:31:03 -0800277 if (!shouldShowPublic() && (!mIsLowPriority || isExpanded())
Selim Cinek414ad332017-02-24 19:06:12 -0800278 && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700279 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400280 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
281 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
282 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400283 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
284 nowExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -0800285 onExpansionChanged(true /* userAction */, wasExpanded);
Anthony Chen6bf88a02017-04-10 14:41:44 -0700286 } else if (mEnableNonGroupedNotificationExpand) {
Selim Cineke9bad242016-06-15 11:46:37 -0700287 if (v.isAccessibilityFocused()) {
288 mPrivateLayout.setFocusOnVisibilityChange();
289 }
Selim Cinek31aada42015-12-18 17:51:15 -0800290 boolean nowExpanded;
291 if (isPinned()) {
292 nowExpanded = !mExpandedWhenPinned;
293 mExpandedWhenPinned = nowExpanded;
294 } else {
295 nowExpanded = !isExpanded();
296 setUserExpanded(nowExpanded);
297 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800298 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800299 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400300 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
301 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800302 }
303 }
304 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700305 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700306 private boolean mDismissed;
307 private boolean mKeepInParent;
308 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700309 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
310 new FloatProperty<ExpandableNotificationRow>("translate") {
311 @Override
312 public void setValue(ExpandableNotificationRow object, float value) {
313 object.setTranslation(value);
314 }
315
316 @Override
317 public Float get(ExpandableNotificationRow object) {
318 return object.getTranslation();
319 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700320 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700321 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700322 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700323 private View mChildAfterViewWhenDismissed;
324 private View mGroupParentWhenDismissed;
325 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800326 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700327 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700328 private boolean mAboveShelf;
Selim Cinek875a3a12016-11-18 17:52:16 -0800329 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800330 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800331 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800332 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800333 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800334 private boolean mUseIncreasedHeadsUpHeight;
Selim Cinekef8c2252017-02-10 14:52:18 -0800335 private float mTranslationWhenRemoved;
336 private boolean mWasChildInGroupWhenRemoved;
Ahan Wude396fa2018-05-08 20:42:24 +0800337 private NotificationInlineImageResolver mImageResolver;
Beth Thibodeaueab4dde2019-02-07 11:37:02 -0500338 private NotificationMediaManager mMediaManager;
Mady Mellorb0a82462016-04-30 17:31:02 -0700339
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700340 private SystemNotificationAsyncTask mSystemNotificationAsyncTask =
341 new SystemNotificationAsyncTask();
Mady Mellorc3d6f7d2018-11-07 09:36:56 -0800342 private int mStatusBarState = -1;
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700343
344 /**
345 * Returns whether the given {@code statusBarNotification} is a system notification.
346 * <b>Note</b>, this should be run in the background thread if possible as it makes multiple IPC
347 * calls.
348 */
349 private static Boolean isSystemNotification(
350 Context context, StatusBarNotification statusBarNotification) {
351 PackageManager packageManager = StatusBar.getPackageManagerForUser(
352 context, statusBarNotification.getUser().getIdentifier());
353 Boolean isSystemNotification = null;
354
355 try {
356 PackageInfo packageInfo = packageManager.getPackageInfo(
357 statusBarNotification.getPackageName(), PackageManager.GET_SIGNATURES);
358
359 isSystemNotification =
360 com.android.settingslib.Utils.isSystemPackage(
361 context.getResources(), packageManager, packageInfo);
362 } catch (PackageManager.NameNotFoundException e) {
363 Log.e(TAG, "cacheIsSystemNotification: Could not find package info");
364 }
365 return isSystemNotification;
366 }
367
Mady Mellor43c2cd12016-12-12 21:05:13 -0800368 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700369 public boolean isGroupExpansionChanging() {
370 if (isChildInGroup()) {
371 return mNotificationParent.isGroupExpansionChanging();
372 }
373 return mGroupExpansionChanging;
374 }
375
376 public void setGroupExpansionChanging(boolean changing) {
377 mGroupExpansionChanging = changing;
378 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700379
Adrian Roos599be342016-06-13 14:54:39 -0700380 @Override
381 public void setActualHeightAnimating(boolean animating) {
382 if (mPrivateLayout != null) {
383 mPrivateLayout.setContentHeightAnimating(animating);
384 }
385 }
386
Selim Cinek8d490d42015-04-10 00:05:50 -0700387 public NotificationContentView getPrivateLayout() {
388 return mPrivateLayout;
389 }
390
391 public NotificationContentView getPublicLayout() {
392 return mPublicLayout;
393 }
394
Selim Cinekcab4a602014-09-03 14:47:57 +0200395 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800396 for (NotificationContentView l : mLayouts) {
397 setIconAnimationRunning(running, l);
398 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800399 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700400 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek414ad332017-02-24 19:06:12 -0800401 setIconAnimationRunningForChild(running, mChildrenContainer.getLowPriorityHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800402 List<ExpandableNotificationRow> notificationChildren =
403 mChildrenContainer.getNotificationChildren();
404 for (int i = 0; i < notificationChildren.size(); i++) {
405 ExpandableNotificationRow child = notificationChildren.get(i);
406 child.setIconAnimationRunning(running);
407 }
408 }
409 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200410 }
411
412 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
413 if (layout != null) {
414 View contractedChild = layout.getContractedChild();
415 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700416 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200417 setIconAnimationRunningForChild(running, contractedChild);
418 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700419 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200420 }
421 }
422
423 private void setIconAnimationRunningForChild(boolean running, View child) {
424 if (child != null) {
425 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
426 setIconRunning(icon, running);
427 ImageView rightIcon = (ImageView) child.findViewById(
428 com.android.internal.R.id.right_icon);
429 setIconRunning(rightIcon, running);
430 }
431 }
432
433 private void setIconRunning(ImageView imageView, boolean running) {
434 if (imageView != null) {
435 Drawable drawable = imageView.getDrawable();
436 if (drawable instanceof AnimationDrawable) {
437 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
438 if (running) {
439 animationDrawable.start();
440 } else {
441 animationDrawable.stop();
442 }
443 } else if (drawable instanceof AnimatedVectorDrawable) {
444 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
445 if (running) {
446 animationDrawable.start();
447 } else {
448 animationDrawable.stop();
449 }
450 }
451 }
452 }
453
Kevind4660b22018-09-27 10:57:35 -0700454 /**
455 * Set the entry for the row.
456 *
457 * @param entry the entry this row is tied to
458 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500459 public void setEntry(@NonNull NotificationEntry entry) {
Selim Cinekda42d652015-12-04 15:51:16 -0800460 mEntry = entry;
461 mStatusBarNotification = entry.notification;
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700462 cacheIsSystemNotification();
Rohan Shah63411fc2018-03-28 19:05:52 -0700463 }
464
465 /**
Kevin01a53cb2018-11-09 18:19:54 -0800466 * Inflate views based off the inflation flags set. Inflation happens asynchronously.
Kevind4660b22018-09-27 10:57:35 -0700467 */
468 public void inflateViews() {
469 mNotificationInflater.inflateNotificationViews();
470 }
471
472 /**
Kevind5022f92018-10-08 18:30:26 -0700473 * Marks a content view as freeable, setting it so that future inflations do not reinflate
474 * and ensuring that the view is freed when it is safe to remove.
475 *
476 * @param inflationFlag flag corresponding to the content view to be freed
477 */
478 public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) {
479 // View should not be reinflated in the future
480 updateInflationFlag(inflationFlag, false);
481 Runnable freeViewRunnable = () ->
482 mNotificationInflater.freeNotificationView(inflationFlag);
483 switch (inflationFlag) {
484 case FLAG_CONTENT_VIEW_HEADS_UP:
485 getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_HEADSUP,
486 freeViewRunnable);
487 break;
488 case FLAG_CONTENT_VIEW_AMBIENT:
489 getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT,
490 freeViewRunnable);
491 getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT,
492 freeViewRunnable);
493 break;
Kevin38ce6fa2018-10-17 16:00:14 -0700494 case FLAG_CONTENT_VIEW_PUBLIC:
495 getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_CONTRACTED,
496 freeViewRunnable);
Kevind5022f92018-10-08 18:30:26 -0700497 default:
498 break;
499 }
500 }
501
502 /**
Kevind4660b22018-09-27 10:57:35 -0700503 * Update whether or not a content view should be inflated.
504 *
505 * @param flag the flag corresponding to the content view
506 * @param shouldInflate true if it should be inflated, false if it should not
507 */
508 public void updateInflationFlag(@InflationFlag int flag, boolean shouldInflate) {
509 mNotificationInflater.updateInflationFlag(flag, shouldInflate);
510 }
511
512 /**
Kevin01a53cb2018-11-09 18:19:54 -0800513 * Whether or not a content view should be inflated.
514 *
515 * @param flag the flag corresponding to the content view
516 * @return true if the flag is set, false otherwise
517 */
518 public boolean isInflationFlagSet(@InflationFlag int flag) {
519 return mNotificationInflater.isInflationFlagSet(flag);
520 }
521
522 /**
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700523 * Caches whether or not this row contains a system notification. Note, this is only cached
524 * once per notification as the packageInfo can't technically change for a notification row.
Rohan Shah63411fc2018-03-28 19:05:52 -0700525 */
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700526 private void cacheIsSystemNotification() {
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400527 if (mEntry != null && mEntry.mIsSystemNotification == null) {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700528 if (mSystemNotificationAsyncTask.getStatus() == AsyncTask.Status.PENDING) {
529 // Run async task once, only if it hasn't already been executed. Note this is
530 // executed in serial - no need to parallelize this small task.
531 mSystemNotificationAsyncTask.execute();
Rohan Shah63411fc2018-03-28 19:05:52 -0700532 }
533 }
534 }
535
536 /**
Rohan Shahca0447e2018-03-30 15:18:27 -0700537 * Returns whether this row is considered non-blockable (i.e. it's a non-blockable system notif
538 * or is in a whitelist).
Rohan Shah63411fc2018-03-28 19:05:52 -0700539 */
540 public boolean getIsNonblockable() {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700541 boolean isNonblockable = Dependency.get(NotificationBlockingHelperManager.class)
Julia Reynolds0abae112018-06-08 10:36:57 -0400542 .isNonblockable(mStatusBarNotification.getPackageName(),
543 mEntry.channel.getId());
Rohan Shah63411fc2018-03-28 19:05:52 -0700544
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700545 // If the SystemNotifAsyncTask hasn't finished running or retrieved a value, we'll try once
546 // again, but in-place on the main thread this time. This should rarely ever get called.
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400547 if (mEntry != null && mEntry.mIsSystemNotification == null) {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700548 if (DEBUG) {
549 Log.d(TAG, "Retrieving isSystemNotification on main thread");
550 }
551 mSystemNotificationAsyncTask.cancel(true /* mayInterruptIfRunning */);
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400552 mEntry.mIsSystemNotification = isSystemNotification(mContext, mStatusBarNotification);
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700553 }
554
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400555 if (!isNonblockable && mEntry != null && mEntry.mIsSystemNotification != null) {
556 if (mEntry.mIsSystemNotification) {
Rohan Shah63411fc2018-03-28 19:05:52 -0700557 if (mEntry.channel != null
558 && !mEntry.channel.isBlockableSystem()) {
559 isNonblockable = true;
560 }
561 }
562 }
563 return isNonblockable;
Selim Cinekc478f902017-02-22 20:55:44 -0800564 }
565
Selim Cinek5ba22542017-04-20 15:16:10 -0700566 public void onNotificationUpdated() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800567 for (NotificationContentView l : mLayouts) {
Selim Cinekc478f902017-02-22 20:55:44 -0800568 l.onNotificationUpdated(mEntry);
Adrian Rooseb434ff2017-01-11 11:18:48 -0800569 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800570 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800571 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700572 updateNotificationColor();
Mady Mellor4c197602017-04-10 17:57:52 -0700573 if (mMenuRow != null) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700574 mMenuRow.onNotificationUpdated(mStatusBarNotification);
Beverly3f56f052018-05-08 14:56:03 -0400575 mMenuRow.setAppName(mAppName);
Mady Mellor4c197602017-04-10 17:57:52 -0700576 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800577 if (mIsSummaryWithChildren) {
Selim Cinek414ad332017-02-24 19:06:12 -0800578 mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
Selim Cinekc897bd32016-03-18 17:32:31 -0700579 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800580 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800581 if (mIconAnimationRunning) {
582 setIconAnimationRunning(true);
583 }
Kevin38ce6fa2018-10-17 16:00:14 -0700584 if (mLastChronometerRunning) {
585 setChronometerRunning(true);
586 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800587 if (mNotificationParent != null) {
588 mNotificationParent.updateChildrenHeaderAppearance();
589 }
Selim Cinek263398f2015-10-21 17:40:23 -0700590 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800591 // The public layouts expand button is always visible
592 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800593 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700594 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800595 updateShelfIconColor();
Selim Cinekfe24fb72018-02-13 14:34:55 -0800596 updateRippleAllowed();
Selim Cinekab9c7b22018-12-11 18:15:47 -0800597 if (mUpdateBackgroundOnUpdate) {
598 mUpdateBackgroundOnUpdate = false;
599 updateBackgroundColors();
600 }
Selim Cinek6743c0b2017-01-18 18:24:01 -0800601 }
602
Gus Prevas33fbc152018-12-04 13:17:32 -0500603 /** Called when the notification's ranking was changed (but nothing else changed). */
604 public void onNotificationRankingUpdated() {
605 if (mMenuRow != null) {
606 mMenuRow.onNotificationUpdated(mStatusBarNotification);
607 }
608 }
609
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700610 @VisibleForTesting
611 void updateShelfIconColor() {
Selim Cinek6743c0b2017-01-18 18:24:01 -0800612 StatusBarIconView expandedIcon = mEntry.expandedIcon;
613 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
614 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
Lucas Dupina291d192018-06-07 13:59:42 -0700615 ContrastColorUtil.getInstance(mContext));
Selim Cinek875ba9b2017-02-13 16:20:17 -0800616 int color = StatusBarIconView.NO_COLOR;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800617 if (colorize) {
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700618 NotificationHeaderView header = getVisibleNotificationHeader();
619 if (header != null) {
620 color = header.getOriginalIconColor();
621 } else {
622 color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
623 getBackgroundColorWithoutTint());
624 }
Selim Cinek6743c0b2017-01-18 18:24:01 -0800625 }
Selim Cinek875ba9b2017-02-13 16:20:17 -0800626 expandedIcon.setStaticDrawableColor(color);
Selim Cinekda42d652015-12-04 15:51:16 -0800627 }
628
Selim Cinek5cf1d052017-06-01 17:36:46 -0700629 public void setAboveShelfChangedListener(AboveShelfChangedListener aboveShelfChangedListener) {
630 mAboveShelfChangedListener = aboveShelfChangedListener;
631 }
632
Lucas Dupincecc7c22017-09-12 16:02:45 -0700633 /**
634 * Sets a supplier that can determine whether the keyguard is secure or not.
635 * @param secureStateProvider A function that returns true if keyguard is secure.
636 */
637 public void setSecureStateProvider(BooleanSupplier secureStateProvider) {
638 mSecureStateProvider = secureStateProvider;
639 }
640
Selim Cinek4705f292017-04-24 22:18:48 -0700641 @Override
642 public boolean isDimmable() {
643 if (!getShowingLayout().isDimmable()) {
644 return false;
645 }
646 return super.isDimmable();
647 }
648
Selim Cinekda42d652015-12-04 15:51:16 -0800649 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800650 for (NotificationContentView l : mLayouts) {
651 updateLimitsForView(l);
652 }
Selim Cineka1744872016-03-11 15:36:06 -0800653 }
654
655 private void updateLimitsForView(NotificationContentView layout) {
Kevin38ce6fa2018-10-17 16:00:14 -0700656 boolean customView = layout.getContractedChild() != null
657 && layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800658 != com.android.internal.R.id.status_bar_latest_event_content;
659 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800660 boolean beforeP = mEntry.targetSdk < Build.VERSION_CODES.P;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800661 int minHeight;
Beth Thibodeaucb395352019-01-25 15:39:54 -0500662
663 View expandedView = layout.getExpandedChild();
664 boolean isMediaLayout = expandedView != null
665 && expandedView.findViewById(com.android.internal.R.id.media_actions) != null;
Beth Thibodeaueab4dde2019-02-07 11:37:02 -0500666 boolean showCompactMediaSeekbar = mMediaManager.getShowCompactMediaSeekbar();
Beth Thibodeaucb395352019-01-25 15:39:54 -0500667
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800668 if (customView && beforeP && !mIsSummaryWithChildren) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700669 minHeight = beforeN ? mNotificationMinHeightBeforeN : mNotificationMinHeightBeforeP;
Beth Thibodeaueab4dde2019-02-07 11:37:02 -0500670 } else if (isMediaLayout && showCompactMediaSeekbar) {
Beth Thibodeaucb395352019-01-25 15:39:54 -0500671 minHeight = mNotificationMinHeightMedia;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800672 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
673 minHeight = mNotificationMinHeightLarge;
674 } else {
675 minHeight = mNotificationMinHeight;
676 }
Selim Cineka1744872016-03-11 15:36:06 -0800677 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
678 layout.getHeadsUpChild().getId()
679 != com.android.internal.R.id.status_bar_latest_event_content;
Rohan Shahb9d500a2018-06-25 16:27:16 -0700680 int headsUpHeight;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800681 if (headsUpCustom && beforeP) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700682 headsUpHeight = beforeN ? mMaxHeadsUpHeightBeforeN : mMaxHeadsUpHeightBeforeP;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800683 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700684 headsUpHeight = mMaxHeadsUpHeightIncreased;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800685 } else {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700686 headsUpHeight = mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800687 }
Selim Cineke62255c2017-09-28 18:23:23 -0700688 NotificationViewWrapper headsUpWrapper = layout.getVisibleWrapper(
Kevind5022f92018-10-08 18:30:26 -0700689 VISIBLE_TYPE_HEADSUP);
Selim Cineke62255c2017-09-28 18:23:23 -0700690 if (headsUpWrapper != null) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700691 headsUpHeight = Math.max(headsUpHeight, headsUpWrapper.getMinLayoutHeight());
Selim Cineke62255c2017-09-28 18:23:23 -0700692 }
Lucas Dupin00be88f2019-01-03 17:50:52 -0800693 layout.setHeights(minHeight, headsUpHeight, mNotificationMaxHeight, headsUpHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200694 }
695
696 public StatusBarNotification getStatusBarNotification() {
697 return mStatusBarNotification;
698 }
699
Ned Burnsf81c4c42019-01-07 14:10:43 -0500700 public NotificationEntry getEntry() {
Selim Cinek281c2022016-10-13 19:14:43 -0700701 return mEntry;
702 }
703
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700704 public boolean isHeadsUp() {
705 return mIsHeadsUp;
706 }
707
Selim Cinek1a521f32014-11-03 17:39:29 +0100708 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinek5cf1d052017-06-01 17:36:46 -0700709 boolean wasAboveShelf = isAboveShelf();
Selim Cinekc80fdb12015-04-13 15:09:08 -0700710 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100711 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700712 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700713 if (mIsSummaryWithChildren) {
714 // The overflow might change since we allow more lines as HUN.
715 mChildrenContainer.updateGroupOverflow();
716 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700717 if (intrinsicBefore != getIntrinsicHeight()) {
718 notifyHeightChanged(false /* needsAnimation */);
719 }
Selim Cinekd127d792016-11-01 19:11:41 -0700720 if (isHeadsUp) {
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100721 mMustStayOnScreen = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700722 setAboveShelf(true);
Kevind5022f92018-10-08 18:30:26 -0700723 } else if (isAboveShelf() != wasAboveShelf) {
724 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
Selim Cinekd127d792016-11-01 19:11:41 -0700725 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100726 }
727
Selim Cinek5040f2e2019-02-14 18:22:42 -0800728 @Override
Selim Cinek459aee32019-02-20 11:18:56 -0800729 public boolean showingAmbientPulsing() {
730 return mIsAmbientPulsing || mAmbientGoingAway;
Kevina97ea052018-09-11 13:53:18 -0700731 }
732
733 public void setAmbientPulsing(boolean isAmbientPulsing) {
734 mIsAmbientPulsing = isAmbientPulsing;
735 }
736
Selim Cinekb5605e52015-02-20 18:21:41 +0100737 public void setGroupManager(NotificationGroupManager groupManager) {
738 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700739 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100740 }
741
Adrian Roosb88b1a12015-12-09 18:51:05 -0800742 public void setRemoteInputController(RemoteInputController r) {
743 mPrivateLayout.setRemoteInputController(r);
744 }
745
Mady Mellor3fd273e2016-03-15 21:08:14 -0700746 public void setAppName(String appName) {
747 mAppName = appName;
Mady Mellor95d743c2017-01-10 12:05:27 -0800748 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800749 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700750 }
751 }
752
Selim Cinekb5605e52015-02-20 18:21:41 +0100753 public void addChildNotification(ExpandableNotificationRow row) {
754 addChildNotification(row, -1);
755 }
756
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800757 /**
758 * Set the how much the header should be visible. A value of 0 will make the header fully gone
759 * and a value of 1 will make the notification look just like normal.
760 * This is being used for heads up notifications, when they are pinned to the top of the screen
761 * and the header content is extracted to the statusbar.
762 *
763 * @param headerVisibleAmount the amount the header should be visible.
764 */
765 public void setHeaderVisibleAmount(float headerVisibleAmount) {
766 if (mHeaderVisibleAmount != headerVisibleAmount) {
767 mHeaderVisibleAmount = headerVisibleAmount;
768 mPrivateLayout.setHeaderVisibleAmount(headerVisibleAmount);
769 if (mChildrenContainer != null) {
770 mChildrenContainer.setHeaderVisibleAmount(headerVisibleAmount);
771 }
772 notifyHeightChanged(false /* needsAnimation */);
773 }
774 }
775
Selim Cinek99e9adf2018-03-15 09:17:47 -0700776 @Override
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800777 public float getHeaderVisibleAmount() {
778 return mHeaderVisibleAmount;
779 }
780
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100781 @Override
782 public void setHeadsUpIsVisible() {
783 super.setHeadsUpIsVisible();
784 mMustStayOnScreen = false;
785 }
786
Selim Cinekb5605e52015-02-20 18:21:41 +0100787 /**
788 * Add a child notification to this view.
789 *
790 * @param row the row to add
791 * @param childIndex the index to add it at, if -1 it will be added at the end
792 */
793 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
794 if (mChildrenContainer == null) {
795 mChildrenContainerStub.inflate();
796 }
797 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700798 onChildrenCountChanged();
799 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100800 }
801
802 public void removeChildNotification(ExpandableNotificationRow row) {
803 if (mChildrenContainer != null) {
804 mChildrenContainer.removeNotification(row);
805 }
Selim Cinek263398f2015-10-21 17:40:23 -0700806 onChildrenCountChanged();
807 row.setIsChildInGroup(false, null);
Selim Cinek2871bef2017-11-22 08:40:00 -0800808 row.setBottomRoundness(0.0f, false /* animate */);
Selim Cinek263398f2015-10-21 17:40:23 -0700809 }
810
Mady Mellor43c2cd12016-12-12 21:05:13 -0800811 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700812 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700813 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700814 }
815
Rohan Shah524cf7b2018-03-15 14:40:02 -0700816 /**
817 * @return whether this notification is the only child in the group summary
818 */
819 public boolean isOnlyChildInGroup() {
820 return mGroupManager.isOnlyChildInGroup(getStatusBarNotification());
821 }
822
Selim Cinek388df6d2015-10-22 13:25:11 -0700823 public ExpandableNotificationRow getNotificationParent() {
824 return mNotificationParent;
825 }
826
Selim Cinek263398f2015-10-21 17:40:23 -0700827 /**
828 * @param isChildInGroup Is this notification now in a group
829 * @param parent the new parent notification
830 */
Selim Cinekc25989e2018-02-16 16:42:14 -0800831 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500832 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cinekc25989e2018-02-16 16:42:14 -0800833 if (mExpandAnimationRunning && !isChildInGroup && mNotificationParent != null) {
834 mNotificationParent.setChildIsExpanding(false);
835 mNotificationParent.setExtraWidthForClipping(0.0f);
836 mNotificationParent.setMinimumHeightForClipping(0);
837 }
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700838 mNotificationParent = childInGroup ? parent : null;
839 mPrivateLayout.setIsChildInGroup(childInGroup);
Selim Cinek5ba22542017-04-20 15:16:10 -0700840 mNotificationInflater.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400841 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700842 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700843 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700844 if (mNotificationParent != null) {
Selim Cinek9ce32852017-02-15 16:21:10 -0800845 setOverrideTintColor(NO_COLOR, 0.0f);
Selim Cinekeccf4942018-05-30 09:55:36 -0700846 // Let's reset the distance to top roundness, as this isn't applied to group children
847 setDistanceToTopRoundness(NO_ROUNDNESS);
Mady Mellorb0a82462016-04-30 17:31:02 -0700848 mNotificationParent.updateBackgroundForGroupState();
849 }
Selim Cinekdb167372016-11-17 15:41:17 -0800850 updateIconVisibilities();
Selim Cinek2871bef2017-11-22 08:40:00 -0800851 updateBackgroundClipping();
Selim Cinek34d93b02015-10-22 12:30:38 -0700852 }
853
854 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800855 public boolean onTouchEvent(MotionEvent event) {
856 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
857 || !isChildInGroup() || isGroupExpanded()) {
858 return super.onTouchEvent(event);
859 } else {
860 return false;
861 }
862 }
863
864 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800865 protected boolean handleSlideBack() {
Mady Mellor95d743c2017-01-10 12:05:27 -0800866 if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800867 animateTranslateNotification(0 /* targetLeft */);
868 return true;
869 }
870 return false;
871 }
872
873 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700874 protected boolean shouldHideBackground() {
875 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700876 }
877
878 @Override
879 public boolean isSummaryWithChildren() {
880 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100881 }
882
883 @Override
884 public boolean areChildrenExpanded() {
885 return mChildrenExpanded;
886 }
887
888 public List<ExpandableNotificationRow> getNotificationChildren() {
889 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
890 }
891
Selim Cinekeef84282015-10-30 16:28:00 -0700892 public int getNumberOfNotificationChildren() {
893 if (mChildrenContainer == null) {
894 return 0;
895 }
896 return mChildrenContainer.getNotificationChildren().size();
897 }
898
Selim Cinekb5605e52015-02-20 18:21:41 +0100899 /**
900 * Apply the order given in the list to the children.
901 *
902 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800903 * @param visualStabilityManager
904 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100905 * @return whether the list order has changed
906 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800907 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
908 VisualStabilityManager visualStabilityManager,
909 VisualStabilityManager.Callback callback) {
910 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
911 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100912 }
913
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500914 /** Updates states of all children. */
915 public void updateChildrenStates(AmbientState ambientState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700916 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500917 ExpandableViewState parentState = getViewState();
918 mChildrenContainer.updateState(parentState, ambientState);
Selim Cinekb5605e52015-02-20 18:21:41 +0100919 }
920 }
921
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500922 /** Applies children states. */
923 public void applyChildrenState() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700924 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500925 mChildrenContainer.applyState();
Selim Cinekb5605e52015-02-20 18:21:41 +0100926 }
927 }
928
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500929 /** Prepares expansion changed. */
930 public void prepareExpansionChanged() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700931 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500932 mChildrenContainer.prepareExpansionChanged();
Selim Cinekb5605e52015-02-20 18:21:41 +0100933 }
934 }
935
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500936 /** Starts child animations. */
937 public void startChildAnimation(AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700938 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500939 mChildrenContainer.startAnimationToState(properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100940 }
941 }
942
943 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800944 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100945 return this;
946 } else {
947 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
948 return view == null ? this : view;
949 }
950 }
951
Selim Cinekab29aeb2015-02-20 18:18:32 +0100952 public NotificationGuts getGuts() {
953 return mGuts;
954 }
955
Selim Cinek684a4422015-04-15 16:18:39 -0700956 /**
957 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
958 * the notification will be rendered on top of the screen.
959 *
960 * @param pinned whether it is pinned
961 */
962 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700963 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek5cf1d052017-06-01 17:36:46 -0700964 boolean wasAboveShelf = isAboveShelf();
Selim Cinek684a4422015-04-15 16:18:39 -0700965 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700966 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700967 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700968 }
Selim Cinek31aada42015-12-18 17:51:15 -0800969 if (pinned) {
970 setIconAnimationRunning(true);
971 mExpandedWhenPinned = false;
972 } else if (mExpandedWhenPinned) {
973 setUserExpanded(true);
974 }
Selim Cinek98713a42015-09-21 15:47:20 +0200975 setChronometerRunning(mLastChronometerRunning);
Selim Cinek5cf1d052017-06-01 17:36:46 -0700976 if (isAboveShelf() != wasAboveShelf) {
977 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
978 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700979 }
980
Selim Cinek29aab962018-02-27 17:05:45 -0800981 @Override
Selim Cinek684a4422015-04-15 16:18:39 -0700982 public boolean isPinned() {
983 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700984 }
985
Selim Cinekd127d792016-11-01 19:11:41 -0700986 @Override
987 public int getPinnedHeadsUpHeight() {
988 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
989 }
990
Selim Cinek31aada42015-12-18 17:51:15 -0800991 /**
992 * @param atLeastMinHeight should the value returned be at least the minimum height.
993 * Used to avoid cyclic calls
994 * @return the height of the heads up notification when pinned
995 */
Selim Cinekd127d792016-11-01 19:11:41 -0700996 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800997 if (mIsSummaryWithChildren) {
998 return mChildrenContainer.getIntrinsicHeight();
999 }
Selim Cinek31aada42015-12-18 17:51:15 -08001000 if(mExpandedWhenPinned) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08001001 return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
Selim Cinek31aada42015-12-18 17:51:15 -08001002 } else if (atLeastMinHeight) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08001003 return Math.max(getCollapsedHeight(), getHeadsUpHeight());
Selim Cinek31aada42015-12-18 17:51:15 -08001004 } else {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08001005 return getHeadsUpHeight();
Selim Cinek31aada42015-12-18 17:51:15 -08001006 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001007 }
1008
Jorim Jaggi5eb67c22015-08-19 19:50:49 -07001009 /**
1010 * Mark whether this notification was just clicked, i.e. the user has just clicked this
1011 * notification in this frame.
1012 */
1013 public void setJustClicked(boolean justClicked) {
1014 mJustClicked = justClicked;
1015 }
1016
1017 /**
1018 * @return true if this notification has been clicked in this frame, false otherwise
1019 */
1020 public boolean wasJustClicked() {
1021 return mJustClicked;
1022 }
1023
Selim Cinek98713a42015-09-21 15:47:20 +02001024 public void setChronometerRunning(boolean running) {
1025 mLastChronometerRunning = running;
1026 setChronometerRunning(running, mPrivateLayout);
1027 setChronometerRunning(running, mPublicLayout);
1028 if (mChildrenContainer != null) {
1029 List<ExpandableNotificationRow> notificationChildren =
1030 mChildrenContainer.getNotificationChildren();
1031 for (int i = 0; i < notificationChildren.size(); i++) {
1032 ExpandableNotificationRow child = notificationChildren.get(i);
1033 child.setChronometerRunning(running);
1034 }
1035 }
1036 }
1037
1038 private void setChronometerRunning(boolean running, NotificationContentView layout) {
1039 if (layout != null) {
1040 running = running || isPinned();
1041 View contractedChild = layout.getContractedChild();
1042 View expandedChild = layout.getExpandedChild();
1043 View headsUpChild = layout.getHeadsUpChild();
1044 setChronometerRunningForChild(running, contractedChild);
1045 setChronometerRunningForChild(running, expandedChild);
1046 setChronometerRunningForChild(running, headsUpChild);
1047 }
1048 }
1049
1050 private void setChronometerRunningForChild(boolean running, View child) {
1051 if (child != null) {
1052 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
1053 if (chronometer instanceof Chronometer) {
1054 ((Chronometer) chronometer).setStarted(running);
1055 }
1056 }
1057 }
1058
Selim Cinekea4bef72015-12-02 15:51:10 -08001059 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -07001060 if (mIsSummaryWithChildren) {
1061 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -07001062 }
Selim Cinekea4bef72015-12-02 15:51:10 -08001063 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -07001064 }
1065
Selim Cinek414ad332017-02-24 19:06:12 -08001066 /**
1067 * @return the currently visible notification header. This can be different from
1068 * {@link #getNotificationHeader()} in case it is a low-priority group.
1069 */
1070 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08001071 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek414ad332017-02-24 19:06:12 -08001072 return mChildrenContainer.getVisibleHeader();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001073 }
1074 return getShowingLayout().getVisibleNotificationHeader();
1075 }
1076
Selim Cinekb26afa32017-06-29 10:28:17 +02001077
1078 /**
1079 * @return the contracted notification header. This can be different from
1080 * {@link #getNotificationHeader()} and also {@link #getVisibleNotificationHeader()} and only
1081 * returns the contracted version.
1082 */
1083 public NotificationHeaderView getContractedNotificationHeader() {
1084 if (mIsSummaryWithChildren) {
1085 return mChildrenContainer.getHeaderView();
1086 }
1087 return mPrivateLayout.getContractedNotificationHeader();
1088 }
1089
Selim Cinek570981d2015-12-01 11:37:01 -08001090 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
1091 mOnExpandClickListener = onExpandClickListener;
1092 }
1093
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001094 public void setLongPressListener(LongPressListener longPressListener) {
1095 mLongPressListener = longPressListener;
1096 }
1097
Selim Cinekddf1b392016-05-27 16:33:10 -07001098 @Override
1099 public void setOnClickListener(@Nullable OnClickListener l) {
1100 super.setOnClickListener(l);
1101 mOnClickListener = l;
1102 updateClickAndFocus();
1103 }
1104
1105 private void updateClickAndFocus() {
1106 boolean normalChild = !isChildInGroup() || isGroupExpanded();
1107 boolean clickable = mOnClickListener != null && normalChild;
1108 if (isFocusable() != normalChild) {
1109 setFocusable(normalChild);
1110 }
1111 if (isClickable() != clickable) {
1112 setClickable(clickable);
1113 }
1114 }
1115
Selim Cinek31aada42015-12-18 17:51:15 -08001116 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
1117 mHeadsUpManager = headsUpManager;
1118 }
1119
Gustav Senntond0e84532018-12-03 16:48:36 +00001120 public HeadsUpManager getHeadsUpManager() {
1121 return mHeadsUpManager;
1122 }
1123
Mady Mellor87d79452017-01-10 11:52:52 -08001124 public void setGutsView(MenuItem item) {
Rohan Shah20790b82018-07-02 17:21:04 -07001125 if (mGuts != null && item.getGutsView() instanceof NotificationGuts.GutsContent) {
1126 ((NotificationGuts.GutsContent) item.getGutsView()).setGutsParent(mGuts);
1127 mGuts.setGutsContent((NotificationGuts.GutsContent) item.getGutsView());
Mady Mellor87d79452017-01-10 11:52:52 -08001128 }
1129 }
1130
Mady Mellor95d743c2017-01-10 12:05:27 -08001131 @Override
1132 protected void onAttachedToWindow() {
1133 super.onAttachedToWindow();
Aaron Heuckroth1dd67cb2018-06-14 14:28:08 -04001134 mEntry.setInitializationTime(SystemClock.elapsedRealtime());
Mady Mellor95d743c2017-01-10 12:05:27 -08001135 Dependency.get(PluginManager.class).addPluginListener(this,
1136 NotificationMenuRowPlugin.class, false /* Allow multiple */);
1137 }
1138
1139 @Override
1140 protected void onDetachedFromWindow() {
1141 super.onDetachedFromWindow();
1142 Dependency.get(PluginManager.class).removePluginListener(this);
1143 }
1144
1145 @Override
1146 public void onPluginConnected(NotificationMenuRowPlugin plugin, Context pluginContext) {
1147 boolean existed = mMenuRow.getMenuView() != null;
1148 if (existed) {
1149 removeView(mMenuRow.getMenuView());
1150 }
1151 mMenuRow = plugin;
Aaron Heuckroth266cb342018-09-07 14:52:04 -04001152 if (mMenuRow.shouldUseDefaultMenuItems()) {
Mady Mellor4c197602017-04-10 17:57:52 -07001153 ArrayList<MenuItem> items = new ArrayList<>();
1154 items.add(NotificationMenuRow.createInfoItem(mContext));
1155 items.add(NotificationMenuRow.createSnoozeItem(mContext));
Julia Reynoldsb5867452018-02-28 16:31:35 -05001156 items.add(NotificationMenuRow.createAppOpsItem(mContext));
Mady Mellor4c197602017-04-10 17:57:52 -07001157 mMenuRow.setMenuItems(items);
Mady Mellor95d743c2017-01-10 12:05:27 -08001158 }
1159 if (existed) {
1160 createMenu();
1161 }
1162 }
1163
1164 @Override
1165 public void onPluginDisconnected(NotificationMenuRowPlugin plugin) {
1166 boolean existed = mMenuRow.getMenuView() != null;
1167 mMenuRow = new NotificationMenuRow(mContext); // Back to default
1168 if (existed) {
1169 createMenu();
1170 }
1171 }
1172
1173 public NotificationMenuRowPlugin createMenu() {
1174 if (mMenuRow.getMenuView() == null) {
Mady Mellor4ab28202017-06-06 11:42:50 -07001175 mMenuRow.createMenu(this, mStatusBarNotification);
Mady Mellor95d743c2017-01-10 12:05:27 -08001176 mMenuRow.setAppName(mAppName);
1177 FrameLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
1178 LayoutParams.MATCH_PARENT);
1179 addView(mMenuRow.getMenuView(), MENU_VIEW_INDEX, lp);
1180 }
1181 return mMenuRow;
1182 }
1183
Mady Mellor95d743c2017-01-10 12:05:27 -08001184 public NotificationMenuRowPlugin getProvider() {
1185 return mMenuRow;
1186 }
1187
Anthony Chen9fe1ee72017-04-07 13:53:37 -07001188 @Override
Selim Cinek1a48bab2017-02-17 19:38:40 -08001189 public void onDensityOrFontScaleChanged() {
Anthony Chen9fe1ee72017-04-07 13:53:37 -07001190 super.onDensityOrFontScaleChanged();
Selim Cinek01af3342016-02-09 19:25:31 -08001191 initDimens();
Anthony Chenad4d1582017-04-10 16:07:58 -07001192 initBackground();
Lucas Dupinf03e7522018-06-25 16:21:13 -07001193 reInflateViews();
1194 }
1195
1196 private void reInflateViews() {
Selim Cinek817abe72017-05-24 11:08:55 -07001197 // Let's update our childrencontainer. This is intentionally not guarded with
1198 // mIsSummaryWithChildren since we might have had children but not anymore.
1199 if (mChildrenContainer != null) {
1200 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -08001201 }
1202 if (mGuts != null) {
1203 View oldGuts = mGuts;
1204 int index = indexOfChild(oldGuts);
1205 removeView(oldGuts);
1206 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
1207 R.layout.notification_guts, this, false);
1208 mGuts.setVisibility(oldGuts.getVisibility());
1209 addView(mGuts, index);
1210 }
Mady Mellor95d743c2017-01-10 12:05:27 -08001211 View oldMenu = mMenuRow.getMenuView();
1212 if (oldMenu != null) {
Mady Mellor761cde12017-01-10 11:36:39 -08001213 int menuIndex = indexOfChild(oldMenu);
1214 removeView(oldMenu);
Mady Mellor4ab28202017-06-06 11:42:50 -07001215 mMenuRow.createMenu(ExpandableNotificationRow.this, mStatusBarNotification);
Mady Mellor761cde12017-01-10 11:36:39 -08001216 mMenuRow.setAppName(mAppName);
Mady Mellor95d743c2017-01-10 12:05:27 -08001217 addView(mMenuRow.getMenuView(), menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -08001218 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001219 for (NotificationContentView l : mLayouts) {
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001220 l.initView();
Adrian Rooseb434ff2017-01-11 11:18:48 -08001221 l.reInflateViews();
1222 }
Amin Shaikhc3f0b062019-02-12 19:00:17 -05001223 mStatusBarNotification.clearPackageContext();
Lucas Dupinf03e7522018-06-25 16:21:13 -07001224 mNotificationInflater.clearCachesAndReInflate();
Selim Cinek1a48bab2017-02-17 19:38:40 -08001225 onNotificationUpdated();
Selim Cinek01af3342016-02-09 19:25:31 -08001226 }
1227
Mady Mellor9d03a522017-04-04 18:45:30 -07001228 @Override
1229 public void onConfigurationChanged(Configuration newConfig) {
1230 if (mMenuRow.getMenuView() != null) {
1231 mMenuRow.onConfigurationChanged();
1232 }
1233 }
1234
Lucas Dupinf03e7522018-06-25 16:21:13 -07001235 public void onUiModeChanged() {
Selim Cinekab9c7b22018-12-11 18:15:47 -08001236 mUpdateBackgroundOnUpdate = true;
Lucas Dupinf03e7522018-06-25 16:21:13 -07001237 reInflateViews();
1238 if (mChildrenContainer != null) {
1239 for (ExpandableNotificationRow child : mChildrenContainer.getNotificationChildren()) {
1240 child.onUiModeChanged();
1241 }
1242 }
1243 }
1244
Selim Cinekc3179332016-03-04 14:44:56 -08001245 public void setContentBackground(int customBackgroundColor, boolean animate,
1246 NotificationContentView notificationContentView) {
1247 if (getShowingLayout() == notificationContentView) {
1248 setTintColor(customBackgroundColor, animate);
1249 }
1250 }
1251
Kenny Guy14d035c2018-05-02 19:10:36 +01001252 @Override
1253 protected void setBackgroundTintColor(int color) {
1254 super.setBackgroundTintColor(color);
1255 NotificationContentView view = getShowingLayout();
1256 if (view != null) {
1257 view.setBackgroundTintColor(color);
1258 }
1259 }
1260
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001261 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -08001262 for (NotificationContentView l : mLayouts) {
1263 l.closeRemoteInput();
1264 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001265 }
1266
Selim Cinekc897bd32016-03-18 17:32:31 -07001267 /**
1268 * Set by how much the single line view should be indented.
1269 */
1270 public void setSingleLineWidthIndention(int indention) {
1271 mPrivateLayout.setSingleLineWidthIndention(indention);
1272 }
1273
1274 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -07001275 return mNotificationColor;
1276 }
1277
1278 private void updateNotificationColor() {
Lucas Dupind26facc2018-09-10 18:07:30 -07001279 Configuration currentConfig = getResources().getConfiguration();
1280 boolean nightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
1281 == Configuration.UI_MODE_NIGHT_YES;
1282
Lucas Dupina291d192018-06-07 13:59:42 -07001283 mNotificationColor = ContrastColorUtil.resolveContrastColor(mContext,
Selim Cinekac5f0272017-05-02 16:05:41 -07001284 getStatusBarNotification().getNotification().color,
Lucas Dupind26facc2018-09-10 18:07:30 -07001285 getBackgroundColorWithoutTint(), nightMode);
Selim Cinekc897bd32016-03-18 17:32:31 -07001286 }
1287
1288 public HybridNotificationView getSingleLineView() {
1289 return mPrivateLayout.getSingleLineView();
1290 }
1291
Selim Cinekf07d0622016-03-21 19:52:52 -07001292 public boolean isOnKeyguard() {
1293 return mOnKeyguard;
1294 }
1295
Selim Cinekc1e389d2016-04-07 11:02:57 -07001296 public void removeAllChildren() {
1297 List<ExpandableNotificationRow> notificationChildren
1298 = mChildrenContainer.getNotificationChildren();
1299 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
1300 for (int i = 0; i < clonedList.size(); i++) {
1301 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -07001302 if (row.keepInParent()) {
1303 continue;
1304 }
Selim Cinekc1e389d2016-04-07 11:02:57 -07001305 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -07001306 row.setIsChildInGroup(false, null);
1307 }
1308 onChildrenCountChanged();
1309 }
1310
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001311 public void setForceUnlocked(boolean forceUnlocked) {
1312 mForceUnlocked = forceUnlocked;
1313 if (mIsSummaryWithChildren) {
1314 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
1315 for (ExpandableNotificationRow child : notificationChildren) {
1316 child.setForceUnlocked(forceUnlocked);
1317 }
1318 }
1319 }
1320
Selim Cinekd03518c2018-03-15 12:13:51 -07001321 public void setDismissed(boolean fromAccessibility) {
Rohan Shahc6990a02018-03-23 17:24:17 -07001322 setLongPressListener(null);
Selim Cinekd03518c2018-03-15 12:13:51 -07001323 mDismissed = true;
Selim Cineke9bad242016-06-15 11:46:37 -07001324 mGroupParentWhenDismissed = mNotificationParent;
1325 mRefocusOnDismiss = fromAccessibility;
1326 mChildAfterViewWhenDismissed = null;
Selim Cinekd03518c2018-03-15 12:13:51 -07001327 mEntry.icon.setDismissed();
Selim Cineke9bad242016-06-15 11:46:37 -07001328 if (isChildInGroup()) {
1329 List<ExpandableNotificationRow> notificationChildren =
1330 mNotificationParent.getNotificationChildren();
1331 int i = notificationChildren.indexOf(this);
1332 if (i != -1 && i < notificationChildren.size() - 1) {
1333 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
1334 }
1335 }
Selim Cinek3f19f602016-05-02 18:01:56 -07001336 }
1337
1338 public boolean isDismissed() {
1339 return mDismissed;
1340 }
1341
1342 public boolean keepInParent() {
1343 return mKeepInParent;
1344 }
1345
1346 public void setKeepInParent(boolean keepInParent) {
1347 mKeepInParent = keepInParent;
1348 }
1349
Selim Cinekd9b7dd42017-11-10 17:53:47 -08001350 @Override
Selim Cinek3f19f602016-05-02 18:01:56 -07001351 public boolean isRemoved() {
1352 return mRemoved;
1353 }
1354
Adrian Roosd009ab12016-05-20 17:58:53 -07001355 public void setRemoved() {
1356 mRemoved = true;
Selim Cinekef8c2252017-02-10 14:52:18 -08001357 mTranslationWhenRemoved = getTranslationY();
1358 mWasChildInGroupWhenRemoved = isChildInGroup();
1359 if (isChildInGroup()) {
1360 mTranslationWhenRemoved += getNotificationParent().getTranslationY();
1361 }
Adrian Roosd009ab12016-05-20 17:58:53 -07001362 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -07001363 }
1364
Selim Cinekef8c2252017-02-10 14:52:18 -08001365 public boolean wasChildInGroupWhenRemoved() {
1366 return mWasChildInGroupWhenRemoved;
1367 }
1368
1369 public float getTranslationWhenRemoved() {
1370 return mTranslationWhenRemoved;
1371 }
1372
Selim Cinekd1395642016-04-28 12:22:42 -07001373 public NotificationChildrenContainer getChildrenContainer() {
1374 return mChildrenContainer;
1375 }
1376
Selim Cinekcafa87f2016-10-26 17:00:17 -07001377 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07001378 boolean wasAboveShelf = isAboveShelf();
Selim Cinek8875de12018-03-22 10:14:32 -07001379 boolean changed = headsUpAnimatingAway != mHeadsupDisappearRunning;
Selim Cinekcafa87f2016-10-26 17:00:17 -07001380 mHeadsupDisappearRunning = headsUpAnimatingAway;
1381 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
Selim Cinek8875de12018-03-22 10:14:32 -07001382 if (changed && mHeadsUpAnimatingAwayListener != null) {
1383 mHeadsUpAnimatingAwayListener.accept(headsUpAnimatingAway);
1384 }
Selim Cinek5cf1d052017-06-01 17:36:46 -07001385 if (isAboveShelf() != wasAboveShelf) {
1386 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
1387 }
Selim Cinekcafa87f2016-10-26 17:00:17 -07001388 }
1389
Selim Cinek8875de12018-03-22 10:14:32 -07001390 public void setHeadsUpAnimatingAwayListener(Consumer<Boolean> listener) {
1391 mHeadsUpAnimatingAwayListener = listener;
1392 }
1393
Selim Cinekcafa87f2016-10-26 17:00:17 -07001394 /**
1395 * @return if the view was just heads upped and is now animating away. During such a time the
1396 * layout needs to be kept consistent
1397 */
Selim Cinek29aab962018-02-27 17:05:45 -08001398 @Override
Selim Cinekcafa87f2016-10-26 17:00:17 -07001399 public boolean isHeadsUpAnimatingAway() {
1400 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -07001401 }
1402
Selim Cineke9bad242016-06-15 11:46:37 -07001403 public View getChildAfterViewWhenDismissed() {
1404 return mChildAfterViewWhenDismissed;
1405 }
1406
1407 public View getGroupParentWhenDismissed() {
1408 return mGroupParentWhenDismissed;
1409 }
1410
Rohan Shah524cf7b2018-03-15 14:40:02 -07001411 /**
1412 * Dismisses the notification with the option of showing the blocking helper in-place if we have
1413 * a negative user sentiment.
1414 *
1415 * @param fromAccessibility whether this dismiss is coming from an accessibility action
1416 * @return whether a blocking helper is shown in this row
1417 */
1418 public boolean performDismissWithBlockingHelper(boolean fromAccessibility) {
1419 NotificationBlockingHelperManager manager =
1420 Dependency.get(NotificationBlockingHelperManager.class);
1421 boolean isBlockingHelperShown = manager.perhapsShowBlockingHelper(this, mMenuRow);
1422
Rohan Shahda5dcdd2018-04-27 17:21:50 -07001423 Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
1424
Rohan Shah524cf7b2018-03-15 14:40:02 -07001425 // Continue with dismiss since we don't want the blocking helper to be directly associated
1426 // with a certain notification.
1427 performDismiss(fromAccessibility);
1428 return isBlockingHelperShown;
1429 }
1430
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001431 public void performDismiss(boolean fromAccessibility) {
Rohan Shah524cf7b2018-03-15 14:40:02 -07001432 if (isOnlyChildInGroup()) {
Ned Burnsf81c4c42019-01-07 14:10:43 -05001433 NotificationEntry groupSummary =
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001434 mGroupManager.getLogicalGroupSummary(getStatusBarNotification());
1435 if (groupSummary.isClearable()) {
Rohan Shah524cf7b2018-03-15 14:40:02 -07001436 // If this is the only child in the group, dismiss the group, but don't try to show
1437 // the blocking helper affordance!
Evan Laird94492852018-10-25 13:43:01 -04001438 groupSummary.getRow().performDismiss(fromAccessibility);
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001439 }
1440 }
Selim Cinekd03518c2018-03-15 12:13:51 -07001441 setDismissed(fromAccessibility);
Evan Laird94492852018-10-25 13:43:01 -04001442 if (mEntry.isClearable()) {
Julia Reynoldsfd4099d2018-08-21 11:06:06 -04001443 // TODO: track dismiss sentiment
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001444 if (mOnDismissRunnable != null) {
1445 mOnDismissRunnable.run();
1446 }
Selim Cineke9079112016-12-14 14:41:01 -08001447 }
Selim Cinek9e624e72016-07-20 13:46:49 -07001448 }
1449
Rohan Shah524cf7b2018-03-15 14:40:02 -07001450 public void setBlockingHelperShowing(boolean isBlockingHelperShowing) {
1451 mIsBlockingHelperShowing = isBlockingHelperShowing;
1452 }
1453
1454 public boolean isBlockingHelperShowing() {
1455 return mIsBlockingHelperShowing;
1456 }
1457
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001458 public boolean isBlockingHelperShowingAndTranslationFinished() {
1459 return mIsBlockingHelperShowing && mNotificationTranslationFinished;
1460 }
1461
Selim Cineke9079112016-12-14 14:41:01 -08001462 public void setOnDismissRunnable(Runnable onDismissRunnable) {
1463 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -07001464 }
1465
Selim Cinek281c2022016-10-13 19:14:43 -07001466 public View getNotificationIcon() {
Selim Cinek414ad332017-02-24 19:06:12 -08001467 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek281c2022016-10-13 19:14:43 -07001468 if (notificationHeader != null) {
1469 return notificationHeader.getIcon();
1470 }
1471 return null;
1472 }
1473
1474 /**
1475 * @return whether the notification is currently showing a view with an icon.
1476 */
1477 public boolean isShowingIcon() {
Mady Mellor434180c2017-02-13 11:29:42 -08001478 if (areGutsExposed()) {
1479 return false;
1480 }
Selim Cinek2ffa02f2017-03-06 15:56:37 -08001481 return getVisibleNotificationHeader() != null;
Selim Cinek281c2022016-10-13 19:14:43 -07001482 }
1483
Selim Cinek0242fbb2016-10-19 13:38:32 -07001484 /**
1485 * Set how much this notification is transformed into an icon.
1486 *
Selim Cinek2b549f42016-11-22 16:38:51 -08001487 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
1488 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -08001489 * @param isLastChild is this the last child in the list. If true, then the transformation is
1490 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -07001491 */
Selim Cinek2b549f42016-11-22 16:38:51 -08001492 public void setContentTransformationAmount(float contentTransformationAmount,
1493 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -08001494 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001495 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001496 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001497 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001498 if (changeTransformation) {
1499 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -08001500 }
1501 }
1502
1503 /**
1504 * Set the icons to be visible of this notification.
1505 */
1506 public void setIconsVisible(boolean iconsVisible) {
1507 if (iconsVisible != mIconsVisible) {
1508 mIconsVisible = iconsVisible;
1509 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -07001510 }
1511 }
1512
Selim Cinekdb167372016-11-17 15:41:17 -08001513 @Override
1514 protected void onBelowSpeedBumpChanged() {
1515 updateIconVisibilities();
1516 }
1517
Selim Cinek875a3a12016-11-18 17:52:16 -08001518 private void updateContentTransformation() {
Selim Cinek2627d722018-01-19 12:16:49 -08001519 if (mExpandAnimationRunning) {
1520 return;
1521 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001522 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -08001523 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -08001524 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -08001525 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001526 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001527 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -08001528 translationY *= 0.4f;
1529 } else {
1530 contentAlpha = 1.0f;
1531 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001532 for (NotificationContentView l : mLayouts) {
1533 l.setAlpha(contentAlpha);
1534 l.setTranslationY(translationY);
1535 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001536 if (mChildrenContainer != null) {
1537 mChildrenContainer.setAlpha(contentAlpha);
1538 mChildrenContainer.setTranslationY(translationY);
1539 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -07001540 }
1541 }
1542
1543 private void updateIconVisibilities() {
Gus Prevas4b3c0ff22018-11-02 13:15:23 -04001544 boolean visible = isChildInGroup() || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -08001545 for (NotificationContentView l : mLayouts) {
1546 l.setIconsVisible(visible);
1547 }
Selim Cinekdb167372016-11-17 15:41:17 -08001548 if (mChildrenContainer != null) {
1549 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001550 }
1551 }
1552
Selim Cinek875a3a12016-11-18 17:52:16 -08001553 /**
1554 * Get the relative top padding of a view relative to this view. This recursively walks up the
1555 * hierarchy and does the corresponding measuring.
1556 *
1557 * @param view the view to the the padding for. The requested view has to be a child of this
1558 * notification.
1559 * @return the toppadding
1560 */
1561 public int getRelativeTopPadding(View view) {
1562 int topPadding = 0;
1563 while (view.getParent() instanceof ViewGroup) {
1564 topPadding += view.getTop();
1565 view = (View) view.getParent();
1566 if (view instanceof ExpandableNotificationRow) {
1567 return topPadding;
1568 }
1569 }
1570 return topPadding;
1571 }
1572
Selim Cineka1d97902016-12-14 16:31:40 -08001573 public float getContentTranslation() {
1574 return mPrivateLayout.getTranslationY();
1575 }
1576
Selim Cinek6743c0b2017-01-18 18:24:01 -08001577 public void setIsLowPriority(boolean isLowPriority) {
1578 mIsLowPriority = isLowPriority;
1579 mPrivateLayout.setIsLowPriority(isLowPriority);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001580 mNotificationInflater.setIsLowPriority(mIsLowPriority);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001581 if (mChildrenContainer != null) {
1582 mChildrenContainer.setIsLowPriority(isLowPriority);
1583 }
1584 }
1585
Selim Cinek414ad332017-02-24 19:06:12 -08001586 public boolean isLowPriority() {
1587 return mIsLowPriority;
1588 }
1589
Selim Cinek7d1009b2017-01-25 15:28:28 -08001590 public void setUseIncreasedCollapsedHeight(boolean use) {
1591 mUseIncreasedCollapsedHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001592 mNotificationInflater.setUsesIncreasedHeight(use);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001593 }
1594
Selim Cinek87ed69b2017-02-09 15:59:43 -08001595 public void setUseIncreasedHeadsUpHeight(boolean use) {
1596 mUseIncreasedHeadsUpHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001597 mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
1598 }
1599
1600 public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
1601 mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001602 }
1603
Selim Cinek5ba22542017-04-20 15:16:10 -07001604 public void setInflationCallback(InflationCallback callback) {
1605 mNotificationInflater.setInflationCallback(callback);
Selim Cinekc478f902017-02-22 20:55:44 -08001606 }
1607
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001608 public void setNeedsRedaction(boolean needsRedaction) {
Kevin38ce6fa2018-10-17 16:00:14 -07001609 if (mNeedsRedaction != needsRedaction) {
1610 mNeedsRedaction = needsRedaction;
1611 updateInflationFlag(FLAG_CONTENT_VIEW_PUBLIC, needsRedaction /* shouldInflate */);
1612 mNotificationInflater.updateNeedsRedaction(needsRedaction);
1613 if (!needsRedaction) {
1614 freeContentViewWhenSafe(FLAG_CONTENT_VIEW_PUBLIC);
1615 }
1616 }
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001617 }
1618
Selim Cinek5ba22542017-04-20 15:16:10 -07001619 @VisibleForTesting
Ned Burns1a5e22f2019-02-14 15:11:52 -05001620 public NotificationContentInflater getNotificationInflater() {
Selim Cinek5ba22542017-04-20 15:16:10 -07001621 return mNotificationInflater;
1622 }
1623
Chris Wren78403d72014-07-28 10:23:24 +01001624 public interface ExpansionLogger {
Anthony Chen6bf88a02017-04-10 14:41:44 -07001625 void logNotificationExpansion(String key, boolean userAction, boolean expanded);
Chris Wren78403d72014-07-28 10:23:24 +01001626 }
Selim Cinek1685e632014-04-08 02:27:49 +02001627
Chris Wren51c75102013-07-16 20:49:17 -04001628 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1629 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001630 mFalsingManager = FalsingManager.getInstance(context);
Ned Burns1a5e22f2019-02-14 15:11:52 -05001631 mNotificationInflater = new NotificationContentInflater(this);
Mady Mellor95d743c2017-01-10 12:05:27 -08001632 mMenuRow = new NotificationMenuRow(mContext);
Ahan Wude396fa2018-05-08 20:42:24 +08001633 mImageResolver = new NotificationInlineImageResolver(context,
1634 new NotificationInlineImageCache());
Beth Thibodeaueab4dde2019-02-07 11:37:02 -05001635 mMediaManager = Dependency.get(NotificationMediaManager.class);
Selim Cinek01af3342016-02-09 19:25:31 -08001636 initDimens();
1637 }
1638
1639 private void initDimens() {
Rohan Shahb9d500a2018-06-25 16:27:16 -07001640 mNotificationMinHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
Selim Cineke62255c2017-09-28 18:23:23 -07001641 R.dimen.notification_min_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001642 mNotificationMinHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1643 R.dimen.notification_min_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001644 mNotificationMinHeight = NotificationUtils.getFontScaledHeight(mContext,
1645 R.dimen.notification_min_height);
1646 mNotificationMinHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001647 R.dimen.notification_min_height_increased);
Beth Thibodeaucb395352019-01-25 15:39:54 -05001648 mNotificationMinHeightMedia = NotificationUtils.getFontScaledHeight(mContext,
1649 R.dimen.notification_min_height_media);
Selim Cineke62255c2017-09-28 18:23:23 -07001650 mNotificationMaxHeight = NotificationUtils.getFontScaledHeight(mContext,
1651 R.dimen.notification_max_height);
Rohan Shahb9d500a2018-06-25 16:27:16 -07001652 mMaxHeadsUpHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek77019c72015-12-09 10:18:02 -08001653 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001654 mMaxHeadsUpHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1655 R.dimen.notification_max_heads_up_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001656 mMaxHeadsUpHeight = NotificationUtils.getFontScaledHeight(mContext,
1657 R.dimen.notification_max_heads_up_height);
1658 mMaxHeadsUpHeightIncreased = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001659 R.dimen.notification_max_heads_up_height_increased);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001660
Anthony Chen7acbb772017-04-07 16:45:25 -07001661 Resources res = getResources();
1662 mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
1663 R.dimen.notification_divider_height_increased);
1664 mIconTransformContentShiftNoIcon = res.getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001665 R.dimen.notification_icon_transform_content_shift);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001666 mEnableNonGroupedNotificationExpand =
1667 res.getBoolean(R.bool.config_enableNonGroupedNotificationExpand);
1668 mShowGroupBackgroundWhenExpanded =
1669 res.getBoolean(R.bool.config_showGroupNotificationBgWhenExpanded);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001670 }
1671
Ahan Wude396fa2018-05-08 20:42:24 +08001672 NotificationInlineImageResolver getImageResolver() {
1673 return mImageResolver;
1674 }
1675
Selim Cinekf619ffc2016-02-17 14:53:05 -08001676 /**
Christoph Studera7fe6312014-06-27 19:32:44 +02001677 * Resets this view so it can be re-used for an updated notification.
1678 */
1679 public void reset() {
Jorim Jaggiae441282014-08-01 02:45:18 +02001680 mShowingPublicInitialized = false;
Selim Cinek31094df2014-08-14 19:28:15 +02001681 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001682 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001683 }
1684
Julia Reynoldsfc640012018-02-21 12:25:27 -05001685 public void showAppOpsIcons(ArraySet<Integer> activeOps) {
1686 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
1687 mChildrenContainer.getHeaderView().showAppOpsIcons(activeOps);
1688 }
1689 mPrivateLayout.showAppOpsIcons(activeOps);
1690 mPublicLayout.showAppOpsIcons(activeOps);
1691 }
1692
Gus Prevas7306b902018-12-11 10:57:06 -05001693 /** Sets the last time the notification being displayed audibly alerted the user. */
1694 public void setLastAudiblyAlertedMs(long lastAudiblyAlertedMs) {
Gus Prevasa3226492018-10-23 11:10:09 -04001695 if (NotificationUtils.useNewInterruptionModel(mContext)) {
Ned Burns3da3c782019-01-08 21:14:39 -05001696 long timeSinceAlertedAudibly = System.currentTimeMillis() - lastAudiblyAlertedMs;
1697 boolean alertedRecently =
1698 timeSinceAlertedAudibly < RECENTLY_ALERTED_THRESHOLD_MS;
1699
1700 applyAudiblyAlertedRecently(alertedRecently);
1701
1702 removeCallbacks(mExpireRecentlyAlertedFlag);
1703 if (alertedRecently) {
1704 long timeUntilNoLongerRecent =
1705 RECENTLY_ALERTED_THRESHOLD_MS - timeSinceAlertedAudibly;
1706 postDelayed(mExpireRecentlyAlertedFlag, timeUntilNoLongerRecent);
Gus Prevasa3226492018-10-23 11:10:09 -04001707 }
Gus Prevasa3226492018-10-23 11:10:09 -04001708 }
1709 }
1710
Ned Burns3da3c782019-01-08 21:14:39 -05001711 private final Runnable mExpireRecentlyAlertedFlag = () -> applyAudiblyAlertedRecently(false);
1712
1713 private void applyAudiblyAlertedRecently(boolean audiblyAlertedRecently) {
1714 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
1715 mChildrenContainer.getHeaderView().setRecentlyAudiblyAlerted(audiblyAlertedRecently);
1716 }
1717 mPrivateLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
1718 mPublicLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
1719 }
1720
Julia Reynoldsb5867452018-02-28 16:31:35 -05001721 public View.OnClickListener getAppOpsOnClickListener() {
1722 return mOnAppOpsClickListener;
1723 }
1724
Rohan Shah20790b82018-07-02 17:21:04 -07001725 public void setAppOpsOnClickListener(ExpandableNotificationRow.OnAppOpsClickListener l) {
Julia Reynoldsb5867452018-02-28 16:31:35 -05001726 mOnAppOpsClickListener = v -> {
1727 createMenu();
1728 MenuItem menuItem = getProvider().getAppOpsMenuItem(mContext);
1729 if (menuItem != null) {
1730 l.onClick(this, v.getWidth() / 2, v.getHeight() / 2, menuItem);
1731 }
1732 };
1733 }
1734
Jorim Jaggi251957d2014-04-09 04:24:09 +02001735 @Override
1736 protected void onFinishInflate() {
1737 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001738 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1739 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001740 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1741
1742 for (NotificationContentView l : mLayouts) {
1743 l.setExpandClickListener(mExpandClickListener);
1744 l.setContainingNotification(this);
1745 }
Selim Cinekab29aeb2015-02-20 18:18:32 +01001746 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1747 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001748 @Override
1749 public void onInflate(ViewStub stub, View inflated) {
1750 mGuts = (NotificationGuts) inflated;
1751 mGuts.setClipTopAmount(getClipTopAmount());
1752 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001753 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001754 }
1755 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001756 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1757 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1758
1759 @Override
1760 public void onInflate(ViewStub stub, View inflated) {
1761 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001762 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek414ad332017-02-24 19:06:12 -08001763 mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001764 mChildrenContainer.onNotificationUpdated();
Anthony Chen7acbb772017-04-07 16:45:25 -07001765
1766 if (mShouldTranslateContents) {
1767 mTranslateableViews.add(mChildrenContainer);
1768 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001769 }
1770 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001771
Anthony Chen7acbb772017-04-07 16:45:25 -07001772 if (mShouldTranslateContents) {
1773 // Add the views that we translate to reveal the menu
1774 mTranslateableViews = new ArrayList<>();
1775 for (int i = 0; i < getChildCount(); i++) {
1776 mTranslateableViews.add(getChildAt(i));
1777 }
1778 // Remove views that don't translate
1779 mTranslateableViews.remove(mChildrenContainerStub);
1780 mTranslateableViews.remove(mGutsStub);
Mady Mellor4b80b102016-01-22 08:03:58 -08001781 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001782 }
1783
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001784 private void doLongClickCallback() {
1785 doLongClickCallback(getWidth() / 2, getHeight() / 2);
1786 }
1787
1788 public void doLongClickCallback(int x, int y) {
1789 createMenu();
1790 MenuItem menuItem = getProvider().getLongpressMenuItem(mContext);
Mady Mellorb3a6aed2018-05-11 13:24:07 -07001791 doLongClickCallback(x, y, menuItem);
1792 }
1793
1794 private void doLongClickCallback(int x, int y, MenuItem menuItem) {
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001795 if (mLongPressListener != null && menuItem != null) {
1796 mLongPressListener.onLongPress(this, x, y, menuItem);
1797 }
1798 }
1799
1800 @Override
1801 public boolean onKeyDown(int keyCode, KeyEvent event) {
1802 if (KeyEvent.isConfirmKey(keyCode)) {
1803 event.startTracking();
1804 return true;
1805 }
1806 return super.onKeyDown(keyCode, event);
1807 }
1808
1809 @Override
1810 public boolean onKeyUp(int keyCode, KeyEvent event) {
1811 if (KeyEvent.isConfirmKey(keyCode)) {
1812 if (!event.isCanceled()) {
1813 performClick();
1814 }
1815 return true;
1816 }
1817 return super.onKeyUp(keyCode, event);
1818 }
1819
1820 @Override
1821 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
1822 if (KeyEvent.isConfirmKey(keyCode)) {
1823 doLongClickCallback();
1824 return true;
1825 }
1826 return false;
1827 }
1828
Mady Mellor4b80b102016-01-22 08:03:58 -08001829 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001830 if (mTranslateAnim != null) {
1831 mTranslateAnim.cancel();
1832 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001833
1834 if (!mShouldTranslateContents) {
1835 setTranslationX(0);
1836 } else if (mTranslateableViews != null) {
Mady Mellor4b80b102016-01-22 08:03:58 -08001837 for (int i = 0; i < mTranslateableViews.size(); i++) {
1838 mTranslateableViews.get(i).setTranslationX(0);
1839 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001840 invalidateOutline();
shawnlin4fbeac42018-04-30 20:32:40 +08001841 getEntry().expandedIcon.setScrollX(0);
Mady Mellor4b80b102016-01-22 08:03:58 -08001842 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001843
Mady Mellor95d743c2017-01-10 12:05:27 -08001844 mMenuRow.resetMenu();
Mady Mellor4b80b102016-01-22 08:03:58 -08001845 }
1846
Rohan Shah56eb0912018-05-10 21:49:04 -07001847 void onGutsOpened() {
Rohan Shah56eb0912018-05-10 21:49:04 -07001848 updateContentAccessibilityImportanceForGuts(false /* isEnabled */);
1849 }
1850
1851 void onGutsClosed() {
1852 updateContentAccessibilityImportanceForGuts(true /* isEnabled */);
1853 }
1854
1855 /**
1856 * Updates whether all the non-guts content inside this row is important for accessibility.
1857 *
1858 * @param isEnabled whether the content views should be enabled for accessibility
1859 */
1860 private void updateContentAccessibilityImportanceForGuts(boolean isEnabled) {
1861 if (mChildrenContainer != null) {
1862 updateChildAccessibilityImportance(mChildrenContainer, isEnabled);
1863 }
1864 if (mLayouts != null) {
1865 for (View view : mLayouts) {
1866 updateChildAccessibilityImportance(view, isEnabled);
1867 }
1868 }
1869
1870 if (isEnabled) {
1871 this.requestAccessibilityFocus();
1872 }
1873 }
1874
1875 /**
1876 * Updates whether the given childView is important for accessibility based on
1877 * {@code isEnabled}.
1878 */
1879 private void updateChildAccessibilityImportance(View childView, boolean isEnabled) {
1880 childView.setImportantForAccessibility(isEnabled
1881 ? View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
1882 : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
1883 }
1884
Selim Cinekde4de0e2018-01-24 16:21:07 -08001885 public CharSequence getActiveRemoteInputText() {
1886 return mPrivateLayout.getActiveRemoteInputText();
1887 }
1888
Mady Mellor4b80b102016-01-22 08:03:58 -08001889 public void animateTranslateNotification(final float leftTarget) {
1890 if (mTranslateAnim != null) {
1891 mTranslateAnim.cancel();
1892 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001893 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001894 if (mTranslateAnim != null) {
1895 mTranslateAnim.start();
1896 }
1897 }
1898
1899 @Override
1900 public void setTranslation(float translationX) {
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001901 if (isBlockingHelperShowingAndTranslationFinished()) {
1902 mGuts.setTranslationX(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001903 return;
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001904 } else if (!mShouldTranslateContents) {
Anthony Chen7acbb772017-04-07 16:45:25 -07001905 setTranslationX(translationX);
1906 } else if (mTranslateableViews != null) {
1907 // Translate the group of views
1908 for (int i = 0; i < mTranslateableViews.size(); i++) {
1909 if (mTranslateableViews.get(i) != null) {
1910 mTranslateableViews.get(i).setTranslationX(translationX);
1911 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001912 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001913 invalidateOutline();
Selim Cinek143672c2018-03-23 20:04:32 -07001914
1915 // In order to keep the shelf in sync with this swiping, we're simply translating
1916 // it's icon by the same amount. The translation is already being used for the normal
1917 // positioning, so we can use the scrollX instead.
1918 getEntry().expandedIcon.setScrollX((int) -translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001919 }
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001920
Mady Mellor95d743c2017-01-10 12:05:27 -08001921 if (mMenuRow.getMenuView() != null) {
Aaron Heuckroth266cb342018-09-07 14:52:04 -04001922 mMenuRow.onParentTranslationUpdate(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001923 }
1924 }
1925
1926 @Override
1927 public float getTranslation() {
Anthony Chene04afcb2017-04-21 13:51:32 -07001928 if (!mShouldTranslateContents) {
Anthony Chen7acbb772017-04-07 16:45:25 -07001929 return getTranslationX();
1930 }
1931
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001932 if (isBlockingHelperShowingAndCanTranslate()) {
1933 return mGuts.getTranslationX();
1934 }
1935
Mady Mellor34958fa2016-02-23 09:52:17 -08001936 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1937 // All of the views in the list should have same translation, just use first one.
1938 return mTranslateableViews.get(0).getTranslationX();
1939 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001940
Mady Mellor34958fa2016-02-23 09:52:17 -08001941 return 0;
1942 }
1943
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001944 private boolean isBlockingHelperShowingAndCanTranslate() {
1945 return areGutsExposed() && mIsBlockingHelperShowing && mNotificationTranslationFinished;
1946 }
1947
Mady Mellor34958fa2016-02-23 09:52:17 -08001948 public Animator getTranslateViewAnimator(final float leftTarget,
1949 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001950 if (mTranslateAnim != null) {
1951 mTranslateAnim.cancel();
1952 }
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001953
Mady Mellorb0a82462016-04-30 17:31:02 -07001954 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1955 leftTarget);
1956 if (listener != null) {
1957 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001958 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001959 translateAnim.addListener(new AnimatorListenerAdapter() {
1960 boolean cancelled = false;
1961
1962 @Override
1963 public void onAnimationCancel(Animator anim) {
1964 cancelled = true;
1965 }
1966
1967 @Override
1968 public void onAnimationEnd(Animator anim) {
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001969 if (mIsBlockingHelperShowing) {
1970 mNotificationTranslationFinished = true;
1971 }
Mady Mellor95d743c2017-01-10 12:05:27 -08001972 if (!cancelled && leftTarget == 0) {
1973 mMenuRow.resetMenu();
Mady Mellorb0a82462016-04-30 17:31:02 -07001974 mTranslateAnim = null;
1975 }
1976 }
1977 });
1978 mTranslateAnim = translateAnim;
1979 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001980 }
1981
Selim Cinekab29aeb2015-02-20 18:18:32 +01001982 public void inflateGuts() {
1983 if (mGuts == null) {
1984 mGutsStub.inflate();
1985 }
1986 }
1987
Selim Cinekda42d652015-12-04 15:51:16 -08001988 private void updateChildrenVisibility() {
Selim Cinek7fa385a2018-01-24 08:35:28 -08001989 boolean hideContentWhileLaunching = mExpandAnimationRunning && mGuts != null
1990 && mGuts.isExposed();
1991 mPrivateLayout.setVisibility(!shouldShowPublic() && !mIsSummaryWithChildren
1992 && !hideContentWhileLaunching ? VISIBLE : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001993 if (mChildrenContainer != null) {
Selim Cinek7fa385a2018-01-24 08:35:28 -08001994 mChildrenContainer.setVisibility(!shouldShowPublic() && mIsSummaryWithChildren
1995 && !hideContentWhileLaunching ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001996 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001997 }
Selim Cinekda42d652015-12-04 15:51:16 -08001998 // The limits might have changed if the view suddenly became a group or vice versa
1999 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01002000 }
2001
Jorim Jaggife40f7d2014-04-28 15:20:04 +02002002 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08002003 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
2004 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02002005 // Add a record for the entire layout since its content is somehow small.
2006 // The event comes from a leaf view that is interacted with.
2007 AccessibilityEvent record = AccessibilityEvent.obtain();
2008 onInitializeAccessibilityEvent(record);
2009 dispatchPopulateAccessibilityEvent(record);
2010 event.appendRecord(record);
2011 return true;
2012 }
2013 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02002014 }
Chris Wren51c75102013-07-16 20:49:17 -04002015
John Spurlocke15452b2014-08-21 09:44:39 -04002016 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01002017 public void setDark(boolean dark, boolean fade, long delay) {
Lucas Dupin00be88f2019-01-03 17:50:52 -08002018 if (mDark == dark) {
2019 return;
2020 }
Jorim Jaggi4e857f42014-11-17 19:14:04 +01002021 super.setDark(dark, fade, delay);
Kevina97ea052018-09-11 13:53:18 -07002022 if (!mIsAmbientPulsing) {
Adrian Roos28f90c72017-05-08 17:24:26 -07002023 // Only fade the showing view of the pulsing notification.
2024 fade = false;
2025 }
John Spurlocke15452b2014-08-21 09:44:39 -04002026 final NotificationContentView showing = getShowingLayout();
2027 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01002028 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04002029 }
Selim Cineka7c69632017-06-07 15:51:29 -07002030 updateShelfIconColor();
John Spurlocke15452b2014-08-21 09:44:39 -04002031 }
2032
Selim Cinek2627d722018-01-19 12:16:49 -08002033 public void applyExpandAnimationParams(ExpandAnimationParameters params) {
2034 if (params == null) {
2035 return;
2036 }
Selim Cinek2627d722018-01-19 12:16:49 -08002037 float zProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
2038 params.getProgress(0, 50));
2039 float translationZ = MathUtils.lerp(params.getStartTranslationZ(),
2040 mNotificationLaunchHeight,
2041 zProgress);
2042 setTranslationZ(translationZ);
Selim Cinekc25989e2018-02-16 16:42:14 -08002043 float extraWidthForClipping = params.getWidth() - getWidth()
2044 + MathUtils.lerp(0, mOutlineRadius * 2, params.getProgress());
2045 setExtraWidthForClipping(extraWidthForClipping);
2046 int top = params.getTop();
2047 float interpolation = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(params.getProgress());
2048 int startClipTopAmount = params.getStartClipTopAmount();
2049 if (mNotificationParent != null) {
Selim Cinekc42db8d2018-12-04 13:29:25 -08002050 float parentY = mNotificationParent.getTranslationY();
2051 top -= parentY;
Selim Cinekc25989e2018-02-16 16:42:14 -08002052 mNotificationParent.setTranslationZ(translationZ);
2053 int parentStartClipTopAmount = params.getParentStartClipTopAmount();
2054 if (startClipTopAmount != 0) {
2055 int clipTopAmount = (int) MathUtils.lerp(parentStartClipTopAmount,
2056 parentStartClipTopAmount - startClipTopAmount,
2057 interpolation);
2058 mNotificationParent.setClipTopAmount(clipTopAmount);
2059 }
2060 mNotificationParent.setExtraWidthForClipping(extraWidthForClipping);
Selim Cinekc42db8d2018-12-04 13:29:25 -08002061 float clipBottom = Math.max(params.getBottom(),
2062 parentY + mNotificationParent.getActualHeight()
2063 - mNotificationParent.getClipBottomAmount());
2064 float clipTop = Math.min(params.getTop(), parentY);
2065 int minimumHeightForClipping = (int) (clipBottom - clipTop);
2066 mNotificationParent.setMinimumHeightForClipping(minimumHeightForClipping);
Selim Cinekc25989e2018-02-16 16:42:14 -08002067 } else if (startClipTopAmount != 0) {
2068 int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, interpolation);
2069 setClipTopAmount(clipTopAmount);
2070 }
2071 setTranslationY(top);
Selim Cinek2627d722018-01-19 12:16:49 -08002072 setActualHeight(params.getHeight());
Selim Cinekc25989e2018-02-16 16:42:14 -08002073
Selim Cinek2627d722018-01-19 12:16:49 -08002074 mBackgroundNormal.setExpandAnimationParams(params);
2075 }
2076
2077 public void setExpandAnimationRunning(boolean expandAnimationRunning) {
Selim Cinekc25989e2018-02-16 16:42:14 -08002078 View contentView;
2079 if (mIsSummaryWithChildren) {
2080 contentView = mChildrenContainer;
2081 } else {
2082 contentView = getShowingLayout();
2083 }
2084 if (mGuts != null && mGuts.isExposed()) {
2085 contentView = mGuts;
2086 }
Selim Cinek2627d722018-01-19 12:16:49 -08002087 if (expandAnimationRunning) {
Selim Cinek2627d722018-01-19 12:16:49 -08002088 contentView.animate()
2089 .alpha(0f)
2090 .setDuration(ActivityLaunchAnimator.ANIMATION_DURATION_FADE_CONTENT)
2091 .setInterpolator(Interpolators.ALPHA_OUT);
2092 setAboveShelf(true);
2093 mExpandAnimationRunning = true;
Dave Mankoffa4d195d2018-11-16 13:33:27 -05002094 getViewState().cancelAnimations(this);
Selim Cinek2627d722018-01-19 12:16:49 -08002095 mNotificationLaunchHeight = AmbientState.getNotificationLaunchHeight(getContext());
2096 } else {
2097 mExpandAnimationRunning = false;
2098 setAboveShelf(isAboveShelf());
Selim Cinek7fa385a2018-01-24 08:35:28 -08002099 if (mGuts != null) {
2100 mGuts.setAlpha(1.0f);
2101 }
Selim Cinekc25989e2018-02-16 16:42:14 -08002102 if (contentView != null) {
2103 contentView.setAlpha(1.0f);
2104 }
2105 setExtraWidthForClipping(0.0f);
2106 if (mNotificationParent != null) {
2107 mNotificationParent.setExtraWidthForClipping(0.0f);
2108 mNotificationParent.setMinimumHeightForClipping(0);
2109 }
2110 }
2111 if (mNotificationParent != null) {
2112 mNotificationParent.setChildIsExpanding(mExpandAnimationRunning);
Selim Cinek2627d722018-01-19 12:16:49 -08002113 }
Selim Cinek7fa385a2018-01-24 08:35:28 -08002114 updateChildrenVisibility();
Selim Cinek2627d722018-01-19 12:16:49 -08002115 updateClipping();
2116 mBackgroundNormal.setExpandAnimationRunning(expandAnimationRunning);
2117 }
2118
Selim Cinekc25989e2018-02-16 16:42:14 -08002119 private void setChildIsExpanding(boolean isExpanding) {
2120 mChildIsExpanding = isExpanding;
Selim Cinek6487ebf2018-11-28 18:57:40 -08002121 updateClipping();
2122 invalidate();
Selim Cinekc25989e2018-02-16 16:42:14 -08002123 }
2124
2125 @Override
2126 public boolean hasExpandingChild() {
2127 return mChildIsExpanding;
2128 }
2129
Selim Cinek2627d722018-01-19 12:16:49 -08002130 @Override
2131 protected boolean shouldClipToActualHeight() {
Selim Cinek53328492018-12-05 14:58:44 -08002132 return super.shouldClipToActualHeight() && !mExpandAnimationRunning;
Selim Cinek2627d722018-01-19 12:16:49 -08002133 }
2134
2135 @Override
2136 public boolean isExpandAnimationRunning() {
2137 return mExpandAnimationRunning;
2138 }
2139
Lucas Dupincecc7c22017-09-12 16:02:45 -07002140 /**
2141 * Tap sounds should not be played when we're unlocking.
2142 * Doing so would cause audio collision and the system would feel unpolished.
2143 */
2144 @Override
2145 public boolean isSoundEffectsEnabled() {
2146 final boolean mute = mDark && mSecureStateProvider != null &&
2147 !mSecureStateProvider.getAsBoolean();
2148 return !mute && super.isSoundEffectsEnabled();
2149 }
2150
Chris Wren51c75102013-07-16 20:49:17 -04002151 public boolean isExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002152 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek388df6d2015-10-22 13:25:11 -07002153 return !mChildrenExpanded;
2154 }
Anthony Chen6bf88a02017-04-10 14:41:44 -07002155 return mEnableNonGroupedNotificationExpand && mExpandable;
Chris Wren51c75102013-07-16 20:49:17 -04002156 }
2157
2158 public void setExpandable(boolean expandable) {
2159 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002160 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04002161 }
2162
Selim Cinek4ffd6362015-12-29 15:12:23 +01002163 @Override
2164 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08002165 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
2166 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01002167 }
2168
Selim Cinek1685e632014-04-08 02:27:49 +02002169 /**
2170 * @return whether the user has changed the expansion state
2171 */
2172 public boolean hasUserChangedExpansion() {
2173 return mHasUserChangedExpansion;
2174 }
2175
Chris Wren51c75102013-07-16 20:49:17 -04002176 public boolean isUserExpanded() {
2177 return mUserExpanded;
2178 }
2179
Selim Cinek1685e632014-04-08 02:27:49 +02002180 /**
2181 * Set this notification to be expanded by the user
2182 *
2183 * @param userExpanded whether the user wants this notification to be expanded
2184 */
Chris Wren51c75102013-07-16 20:49:17 -04002185 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07002186 setUserExpanded(userExpanded, false /* allowChildExpansion */);
2187 }
2188
2189 /**
2190 * Set this notification to be expanded by the user
2191 *
2192 * @param userExpanded whether the user wants this notification to be expanded
2193 * @param allowChildExpansion whether a call to this method allows expanding children
2194 */
2195 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07002196 mFalsingManager.setNotificationExpanded();
Selim Cinek0b9cf462017-12-07 16:31:03 -08002197 if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
Selim Cinek414ad332017-02-24 19:06:12 -08002198 && !mChildrenContainer.showingAsLowPriority()) {
Chris Wren698b1702016-05-23 11:16:32 -04002199 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07002200 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -08002201 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07002202 return;
2203 }
Christoph Studera7fe6312014-06-27 19:32:44 +02002204 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01002205 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02002206 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04002207 mUserExpanded = userExpanded;
Selim Cinek414ad332017-02-24 19:06:12 -08002208 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002209 if (!wasExpanded && isExpanded()
2210 && getActualHeight() != getIntrinsicHeight()) {
2211 notifyHeightChanged(true /* needsAnimation */);
2212 }
Chris Wren51c75102013-07-16 20:49:17 -04002213 }
2214
Selim Cinekccd14fb2014-08-12 18:53:24 +02002215 public void resetUserExpansion() {
Selim Cinek414ad332017-02-24 19:06:12 -08002216 boolean changed = mUserExpanded;
Selim Cinekccd14fb2014-08-12 18:53:24 +02002217 mHasUserChangedExpansion = false;
2218 mUserExpanded = false;
Selim Cinek414ad332017-02-24 19:06:12 -08002219 if (changed && mIsSummaryWithChildren) {
2220 mChildrenContainer.onExpansionChanged();
2221 }
2222 updateShelfIconColor();
Selim Cinekccd14fb2014-08-12 18:53:24 +02002223 }
2224
Chris Wren51c75102013-07-16 20:49:17 -04002225 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07002226 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04002227 }
2228
2229 public void setUserLocked(boolean userLocked) {
2230 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08002231 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07002232 // This is intentionally not guarded with mIsSummaryWithChildren since we might have had
2233 // children but not anymore.
2234 if (mChildrenContainer != null) {
Selim Cinek42357e02016-02-24 18:48:01 -08002235 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07002236 if (mIsSummaryWithChildren && (userLocked || !isGroupExpanded())) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002237 updateBackgroundForGroupState();
2238 }
Selim Cinek42357e02016-02-24 18:48:01 -08002239 }
Chris Wren51c75102013-07-16 20:49:17 -04002240 }
2241
Selim Cinek1685e632014-04-08 02:27:49 +02002242 /**
2243 * @return has the system set this notification to be expanded
2244 */
2245 public boolean isSystemExpanded() {
2246 return mIsSystemExpanded;
2247 }
2248
2249 /**
2250 * Set this notification to be expanded by the system.
2251 *
2252 * @param expand whether the system wants this notification to be expanded.
2253 */
2254 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02002255 if (expand != mIsSystemExpanded) {
2256 final boolean wasExpanded = isExpanded();
2257 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01002258 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek414ad332017-02-24 19:06:12 -08002259 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07002260 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07002261 mChildrenContainer.updateGroupOverflow();
2262 }
Selim Cinek31094df2014-08-14 19:28:15 +02002263 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02002264 }
2265
2266 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07002267 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02002268 */
Selim Cinek83bc7832015-10-22 13:26:54 -07002269 public void setOnKeyguard(boolean onKeyguard) {
2270 if (onKeyguard != mOnKeyguard) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07002271 boolean wasAboveShelf = isAboveShelf();
Selim Cinek31094df2014-08-14 19:28:15 +02002272 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07002273 mOnKeyguard = onKeyguard;
Selim Cinek414ad332017-02-24 19:06:12 -08002274 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cinek31094df2014-08-14 19:28:15 +02002275 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07002276 if (mIsSummaryWithChildren) {
2277 mChildrenContainer.updateGroupOverflow();
2278 }
Mady Mellor4b80b102016-01-22 08:03:58 -08002279 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02002280 }
Selim Cinek5cf1d052017-06-01 17:36:46 -07002281 if (isAboveShelf() != wasAboveShelf) {
2282 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
2283 }
Selim Cinek31094df2014-08-14 19:28:15 +02002284 }
Selim Cinekfe24fb72018-02-13 14:34:55 -08002285 updateRippleAllowed();
2286 }
2287
2288 private void updateRippleAllowed() {
2289 boolean allowed = isOnKeyguard()
2290 || mEntry.notification.getNotification().contentIntent == null;
2291 setRippleAllowed(allowed);
Selim Cinek1685e632014-04-08 02:27:49 +02002292 }
2293
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02002294 @Override
2295 public int getIntrinsicHeight() {
Mady Mellorc3d6f7d2018-11-07 09:36:56 -08002296 if (isShownAsBubble()) {
2297 return getMaxExpandHeight();
2298 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002299 if (isUserLocked()) {
2300 return getActualHeight();
2301 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002302 if (mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07002303 return mGuts.getIntrinsicHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08002304 } else if ((isChildInGroup() && !isGroupExpanded())) {
2305 return mPrivateLayout.getMinHeight();
2306 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
2307 return getMinHeight();
Selim Cinek7927c732019-03-06 15:21:39 -08002308 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002309 return mChildrenContainer.getIntrinsicHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07002310 } else if (isHeadsUpAllowed() && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07002311 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08002312 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
2313 } else if (isExpanded()) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002314 return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
Selim Cinek8d490d42015-04-10 00:05:50 -07002315 } else {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002316 return Math.max(getCollapsedHeight(), getHeadsUpHeight());
Selim Cinek8d490d42015-04-10 00:05:50 -07002317 }
Selim Cinek31aada42015-12-18 17:51:15 -08002318 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07002319 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08002320 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07002321 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02002322 }
Selim Cinekb5605e52015-02-20 18:21:41 +01002323 }
Selim Cinek1685e632014-04-08 02:27:49 +02002324
Adrian Roos6f6e1592017-05-02 16:22:53 -07002325 private boolean isHeadsUpAllowed() {
Kevina97ea052018-09-11 13:53:18 -07002326 return !mOnKeyguard && !mOnAmbient;
Adrian Roos6f6e1592017-05-02 16:22:53 -07002327 }
2328
Mady Mellorc3d6f7d2018-11-07 09:36:56 -08002329 private boolean isShownAsBubble() {
Mady Mellor3f2efdb2018-11-21 11:30:45 -08002330 return mEntry.isBubble() && !mEntry.showInShadeWhenBubble() && !mEntry.isBubbleDismissed();
Mady Mellorc3d6f7d2018-11-07 09:36:56 -08002331 }
2332
2333 /**
2334 * Set the current status bar state.
2335 * @param state should be from {@link com.android.systemui.statusbar.StatusBarState}.
2336 */
2337 public void setStatusBarState(int state) {
2338 if (mStatusBarState != state) {
2339 mStatusBarState = state;
2340 }
2341 }
2342
Mady Mellor43c2cd12016-12-12 21:05:13 -08002343 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07002344 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07002345 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01002346 }
2347
Selim Cinek263398f2015-10-21 17:40:23 -07002348 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05002349 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07002350 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
2351 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
Selim Cinek414ad332017-02-24 19:06:12 -08002352 mChildrenContainer.recreateNotificationHeader(mExpandClickListener
2353 );
Selim Cinek263398f2015-10-21 17:40:23 -07002354 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07002355 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002356 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08002357 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08002358 updateChildrenVisibility();
Selim Cinek2871bef2017-11-22 08:40:00 -08002359 applyChildrenRoundness();
Selim Cinek263398f2015-10-21 17:40:23 -07002360 }
Rohan Shah63411fc2018-03-28 19:05:52 -07002361 /**
2362 * Returns the number of channels covered by the notification row (including its children if
2363 * it's a summary notification).
2364 */
2365 public int getNumUniqueChannels() {
2366 ArraySet<NotificationChannel> channels = new ArraySet<>();
2367
2368 channels.add(mEntry.channel);
2369
2370 // If this is a summary, then add in the children notification channels for the
2371 // same user and pkg.
2372 if (mIsSummaryWithChildren) {
2373 final List<ExpandableNotificationRow> childrenRows = getNotificationChildren();
2374 final int numChildren = childrenRows.size();
2375 for (int i = 0; i < numChildren; i++) {
2376 final ExpandableNotificationRow childRow = childrenRows.get(i);
2377 final NotificationChannel childChannel = childRow.getEntry().channel;
2378 final StatusBarNotification childSbn = childRow.getStatusBarNotification();
2379 if (childSbn.getUser().equals(mStatusBarNotification.getUser()) &&
2380 childSbn.getPackageName().equals(mStatusBarNotification.getPackageName())) {
2381 channels.add(childChannel);
2382 }
2383 }
2384 }
2385 return channels.size();
2386 }
Selim Cinek263398f2015-10-21 17:40:23 -07002387
Mady Mellorb0a82462016-04-30 17:31:02 -07002388 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07002389 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002390 mChildrenContainer.updateChildrenHeaderAppearance();
2391 }
2392 }
2393
Selim Cinek1685e632014-04-08 02:27:49 +02002394 /**
2395 * Check whether the view state is currently expanded. This is given by the system in {@link
2396 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
2397 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
2398 * view can differ from this state, if layout params are modified from outside.
2399 *
2400 * @return whether the view state is currently expanded.
2401 */
Selim Cinek83bc7832015-10-22 13:26:54 -07002402 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08002403 return isExpanded(false /* allowOnKeyguard */);
2404 }
2405
2406 public boolean isExpanded(boolean allowOnKeyguard) {
2407 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01002408 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
2409 || isUserExpanded());
2410 }
2411
2412 private boolean isSystemChildExpanded() {
2413 return mIsSystemChildExpanded;
2414 }
2415
2416 public void setSystemChildExpanded(boolean expanded) {
2417 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02002418 }
2419
Mady Mellor035badd2017-04-04 18:45:30 -07002420 public void setLayoutListener(LayoutListener listener) {
2421 mLayoutListener = listener;
2422 }
2423
2424 public void removeListener() {
2425 mLayoutListener = null;
2426 }
2427
Selim Cinek1685e632014-04-08 02:27:49 +02002428 @Override
2429 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002430 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02002431 super.onLayout(changed, left, top, right, bottom);
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002432 if (intrinsicBefore != getIntrinsicHeight()) {
2433 notifyHeightChanged(true /* needsAnimation */);
2434 }
Mady Mellor95d743c2017-01-10 12:05:27 -08002435 if (mMenuRow.getMenuView() != null) {
Aaron Heuckroth266cb342018-09-07 14:52:04 -04002436 mMenuRow.onParentHeightUpdate();
Mady Mellora6edc872016-04-26 11:01:03 -07002437 }
Selim Cinek875a3a12016-11-18 17:52:16 -08002438 updateContentShiftHeight();
Mady Mellor035badd2017-04-04 18:45:30 -07002439 if (mLayoutListener != null) {
2440 mLayoutListener.onLayout();
2441 }
Selim Cinek875a3a12016-11-18 17:52:16 -08002442 }
2443
2444 /**
2445 * Updates the content shift height such that the header is completely hidden when coming from
2446 * the top.
2447 */
2448 private void updateContentShiftHeight() {
Selim Cinek414ad332017-02-24 19:06:12 -08002449 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek875a3a12016-11-18 17:52:16 -08002450 if (notificationHeader != null) {
2451 CachingIconView icon = notificationHeader.getIcon();
2452 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
2453 } else {
2454 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
2455 }
Selim Cinek1685e632014-04-08 02:27:49 +02002456 }
2457
Selim Cinekfa0a2d32016-01-14 13:02:21 -08002458 @Override
2459 public void notifyHeightChanged(boolean needsAnimation) {
2460 super.notifyHeightChanged(needsAnimation);
2461 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
2462 }
2463
Selim Cinek3c76d502016-02-19 15:16:33 -08002464 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02002465 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08002466 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02002467 }
2468
Mady Mellor43c2cd12016-12-12 21:05:13 -08002469 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02002470 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07002471 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08002472 if (mIsSummaryWithChildren) {
2473 List<ExpandableNotificationRow> notificationChildren =
2474 mChildrenContainer.getNotificationChildren();
2475 for (int i = 0; i < notificationChildren.size(); i++) {
2476 ExpandableNotificationRow child = notificationChildren.get(i);
2477 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
2478 }
2479 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002480 }
2481
Mady Mellor43c2cd12016-12-12 21:05:13 -08002482 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02002483 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
2484 long duration) {
Selim Cinek69594fb2018-05-18 12:06:10 -07002485 if (getVisibility() == GONE) {
2486 // If we are GONE, the hideSensitive parameter will not be calculated and always be
2487 // false, which is incorrect, let's wait until a real call comes in later.
2488 return;
2489 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002490 boolean oldShowingPublic = mShowingPublic;
2491 mShowingPublic = mSensitive && hideSensitive;
2492 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
2493 return;
2494 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05002495
2496 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02002497 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002498
Jorim Jaggiae441282014-08-01 02:45:18 +02002499 if (!animated) {
2500 mPublicLayout.animate().cancel();
2501 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07002502 if (mChildrenContainer != null) {
2503 mChildrenContainer.animate().cancel();
2504 mChildrenContainer.setAlpha(1f);
2505 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002506 mPublicLayout.setAlpha(1f);
2507 mPrivateLayout.setAlpha(1f);
2508 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08002509 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02002510 } else {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002511 animateShowingPublic(delay, duration, mShowingPublic);
Jorim Jaggiae441282014-08-01 02:45:18 +02002512 }
Selim Cinekc3179332016-03-04 14:44:56 -08002513 NotificationContentView showingLayout = getShowingLayout();
2514 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002515 mPrivateLayout.updateExpandButtons(isExpandable());
Lucas Dupinb6ed63b2017-05-30 16:17:42 -07002516 updateShelfIconColor();
Adrian Roose5726a22016-12-19 14:26:51 -08002517 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02002518 mShowingPublicInitialized = true;
2519 }
2520
Selim Cinek0b9cf462017-12-07 16:31:03 -08002521 private void animateShowingPublic(long delay, long duration, boolean showingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002522 View[] privateViews = mIsSummaryWithChildren
2523 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08002524 : new View[] {mPrivateLayout};
2525 View[] publicViews = new View[] {mPublicLayout};
Selim Cinek0b9cf462017-12-07 16:31:03 -08002526 View[] hiddenChildren = showingPublic ? privateViews : publicViews;
2527 View[] shownChildren = showingPublic ? publicViews : privateViews;
Selim Cinekd84a5932015-12-15 11:45:36 -08002528 for (final View hiddenView : hiddenChildren) {
2529 hiddenView.setVisibility(View.VISIBLE);
2530 hiddenView.animate().cancel();
2531 hiddenView.animate()
2532 .alpha(0f)
2533 .setStartDelay(delay)
2534 .setDuration(duration)
2535 .withEndAction(new Runnable() {
2536 @Override
2537 public void run() {
2538 hiddenView.setVisibility(View.INVISIBLE);
2539 }
2540 });
2541 }
2542 for (View showView : shownChildren) {
2543 showView.setVisibility(View.VISIBLE);
2544 showView.setAlpha(0f);
2545 showView.animate().cancel();
2546 showView.animate()
2547 .alpha(1f)
2548 .setStartDelay(delay)
2549 .setDuration(duration);
2550 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04002551 }
2552
Mady Mellor43c2cd12016-12-12 21:05:13 -08002553 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08002554 public boolean mustStayOnScreen() {
Selim Cinek9b9d6e12017-11-30 12:29:47 +01002555 return mIsHeadsUp && mMustStayOnScreen;
Selim Cinek3776fe02016-02-04 13:32:43 -08002556 }
2557
Selim Cinek9e624e72016-07-20 13:46:49 -07002558 /**
2559 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
2560 * otherwise some state might not be updated. To request about the general clearability
Ned Burnsf81c4c42019-01-07 14:10:43 -05002561 * see {@link NotificationEntry#isClearable()}.
Selim Cinek9e624e72016-07-20 13:46:49 -07002562 */
2563 public boolean canViewBeDismissed() {
Evan Laird94492852018-10-25 13:43:01 -04002564 return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
Selim Cinek0b9cf462017-12-07 16:31:03 -08002565 }
2566
2567 private boolean shouldShowPublic() {
2568 return mSensitive && mHideSensitiveForIntrinsicHeight;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002569 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02002570
Ricky Waicd35def2016-05-03 11:07:07 +01002571 public void makeActionsVisibile() {
2572 setUserExpanded(true, true);
2573 if (isChildInGroup()) {
2574 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
2575 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07002576 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01002577 }
2578
Selim Cinekb5605e52015-02-20 18:21:41 +01002579 public void setChildrenExpanded(boolean expanded, boolean animate) {
2580 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07002581 if (mChildrenContainer != null) {
2582 mChildrenContainer.setChildrenExpanded(expanded);
2583 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07002584 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07002585 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01002586 }
2587
Selim Cinekb5605e52015-02-20 18:21:41 +01002588 public static void applyTint(View v, int color) {
2589 int alpha;
2590 if (color != 0) {
2591 alpha = COLORED_DIVIDER_ALPHA;
2592 } else {
2593 color = 0xff000000;
2594 alpha = DEFAULT_DIVIDER_ALPHA;
2595 }
2596 if (v.getBackground() instanceof ColorDrawable) {
2597 ColorDrawable background = (ColorDrawable) v.getBackground();
2598 background.mutate();
2599 background.setColor(color);
2600 background.setAlpha(alpha);
2601 }
2602 }
2603
Selim Cinek1685e632014-04-08 02:27:49 +02002604 public int getMaxExpandHeight() {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002605 return mPrivateLayout.getExpandHeight();
2606 }
2607
2608
2609 private int getHeadsUpHeight() {
2610 return mPrivateLayout.getHeadsUpHeight();
Chris Wren51c75102013-07-16 20:49:17 -04002611 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02002612
Mady Mellor34958fa2016-02-23 09:52:17 -08002613 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002614 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08002615 }
2616
Jorim Jaggibe565df2014-04-28 17:51:23 +02002617 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002618 public boolean isContentExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002619 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002620 return true;
2621 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002622 NotificationContentView showingLayout = getShowingLayout();
2623 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002624 }
2625
2626 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07002627 protected View getContentView() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002628 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cineka5703182016-05-11 21:23:16 -04002629 return mChildrenContainer;
2630 }
Selim Cinek560e64d2015-06-09 19:58:11 -07002631 return getShowingLayout();
2632 }
2633
2634 @Override
Gus Prevas211181532018-12-13 14:49:33 -05002635 public long performRemoveAnimation(long duration, long delay, float translationDirection,
2636 boolean isHeadsUpAnimation, float endLocation, Runnable onFinishedRunnable,
2637 AnimatorListenerAdapter animationListener) {
2638 if (mMenuRow.isMenuVisible()) {
2639 Animator anim = getTranslateViewAnimator(0f, null /* listener */);
2640 if (anim != null) {
2641 anim.addListener(new AnimatorListenerAdapter() {
2642 @Override
2643 public void onAnimationEnd(Animator animation) {
2644 ExpandableNotificationRow.super.performRemoveAnimation(
2645 duration, delay, translationDirection, isHeadsUpAnimation,
2646 endLocation, onFinishedRunnable, animationListener);
2647 }
2648 });
2649 anim.start();
2650 return anim.getDuration();
2651 }
2652 }
2653 return super.performRemoveAnimation(duration, delay, translationDirection,
2654 isHeadsUpAnimation, endLocation, onFinishedRunnable, animationListener);
2655 }
2656
2657 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07002658 protected void onAppearAnimationFinished(boolean wasAppearing) {
2659 super.onAppearAnimationFinished(wasAppearing);
2660 if (wasAppearing) {
2661 // During the animation the visible view might have changed, so let's make sure all
2662 // alphas are reset
2663 if (mChildrenContainer != null) {
2664 mChildrenContainer.setAlpha(1.0f);
2665 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
2666 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08002667 for (NotificationContentView l : mLayouts) {
2668 l.setAlpha(1.0f);
2669 l.setLayerType(LAYER_TYPE_NONE, null);
2670 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07002671 }
2672 }
2673
2674 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07002675 public int getExtraBottomPadding() {
2676 if (mIsSummaryWithChildren && isGroupExpanded()) {
2677 return mIncreasedPaddingBetweenElements;
2678 }
2679 return 0;
2680 }
2681
2682 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02002683 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinek4ca6c632017-02-23 18:03:37 -08002684 boolean changed = height != getActualHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +01002685 super.setActualHeight(height, notifyListeners);
Selim Cinek4ca6c632017-02-23 18:03:37 -08002686 if (changed && isRemoved()) {
2687 // TODO: remove this once we found the gfx bug for this.
2688 // This is a hack since a removed view sometimes would just stay blank. it occured
2689 // when sending yourself a message and then clicking on it.
2690 ViewGroup parent = (ViewGroup) getParent();
2691 if (parent != null) {
2692 parent.invalidate();
2693 }
2694 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002695 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08002696 mGuts.setActualHeight(height);
2697 return;
2698 }
Selim Cinekeef84282015-10-30 16:28:00 -07002699 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002700 for (NotificationContentView l : mLayouts) {
2701 l.setContentHeight(contentHeight);
2702 }
Selim Cinek42357e02016-02-24 18:48:01 -08002703 if (mIsSummaryWithChildren) {
2704 mChildrenContainer.setActualHeight(height);
2705 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002706 if (mGuts != null) {
2707 mGuts.setActualHeight(height);
2708 }
Mady Mellor54540972017-06-07 11:55:36 -07002709 if (mMenuRow.getMenuView() != null) {
Aaron Heuckroth266cb342018-09-07 14:52:04 -04002710 mMenuRow.onParentHeightUpdate();
Mady Mellor54540972017-06-07 11:55:36 -07002711 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002712 }
2713
2714 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01002715 public int getMaxContentHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002716 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002717 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002718 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002719 NotificationContentView showingLayout = getShowingLayout();
2720 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02002721 }
2722
2723 @Override
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002724 public int getMinHeight(boolean ignoreTemporaryStates) {
2725 if (!ignoreTemporaryStates && mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07002726 return mGuts.getIntrinsicHeight();
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002727 } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp
2728 && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08002729 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
Selim Cinek0b9cf462017-12-07 16:31:03 -08002730 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !shouldShowPublic()) {
Selim Cinekb55386d2015-12-16 17:26:49 -08002731 return mChildrenContainer.getMinHeight();
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002732 } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002733 return getHeadsUpHeight();
Selim Cinekb55386d2015-12-16 17:26:49 -08002734 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002735 NotificationContentView showingLayout = getShowingLayout();
2736 return showingLayout.getMinHeight();
2737 }
2738
2739 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07002740 public int getCollapsedHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002741 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek567e8452016-03-24 10:54:56 -07002742 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002743 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002744 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002745 }
2746
2747 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02002748 public void setClipTopAmount(int clipTopAmount) {
2749 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002750 for (NotificationContentView l : mLayouts) {
2751 l.setClipTopAmount(clipTopAmount);
2752 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002753 if (mGuts != null) {
2754 mGuts.setClipTopAmount(clipTopAmount);
2755 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002756 }
2757
Selim Cineka686b2c2016-10-26 13:58:27 -07002758 @Override
2759 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek2627d722018-01-19 12:16:49 -08002760 if (mExpandAnimationRunning) {
2761 return;
2762 }
Selim Cinek65d418e2016-11-29 15:42:34 -08002763 if (clipBottomAmount != mClipBottomAmount) {
2764 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002765 for (NotificationContentView l : mLayouts) {
2766 l.setClipBottomAmount(clipBottomAmount);
2767 }
Selim Cinek65d418e2016-11-29 15:42:34 -08002768 if (mGuts != null) {
2769 mGuts.setClipBottomAmount(clipBottomAmount);
2770 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002771 }
Selim Cinekc25989e2018-02-16 16:42:14 -08002772 if (mChildrenContainer != null && !mChildIsExpanding) {
Selim Cinek65d418e2016-11-29 15:42:34 -08002773 // We have to update this even if it hasn't changed, since the children locations can
2774 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08002775 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
2776 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002777 }
2778
Selim Cinek42357e02016-02-24 18:48:01 -08002779 public NotificationContentView getShowingLayout() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002780 return shouldShowPublic() ? mPublicLayout : mPrivateLayout;
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002781 }
Chris Wren78403d72014-07-28 10:23:24 +01002782
Kevind4660b22018-09-27 10:57:35 -07002783 public View getExpandedContentView() {
2784 return getPrivateLayout().getExpandedChild();
2785 }
2786
Selim Cinek1a48bab2017-02-17 19:38:40 -08002787 public void setLegacy(boolean legacy) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08002788 for (NotificationContentView l : mLayouts) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08002789 l.setLegacy(legacy);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002790 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07002791 }
2792
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002793 @Override
2794 protected void updateBackgroundTint() {
2795 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07002796 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002797 if (mIsSummaryWithChildren) {
2798 List<ExpandableNotificationRow> notificationChildren =
2799 mChildrenContainer.getNotificationChildren();
2800 for (int i = 0; i < notificationChildren.size(); i++) {
2801 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07002802 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002803 }
2804 }
2805 }
2806
Mady Mellorb0a82462016-04-30 17:31:02 -07002807 /**
2808 * Called when a group has finished animating from collapsed or expanded state.
2809 */
2810 public void onFinishedExpansionChange() {
2811 mGroupExpansionChanging = false;
2812 updateBackgroundForGroupState();
2813 }
2814
2815 /**
2816 * Updates the parent and children backgrounds in a group based on the expansion state.
2817 */
2818 public void updateBackgroundForGroupState() {
2819 if (mIsSummaryWithChildren) {
2820 // Only when the group has finished expanding do we hide its background.
Anthony Chen6bf88a02017-04-10 14:41:44 -07002821 mShowNoBackground = !mShowGroupBackgroundWhenExpanded && isGroupExpanded()
2822 && !isGroupExpansionChanging() && !isUserLocked();
Mady Mellorb0a82462016-04-30 17:31:02 -07002823 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
2824 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
2825 for (int i = 0; i < children.size(); i++) {
2826 children.get(i).updateBackgroundForGroupState();
2827 }
2828 } else if (isChildInGroup()) {
2829 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
2830 // Only show a background if the group is expanded OR if it is expanding / collapsing
Anthony Chen6bf88a02017-04-10 14:41:44 -07002831 // and has a custom background color.
Mady Mellorb0a82462016-04-30 17:31:02 -07002832 final boolean showBackground = isGroupExpanded()
2833 || ((mNotificationParent.isGroupExpansionChanging()
Anthony Chen6bf88a02017-04-10 14:41:44 -07002834 || mNotificationParent.isUserLocked()) && childColor != 0);
Mady Mellorb0a82462016-04-30 17:31:02 -07002835 mShowNoBackground = !showBackground;
2836 } else {
2837 // Only children or parents ever need no background.
2838 mShowNoBackground = false;
2839 }
2840 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002841 updateBackground();
2842 }
2843
Adrian Roos4a579672016-05-24 16:54:37 -07002844 public int getPositionOfChild(ExpandableNotificationRow childRow) {
2845 if (mIsSummaryWithChildren) {
2846 return mChildrenContainer.getPositionInLinearLayout(childRow);
2847 }
2848 return 0;
2849 }
2850
Chris Wren78403d72014-07-28 10:23:24 +01002851 public void setExpansionLogger(ExpansionLogger logger, String key) {
2852 mLogger = logger;
2853 mLoggingKey = key;
2854 }
2855
Chris Wren6abeeb92016-05-26 14:44:38 -04002856 public void onExpandedByGesture(boolean userExpanded) {
2857 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
2858 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
2859 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
2860 }
2861 MetricsLogger.action(mContext, event, userExpanded);
2862 }
2863
Selim Cinek6183d122016-01-14 18:48:41 -08002864 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08002865 public float getIncreasedPaddingAmount() {
2866 if (mIsSummaryWithChildren) {
2867 if (isGroupExpanded()) {
2868 return 1.0f;
2869 } else if (isUserLocked()) {
Selim Cinek414ad332017-02-24 19:06:12 -08002870 return mChildrenContainer.getIncreasedPaddingAmount();
Selim Cinek42357e02016-02-24 18:48:01 -08002871 }
Selim Cinek99104832017-01-25 14:47:33 -08002872 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08002873 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08002874 }
2875 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08002876 }
2877
Selim Cineka7ed2c12017-01-23 20:47:24 -08002878 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08002879 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08002880 }
2881
Selim Cinek61633a82016-01-25 15:54:10 -08002882 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08002883 protected boolean disallowSingleClick(MotionEvent event) {
dongwan0605.kimc4ddef42018-05-06 17:40:23 +09002884 if (areGutsExposed()) {
2885 return false;
2886 }
Selim Cinek6183d122016-01-14 18:48:41 -08002887 float x = event.getX();
2888 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08002889 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002890 if (header != null && header.isInTouchRect(x - getTranslation(), y)) {
2891 return true;
2892 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002893 if ((!mIsSummaryWithChildren || shouldShowPublic())
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002894 && getShowingLayout().disallowSingleClick(x, y)) {
2895 return true;
Selim Cinek6183d122016-01-14 18:48:41 -08002896 }
2897 return super.disallowSingleClick(event);
2898 }
2899
Selim Cinek414ad332017-02-24 19:06:12 -08002900 private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04002901 boolean nowExpanded = isExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08002902 if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
Chris Wren698b1702016-05-23 11:16:32 -04002903 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
2904 }
Selim Cinek414ad332017-02-24 19:06:12 -08002905 if (nowExpanded != wasExpanded) {
2906 updateShelfIconColor();
2907 if (mLogger != null) {
2908 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded);
2909 }
2910 if (mIsSummaryWithChildren) {
2911 mChildrenContainer.onExpansionChanged();
2912 }
Chris Wren78403d72014-07-28 10:23:24 +01002913 }
2914 }
Selim Cinek570981d2015-12-01 11:37:01 -08002915
Selim Cineke9bad242016-06-15 11:46:37 -07002916 @Override
2917 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2918 super.onInitializeAccessibilityNodeInfoInternal(info);
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002919 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
Selim Cineke9bad242016-06-15 11:46:37 -07002920 if (canViewBeDismissed()) {
2921 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
2922 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002923 boolean expandable = shouldShowPublic();
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002924 boolean isExpanded = false;
2925 if (!expandable) {
2926 if (mIsSummaryWithChildren) {
2927 expandable = true;
2928 if (!mIsLowPriority || isExpanded()) {
2929 isExpanded = isGroupExpanded();
2930 }
2931 } else {
2932 expandable = mPrivateLayout.isContentExpandable();
2933 isExpanded = isExpanded();
2934 }
2935 }
2936 if (expandable) {
2937 if (isExpanded) {
2938 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
2939 } else {
2940 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
2941 }
2942 }
Mady Mellorb3a6aed2018-05-11 13:24:07 -07002943 NotificationMenuRowPlugin provider = getProvider();
2944 if (provider != null) {
2945 MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
2946 if (snoozeMenu != null) {
2947 AccessibilityAction action = new AccessibilityAction(R.id.action_snooze,
2948 getContext().getResources()
2949 .getString(R.string.notification_menu_snooze_action));
2950 info.addAction(action);
2951 }
2952 }
Selim Cineke9bad242016-06-15 11:46:37 -07002953 }
2954
2955 @Override
2956 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
2957 if (super.performAccessibilityActionInternal(action, arguments)) {
2958 return true;
2959 }
2960 switch (action) {
2961 case AccessibilityNodeInfo.ACTION_DISMISS:
Rohan Shah524cf7b2018-03-15 14:40:02 -07002962 performDismissWithBlockingHelper(true /* fromAccessibility */);
Selim Cineke9bad242016-06-15 11:46:37 -07002963 return true;
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002964 case AccessibilityNodeInfo.ACTION_COLLAPSE:
2965 case AccessibilityNodeInfo.ACTION_EXPAND:
2966 mExpandClickListener.onClick(this);
2967 return true;
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002968 case AccessibilityNodeInfo.ACTION_LONG_CLICK:
2969 doLongClickCallback();
2970 return true;
Jason Monk05dd5672018-08-09 09:38:21 -04002971 default:
2972 if (action == R.id.action_snooze) {
2973 NotificationMenuRowPlugin provider = getProvider();
2974 if (provider == null) {
2975 provider = createMenu();
2976 }
2977 MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
2978 if (snoozeMenu != null) {
2979 doLongClickCallback(getWidth() / 2, getHeight() / 2, snoozeMenu);
2980 }
2981 return true;
Mady Mellorb3a6aed2018-05-11 13:24:07 -07002982 }
Selim Cineke9bad242016-06-15 11:46:37 -07002983 }
2984 return false;
2985 }
2986
2987 public boolean shouldRefocusOnDismiss() {
2988 return mRefocusOnDismiss || isAccessibilityFocused();
2989 }
2990
Selim Cinek570981d2015-12-01 11:37:01 -08002991 public interface OnExpandClickListener {
Ned Burnsf81c4c42019-01-07 14:10:43 -05002992 void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08002993 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002994
2995 @Override
Dave Mankoffa4d195d2018-11-16 13:33:27 -05002996 public ExpandableViewState createExpandableViewState() {
2997 return new NotificationViewState();
Selim Cinekf93bf3e2018-05-08 14:43:21 -07002998 }
2999
Selim Cinekd127d792016-11-01 19:11:41 -07003000 @Override
3001 public boolean isAboveShelf() {
Selim Cinek459aee32019-02-20 11:18:56 -08003002 return showingAmbientPulsing() || (!isOnKeyguard()
Selim Cinek2627d722018-01-19 12:16:49 -08003003 && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf)
Selim Cinek5040f2e2019-02-14 18:22:42 -08003004 || mExpandAnimationRunning || mChildIsExpanding));
Selim Cinekd127d792016-11-01 19:11:41 -07003005 }
3006
Kevina97ea052018-09-11 13:53:18 -07003007 public void setOnAmbient(boolean onAmbient) {
3008 if (onAmbient != mOnAmbient) {
3009 mOnAmbient = onAmbient;
Adrian Roos0aac04f2016-12-08 15:59:29 -08003010 notifyHeightChanged(false /* needsAnimation */);
3011 }
3012 }
3013
Selim Cinek0fe07392017-11-09 13:26:34 -08003014 @Override
Tony Huangc092c432018-05-18 17:38:54 +08003015 public boolean topAmountNeedsClipping() {
3016 if (isGroupExpanded()) {
3017 return true;
3018 }
3019 if (isGroupExpansionChanging()) {
3020 return true;
3021 }
3022 if (getShowingLayout().shouldClipToRounding(true /* topRounded */,
3023 false /* bottomRounded */)) {
3024 return true;
3025 }
3026 if (mGuts != null && mGuts.getAlpha() != 0.0f) {
3027 return true;
3028 }
3029 return false;
3030 }
3031
3032 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08003033 protected boolean childNeedsClipping(View child) {
3034 if (child instanceof NotificationContentView) {
3035 NotificationContentView contentView = (NotificationContentView) child;
3036 if (isClippingNeeded()) {
3037 return true;
Selim Cinek86bfcee2018-01-17 11:00:47 -08003038 } else if (!hasNoRounding()
3039 && contentView.shouldClipToRounding(getCurrentTopRoundness() != 0.0f,
3040 getCurrentBottomRoundness() != 0.0f)) {
Selim Cinek515b2032017-11-15 10:20:19 -08003041 return true;
3042 }
3043 } else if (child == mChildrenContainer) {
Selim Cinek6487ebf2018-11-28 18:57:40 -08003044 if (isClippingNeeded() || !hasNoRounding()) {
Selim Cinek515b2032017-11-15 10:20:19 -08003045 return true;
3046 }
3047 } else if (child instanceof NotificationGuts) {
Selim Cinekb95fd182017-12-21 13:03:32 -08003048 return !hasNoRounding();
Selim Cinek515b2032017-11-15 10:20:19 -08003049 }
3050 return super.childNeedsClipping(child);
3051 }
3052
3053 @Override
Selim Cinek2871bef2017-11-22 08:40:00 -08003054 protected void applyRoundness() {
3055 super.applyRoundness();
3056 applyChildrenRoundness();
3057 }
3058
3059 private void applyChildrenRoundness() {
3060 if (mIsSummaryWithChildren) {
3061 mChildrenContainer.setCurrentBottomRoundness(getCurrentBottomRoundness());
3062 }
3063 }
3064
3065 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08003066 public Path getCustomClipPath(View child) {
3067 if (child instanceof NotificationGuts) {
Selim Cinekdefd46f2018-05-30 11:47:08 -07003068 return getClipPath(true /* ignoreTranslation */);
Selim Cinek515b2032017-11-15 10:20:19 -08003069 }
3070 return super.getCustomClipPath(child);
3071 }
3072
Selim Cinekb95fd182017-12-21 13:03:32 -08003073 private boolean hasNoRounding() {
3074 return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f;
Selim Cinek0fe07392017-11-09 13:26:34 -08003075 }
3076
Kevina97ea052018-09-11 13:53:18 -07003077 public boolean isOnAmbient() {
3078 return mOnAmbient;
Adrian Roos6f6e1592017-05-02 16:22:53 -07003079 }
3080
Evan Laird94492852018-10-25 13:43:01 -04003081 //TODO: this logic can't depend on layout if we are recycling!
3082 public boolean isMediaRow() {
3083 return getExpandedContentView() != null
3084 && getExpandedContentView().findViewById(
3085 com.android.internal.R.id.media_actions) != null;
3086 }
3087
3088 public boolean isTopLevelChild() {
3089 return getParent() instanceof NotificationStackScrollLayout;
3090 }
3091
3092 public boolean isGroupNotFullyVisible() {
3093 return getClipTopAmount() > 0 || getTranslationY() < 0;
3094 }
3095
Selim Cinekd127d792016-11-01 19:11:41 -07003096 public void setAboveShelf(boolean aboveShelf) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07003097 boolean wasAboveShelf = isAboveShelf();
Selim Cinekd127d792016-11-01 19:11:41 -07003098 mAboveShelf = aboveShelf;
Selim Cinek5cf1d052017-06-01 17:36:46 -07003099 if (isAboveShelf() != wasAboveShelf) {
3100 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
3101 }
Selim Cinekd127d792016-11-01 19:11:41 -07003102 }
3103
Gus Prevasa18dc572019-01-14 16:11:22 -05003104 /** Sets whether dismiss gestures are right-to-left (instead of left-to-right). */
3105 public void setDismissRtl(boolean dismissRtl) {
3106 mMenuRow.setDismissRtl(dismissRtl);
3107 }
3108
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003109 private static class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08003110
3111 @Override
3112 public void applyToView(View view) {
Selim Cinekbbcebde2016-11-09 18:28:20 -08003113 if (view instanceof ExpandableNotificationRow) {
3114 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinek2627d722018-01-19 12:16:49 -08003115 if (row.isExpandAnimationRunning()) {
3116 return;
3117 }
Selim Cinekc25989e2018-02-16 16:42:14 -08003118 handleFixedTranslationZ(row);
Selim Cinek2627d722018-01-19 12:16:49 -08003119 super.applyToView(view);
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003120 row.applyChildrenState();
Selim Cinekbbcebde2016-11-09 18:28:20 -08003121 }
3122 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08003123
Selim Cinekc25989e2018-02-16 16:42:14 -08003124 private void handleFixedTranslationZ(ExpandableNotificationRow row) {
3125 if (row.hasExpandingChild()) {
3126 zTranslation = row.getTranslationZ();
3127 clipTopAmount = row.getClipTopAmount();
3128 }
3129 }
3130
Selim Cinek0cfbef42016-11-09 19:06:36 -08003131 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08003132 protected void onYTranslationAnimationFinished(View view) {
3133 super.onYTranslationAnimationFinished(view);
Selim Cinekd4776a52017-02-14 18:50:16 -08003134 if (view instanceof ExpandableNotificationRow) {
3135 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
3136 if (row.isHeadsUpAnimatingAway()) {
3137 row.setHeadsUpAnimatingAway(false);
3138 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08003139 }
3140 }
3141
3142 @Override
3143 public void animateTo(View child, AnimationProperties properties) {
Selim Cinek0cfbef42016-11-09 19:06:36 -08003144 if (child instanceof ExpandableNotificationRow) {
3145 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
Selim Cinek2627d722018-01-19 12:16:49 -08003146 if (row.isExpandAnimationRunning()) {
3147 return;
3148 }
Selim Cinekc25989e2018-02-16 16:42:14 -08003149 handleFixedTranslationZ(row);
Selim Cinek2627d722018-01-19 12:16:49 -08003150 super.animateTo(child, properties);
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003151 row.startChildAnimation(properties);
Selim Cinek0cfbef42016-11-09 19:06:36 -08003152 }
3153 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08003154 }
Selim Cinek817abe72017-05-24 11:08:55 -07003155
Selim Cinek459aee32019-02-20 11:18:56 -08003156 public void setAmbientGoingAway(boolean goingAway) {
3157 mAmbientGoingAway = goingAway;
3158 }
3159
Selim Cinek817abe72017-05-24 11:08:55 -07003160 @VisibleForTesting
3161 protected void setChildrenContainer(NotificationChildrenContainer childrenContainer) {
3162 mChildrenContainer = childrenContainer;
3163 }
Geoffrey Pitsch409db272017-08-28 14:51:52 +00003164
Julia Reynoldsfc640012018-02-21 12:25:27 -05003165 @VisibleForTesting
3166 protected void setPrivateLayout(NotificationContentView privateLayout) {
3167 mPrivateLayout = privateLayout;
3168 }
3169
3170 @VisibleForTesting
3171 protected void setPublicLayout(NotificationContentView publicLayout) {
3172 mPublicLayout = publicLayout;
3173 }
3174
Geoffrey Pitsch409db272017-08-28 14:51:52 +00003175 /**
3176 * Equivalent to View.OnLongClickListener with coordinates
3177 */
3178 public interface LongPressListener {
3179 /**
3180 * Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
3181 * @return whether the longpress was handled
3182 */
3183 boolean onLongPress(View v, int x, int y, MenuItem item);
3184 }
Julia Reynoldsb5867452018-02-28 16:31:35 -05003185
3186 /**
3187 * Equivalent to View.OnClickListener with coordinates
3188 */
3189 public interface OnAppOpsClickListener {
3190 /**
3191 * Equivalent to {@link View.OnClickListener#onClick(View)} with coordinates
3192 * @return whether the click was handled
3193 */
3194 boolean onClick(View v, int x, int y, MenuItem item);
3195 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07003196
Selim Cinek30887662018-10-15 17:37:21 -07003197 @Override
3198 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3199 super.dump(fd, pw, args);
3200 pw.println(" Notification: " + getStatusBarNotification().getKey());
3201 pw.print(" visibility: " + getVisibility());
3202 pw.print(", alpha: " + getAlpha());
3203 pw.print(", translation: " + getTranslation());
3204 pw.print(", removed: " + isRemoved());
Selim Cinek0db74592018-12-05 17:42:51 -08003205 pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
Selim Cinek85a8f9f2018-11-21 13:58:27 -08003206 NotificationContentView showingLayout = getShowingLayout();
3207 pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
Selim Cinek30887662018-10-15 17:37:21 -07003208 pw.println();
Selim Cinek85a8f9f2018-11-21 13:58:27 -08003209 showingLayout.dump(fd, pw, args);
Selim Cinek30887662018-10-15 17:37:21 -07003210 pw.print(" ");
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003211 if (getViewState() != null) {
3212 getViewState().dump(fd, pw, args);
Selim Cinek30887662018-10-15 17:37:21 -07003213 } else {
3214 pw.print("no viewState!!!");
3215 }
3216 pw.println();
3217 pw.println();
3218 if (mIsSummaryWithChildren) {
Selim Cinek0db74592018-12-05 17:42:51 -08003219 pw.print(" ChildrenContainer");
3220 pw.print(" visibility: " + mChildrenContainer.getVisibility());
3221 pw.print(", alpha: " + mChildrenContainer.getAlpha());
3222 pw.print(", translationY: " + mChildrenContainer.getTranslationY());
3223 pw.println();
Selim Cinek30887662018-10-15 17:37:21 -07003224 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
3225 pw.println(" Children: " + notificationChildren.size());
3226 pw.println(" {");
3227 for(ExpandableNotificationRow child : notificationChildren) {
3228 child.dump(fd, pw, args);
3229 }
3230 pw.println(" }");
3231 pw.println();
3232 }
3233 }
3234
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07003235 /**
3236 * Background task for executing IPCs to check if the notification is a system notification. The
3237 * output is used for both the blocking helper and the notification info.
3238 */
3239 private class SystemNotificationAsyncTask extends AsyncTask<Void, Void, Boolean> {
3240
3241 @Override
3242 protected Boolean doInBackground(Void... voids) {
3243 return isSystemNotification(mContext, mStatusBarNotification);
3244 }
3245
3246 @Override
3247 protected void onPostExecute(Boolean result) {
Julia Reynoldsaa96cf32018-04-17 09:09:04 -04003248 if (mEntry != null) {
3249 mEntry.mIsSystemNotification = result;
3250 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07003251 }
3252 }
Chris Wren51c75102013-07-16 20:49:17 -04003253}