blob: 12d537d3c646aa9f180998f05b928408bcca7bce [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_HEADS_UP;
21import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_PUBLIC;
22import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationCallback;
Dave Mankoffa4d195d2018-11-16 13:33:27 -050023import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
24import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
Selim Cinekc478f902017-02-22 20:55:44 -080025
Mady Mellor4b80b102016-01-22 08:03:58 -080026import android.animation.Animator;
27import android.animation.AnimatorListenerAdapter;
Mady Mellor4b80b102016-01-22 08:03:58 -080028import android.animation.ObjectAnimator;
Mady Mellor4b80b102016-01-22 08:03:58 -080029import android.animation.ValueAnimator.AnimatorUpdateListener;
Kevind4660b22018-09-27 10:57:35 -070030import android.annotation.NonNull;
Selim Cinekddf1b392016-05-27 16:33:10 -070031import android.annotation.Nullable;
Rohan Shah63411fc2018-03-28 19:05:52 -070032import android.app.NotificationChannel;
Chris Wren51c75102013-07-16 20:49:17 -040033import android.content.Context;
Rohan Shah63411fc2018-03-28 19:05:52 -070034import android.content.pm.PackageInfo;
35import android.content.pm.PackageManager;
Mady Mellor9d03a522017-04-04 18:45:30 -070036import android.content.res.Configuration;
Julia Reynoldsb5867452018-02-28 16:31:35 -050037import android.content.res.Resources;
Selim Cinek515b2032017-11-15 10:20:19 -080038import android.graphics.Path;
Selim Cinekcab4a602014-09-03 14:47:57 +020039import android.graphics.drawable.AnimatedVectorDrawable;
40import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010041import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020042import android.graphics.drawable.Drawable;
Rohan Shah4ed1b2a2018-03-30 13:26:01 -070043import android.os.AsyncTask;
Selim Cinekda42d652015-12-04 15:51:16 -080044import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070045import android.os.Bundle;
Kevin38ce6fa2018-10-17 16:00:14 -070046import android.os.SystemClock;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020047import android.service.notification.StatusBarNotification;
Julia Reynoldsfc640012018-02-21 12:25:27 -050048import android.util.ArraySet;
Chris Wren51c75102013-07-16 20:49:17 -040049import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070050import android.util.FloatProperty;
Rohan Shah63411fc2018-03-28 19:05:52 -070051import android.util.Log;
Selim Cinek2627d722018-01-19 12:16:49 -080052import android.util.MathUtils;
Mady Mellorb0a82462016-04-30 17:31:02 -070053import android.util.Property;
Geoffrey Pitsch409db272017-08-28 14:51:52 +000054import android.view.KeyEvent;
Selim Cinek01af3342016-02-09 19:25:31 -080055import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080056import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080057import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050058import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080059import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020060import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020061import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070062import android.view.accessibility.AccessibilityNodeInfo;
Mady Mellorb3a6aed2018-05-11 13:24:07 -070063import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Selim Cinek98713a42015-09-21 15:47:20 +020064import android.widget.Chronometer;
Mady Mellor95d743c2017-01-10 12:05:27 -080065import android.widget.FrameLayout;
Selim Cinekcab4a602014-09-03 14:47:57 +020066import android.widget.ImageView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080067import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010068
Selim Cinek5ba22542017-04-20 15:16:10 -070069import com.android.internal.annotations.VisibleForTesting;
Chris Wren698b1702016-05-23 11:16:32 -040070import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010071import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Lucas Dupina291d192018-06-07 13:59:42 -070072import com.android.internal.util.ContrastColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080073import com.android.internal.widget.CachingIconView;
Mady Mellor95d743c2017-01-10 12:05:27 -080074import com.android.systemui.Dependency;
Selim Cinek0242fbb2016-10-19 13:38:32 -070075import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050076import com.android.systemui.R;
Dave Mankoff468d4f62019-05-08 14:56:29 -040077import com.android.systemui.plugins.FalsingManager;
Mady Mellor95d743c2017-01-10 12:05:27 -080078import com.android.systemui.plugins.PluginListener;
Mady Mellor95d743c2017-01-10 12:05:27 -080079import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
80import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
Selim Cinekc3fec682019-06-06 18:11:07 -070081import com.android.systemui.plugins.statusbar.StatusBarStateController;
Kevin38ce6fa2018-10-17 16:00:14 -070082import com.android.systemui.shared.plugins.PluginManager;
Beth Thibodeaueab4dde2019-02-07 11:37:02 -050083import com.android.systemui.statusbar.NotificationMediaManager;
Rohan Shah20790b82018-07-02 17:21:04 -070084import com.android.systemui.statusbar.RemoteInputController;
85import com.android.systemui.statusbar.StatusBarIconView;
Selim Cinek5cf1d052017-06-01 17:36:46 -070086import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
Selim Cinek2627d722018-01-19 12:16:49 -080087import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
Selim Cinek6743c0b2017-01-18 18:24:01 -080088import com.android.systemui.statusbar.notification.NotificationUtils;
Kevin38ce6fa2018-10-17 16:00:14 -070089import com.android.systemui.statusbar.notification.VisualStabilityManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050090import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Kevin38ce6fa2018-10-17 16:00:14 -070091import com.android.systemui.statusbar.notification.logging.NotificationCounters;
Ned Burns1a5e22f2019-02-14 15:11:52 -050092import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
Rohan Shah20790b82018-07-02 17:21:04 -070093import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
Rohan Shah20790b82018-07-02 17:21:04 -070094import com.android.systemui.statusbar.notification.stack.AmbientState;
95import com.android.systemui.statusbar.notification.stack.AnimationProperties;
96import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
97import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
Evan Laird94492852018-10-25 13:43:01 -040098import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
Selim Cinekc3fec682019-06-06 18:11:07 -070099import com.android.systemui.statusbar.phone.KeyguardBypassController;
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;
Gustav Sennton8a52dc32019-04-15 12:48:23 +0100103import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions;
Selim Cinekb5605e52015-02-20 18:21:41 +0100104
Selim Cinek30887662018-10-15 17:37:21 -0700105import java.io.FileDescriptor;
106import java.io.PrintWriter;
Mady Mellor4b80b102016-01-22 08:03:58 -0800107import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +0100108import java.util.List;
Ned Burns3da3c782019-01-08 21:14:39 -0500109import java.util.concurrent.TimeUnit;
Lucas Dupincecc7c22017-09-12 16:02:45 -0700110import java.util.function.BooleanSupplier;
Selim Cinek8875de12018-03-22 10:14:32 -0700111import java.util.function.Consumer;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500112
Rohan Shah63411fc2018-03-28 19:05:52 -0700113/**
114 * View representing a notification item - this can be either the individual child notification or
115 * the group summary (which contains 1 or more child notifications).
116 */
Mady Mellor95d743c2017-01-10 12:05:27 -0800117public class ExpandableNotificationRow extends ActivatableNotificationView
118 implements PluginListener<NotificationMenuRowPlugin> {
Selim Cinekb5605e52015-02-20 18:21:41 +0100119
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700120 private static final boolean DEBUG = false;
Selim Cinekb5605e52015-02-20 18:21:41 +0100121 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
122 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Mady Mellor95d743c2017-01-10 12:05:27 -0800123 private static final int MENU_VIEW_INDEX = 0;
Rohan Shah63411fc2018-03-28 19:05:52 -0700124 private static final String TAG = "ExpandableNotifRow";
felkachange6c03a02018-05-24 15:38:04 +0800125 public static final float DEFAULT_HEADER_VISIBLE_AMOUNT = 1.0f;
Ned Burns3da3c782019-01-08 21:14:39 -0500126 private static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
Selim Cinekab9c7b22018-12-11 18:15:47 -0800127 private boolean mUpdateBackgroundOnUpdate;
Nadia Benbernou7a18c812019-02-08 16:23:10 -0500128 private boolean mNotificationTranslationFinished = false;
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();
Selim Cinekc3fec682019-06-06 18:11:07 -0700134
Mady Mellor035badd2017-04-04 18:45:30 -0700135 }
136
Selim Cinekc3fec682019-06-06 18:11:07 -0700137 private StatusBarStateController mStatusbarStateController;
138 private KeyguardBypassController mBypassController;
Mady Mellor035badd2017-04-04 18:45:30 -0700139 private LayoutListener mLayoutListener;
Ned Burns1a5e22f2019-02-14 15:11:52 -0500140 private final NotificationContentInflater mNotificationInflater;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700141 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800142 private int mIconTransformContentShiftNoIcon;
Rohan Shahb9d500a2018-06-25 16:27:16 -0700143 private int mMaxHeadsUpHeightBeforeN;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800144 private int mMaxHeadsUpHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800145 private int mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800146 private int mMaxHeadsUpHeightIncreased;
Rohan Shahb9d500a2018-06-25 16:27:16 -0700147 private int mNotificationMinHeightBeforeN;
148 private int mNotificationMinHeightBeforeP;
Selim Cinek01af3342016-02-09 19:25:31 -0800149 private int mNotificationMinHeight;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800150 private int mNotificationMinHeightLarge;
Beth Thibodeaucb395352019-01-25 15:39:54 -0500151 private int mNotificationMinHeightMedia;
Selim Cinek01af3342016-02-09 19:25:31 -0800152 private int mNotificationMaxHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -0700153 private int mIncreasedPaddingBetweenElements;
Selim Cinek2627d722018-01-19 12:16:49 -0800154 private int mNotificationLaunchHeight;
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100155 private boolean mMustStayOnScreen;
Chris Wren51c75102013-07-16 20:49:17 -0400156
Selim Cinek1685e632014-04-08 02:27:49 +0200157 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -0400158 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +0200159 /** Has the user actively changed the expansion state of this row */
160 private boolean mHasUserChangedExpansion;
161 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -0400162 private boolean mUserExpanded;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700163 /** Whether the blocking helper is showing on this notification (even if dismissed) */
164 private boolean mIsBlockingHelperShowing;
Selim Cinek31aada42015-12-18 17:51:15 -0800165
166 /**
167 * Has this notification been expanded while it was pinned
168 */
169 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +0200170 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -0400171 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +0200172 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -0500173 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +0200174 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -0800175 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +0200176 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700177 private boolean mHideSensitiveForIntrinsicHeight;
felkachange6c03a02018-05-24 15:38:04 +0800178 private float mHeaderVisibleAmount = DEFAULT_HEADER_VISIBLE_AMOUNT;
Chris Wren51c75102013-07-16 20:49:17 -0400179
Selim Cinek1685e632014-04-08 02:27:49 +0200180 /**
181 * Is this notification expanded by the system. The expansion state can be overridden by the
182 * user expansion.
183 */
184 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200185
186 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700187 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200188 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700189 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200190
Mady Mellorb0a82462016-04-30 17:31:02 -0700191 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800192 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200193 private NotificationContentView mPublicLayout;
194 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800195 private NotificationContentView[] mLayouts;
Selim Cinek4bb59342016-04-08 19:29:35 -0700196 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100197 private ExpansionLogger mLogger;
198 private String mLoggingKey;
Selim Cinek8d490d42015-04-10 00:05:50 -0700199 private NotificationGuts mGuts;
Ned Burnsf81c4c42019-01-07 14:10:43 -0500200 private NotificationEntry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200201 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700202 private String mAppName;
Kevina97ea052018-09-11 13:53:18 -0700203
204 /**
205 * Whether or not the notification is using the heads up view and should peek from the top.
206 */
Selim Cinek1a521f32014-11-03 17:39:29 +0100207 private boolean mIsHeadsUp;
Kevina97ea052018-09-11 13:53:18 -0700208
209 /**
Kevin38ce6fa2018-10-17 16:00:14 -0700210 * Whether or not the notification should be redacted on the lock screen, i.e has sensitive
211 * content which should be redacted on the lock screen.
212 */
213 private boolean mNeedsRedaction;
Selim Cinek98713a42015-09-21 15:47:20 +0200214 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100215 private ViewStub mChildrenContainerStub;
216 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100217 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700218 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100219 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor95d743c2017-01-10 12:05:27 -0800220 private NotificationMenuRowPlugin mMenuRow;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100221 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100222 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700223 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700224 private FalsingManager mFalsingManager;
Selim Cinek2627d722018-01-19 12:16:49 -0800225 private boolean mExpandAnimationRunning;
Selim Cinek5cf1d052017-06-01 17:36:46 -0700226 private AboveShelfChangedListener mAboveShelfChangedListener;
Selim Cinek31aada42015-12-18 17:51:15 -0800227 private HeadsUpManager mHeadsUpManager;
Selim Cinek8875de12018-03-22 10:14:32 -0700228 private Consumer<Boolean> mHeadsUpAnimatingAwayListener;
Selim Cinekc25989e2018-02-16 16:42:14 -0800229 private boolean mChildIsExpanding;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200230
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700231 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800232 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700233 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700234 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800235 private OnExpandClickListener mOnExpandClickListener;
Julia Reynoldsb5867452018-02-28 16:31:35 -0500236 private View.OnClickListener mOnAppOpsClickListener;
Geoffrey Pitsch409db272017-08-28 14:51:52 +0000237
238 // Listener will be called when receiving a long click event.
239 // Use #setLongPressPosition to optionally assign positional data with the long press.
240 private LongPressListener mLongPressListener;
241
Mady Mellorb0a82462016-04-30 17:31:02 -0700242 private boolean mGroupExpansionChanging;
243
Anthony Chen6bf88a02017-04-10 14:41:44 -0700244 /**
Lucas Dupincecc7c22017-09-12 16:02:45 -0700245 * A supplier that returns true if keyguard is secure.
246 */
247 private BooleanSupplier mSecureStateProvider;
248
249 /**
Anthony Chen6bf88a02017-04-10 14:41:44 -0700250 * Whether or not a notification that is not part of a group of notifications can be manually
251 * expanded by the user.
252 */
253 private boolean mEnableNonGroupedNotificationExpand;
254
255 /**
256 * Whether or not to update the background of the header of the notification when its expanded.
257 * If {@code true}, the header background will disappear when expanded.
258 */
259 private boolean mShowGroupBackgroundWhenExpanded;
260
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800261 private OnClickListener mExpandClickListener = new OnClickListener() {
262 @Override
263 public void onClick(View v) {
Selim Cinek0b9cf462017-12-07 16:31:03 -0800264 if (!shouldShowPublic() && (!mIsLowPriority || isExpanded())
Selim Cinek414ad332017-02-24 19:06:12 -0800265 && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700266 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400267 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
268 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
269 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400270 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
271 nowExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -0800272 onExpansionChanged(true /* userAction */, wasExpanded);
Anthony Chen6bf88a02017-04-10 14:41:44 -0700273 } else if (mEnableNonGroupedNotificationExpand) {
Selim Cineke9bad242016-06-15 11:46:37 -0700274 if (v.isAccessibilityFocused()) {
275 mPrivateLayout.setFocusOnVisibilityChange();
276 }
Selim Cinek31aada42015-12-18 17:51:15 -0800277 boolean nowExpanded;
278 if (isPinned()) {
279 nowExpanded = !mExpandedWhenPinned;
280 mExpandedWhenPinned = nowExpanded;
281 } else {
282 nowExpanded = !isExpanded();
283 setUserExpanded(nowExpanded);
284 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800285 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800286 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400287 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
288 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800289 }
290 }
291 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700292 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700293 private boolean mDismissed;
294 private boolean mKeepInParent;
295 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700296 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
297 new FloatProperty<ExpandableNotificationRow>("translate") {
298 @Override
299 public void setValue(ExpandableNotificationRow object, float value) {
300 object.setTranslation(value);
301 }
302
303 @Override
304 public Float get(ExpandableNotificationRow object) {
305 return object.getTranslation();
306 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700307 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700308 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700309 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700310 private View mChildAfterViewWhenDismissed;
311 private View mGroupParentWhenDismissed;
312 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800313 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700314 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700315 private boolean mAboveShelf;
Selim Cinek875a3a12016-11-18 17:52:16 -0800316 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800317 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800318 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800319 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800320 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800321 private boolean mUseIncreasedHeadsUpHeight;
Selim Cinekef8c2252017-02-10 14:52:18 -0800322 private float mTranslationWhenRemoved;
323 private boolean mWasChildInGroupWhenRemoved;
Ahan Wude396fa2018-05-08 20:42:24 +0800324 private NotificationInlineImageResolver mImageResolver;
Beth Thibodeaueab4dde2019-02-07 11:37:02 -0500325 private NotificationMediaManager mMediaManager;
Mady Mellorb0a82462016-04-30 17:31:02 -0700326
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700327 private SystemNotificationAsyncTask mSystemNotificationAsyncTask =
328 new SystemNotificationAsyncTask();
329
330 /**
331 * Returns whether the given {@code statusBarNotification} is a system notification.
332 * <b>Note</b>, this should be run in the background thread if possible as it makes multiple IPC
333 * calls.
334 */
335 private static Boolean isSystemNotification(
336 Context context, StatusBarNotification statusBarNotification) {
337 PackageManager packageManager = StatusBar.getPackageManagerForUser(
338 context, statusBarNotification.getUser().getIdentifier());
339 Boolean isSystemNotification = null;
340
341 try {
342 PackageInfo packageInfo = packageManager.getPackageInfo(
343 statusBarNotification.getPackageName(), PackageManager.GET_SIGNATURES);
344
345 isSystemNotification =
346 com.android.settingslib.Utils.isSystemPackage(
347 context.getResources(), packageManager, packageInfo);
348 } catch (PackageManager.NameNotFoundException e) {
349 Log.e(TAG, "cacheIsSystemNotification: Could not find package info");
350 }
351 return isSystemNotification;
352 }
353
Mady Mellor43c2cd12016-12-12 21:05:13 -0800354 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700355 public boolean isGroupExpansionChanging() {
356 if (isChildInGroup()) {
357 return mNotificationParent.isGroupExpansionChanging();
358 }
359 return mGroupExpansionChanging;
360 }
361
362 public void setGroupExpansionChanging(boolean changing) {
363 mGroupExpansionChanging = changing;
364 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700365
Adrian Roos599be342016-06-13 14:54:39 -0700366 @Override
367 public void setActualHeightAnimating(boolean animating) {
368 if (mPrivateLayout != null) {
369 mPrivateLayout.setContentHeightAnimating(animating);
370 }
371 }
372
Selim Cinek8d490d42015-04-10 00:05:50 -0700373 public NotificationContentView getPrivateLayout() {
374 return mPrivateLayout;
375 }
376
377 public NotificationContentView getPublicLayout() {
378 return mPublicLayout;
379 }
380
Selim Cinekcab4a602014-09-03 14:47:57 +0200381 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800382 for (NotificationContentView l : mLayouts) {
383 setIconAnimationRunning(running, l);
384 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800385 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700386 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek414ad332017-02-24 19:06:12 -0800387 setIconAnimationRunningForChild(running, mChildrenContainer.getLowPriorityHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800388 List<ExpandableNotificationRow> notificationChildren =
389 mChildrenContainer.getNotificationChildren();
390 for (int i = 0; i < notificationChildren.size(); i++) {
391 ExpandableNotificationRow child = notificationChildren.get(i);
392 child.setIconAnimationRunning(running);
393 }
394 }
395 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200396 }
397
398 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
399 if (layout != null) {
400 View contractedChild = layout.getContractedChild();
401 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700402 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200403 setIconAnimationRunningForChild(running, contractedChild);
404 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700405 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200406 }
407 }
408
409 private void setIconAnimationRunningForChild(boolean running, View child) {
410 if (child != null) {
411 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
412 setIconRunning(icon, running);
413 ImageView rightIcon = (ImageView) child.findViewById(
414 com.android.internal.R.id.right_icon);
415 setIconRunning(rightIcon, running);
416 }
417 }
418
419 private void setIconRunning(ImageView imageView, boolean running) {
420 if (imageView != null) {
421 Drawable drawable = imageView.getDrawable();
422 if (drawable instanceof AnimationDrawable) {
423 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
424 if (running) {
425 animationDrawable.start();
426 } else {
427 animationDrawable.stop();
428 }
429 } else if (drawable instanceof AnimatedVectorDrawable) {
430 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
431 if (running) {
432 animationDrawable.start();
433 } else {
434 animationDrawable.stop();
435 }
436 }
437 }
438 }
439
Kevind4660b22018-09-27 10:57:35 -0700440 /**
441 * Set the entry for the row.
442 *
443 * @param entry the entry this row is tied to
444 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500445 public void setEntry(@NonNull NotificationEntry entry) {
Selim Cinekda42d652015-12-04 15:51:16 -0800446 mEntry = entry;
447 mStatusBarNotification = entry.notification;
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700448 cacheIsSystemNotification();
Rohan Shah63411fc2018-03-28 19:05:52 -0700449 }
450
451 /**
Kevin01a53cb2018-11-09 18:19:54 -0800452 * Inflate views based off the inflation flags set. Inflation happens asynchronously.
Kevind4660b22018-09-27 10:57:35 -0700453 */
454 public void inflateViews() {
455 mNotificationInflater.inflateNotificationViews();
456 }
457
458 /**
Kevind5022f92018-10-08 18:30:26 -0700459 * Marks a content view as freeable, setting it so that future inflations do not reinflate
460 * and ensuring that the view is freed when it is safe to remove.
461 *
462 * @param inflationFlag flag corresponding to the content view to be freed
463 */
464 public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) {
465 // View should not be reinflated in the future
466 updateInflationFlag(inflationFlag, false);
467 Runnable freeViewRunnable = () ->
468 mNotificationInflater.freeNotificationView(inflationFlag);
469 switch (inflationFlag) {
470 case FLAG_CONTENT_VIEW_HEADS_UP:
471 getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_HEADSUP,
472 freeViewRunnable);
473 break;
Kevin38ce6fa2018-10-17 16:00:14 -0700474 case FLAG_CONTENT_VIEW_PUBLIC:
475 getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_CONTRACTED,
476 freeViewRunnable);
Kevind5022f92018-10-08 18:30:26 -0700477 default:
478 break;
479 }
480 }
481
482 /**
Kevind4660b22018-09-27 10:57:35 -0700483 * Update whether or not a content view should be inflated.
484 *
485 * @param flag the flag corresponding to the content view
486 * @param shouldInflate true if it should be inflated, false if it should not
487 */
488 public void updateInflationFlag(@InflationFlag int flag, boolean shouldInflate) {
489 mNotificationInflater.updateInflationFlag(flag, shouldInflate);
490 }
491
492 /**
Kevin01a53cb2018-11-09 18:19:54 -0800493 * Whether or not a content view should be inflated.
494 *
495 * @param flag the flag corresponding to the content view
496 * @return true if the flag is set, false otherwise
497 */
498 public boolean isInflationFlagSet(@InflationFlag int flag) {
499 return mNotificationInflater.isInflationFlagSet(flag);
500 }
501
502 /**
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700503 * Caches whether or not this row contains a system notification. Note, this is only cached
504 * once per notification as the packageInfo can't technically change for a notification row.
Rohan Shah63411fc2018-03-28 19:05:52 -0700505 */
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700506 private void cacheIsSystemNotification() {
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400507 if (mEntry != null && mEntry.mIsSystemNotification == null) {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700508 if (mSystemNotificationAsyncTask.getStatus() == AsyncTask.Status.PENDING) {
509 // Run async task once, only if it hasn't already been executed. Note this is
510 // executed in serial - no need to parallelize this small task.
511 mSystemNotificationAsyncTask.execute();
Rohan Shah63411fc2018-03-28 19:05:52 -0700512 }
513 }
514 }
515
516 /**
Rohan Shahca0447e2018-03-30 15:18:27 -0700517 * Returns whether this row is considered non-blockable (i.e. it's a non-blockable system notif
518 * or is in a whitelist).
Rohan Shah63411fc2018-03-28 19:05:52 -0700519 */
520 public boolean getIsNonblockable() {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700521 boolean isNonblockable = Dependency.get(NotificationBlockingHelperManager.class)
Julia Reynolds0abae112018-06-08 10:36:57 -0400522 .isNonblockable(mStatusBarNotification.getPackageName(),
523 mEntry.channel.getId());
Rohan Shah63411fc2018-03-28 19:05:52 -0700524
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700525 // If the SystemNotifAsyncTask hasn't finished running or retrieved a value, we'll try once
526 // again, but in-place on the main thread this time. This should rarely ever get called.
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400527 if (mEntry != null && mEntry.mIsSystemNotification == null) {
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700528 if (DEBUG) {
529 Log.d(TAG, "Retrieving isSystemNotification on main thread");
530 }
531 mSystemNotificationAsyncTask.cancel(true /* mayInterruptIfRunning */);
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400532 mEntry.mIsSystemNotification = isSystemNotification(mContext, mStatusBarNotification);
Rohan Shah4ed1b2a2018-03-30 13:26:01 -0700533 }
534
Julia Reynolds0c245002019-03-27 16:10:11 -0400535 isNonblockable |= mEntry.channel.isImportanceLockedByOEM();
536 isNonblockable |= mEntry.channel.isImportanceLockedByCriticalDeviceFunction();
537
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400538 if (!isNonblockable && mEntry != null && mEntry.mIsSystemNotification != null) {
539 if (mEntry.mIsSystemNotification) {
Rohan Shah63411fc2018-03-28 19:05:52 -0700540 if (mEntry.channel != null
541 && !mEntry.channel.isBlockableSystem()) {
542 isNonblockable = true;
543 }
544 }
545 }
546 return isNonblockable;
Selim Cinekc478f902017-02-22 20:55:44 -0800547 }
548
Selim Cinek5ba22542017-04-20 15:16:10 -0700549 public void onNotificationUpdated() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800550 for (NotificationContentView l : mLayouts) {
Selim Cinekc478f902017-02-22 20:55:44 -0800551 l.onNotificationUpdated(mEntry);
Adrian Rooseb434ff2017-01-11 11:18:48 -0800552 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800553 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800554 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700555 updateNotificationColor();
Mady Mellor4c197602017-04-10 17:57:52 -0700556 if (mMenuRow != null) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700557 mMenuRow.onNotificationUpdated(mStatusBarNotification);
Beverly3f56f052018-05-08 14:56:03 -0400558 mMenuRow.setAppName(mAppName);
Mady Mellor4c197602017-04-10 17:57:52 -0700559 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800560 if (mIsSummaryWithChildren) {
Selim Cinek414ad332017-02-24 19:06:12 -0800561 mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
Selim Cinekc897bd32016-03-18 17:32:31 -0700562 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800563 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800564 if (mIconAnimationRunning) {
565 setIconAnimationRunning(true);
566 }
Kevin38ce6fa2018-10-17 16:00:14 -0700567 if (mLastChronometerRunning) {
568 setChronometerRunning(true);
569 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800570 if (mNotificationParent != null) {
571 mNotificationParent.updateChildrenHeaderAppearance();
572 }
Selim Cinek263398f2015-10-21 17:40:23 -0700573 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800574 // The public layouts expand button is always visible
575 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800576 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700577 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800578 updateShelfIconColor();
Selim Cinekfe24fb72018-02-13 14:34:55 -0800579 updateRippleAllowed();
Selim Cinekab9c7b22018-12-11 18:15:47 -0800580 if (mUpdateBackgroundOnUpdate) {
581 mUpdateBackgroundOnUpdate = false;
582 updateBackgroundColors();
583 }
Selim Cinek6743c0b2017-01-18 18:24:01 -0800584 }
585
Gus Prevas33fbc152018-12-04 13:17:32 -0500586 /** Called when the notification's ranking was changed (but nothing else changed). */
587 public void onNotificationRankingUpdated() {
588 if (mMenuRow != null) {
589 mMenuRow.onNotificationUpdated(mStatusBarNotification);
590 }
591 }
592
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700593 @VisibleForTesting
594 void updateShelfIconColor() {
Selim Cinek6743c0b2017-01-18 18:24:01 -0800595 StatusBarIconView expandedIcon = mEntry.expandedIcon;
596 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
597 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
Lucas Dupina291d192018-06-07 13:59:42 -0700598 ContrastColorUtil.getInstance(mContext));
Selim Cinek875ba9b2017-02-13 16:20:17 -0800599 int color = StatusBarIconView.NO_COLOR;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800600 if (colorize) {
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700601 NotificationHeaderView header = getVisibleNotificationHeader();
602 if (header != null) {
603 color = header.getOriginalIconColor();
604 } else {
605 color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
606 getBackgroundColorWithoutTint());
607 }
Selim Cinek6743c0b2017-01-18 18:24:01 -0800608 }
Selim Cinek875ba9b2017-02-13 16:20:17 -0800609 expandedIcon.setStaticDrawableColor(color);
Selim Cinekda42d652015-12-04 15:51:16 -0800610 }
611
Selim Cinek5cf1d052017-06-01 17:36:46 -0700612 public void setAboveShelfChangedListener(AboveShelfChangedListener aboveShelfChangedListener) {
613 mAboveShelfChangedListener = aboveShelfChangedListener;
614 }
615
Lucas Dupincecc7c22017-09-12 16:02:45 -0700616 /**
617 * Sets a supplier that can determine whether the keyguard is secure or not.
618 * @param secureStateProvider A function that returns true if keyguard is secure.
619 */
620 public void setSecureStateProvider(BooleanSupplier secureStateProvider) {
621 mSecureStateProvider = secureStateProvider;
622 }
623
Selim Cinek4705f292017-04-24 22:18:48 -0700624 @Override
625 public boolean isDimmable() {
626 if (!getShowingLayout().isDimmable()) {
627 return false;
628 }
Selim Cinekc3fec682019-06-06 18:11:07 -0700629 if (showingPulsing()) {
Selim Cinekf434a742019-05-28 17:39:49 -0700630 return false;
631 }
Selim Cinek4705f292017-04-24 22:18:48 -0700632 return super.isDimmable();
633 }
634
Selim Cinekda42d652015-12-04 15:51:16 -0800635 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800636 for (NotificationContentView l : mLayouts) {
637 updateLimitsForView(l);
638 }
Selim Cineka1744872016-03-11 15:36:06 -0800639 }
640
641 private void updateLimitsForView(NotificationContentView layout) {
Kevin38ce6fa2018-10-17 16:00:14 -0700642 boolean customView = layout.getContractedChild() != null
643 && layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800644 != com.android.internal.R.id.status_bar_latest_event_content;
645 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800646 boolean beforeP = mEntry.targetSdk < Build.VERSION_CODES.P;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800647 int minHeight;
Beth Thibodeaucb395352019-01-25 15:39:54 -0500648
649 View expandedView = layout.getExpandedChild();
650 boolean isMediaLayout = expandedView != null
651 && expandedView.findViewById(com.android.internal.R.id.media_actions) != null;
Beth Thibodeaueab4dde2019-02-07 11:37:02 -0500652 boolean showCompactMediaSeekbar = mMediaManager.getShowCompactMediaSeekbar();
Beth Thibodeaucb395352019-01-25 15:39:54 -0500653
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800654 if (customView && beforeP && !mIsSummaryWithChildren) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700655 minHeight = beforeN ? mNotificationMinHeightBeforeN : mNotificationMinHeightBeforeP;
Beth Thibodeaueab4dde2019-02-07 11:37:02 -0500656 } else if (isMediaLayout && showCompactMediaSeekbar) {
Beth Thibodeaucb395352019-01-25 15:39:54 -0500657 minHeight = mNotificationMinHeightMedia;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800658 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
659 minHeight = mNotificationMinHeightLarge;
660 } else {
661 minHeight = mNotificationMinHeight;
662 }
Selim Cineka1744872016-03-11 15:36:06 -0800663 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
664 layout.getHeadsUpChild().getId()
665 != com.android.internal.R.id.status_bar_latest_event_content;
Rohan Shahb9d500a2018-06-25 16:27:16 -0700666 int headsUpHeight;
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800667 if (headsUpCustom && beforeP) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700668 headsUpHeight = beforeN ? mMaxHeadsUpHeightBeforeN : mMaxHeadsUpHeightBeforeP;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800669 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700670 headsUpHeight = mMaxHeadsUpHeightIncreased;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800671 } else {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700672 headsUpHeight = mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800673 }
Selim Cineke62255c2017-09-28 18:23:23 -0700674 NotificationViewWrapper headsUpWrapper = layout.getVisibleWrapper(
Kevind5022f92018-10-08 18:30:26 -0700675 VISIBLE_TYPE_HEADSUP);
Selim Cineke62255c2017-09-28 18:23:23 -0700676 if (headsUpWrapper != null) {
Rohan Shahb9d500a2018-06-25 16:27:16 -0700677 headsUpHeight = Math.max(headsUpHeight, headsUpWrapper.getMinLayoutHeight());
Selim Cineke62255c2017-09-28 18:23:23 -0700678 }
Selim Cinekc3fec682019-06-06 18:11:07 -0700679 layout.setHeights(minHeight, headsUpHeight, mNotificationMaxHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200680 }
681
682 public StatusBarNotification getStatusBarNotification() {
683 return mStatusBarNotification;
684 }
685
Ned Burnsf81c4c42019-01-07 14:10:43 -0500686 public NotificationEntry getEntry() {
Selim Cinek281c2022016-10-13 19:14:43 -0700687 return mEntry;
688 }
689
Selim Cinekc3fec682019-06-06 18:11:07 -0700690 @Override
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700691 public boolean isHeadsUp() {
692 return mIsHeadsUp;
693 }
694
Selim Cinek1a521f32014-11-03 17:39:29 +0100695 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinek5cf1d052017-06-01 17:36:46 -0700696 boolean wasAboveShelf = isAboveShelf();
Selim Cinekc80fdb12015-04-13 15:09:08 -0700697 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100698 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700699 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700700 if (mIsSummaryWithChildren) {
701 // The overflow might change since we allow more lines as HUN.
702 mChildrenContainer.updateGroupOverflow();
703 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700704 if (intrinsicBefore != getIntrinsicHeight()) {
705 notifyHeightChanged(false /* needsAnimation */);
706 }
Selim Cinekd127d792016-11-01 19:11:41 -0700707 if (isHeadsUp) {
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100708 mMustStayOnScreen = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700709 setAboveShelf(true);
Kevind5022f92018-10-08 18:30:26 -0700710 } else if (isAboveShelf() != wasAboveShelf) {
711 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
Selim Cinekd127d792016-11-01 19:11:41 -0700712 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100713 }
714
Selim Cinek5040f2e2019-02-14 18:22:42 -0800715 @Override
Selim Cinekc3fec682019-06-06 18:11:07 -0700716 public boolean showingPulsing() {
Selim Cinek94e56f92019-06-11 19:13:54 -0700717 return isHeadsUpState() && (isDozing() || (mOnKeyguard && isBypassEnabled()));
Kevina97ea052018-09-11 13:53:18 -0700718 }
719
Selim Cinekc3fec682019-06-06 18:11:07 -0700720 /**
721 * @return if the view is in heads up state, i.e either still heads upped or it's disappearing.
722 */
723 public boolean isHeadsUpState() {
724 return mIsHeadsUp || mHeadsupDisappearRunning;
Kevina97ea052018-09-11 13:53:18 -0700725 }
726
Selim Cinekc3fec682019-06-06 18:11:07 -0700727
Selim Cinekb5605e52015-02-20 18:21:41 +0100728 public void setGroupManager(NotificationGroupManager groupManager) {
729 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700730 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100731 }
732
Adrian Roosb88b1a12015-12-09 18:51:05 -0800733 public void setRemoteInputController(RemoteInputController r) {
734 mPrivateLayout.setRemoteInputController(r);
735 }
736
Mady Mellor3fd273e2016-03-15 21:08:14 -0700737 public void setAppName(String appName) {
738 mAppName = appName;
Mady Mellor95d743c2017-01-10 12:05:27 -0800739 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800740 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700741 }
742 }
743
Selim Cinekb5605e52015-02-20 18:21:41 +0100744 public void addChildNotification(ExpandableNotificationRow row) {
745 addChildNotification(row, -1);
746 }
747
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800748 /**
749 * Set the how much the header should be visible. A value of 0 will make the header fully gone
750 * and a value of 1 will make the notification look just like normal.
751 * This is being used for heads up notifications, when they are pinned to the top of the screen
752 * and the header content is extracted to the statusbar.
753 *
754 * @param headerVisibleAmount the amount the header should be visible.
755 */
756 public void setHeaderVisibleAmount(float headerVisibleAmount) {
757 if (mHeaderVisibleAmount != headerVisibleAmount) {
758 mHeaderVisibleAmount = headerVisibleAmount;
Selim Cinek4b259a12019-05-09 19:10:51 -0700759 for (NotificationContentView l : mLayouts) {
760 l.setHeaderVisibleAmount(headerVisibleAmount);
761 }
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800762 if (mChildrenContainer != null) {
763 mChildrenContainer.setHeaderVisibleAmount(headerVisibleAmount);
764 }
765 notifyHeightChanged(false /* needsAnimation */);
766 }
767 }
768
Selim Cinek99e9adf2018-03-15 09:17:47 -0700769 @Override
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800770 public float getHeaderVisibleAmount() {
771 return mHeaderVisibleAmount;
772 }
773
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100774 @Override
775 public void setHeadsUpIsVisible() {
776 super.setHeadsUpIsVisible();
777 mMustStayOnScreen = false;
778 }
779
Selim Cinekb5605e52015-02-20 18:21:41 +0100780 /**
781 * Add a child notification to this view.
782 *
783 * @param row the row to add
784 * @param childIndex the index to add it at, if -1 it will be added at the end
785 */
786 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
787 if (mChildrenContainer == null) {
788 mChildrenContainerStub.inflate();
789 }
790 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700791 onChildrenCountChanged();
792 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100793 }
794
795 public void removeChildNotification(ExpandableNotificationRow row) {
796 if (mChildrenContainer != null) {
797 mChildrenContainer.removeNotification(row);
798 }
Selim Cinek263398f2015-10-21 17:40:23 -0700799 onChildrenCountChanged();
800 row.setIsChildInGroup(false, null);
Selim Cinek2871bef2017-11-22 08:40:00 -0800801 row.setBottomRoundness(0.0f, false /* animate */);
Selim Cinek263398f2015-10-21 17:40:23 -0700802 }
803
Mady Mellor43c2cd12016-12-12 21:05:13 -0800804 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700805 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700806 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700807 }
808
Rohan Shah524cf7b2018-03-15 14:40:02 -0700809 /**
810 * @return whether this notification is the only child in the group summary
811 */
812 public boolean isOnlyChildInGroup() {
813 return mGroupManager.isOnlyChildInGroup(getStatusBarNotification());
814 }
815
Selim Cinek388df6d2015-10-22 13:25:11 -0700816 public ExpandableNotificationRow getNotificationParent() {
817 return mNotificationParent;
818 }
819
Selim Cinek263398f2015-10-21 17:40:23 -0700820 /**
821 * @param isChildInGroup Is this notification now in a group
822 * @param parent the new parent notification
823 */
Selim Cinekc25989e2018-02-16 16:42:14 -0800824 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500825 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cinekc25989e2018-02-16 16:42:14 -0800826 if (mExpandAnimationRunning && !isChildInGroup && mNotificationParent != null) {
827 mNotificationParent.setChildIsExpanding(false);
828 mNotificationParent.setExtraWidthForClipping(0.0f);
829 mNotificationParent.setMinimumHeightForClipping(0);
830 }
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700831 mNotificationParent = childInGroup ? parent : null;
832 mPrivateLayout.setIsChildInGroup(childInGroup);
Selim Cinek5ba22542017-04-20 15:16:10 -0700833 mNotificationInflater.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400834 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700835 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700836 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700837 if (mNotificationParent != null) {
Selim Cinek9ce32852017-02-15 16:21:10 -0800838 setOverrideTintColor(NO_COLOR, 0.0f);
Selim Cinekeccf4942018-05-30 09:55:36 -0700839 // Let's reset the distance to top roundness, as this isn't applied to group children
840 setDistanceToTopRoundness(NO_ROUNDNESS);
Mady Mellorb0a82462016-04-30 17:31:02 -0700841 mNotificationParent.updateBackgroundForGroupState();
842 }
Selim Cinekdb167372016-11-17 15:41:17 -0800843 updateIconVisibilities();
Selim Cinek2871bef2017-11-22 08:40:00 -0800844 updateBackgroundClipping();
Selim Cinek34d93b02015-10-22 12:30:38 -0700845 }
846
847 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800848 public boolean onTouchEvent(MotionEvent event) {
849 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
850 || !isChildInGroup() || isGroupExpanded()) {
851 return super.onTouchEvent(event);
852 } else {
853 return false;
854 }
855 }
856
857 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800858 protected boolean handleSlideBack() {
Mady Mellor95d743c2017-01-10 12:05:27 -0800859 if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800860 animateTranslateNotification(0 /* targetLeft */);
861 return true;
862 }
863 return false;
864 }
865
866 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700867 protected boolean shouldHideBackground() {
868 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700869 }
870
871 @Override
872 public boolean isSummaryWithChildren() {
873 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100874 }
875
876 @Override
877 public boolean areChildrenExpanded() {
878 return mChildrenExpanded;
879 }
880
881 public List<ExpandableNotificationRow> getNotificationChildren() {
882 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
883 }
884
Selim Cinekeef84282015-10-30 16:28:00 -0700885 public int getNumberOfNotificationChildren() {
886 if (mChildrenContainer == null) {
887 return 0;
888 }
889 return mChildrenContainer.getNotificationChildren().size();
890 }
891
Selim Cinekb5605e52015-02-20 18:21:41 +0100892 /**
893 * Apply the order given in the list to the children.
894 *
895 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800896 * @param visualStabilityManager
897 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100898 * @return whether the list order has changed
899 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800900 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
901 VisualStabilityManager visualStabilityManager,
902 VisualStabilityManager.Callback callback) {
903 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
904 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100905 }
906
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500907 /** Updates states of all children. */
908 public void updateChildrenStates(AmbientState ambientState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700909 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500910 ExpandableViewState parentState = getViewState();
911 mChildrenContainer.updateState(parentState, ambientState);
Selim Cinekb5605e52015-02-20 18:21:41 +0100912 }
913 }
914
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500915 /** Applies children states. */
916 public void applyChildrenState() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700917 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500918 mChildrenContainer.applyState();
Selim Cinekb5605e52015-02-20 18:21:41 +0100919 }
920 }
921
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500922 /** Prepares expansion changed. */
923 public void prepareExpansionChanged() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700924 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500925 mChildrenContainer.prepareExpansionChanged();
Selim Cinekb5605e52015-02-20 18:21:41 +0100926 }
927 }
928
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500929 /** Starts child animations. */
930 public void startChildAnimation(AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700931 if (mIsSummaryWithChildren) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500932 mChildrenContainer.startAnimationToState(properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100933 }
934 }
935
936 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800937 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100938 return this;
939 } else {
940 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
941 return view == null ? this : view;
942 }
943 }
944
Selim Cinekab29aeb2015-02-20 18:18:32 +0100945 public NotificationGuts getGuts() {
946 return mGuts;
947 }
948
Selim Cinek684a4422015-04-15 16:18:39 -0700949 /**
950 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
951 * the notification will be rendered on top of the screen.
952 *
953 * @param pinned whether it is pinned
954 */
955 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700956 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek5cf1d052017-06-01 17:36:46 -0700957 boolean wasAboveShelf = isAboveShelf();
Selim Cinek684a4422015-04-15 16:18:39 -0700958 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700959 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700960 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700961 }
Selim Cinek31aada42015-12-18 17:51:15 -0800962 if (pinned) {
963 setIconAnimationRunning(true);
964 mExpandedWhenPinned = false;
965 } else if (mExpandedWhenPinned) {
966 setUserExpanded(true);
967 }
Selim Cinek98713a42015-09-21 15:47:20 +0200968 setChronometerRunning(mLastChronometerRunning);
Selim Cinek5cf1d052017-06-01 17:36:46 -0700969 if (isAboveShelf() != wasAboveShelf) {
970 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
971 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700972 }
973
Selim Cinek29aab962018-02-27 17:05:45 -0800974 @Override
Selim Cinek684a4422015-04-15 16:18:39 -0700975 public boolean isPinned() {
976 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700977 }
978
Selim Cinekd127d792016-11-01 19:11:41 -0700979 @Override
980 public int getPinnedHeadsUpHeight() {
981 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
982 }
983
Selim Cinek31aada42015-12-18 17:51:15 -0800984 /**
985 * @param atLeastMinHeight should the value returned be at least the minimum height.
986 * Used to avoid cyclic calls
987 * @return the height of the heads up notification when pinned
988 */
Selim Cinekd127d792016-11-01 19:11:41 -0700989 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800990 if (mIsSummaryWithChildren) {
991 return mChildrenContainer.getIntrinsicHeight();
992 }
Selim Cinek31aada42015-12-18 17:51:15 -0800993 if(mExpandedWhenPinned) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800994 return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
Selim Cinek31aada42015-12-18 17:51:15 -0800995 } else if (atLeastMinHeight) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800996 return Math.max(getCollapsedHeight(), getHeadsUpHeight());
Selim Cinek31aada42015-12-18 17:51:15 -0800997 } else {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800998 return getHeadsUpHeight();
Selim Cinek31aada42015-12-18 17:51:15 -0800999 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -07001000 }
1001
Jorim Jaggi5eb67c22015-08-19 19:50:49 -07001002 /**
1003 * Mark whether this notification was just clicked, i.e. the user has just clicked this
1004 * notification in this frame.
1005 */
1006 public void setJustClicked(boolean justClicked) {
1007 mJustClicked = justClicked;
1008 }
1009
1010 /**
1011 * @return true if this notification has been clicked in this frame, false otherwise
1012 */
1013 public boolean wasJustClicked() {
1014 return mJustClicked;
1015 }
1016
Selim Cinek98713a42015-09-21 15:47:20 +02001017 public void setChronometerRunning(boolean running) {
1018 mLastChronometerRunning = running;
1019 setChronometerRunning(running, mPrivateLayout);
1020 setChronometerRunning(running, mPublicLayout);
1021 if (mChildrenContainer != null) {
1022 List<ExpandableNotificationRow> notificationChildren =
1023 mChildrenContainer.getNotificationChildren();
1024 for (int i = 0; i < notificationChildren.size(); i++) {
1025 ExpandableNotificationRow child = notificationChildren.get(i);
1026 child.setChronometerRunning(running);
1027 }
1028 }
1029 }
1030
1031 private void setChronometerRunning(boolean running, NotificationContentView layout) {
1032 if (layout != null) {
1033 running = running || isPinned();
1034 View contractedChild = layout.getContractedChild();
1035 View expandedChild = layout.getExpandedChild();
1036 View headsUpChild = layout.getHeadsUpChild();
1037 setChronometerRunningForChild(running, contractedChild);
1038 setChronometerRunningForChild(running, expandedChild);
1039 setChronometerRunningForChild(running, headsUpChild);
1040 }
1041 }
1042
1043 private void setChronometerRunningForChild(boolean running, View child) {
1044 if (child != null) {
1045 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
1046 if (chronometer instanceof Chronometer) {
1047 ((Chronometer) chronometer).setStarted(running);
1048 }
1049 }
1050 }
1051
Selim Cinekea4bef72015-12-02 15:51:10 -08001052 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -07001053 if (mIsSummaryWithChildren) {
1054 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -07001055 }
Selim Cinekea4bef72015-12-02 15:51:10 -08001056 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -07001057 }
1058
Selim Cinek414ad332017-02-24 19:06:12 -08001059 /**
1060 * @return the currently visible notification header. This can be different from
1061 * {@link #getNotificationHeader()} in case it is a low-priority group.
1062 */
1063 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08001064 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek414ad332017-02-24 19:06:12 -08001065 return mChildrenContainer.getVisibleHeader();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001066 }
1067 return getShowingLayout().getVisibleNotificationHeader();
1068 }
1069
Selim Cinekb26afa32017-06-29 10:28:17 +02001070
1071 /**
1072 * @return the contracted notification header. This can be different from
1073 * {@link #getNotificationHeader()} and also {@link #getVisibleNotificationHeader()} and only
1074 * returns the contracted version.
1075 */
1076 public NotificationHeaderView getContractedNotificationHeader() {
1077 if (mIsSummaryWithChildren) {
1078 return mChildrenContainer.getHeaderView();
1079 }
1080 return mPrivateLayout.getContractedNotificationHeader();
1081 }
1082
Selim Cinek570981d2015-12-01 11:37:01 -08001083 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
1084 mOnExpandClickListener = onExpandClickListener;
1085 }
1086
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001087 public void setLongPressListener(LongPressListener longPressListener) {
1088 mLongPressListener = longPressListener;
1089 }
1090
Selim Cinekddf1b392016-05-27 16:33:10 -07001091 @Override
1092 public void setOnClickListener(@Nullable OnClickListener l) {
1093 super.setOnClickListener(l);
1094 mOnClickListener = l;
1095 updateClickAndFocus();
1096 }
1097
1098 private void updateClickAndFocus() {
1099 boolean normalChild = !isChildInGroup() || isGroupExpanded();
1100 boolean clickable = mOnClickListener != null && normalChild;
1101 if (isFocusable() != normalChild) {
1102 setFocusable(normalChild);
1103 }
1104 if (isClickable() != clickable) {
1105 setClickable(clickable);
1106 }
1107 }
1108
Selim Cinek31aada42015-12-18 17:51:15 -08001109 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
1110 mHeadsUpManager = headsUpManager;
1111 }
1112
Gustav Senntond0e84532018-12-03 16:48:36 +00001113 public HeadsUpManager getHeadsUpManager() {
1114 return mHeadsUpManager;
1115 }
1116
Mady Mellor87d79452017-01-10 11:52:52 -08001117 public void setGutsView(MenuItem item) {
Rohan Shah20790b82018-07-02 17:21:04 -07001118 if (mGuts != null && item.getGutsView() instanceof NotificationGuts.GutsContent) {
1119 ((NotificationGuts.GutsContent) item.getGutsView()).setGutsParent(mGuts);
1120 mGuts.setGutsContent((NotificationGuts.GutsContent) item.getGutsView());
Mady Mellor87d79452017-01-10 11:52:52 -08001121 }
1122 }
1123
Mady Mellor95d743c2017-01-10 12:05:27 -08001124 @Override
1125 protected void onAttachedToWindow() {
1126 super.onAttachedToWindow();
Aaron Heuckroth1dd67cb2018-06-14 14:28:08 -04001127 mEntry.setInitializationTime(SystemClock.elapsedRealtime());
Mady Mellor95d743c2017-01-10 12:05:27 -08001128 Dependency.get(PluginManager.class).addPluginListener(this,
1129 NotificationMenuRowPlugin.class, false /* Allow multiple */);
1130 }
1131
1132 @Override
1133 protected void onDetachedFromWindow() {
1134 super.onDetachedFromWindow();
1135 Dependency.get(PluginManager.class).removePluginListener(this);
1136 }
1137
1138 @Override
1139 public void onPluginConnected(NotificationMenuRowPlugin plugin, Context pluginContext) {
Evan Lairde55c6012019-03-13 12:54:37 -04001140 boolean existed = mMenuRow != null && mMenuRow.getMenuView() != null;
Mady Mellor95d743c2017-01-10 12:05:27 -08001141 if (existed) {
1142 removeView(mMenuRow.getMenuView());
1143 }
Evan Lairde55c6012019-03-13 12:54:37 -04001144 if (plugin == null) {
1145 return;
1146 }
Mady Mellor95d743c2017-01-10 12:05:27 -08001147 mMenuRow = plugin;
Aaron Heuckroth266cb342018-09-07 14:52:04 -04001148 if (mMenuRow.shouldUseDefaultMenuItems()) {
Mady Mellor4c197602017-04-10 17:57:52 -07001149 ArrayList<MenuItem> items = new ArrayList<>();
1150 items.add(NotificationMenuRow.createInfoItem(mContext));
1151 items.add(NotificationMenuRow.createSnoozeItem(mContext));
Julia Reynoldsb5867452018-02-28 16:31:35 -05001152 items.add(NotificationMenuRow.createAppOpsItem(mContext));
Mady Mellor4c197602017-04-10 17:57:52 -07001153 mMenuRow.setMenuItems(items);
Mady Mellor95d743c2017-01-10 12:05:27 -08001154 }
1155 if (existed) {
1156 createMenu();
1157 }
1158 }
1159
1160 @Override
1161 public void onPluginDisconnected(NotificationMenuRowPlugin plugin) {
1162 boolean existed = mMenuRow.getMenuView() != null;
1163 mMenuRow = new NotificationMenuRow(mContext); // Back to default
1164 if (existed) {
1165 createMenu();
1166 }
1167 }
1168
Evan Lairde55c6012019-03-13 12:54:37 -04001169 /**
1170 * Get a handle to a NotificationMenuRowPlugin whose menu view has been added to our hierarchy,
1171 * or null if there is no menu row
1172 *
1173 * @return a {@link NotificationMenuRowPlugin}, or null
1174 */
1175 @Nullable
Mady Mellor95d743c2017-01-10 12:05:27 -08001176 public NotificationMenuRowPlugin createMenu() {
Evan Lairde55c6012019-03-13 12:54:37 -04001177 if (mMenuRow == null) {
1178 return null;
1179 }
1180
Mady Mellor95d743c2017-01-10 12:05:27 -08001181 if (mMenuRow.getMenuView() == null) {
Mady Mellor4ab28202017-06-06 11:42:50 -07001182 mMenuRow.createMenu(this, mStatusBarNotification);
Mady Mellor95d743c2017-01-10 12:05:27 -08001183 mMenuRow.setAppName(mAppName);
1184 FrameLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
1185 LayoutParams.MATCH_PARENT);
1186 addView(mMenuRow.getMenuView(), MENU_VIEW_INDEX, lp);
1187 }
1188 return mMenuRow;
1189 }
1190
Evan Lairde55c6012019-03-13 12:54:37 -04001191 @Nullable
Mady Mellor95d743c2017-01-10 12:05:27 -08001192 public NotificationMenuRowPlugin getProvider() {
1193 return mMenuRow;
1194 }
1195
Anthony Chen9fe1ee72017-04-07 13:53:37 -07001196 @Override
Selim Cinek1a48bab2017-02-17 19:38:40 -08001197 public void onDensityOrFontScaleChanged() {
Anthony Chen9fe1ee72017-04-07 13:53:37 -07001198 super.onDensityOrFontScaleChanged();
Selim Cinek01af3342016-02-09 19:25:31 -08001199 initDimens();
Anthony Chenad4d1582017-04-10 16:07:58 -07001200 initBackground();
Lucas Dupinf03e7522018-06-25 16:21:13 -07001201 reInflateViews();
1202 }
1203
1204 private void reInflateViews() {
Selim Cinek817abe72017-05-24 11:08:55 -07001205 // Let's update our childrencontainer. This is intentionally not guarded with
1206 // mIsSummaryWithChildren since we might have had children but not anymore.
1207 if (mChildrenContainer != null) {
1208 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -08001209 }
1210 if (mGuts != null) {
Lucas Dupin91712072019-08-08 15:27:53 -07001211 NotificationGuts oldGuts = mGuts;
Selim Cinek01af3342016-02-09 19:25:31 -08001212 int index = indexOfChild(oldGuts);
1213 removeView(oldGuts);
1214 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
1215 R.layout.notification_guts, this, false);
Lucas Dupin91712072019-08-08 15:27:53 -07001216 mGuts.setVisibility(oldGuts.isExposed() ? VISIBLE : GONE);
Selim Cinek01af3342016-02-09 19:25:31 -08001217 addView(mGuts, index);
1218 }
Evan Lairde55c6012019-03-13 12:54:37 -04001219 View oldMenu = mMenuRow == null ? null : mMenuRow.getMenuView();
Mady Mellor95d743c2017-01-10 12:05:27 -08001220 if (oldMenu != null) {
Mady Mellor761cde12017-01-10 11:36:39 -08001221 int menuIndex = indexOfChild(oldMenu);
1222 removeView(oldMenu);
Mady Mellor4ab28202017-06-06 11:42:50 -07001223 mMenuRow.createMenu(ExpandableNotificationRow.this, mStatusBarNotification);
Mady Mellor761cde12017-01-10 11:36:39 -08001224 mMenuRow.setAppName(mAppName);
Mady Mellor95d743c2017-01-10 12:05:27 -08001225 addView(mMenuRow.getMenuView(), menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -08001226 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001227 for (NotificationContentView l : mLayouts) {
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001228 l.initView();
Adrian Rooseb434ff2017-01-11 11:18:48 -08001229 l.reInflateViews();
1230 }
Amin Shaikhc3f0b062019-02-12 19:00:17 -05001231 mStatusBarNotification.clearPackageContext();
Lucas Dupinf03e7522018-06-25 16:21:13 -07001232 mNotificationInflater.clearCachesAndReInflate();
Selim Cinek01af3342016-02-09 19:25:31 -08001233 }
1234
Mady Mellor9d03a522017-04-04 18:45:30 -07001235 @Override
1236 public void onConfigurationChanged(Configuration newConfig) {
Evan Lairde55c6012019-03-13 12:54:37 -04001237 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Mady Mellor9d03a522017-04-04 18:45:30 -07001238 mMenuRow.onConfigurationChanged();
1239 }
1240 }
1241
Lucas Dupinf03e7522018-06-25 16:21:13 -07001242 public void onUiModeChanged() {
Selim Cinekab9c7b22018-12-11 18:15:47 -08001243 mUpdateBackgroundOnUpdate = true;
Lucas Dupinf03e7522018-06-25 16:21:13 -07001244 reInflateViews();
1245 if (mChildrenContainer != null) {
1246 for (ExpandableNotificationRow child : mChildrenContainer.getNotificationChildren()) {
1247 child.onUiModeChanged();
1248 }
1249 }
1250 }
1251
Selim Cinekc3179332016-03-04 14:44:56 -08001252 public void setContentBackground(int customBackgroundColor, boolean animate,
1253 NotificationContentView notificationContentView) {
1254 if (getShowingLayout() == notificationContentView) {
1255 setTintColor(customBackgroundColor, animate);
1256 }
1257 }
1258
Kenny Guy14d035c2018-05-02 19:10:36 +01001259 @Override
1260 protected void setBackgroundTintColor(int color) {
1261 super.setBackgroundTintColor(color);
1262 NotificationContentView view = getShowingLayout();
1263 if (view != null) {
1264 view.setBackgroundTintColor(color);
1265 }
1266 }
1267
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001268 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -08001269 for (NotificationContentView l : mLayouts) {
1270 l.closeRemoteInput();
1271 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001272 }
1273
Selim Cinekc897bd32016-03-18 17:32:31 -07001274 /**
1275 * Set by how much the single line view should be indented.
1276 */
1277 public void setSingleLineWidthIndention(int indention) {
1278 mPrivateLayout.setSingleLineWidthIndention(indention);
1279 }
1280
1281 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -07001282 return mNotificationColor;
1283 }
1284
1285 private void updateNotificationColor() {
Lucas Dupind26facc2018-09-10 18:07:30 -07001286 Configuration currentConfig = getResources().getConfiguration();
1287 boolean nightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
1288 == Configuration.UI_MODE_NIGHT_YES;
1289
Lucas Dupina291d192018-06-07 13:59:42 -07001290 mNotificationColor = ContrastColorUtil.resolveContrastColor(mContext,
Selim Cinekac5f0272017-05-02 16:05:41 -07001291 getStatusBarNotification().getNotification().color,
Lucas Dupind26facc2018-09-10 18:07:30 -07001292 getBackgroundColorWithoutTint(), nightMode);
Selim Cinekc897bd32016-03-18 17:32:31 -07001293 }
1294
1295 public HybridNotificationView getSingleLineView() {
1296 return mPrivateLayout.getSingleLineView();
1297 }
1298
Selim Cinekf07d0622016-03-21 19:52:52 -07001299 public boolean isOnKeyguard() {
1300 return mOnKeyguard;
1301 }
1302
Selim Cinekc1e389d2016-04-07 11:02:57 -07001303 public void removeAllChildren() {
1304 List<ExpandableNotificationRow> notificationChildren
1305 = mChildrenContainer.getNotificationChildren();
1306 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
1307 for (int i = 0; i < clonedList.size(); i++) {
1308 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -07001309 if (row.keepInParent()) {
1310 continue;
1311 }
Selim Cinekc1e389d2016-04-07 11:02:57 -07001312 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -07001313 row.setIsChildInGroup(false, null);
1314 }
1315 onChildrenCountChanged();
1316 }
1317
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001318 public void setForceUnlocked(boolean forceUnlocked) {
1319 mForceUnlocked = forceUnlocked;
1320 if (mIsSummaryWithChildren) {
1321 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
1322 for (ExpandableNotificationRow child : notificationChildren) {
1323 child.setForceUnlocked(forceUnlocked);
1324 }
1325 }
1326 }
1327
Selim Cinekd03518c2018-03-15 12:13:51 -07001328 public void setDismissed(boolean fromAccessibility) {
Rohan Shahc6990a02018-03-23 17:24:17 -07001329 setLongPressListener(null);
Selim Cinekd03518c2018-03-15 12:13:51 -07001330 mDismissed = true;
Selim Cineke9bad242016-06-15 11:46:37 -07001331 mGroupParentWhenDismissed = mNotificationParent;
1332 mRefocusOnDismiss = fromAccessibility;
1333 mChildAfterViewWhenDismissed = null;
Selim Cinekd03518c2018-03-15 12:13:51 -07001334 mEntry.icon.setDismissed();
Selim Cineke9bad242016-06-15 11:46:37 -07001335 if (isChildInGroup()) {
1336 List<ExpandableNotificationRow> notificationChildren =
1337 mNotificationParent.getNotificationChildren();
1338 int i = notificationChildren.indexOf(this);
1339 if (i != -1 && i < notificationChildren.size() - 1) {
1340 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
1341 }
1342 }
Selim Cinek3f19f602016-05-02 18:01:56 -07001343 }
1344
1345 public boolean isDismissed() {
1346 return mDismissed;
1347 }
1348
1349 public boolean keepInParent() {
1350 return mKeepInParent;
1351 }
1352
1353 public void setKeepInParent(boolean keepInParent) {
1354 mKeepInParent = keepInParent;
1355 }
1356
Selim Cinekd9b7dd42017-11-10 17:53:47 -08001357 @Override
Selim Cinek3f19f602016-05-02 18:01:56 -07001358 public boolean isRemoved() {
1359 return mRemoved;
1360 }
1361
Adrian Roosd009ab12016-05-20 17:58:53 -07001362 public void setRemoved() {
1363 mRemoved = true;
Selim Cinekef8c2252017-02-10 14:52:18 -08001364 mTranslationWhenRemoved = getTranslationY();
1365 mWasChildInGroupWhenRemoved = isChildInGroup();
1366 if (isChildInGroup()) {
1367 mTranslationWhenRemoved += getNotificationParent().getTranslationY();
1368 }
Beth Thibodeau4e4c86e2019-08-01 10:57:29 -04001369 for (NotificationContentView l : mLayouts) {
1370 l.setRemoved();
1371 }
Selim Cinek3f19f602016-05-02 18:01:56 -07001372 }
1373
Selim Cinekef8c2252017-02-10 14:52:18 -08001374 public boolean wasChildInGroupWhenRemoved() {
1375 return mWasChildInGroupWhenRemoved;
1376 }
1377
1378 public float getTranslationWhenRemoved() {
1379 return mTranslationWhenRemoved;
1380 }
1381
Selim Cinekd1395642016-04-28 12:22:42 -07001382 public NotificationChildrenContainer getChildrenContainer() {
1383 return mChildrenContainer;
1384 }
1385
Selim Cinekcafa87f2016-10-26 17:00:17 -07001386 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07001387 boolean wasAboveShelf = isAboveShelf();
Selim Cinek8875de12018-03-22 10:14:32 -07001388 boolean changed = headsUpAnimatingAway != mHeadsupDisappearRunning;
Selim Cinekcafa87f2016-10-26 17:00:17 -07001389 mHeadsupDisappearRunning = headsUpAnimatingAway;
1390 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
Selim Cinek8875de12018-03-22 10:14:32 -07001391 if (changed && mHeadsUpAnimatingAwayListener != null) {
1392 mHeadsUpAnimatingAwayListener.accept(headsUpAnimatingAway);
1393 }
Selim Cinek5cf1d052017-06-01 17:36:46 -07001394 if (isAboveShelf() != wasAboveShelf) {
1395 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
1396 }
Selim Cinekcafa87f2016-10-26 17:00:17 -07001397 }
1398
Selim Cinek8875de12018-03-22 10:14:32 -07001399 public void setHeadsUpAnimatingAwayListener(Consumer<Boolean> listener) {
1400 mHeadsUpAnimatingAwayListener = listener;
1401 }
1402
Selim Cinekcafa87f2016-10-26 17:00:17 -07001403 /**
1404 * @return if the view was just heads upped and is now animating away. During such a time the
1405 * layout needs to be kept consistent
1406 */
Selim Cinek29aab962018-02-27 17:05:45 -08001407 @Override
Selim Cinekcafa87f2016-10-26 17:00:17 -07001408 public boolean isHeadsUpAnimatingAway() {
1409 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -07001410 }
1411
Selim Cineke9bad242016-06-15 11:46:37 -07001412 public View getChildAfterViewWhenDismissed() {
1413 return mChildAfterViewWhenDismissed;
1414 }
1415
1416 public View getGroupParentWhenDismissed() {
1417 return mGroupParentWhenDismissed;
1418 }
1419
Rohan Shah524cf7b2018-03-15 14:40:02 -07001420 /**
1421 * Dismisses the notification with the option of showing the blocking helper in-place if we have
1422 * a negative user sentiment.
1423 *
1424 * @param fromAccessibility whether this dismiss is coming from an accessibility action
1425 * @return whether a blocking helper is shown in this row
1426 */
1427 public boolean performDismissWithBlockingHelper(boolean fromAccessibility) {
1428 NotificationBlockingHelperManager manager =
1429 Dependency.get(NotificationBlockingHelperManager.class);
1430 boolean isBlockingHelperShown = manager.perhapsShowBlockingHelper(this, mMenuRow);
1431
Rohan Shahda5dcdd2018-04-27 17:21:50 -07001432 Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
1433
Rohan Shah524cf7b2018-03-15 14:40:02 -07001434 // Continue with dismiss since we don't want the blocking helper to be directly associated
1435 // with a certain notification.
1436 performDismiss(fromAccessibility);
1437 return isBlockingHelperShown;
1438 }
1439
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001440 public void performDismiss(boolean fromAccessibility) {
Rohan Shah524cf7b2018-03-15 14:40:02 -07001441 if (isOnlyChildInGroup()) {
Ned Burnsf81c4c42019-01-07 14:10:43 -05001442 NotificationEntry groupSummary =
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001443 mGroupManager.getLogicalGroupSummary(getStatusBarNotification());
1444 if (groupSummary.isClearable()) {
Rohan Shah524cf7b2018-03-15 14:40:02 -07001445 // If this is the only child in the group, dismiss the group, but don't try to show
1446 // the blocking helper affordance!
Evan Laird94492852018-10-25 13:43:01 -04001447 groupSummary.getRow().performDismiss(fromAccessibility);
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001448 }
1449 }
Selim Cinekd03518c2018-03-15 12:13:51 -07001450 setDismissed(fromAccessibility);
Evan Laird94492852018-10-25 13:43:01 -04001451 if (mEntry.isClearable()) {
Julia Reynoldsfd4099d2018-08-21 11:06:06 -04001452 // TODO: track dismiss sentiment
yoshiki iguchi85ccbbc2018-01-22 12:33:21 +09001453 if (mOnDismissRunnable != null) {
1454 mOnDismissRunnable.run();
1455 }
Selim Cineke9079112016-12-14 14:41:01 -08001456 }
Selim Cinek9e624e72016-07-20 13:46:49 -07001457 }
1458
Rohan Shah524cf7b2018-03-15 14:40:02 -07001459 public void setBlockingHelperShowing(boolean isBlockingHelperShowing) {
1460 mIsBlockingHelperShowing = isBlockingHelperShowing;
1461 }
1462
1463 public boolean isBlockingHelperShowing() {
1464 return mIsBlockingHelperShowing;
1465 }
1466
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001467 public boolean isBlockingHelperShowingAndTranslationFinished() {
1468 return mIsBlockingHelperShowing && mNotificationTranslationFinished;
1469 }
1470
Selim Cineke9079112016-12-14 14:41:01 -08001471 public void setOnDismissRunnable(Runnable onDismissRunnable) {
1472 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -07001473 }
1474
Selim Cinek281c2022016-10-13 19:14:43 -07001475 public View getNotificationIcon() {
Selim Cinek414ad332017-02-24 19:06:12 -08001476 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek281c2022016-10-13 19:14:43 -07001477 if (notificationHeader != null) {
1478 return notificationHeader.getIcon();
1479 }
1480 return null;
1481 }
1482
1483 /**
1484 * @return whether the notification is currently showing a view with an icon.
1485 */
1486 public boolean isShowingIcon() {
Mady Mellor434180c2017-02-13 11:29:42 -08001487 if (areGutsExposed()) {
1488 return false;
1489 }
Selim Cinek2ffa02f2017-03-06 15:56:37 -08001490 return getVisibleNotificationHeader() != null;
Selim Cinek281c2022016-10-13 19:14:43 -07001491 }
1492
Selim Cinek0242fbb2016-10-19 13:38:32 -07001493 /**
1494 * Set how much this notification is transformed into an icon.
1495 *
Selim Cinek2b549f42016-11-22 16:38:51 -08001496 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
1497 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -08001498 * @param isLastChild is this the last child in the list. If true, then the transformation is
1499 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -07001500 */
Selim Cinek2b549f42016-11-22 16:38:51 -08001501 public void setContentTransformationAmount(float contentTransformationAmount,
1502 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -08001503 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001504 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001505 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001506 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001507 if (changeTransformation) {
1508 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -08001509 }
1510 }
1511
1512 /**
1513 * Set the icons to be visible of this notification.
1514 */
1515 public void setIconsVisible(boolean iconsVisible) {
1516 if (iconsVisible != mIconsVisible) {
1517 mIconsVisible = iconsVisible;
1518 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -07001519 }
1520 }
1521
Selim Cinekdb167372016-11-17 15:41:17 -08001522 @Override
1523 protected void onBelowSpeedBumpChanged() {
1524 updateIconVisibilities();
1525 }
1526
Selim Cinek875a3a12016-11-18 17:52:16 -08001527 private void updateContentTransformation() {
Selim Cinek2627d722018-01-19 12:16:49 -08001528 if (mExpandAnimationRunning) {
1529 return;
1530 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001531 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -08001532 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -08001533 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -08001534 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001535 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001536 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -08001537 translationY *= 0.4f;
1538 } else {
1539 contentAlpha = 1.0f;
1540 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001541 for (NotificationContentView l : mLayouts) {
1542 l.setAlpha(contentAlpha);
1543 l.setTranslationY(translationY);
1544 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001545 if (mChildrenContainer != null) {
1546 mChildrenContainer.setAlpha(contentAlpha);
1547 mChildrenContainer.setTranslationY(translationY);
1548 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -07001549 }
1550 }
1551
1552 private void updateIconVisibilities() {
Gus Prevas4b3c0ff22018-11-02 13:15:23 -04001553 boolean visible = isChildInGroup() || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -08001554 for (NotificationContentView l : mLayouts) {
1555 l.setIconsVisible(visible);
1556 }
Selim Cinekdb167372016-11-17 15:41:17 -08001557 if (mChildrenContainer != null) {
1558 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001559 }
1560 }
1561
Selim Cinek875a3a12016-11-18 17:52:16 -08001562 /**
1563 * Get the relative top padding of a view relative to this view. This recursively walks up the
1564 * hierarchy and does the corresponding measuring.
1565 *
1566 * @param view the view to the the padding for. The requested view has to be a child of this
1567 * notification.
1568 * @return the toppadding
1569 */
1570 public int getRelativeTopPadding(View view) {
1571 int topPadding = 0;
1572 while (view.getParent() instanceof ViewGroup) {
1573 topPadding += view.getTop();
1574 view = (View) view.getParent();
1575 if (view instanceof ExpandableNotificationRow) {
1576 return topPadding;
1577 }
1578 }
1579 return topPadding;
1580 }
1581
Selim Cineka1d97902016-12-14 16:31:40 -08001582 public float getContentTranslation() {
1583 return mPrivateLayout.getTranslationY();
1584 }
1585
Selim Cinek6743c0b2017-01-18 18:24:01 -08001586 public void setIsLowPriority(boolean isLowPriority) {
1587 mIsLowPriority = isLowPriority;
1588 mPrivateLayout.setIsLowPriority(isLowPriority);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001589 mNotificationInflater.setIsLowPriority(mIsLowPriority);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001590 if (mChildrenContainer != null) {
1591 mChildrenContainer.setIsLowPriority(isLowPriority);
1592 }
1593 }
1594
Selim Cinek414ad332017-02-24 19:06:12 -08001595 public boolean isLowPriority() {
1596 return mIsLowPriority;
1597 }
1598
Selim Cinek7d1009b2017-01-25 15:28:28 -08001599 public void setUseIncreasedCollapsedHeight(boolean use) {
1600 mUseIncreasedCollapsedHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001601 mNotificationInflater.setUsesIncreasedHeight(use);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001602 }
1603
Selim Cinek87ed69b2017-02-09 15:59:43 -08001604 public void setUseIncreasedHeadsUpHeight(boolean use) {
1605 mUseIncreasedHeadsUpHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001606 mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
1607 }
1608
1609 public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
1610 mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001611 }
1612
Selim Cinek5ba22542017-04-20 15:16:10 -07001613 public void setInflationCallback(InflationCallback callback) {
1614 mNotificationInflater.setInflationCallback(callback);
Selim Cinekc478f902017-02-22 20:55:44 -08001615 }
1616
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001617 public void setNeedsRedaction(boolean needsRedaction) {
Kevin38ce6fa2018-10-17 16:00:14 -07001618 if (mNeedsRedaction != needsRedaction) {
1619 mNeedsRedaction = needsRedaction;
1620 updateInflationFlag(FLAG_CONTENT_VIEW_PUBLIC, needsRedaction /* shouldInflate */);
1621 mNotificationInflater.updateNeedsRedaction(needsRedaction);
1622 if (!needsRedaction) {
1623 freeContentViewWhenSafe(FLAG_CONTENT_VIEW_PUBLIC);
1624 }
1625 }
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001626 }
1627
Selim Cinek5ba22542017-04-20 15:16:10 -07001628 @VisibleForTesting
Ned Burns1a5e22f2019-02-14 15:11:52 -05001629 public NotificationContentInflater getNotificationInflater() {
Selim Cinek5ba22542017-04-20 15:16:10 -07001630 return mNotificationInflater;
1631 }
1632
Chris Wren78403d72014-07-28 10:23:24 +01001633 public interface ExpansionLogger {
Anthony Chen6bf88a02017-04-10 14:41:44 -07001634 void logNotificationExpansion(String key, boolean userAction, boolean expanded);
Chris Wren78403d72014-07-28 10:23:24 +01001635 }
Selim Cinek1685e632014-04-08 02:27:49 +02001636
Chris Wren51c75102013-07-16 20:49:17 -04001637 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1638 super(context, attrs);
Dave Mankoff781ef7e2019-06-28 16:33:25 -04001639 mFalsingManager = Dependency.get(FalsingManager.class); // TODO: inject into a controller.
Ned Burns1a5e22f2019-02-14 15:11:52 -05001640 mNotificationInflater = new NotificationContentInflater(this);
Mady Mellor95d743c2017-01-10 12:05:27 -08001641 mMenuRow = new NotificationMenuRow(mContext);
Ahan Wude396fa2018-05-08 20:42:24 +08001642 mImageResolver = new NotificationInlineImageResolver(context,
1643 new NotificationInlineImageCache());
Beth Thibodeaueab4dde2019-02-07 11:37:02 -05001644 mMediaManager = Dependency.get(NotificationMediaManager.class);
Selim Cinek01af3342016-02-09 19:25:31 -08001645 initDimens();
1646 }
1647
Selim Cinekc3fec682019-06-06 18:11:07 -07001648 public void setBypassController(KeyguardBypassController bypassController) {
1649 mBypassController = bypassController;
1650 }
1651
1652 public void setStatusBarStateController(StatusBarStateController statusBarStateController) {
1653 mStatusbarStateController = statusBarStateController;
1654 }
1655
Selim Cinek01af3342016-02-09 19:25:31 -08001656 private void initDimens() {
Rohan Shahb9d500a2018-06-25 16:27:16 -07001657 mNotificationMinHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
Selim Cineke62255c2017-09-28 18:23:23 -07001658 R.dimen.notification_min_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001659 mNotificationMinHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1660 R.dimen.notification_min_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001661 mNotificationMinHeight = NotificationUtils.getFontScaledHeight(mContext,
1662 R.dimen.notification_min_height);
1663 mNotificationMinHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001664 R.dimen.notification_min_height_increased);
Beth Thibodeaucb395352019-01-25 15:39:54 -05001665 mNotificationMinHeightMedia = NotificationUtils.getFontScaledHeight(mContext,
1666 R.dimen.notification_min_height_media);
Selim Cineke62255c2017-09-28 18:23:23 -07001667 mNotificationMaxHeight = NotificationUtils.getFontScaledHeight(mContext,
1668 R.dimen.notification_max_height);
Rohan Shahb9d500a2018-06-25 16:27:16 -07001669 mMaxHeadsUpHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek77019c72015-12-09 10:18:02 -08001670 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinek9b49f6d2017-11-13 18:19:35 -08001671 mMaxHeadsUpHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
1672 R.dimen.notification_max_heads_up_height_before_p);
Selim Cineke62255c2017-09-28 18:23:23 -07001673 mMaxHeadsUpHeight = NotificationUtils.getFontScaledHeight(mContext,
1674 R.dimen.notification_max_heads_up_height);
1675 mMaxHeadsUpHeightIncreased = NotificationUtils.getFontScaledHeight(mContext,
Selim Cinek87ed69b2017-02-09 15:59:43 -08001676 R.dimen.notification_max_heads_up_height_increased);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001677
Anthony Chen7acbb772017-04-07 16:45:25 -07001678 Resources res = getResources();
1679 mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
1680 R.dimen.notification_divider_height_increased);
1681 mIconTransformContentShiftNoIcon = res.getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001682 R.dimen.notification_icon_transform_content_shift);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001683 mEnableNonGroupedNotificationExpand =
1684 res.getBoolean(R.bool.config_enableNonGroupedNotificationExpand);
1685 mShowGroupBackgroundWhenExpanded =
1686 res.getBoolean(R.bool.config_showGroupNotificationBgWhenExpanded);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001687 }
1688
Ahan Wude396fa2018-05-08 20:42:24 +08001689 NotificationInlineImageResolver getImageResolver() {
1690 return mImageResolver;
1691 }
1692
Selim Cinekf619ffc2016-02-17 14:53:05 -08001693 /**
Christoph Studera7fe6312014-06-27 19:32:44 +02001694 * Resets this view so it can be re-used for an updated notification.
1695 */
1696 public void reset() {
Jorim Jaggiae441282014-08-01 02:45:18 +02001697 mShowingPublicInitialized = false;
Selim Cinek31094df2014-08-14 19:28:15 +02001698 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001699 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001700 }
1701
Julia Reynoldsfc640012018-02-21 12:25:27 -05001702 public void showAppOpsIcons(ArraySet<Integer> activeOps) {
1703 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
1704 mChildrenContainer.getHeaderView().showAppOpsIcons(activeOps);
1705 }
1706 mPrivateLayout.showAppOpsIcons(activeOps);
1707 mPublicLayout.showAppOpsIcons(activeOps);
1708 }
1709
Gus Prevas7306b902018-12-11 10:57:06 -05001710 /** Sets the last time the notification being displayed audibly alerted the user. */
1711 public void setLastAudiblyAlertedMs(long lastAudiblyAlertedMs) {
Gus Prevasa3226492018-10-23 11:10:09 -04001712 if (NotificationUtils.useNewInterruptionModel(mContext)) {
Ned Burns3da3c782019-01-08 21:14:39 -05001713 long timeSinceAlertedAudibly = System.currentTimeMillis() - lastAudiblyAlertedMs;
1714 boolean alertedRecently =
1715 timeSinceAlertedAudibly < RECENTLY_ALERTED_THRESHOLD_MS;
1716
1717 applyAudiblyAlertedRecently(alertedRecently);
1718
1719 removeCallbacks(mExpireRecentlyAlertedFlag);
1720 if (alertedRecently) {
1721 long timeUntilNoLongerRecent =
1722 RECENTLY_ALERTED_THRESHOLD_MS - timeSinceAlertedAudibly;
1723 postDelayed(mExpireRecentlyAlertedFlag, timeUntilNoLongerRecent);
Gus Prevasa3226492018-10-23 11:10:09 -04001724 }
Gus Prevasa3226492018-10-23 11:10:09 -04001725 }
1726 }
1727
Ned Burns3da3c782019-01-08 21:14:39 -05001728 private final Runnable mExpireRecentlyAlertedFlag = () -> applyAudiblyAlertedRecently(false);
1729
1730 private void applyAudiblyAlertedRecently(boolean audiblyAlertedRecently) {
1731 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
1732 mChildrenContainer.getHeaderView().setRecentlyAudiblyAlerted(audiblyAlertedRecently);
1733 }
1734 mPrivateLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
1735 mPublicLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
1736 }
1737
Julia Reynoldsb5867452018-02-28 16:31:35 -05001738 public View.OnClickListener getAppOpsOnClickListener() {
1739 return mOnAppOpsClickListener;
1740 }
1741
Rohan Shah20790b82018-07-02 17:21:04 -07001742 public void setAppOpsOnClickListener(ExpandableNotificationRow.OnAppOpsClickListener l) {
Julia Reynoldsb5867452018-02-28 16:31:35 -05001743 mOnAppOpsClickListener = v -> {
1744 createMenu();
Evan Lairde55c6012019-03-13 12:54:37 -04001745 NotificationMenuRowPlugin provider = getProvider();
1746 if (provider == null) {
1747 return;
1748 }
1749 MenuItem menuItem = provider.getAppOpsMenuItem(mContext);
Julia Reynoldsb5867452018-02-28 16:31:35 -05001750 if (menuItem != null) {
1751 l.onClick(this, v.getWidth() / 2, v.getHeight() / 2, menuItem);
1752 }
1753 };
1754 }
1755
Jorim Jaggi251957d2014-04-09 04:24:09 +02001756 @Override
1757 protected void onFinishInflate() {
1758 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001759 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1760 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001761 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1762
1763 for (NotificationContentView l : mLayouts) {
1764 l.setExpandClickListener(mExpandClickListener);
1765 l.setContainingNotification(this);
1766 }
Selim Cinekab29aeb2015-02-20 18:18:32 +01001767 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1768 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001769 @Override
1770 public void onInflate(ViewStub stub, View inflated) {
1771 mGuts = (NotificationGuts) inflated;
1772 mGuts.setClipTopAmount(getClipTopAmount());
1773 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001774 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001775 }
1776 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001777 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1778 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1779
1780 @Override
1781 public void onInflate(ViewStub stub, View inflated) {
1782 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001783 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek414ad332017-02-24 19:06:12 -08001784 mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001785 mChildrenContainer.onNotificationUpdated();
Anthony Chen7acbb772017-04-07 16:45:25 -07001786
1787 if (mShouldTranslateContents) {
1788 mTranslateableViews.add(mChildrenContainer);
1789 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001790 }
1791 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001792
Anthony Chen7acbb772017-04-07 16:45:25 -07001793 if (mShouldTranslateContents) {
1794 // Add the views that we translate to reveal the menu
1795 mTranslateableViews = new ArrayList<>();
1796 for (int i = 0; i < getChildCount(); i++) {
1797 mTranslateableViews.add(getChildAt(i));
1798 }
1799 // Remove views that don't translate
1800 mTranslateableViews.remove(mChildrenContainerStub);
1801 mTranslateableViews.remove(mGutsStub);
Mady Mellor4b80b102016-01-22 08:03:58 -08001802 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001803 }
1804
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001805 private void doLongClickCallback() {
1806 doLongClickCallback(getWidth() / 2, getHeight() / 2);
1807 }
1808
1809 public void doLongClickCallback(int x, int y) {
1810 createMenu();
Evan Lairde55c6012019-03-13 12:54:37 -04001811 NotificationMenuRowPlugin provider = getProvider();
1812 MenuItem menuItem = null;
1813 if (provider != null) {
1814 menuItem = provider.getLongpressMenuItem(mContext);
1815 }
Mady Mellorb3a6aed2018-05-11 13:24:07 -07001816 doLongClickCallback(x, y, menuItem);
1817 }
1818
1819 private void doLongClickCallback(int x, int y, MenuItem menuItem) {
Geoffrey Pitsch409db272017-08-28 14:51:52 +00001820 if (mLongPressListener != null && menuItem != null) {
1821 mLongPressListener.onLongPress(this, x, y, menuItem);
1822 }
1823 }
1824
1825 @Override
1826 public boolean onKeyDown(int keyCode, KeyEvent event) {
1827 if (KeyEvent.isConfirmKey(keyCode)) {
1828 event.startTracking();
1829 return true;
1830 }
1831 return super.onKeyDown(keyCode, event);
1832 }
1833
1834 @Override
1835 public boolean onKeyUp(int keyCode, KeyEvent event) {
1836 if (KeyEvent.isConfirmKey(keyCode)) {
1837 if (!event.isCanceled()) {
1838 performClick();
1839 }
1840 return true;
1841 }
1842 return super.onKeyUp(keyCode, event);
1843 }
1844
1845 @Override
1846 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
1847 if (KeyEvent.isConfirmKey(keyCode)) {
1848 doLongClickCallback();
1849 return true;
1850 }
1851 return false;
1852 }
1853
Mady Mellor4b80b102016-01-22 08:03:58 -08001854 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001855 if (mTranslateAnim != null) {
1856 mTranslateAnim.cancel();
1857 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001858
1859 if (!mShouldTranslateContents) {
1860 setTranslationX(0);
1861 } else if (mTranslateableViews != null) {
Mady Mellor4b80b102016-01-22 08:03:58 -08001862 for (int i = 0; i < mTranslateableViews.size(); i++) {
1863 mTranslateableViews.get(i).setTranslationX(0);
1864 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001865 invalidateOutline();
shawnlin4fbeac42018-04-30 20:32:40 +08001866 getEntry().expandedIcon.setScrollX(0);
Mady Mellor4b80b102016-01-22 08:03:58 -08001867 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001868
Evan Lairde55c6012019-03-13 12:54:37 -04001869 if (mMenuRow != null) {
1870 mMenuRow.resetMenu();
1871 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001872 }
1873
Rohan Shah56eb0912018-05-10 21:49:04 -07001874 void onGutsOpened() {
Evan Lairdab1faee2019-05-23 16:53:10 -04001875 resetTranslation();
Rohan Shah56eb0912018-05-10 21:49:04 -07001876 updateContentAccessibilityImportanceForGuts(false /* isEnabled */);
1877 }
1878
1879 void onGutsClosed() {
1880 updateContentAccessibilityImportanceForGuts(true /* isEnabled */);
1881 }
1882
1883 /**
1884 * Updates whether all the non-guts content inside this row is important for accessibility.
1885 *
1886 * @param isEnabled whether the content views should be enabled for accessibility
1887 */
1888 private void updateContentAccessibilityImportanceForGuts(boolean isEnabled) {
1889 if (mChildrenContainer != null) {
1890 updateChildAccessibilityImportance(mChildrenContainer, isEnabled);
1891 }
1892 if (mLayouts != null) {
1893 for (View view : mLayouts) {
1894 updateChildAccessibilityImportance(view, isEnabled);
1895 }
1896 }
1897
1898 if (isEnabled) {
1899 this.requestAccessibilityFocus();
1900 }
1901 }
1902
1903 /**
1904 * Updates whether the given childView is important for accessibility based on
1905 * {@code isEnabled}.
1906 */
1907 private void updateChildAccessibilityImportance(View childView, boolean isEnabled) {
1908 childView.setImportantForAccessibility(isEnabled
1909 ? View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
1910 : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
1911 }
1912
Selim Cinekde4de0e2018-01-24 16:21:07 -08001913 public CharSequence getActiveRemoteInputText() {
1914 return mPrivateLayout.getActiveRemoteInputText();
1915 }
1916
Mady Mellor4b80b102016-01-22 08:03:58 -08001917 public void animateTranslateNotification(final float leftTarget) {
1918 if (mTranslateAnim != null) {
1919 mTranslateAnim.cancel();
1920 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001921 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001922 if (mTranslateAnim != null) {
1923 mTranslateAnim.start();
1924 }
1925 }
1926
1927 @Override
1928 public void setTranslation(float translationX) {
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001929 if (isBlockingHelperShowingAndTranslationFinished()) {
1930 mGuts.setTranslationX(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001931 return;
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001932 } else if (!mShouldTranslateContents) {
Anthony Chen7acbb772017-04-07 16:45:25 -07001933 setTranslationX(translationX);
1934 } else if (mTranslateableViews != null) {
1935 // Translate the group of views
1936 for (int i = 0; i < mTranslateableViews.size(); i++) {
1937 if (mTranslateableViews.get(i) != null) {
1938 mTranslateableViews.get(i).setTranslationX(translationX);
1939 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001940 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001941 invalidateOutline();
Selim Cinek143672c2018-03-23 20:04:32 -07001942
1943 // In order to keep the shelf in sync with this swiping, we're simply translating
1944 // it's icon by the same amount. The translation is already being used for the normal
1945 // positioning, so we can use the scrollX instead.
1946 getEntry().expandedIcon.setScrollX((int) -translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001947 }
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001948
Evan Lairde55c6012019-03-13 12:54:37 -04001949 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Aaron Heuckroth266cb342018-09-07 14:52:04 -04001950 mMenuRow.onParentTranslationUpdate(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001951 }
1952 }
1953
1954 @Override
1955 public float getTranslation() {
Anthony Chene04afcb2017-04-21 13:51:32 -07001956 if (!mShouldTranslateContents) {
Anthony Chen7acbb772017-04-07 16:45:25 -07001957 return getTranslationX();
1958 }
1959
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001960 if (isBlockingHelperShowingAndCanTranslate()) {
1961 return mGuts.getTranslationX();
1962 }
1963
Mady Mellor34958fa2016-02-23 09:52:17 -08001964 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1965 // All of the views in the list should have same translation, just use first one.
1966 return mTranslateableViews.get(0).getTranslationX();
1967 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001968
Mady Mellor34958fa2016-02-23 09:52:17 -08001969 return 0;
1970 }
1971
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001972 private boolean isBlockingHelperShowingAndCanTranslate() {
1973 return areGutsExposed() && mIsBlockingHelperShowing && mNotificationTranslationFinished;
1974 }
1975
Mady Mellor34958fa2016-02-23 09:52:17 -08001976 public Animator getTranslateViewAnimator(final float leftTarget,
1977 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001978 if (mTranslateAnim != null) {
1979 mTranslateAnim.cancel();
1980 }
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001981
Mady Mellorb0a82462016-04-30 17:31:02 -07001982 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1983 leftTarget);
1984 if (listener != null) {
1985 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001986 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001987 translateAnim.addListener(new AnimatorListenerAdapter() {
1988 boolean cancelled = false;
1989
1990 @Override
1991 public void onAnimationCancel(Animator anim) {
1992 cancelled = true;
1993 }
1994
1995 @Override
1996 public void onAnimationEnd(Animator anim) {
Nadia Benbernou7a18c812019-02-08 16:23:10 -05001997 if (mIsBlockingHelperShowing) {
1998 mNotificationTranslationFinished = true;
1999 }
Mady Mellor95d743c2017-01-10 12:05:27 -08002000 if (!cancelled && leftTarget == 0) {
Evan Lairde55c6012019-03-13 12:54:37 -04002001 if (mMenuRow != null) {
2002 mMenuRow.resetMenu();
2003 }
Mady Mellorb0a82462016-04-30 17:31:02 -07002004 mTranslateAnim = null;
2005 }
2006 }
2007 });
2008 mTranslateAnim = translateAnim;
2009 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08002010 }
2011
Evan Lairde55c6012019-03-13 12:54:37 -04002012 void ensureGutsInflated() {
Selim Cinekab29aeb2015-02-20 18:18:32 +01002013 if (mGuts == null) {
2014 mGutsStub.inflate();
2015 }
2016 }
2017
Selim Cinekda42d652015-12-04 15:51:16 -08002018 private void updateChildrenVisibility() {
Selim Cinek7fa385a2018-01-24 08:35:28 -08002019 boolean hideContentWhileLaunching = mExpandAnimationRunning && mGuts != null
2020 && mGuts.isExposed();
Selim Cinek01497392019-05-23 11:22:23 -07002021 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren
Selim Cinek7fa385a2018-01-24 08:35:28 -08002022 && !hideContentWhileLaunching ? VISIBLE : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08002023 if (mChildrenContainer != null) {
Selim Cinek01497392019-05-23 11:22:23 -07002024 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren
Selim Cinek7fa385a2018-01-24 08:35:28 -08002025 && !hideContentWhileLaunching ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08002026 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08002027 }
Selim Cinekda42d652015-12-04 15:51:16 -08002028 // The limits might have changed if the view suddenly became a group or vice versa
2029 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01002030 }
2031
Jorim Jaggife40f7d2014-04-28 15:20:04 +02002032 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08002033 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
2034 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02002035 // Add a record for the entire layout since its content is somehow small.
2036 // The event comes from a leaf view that is interacted with.
2037 AccessibilityEvent record = AccessibilityEvent.obtain();
2038 onInitializeAccessibilityEvent(record);
2039 dispatchPopulateAccessibilityEvent(record);
2040 event.appendRecord(record);
2041 return true;
2042 }
2043 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02002044 }
Chris Wren51c75102013-07-16 20:49:17 -04002045
Selim Cinek2627d722018-01-19 12:16:49 -08002046 public void applyExpandAnimationParams(ExpandAnimationParameters params) {
2047 if (params == null) {
2048 return;
2049 }
Selim Cinek2627d722018-01-19 12:16:49 -08002050 float zProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
2051 params.getProgress(0, 50));
2052 float translationZ = MathUtils.lerp(params.getStartTranslationZ(),
2053 mNotificationLaunchHeight,
2054 zProgress);
2055 setTranslationZ(translationZ);
Selim Cinekc25989e2018-02-16 16:42:14 -08002056 float extraWidthForClipping = params.getWidth() - getWidth()
2057 + MathUtils.lerp(0, mOutlineRadius * 2, params.getProgress());
2058 setExtraWidthForClipping(extraWidthForClipping);
2059 int top = params.getTop();
2060 float interpolation = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(params.getProgress());
2061 int startClipTopAmount = params.getStartClipTopAmount();
2062 if (mNotificationParent != null) {
Selim Cinekc42db8d2018-12-04 13:29:25 -08002063 float parentY = mNotificationParent.getTranslationY();
2064 top -= parentY;
Selim Cinekc25989e2018-02-16 16:42:14 -08002065 mNotificationParent.setTranslationZ(translationZ);
2066 int parentStartClipTopAmount = params.getParentStartClipTopAmount();
2067 if (startClipTopAmount != 0) {
2068 int clipTopAmount = (int) MathUtils.lerp(parentStartClipTopAmount,
2069 parentStartClipTopAmount - startClipTopAmount,
2070 interpolation);
2071 mNotificationParent.setClipTopAmount(clipTopAmount);
2072 }
2073 mNotificationParent.setExtraWidthForClipping(extraWidthForClipping);
Selim Cinekc42db8d2018-12-04 13:29:25 -08002074 float clipBottom = Math.max(params.getBottom(),
2075 parentY + mNotificationParent.getActualHeight()
2076 - mNotificationParent.getClipBottomAmount());
2077 float clipTop = Math.min(params.getTop(), parentY);
2078 int minimumHeightForClipping = (int) (clipBottom - clipTop);
2079 mNotificationParent.setMinimumHeightForClipping(minimumHeightForClipping);
Selim Cinekc25989e2018-02-16 16:42:14 -08002080 } else if (startClipTopAmount != 0) {
2081 int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, interpolation);
2082 setClipTopAmount(clipTopAmount);
2083 }
2084 setTranslationY(top);
Selim Cinek2627d722018-01-19 12:16:49 -08002085 setActualHeight(params.getHeight());
Selim Cinekc25989e2018-02-16 16:42:14 -08002086
Selim Cinek2627d722018-01-19 12:16:49 -08002087 mBackgroundNormal.setExpandAnimationParams(params);
2088 }
2089
2090 public void setExpandAnimationRunning(boolean expandAnimationRunning) {
Selim Cinekc25989e2018-02-16 16:42:14 -08002091 View contentView;
2092 if (mIsSummaryWithChildren) {
2093 contentView = mChildrenContainer;
2094 } else {
2095 contentView = getShowingLayout();
2096 }
2097 if (mGuts != null && mGuts.isExposed()) {
2098 contentView = mGuts;
2099 }
Selim Cinek2627d722018-01-19 12:16:49 -08002100 if (expandAnimationRunning) {
Selim Cinek2627d722018-01-19 12:16:49 -08002101 contentView.animate()
2102 .alpha(0f)
2103 .setDuration(ActivityLaunchAnimator.ANIMATION_DURATION_FADE_CONTENT)
2104 .setInterpolator(Interpolators.ALPHA_OUT);
2105 setAboveShelf(true);
2106 mExpandAnimationRunning = true;
Dave Mankoffa4d195d2018-11-16 13:33:27 -05002107 getViewState().cancelAnimations(this);
Selim Cinek2627d722018-01-19 12:16:49 -08002108 mNotificationLaunchHeight = AmbientState.getNotificationLaunchHeight(getContext());
2109 } else {
2110 mExpandAnimationRunning = false;
2111 setAboveShelf(isAboveShelf());
Selim Cinek7fa385a2018-01-24 08:35:28 -08002112 if (mGuts != null) {
2113 mGuts.setAlpha(1.0f);
2114 }
Selim Cinekc25989e2018-02-16 16:42:14 -08002115 if (contentView != null) {
2116 contentView.setAlpha(1.0f);
2117 }
2118 setExtraWidthForClipping(0.0f);
2119 if (mNotificationParent != null) {
2120 mNotificationParent.setExtraWidthForClipping(0.0f);
2121 mNotificationParent.setMinimumHeightForClipping(0);
2122 }
2123 }
2124 if (mNotificationParent != null) {
2125 mNotificationParent.setChildIsExpanding(mExpandAnimationRunning);
Selim Cinek2627d722018-01-19 12:16:49 -08002126 }
Selim Cinek7fa385a2018-01-24 08:35:28 -08002127 updateChildrenVisibility();
Selim Cinek2627d722018-01-19 12:16:49 -08002128 updateClipping();
2129 mBackgroundNormal.setExpandAnimationRunning(expandAnimationRunning);
2130 }
2131
Selim Cinekc25989e2018-02-16 16:42:14 -08002132 private void setChildIsExpanding(boolean isExpanding) {
2133 mChildIsExpanding = isExpanding;
Selim Cinek6487ebf2018-11-28 18:57:40 -08002134 updateClipping();
2135 invalidate();
Selim Cinekc25989e2018-02-16 16:42:14 -08002136 }
2137
2138 @Override
2139 public boolean hasExpandingChild() {
2140 return mChildIsExpanding;
2141 }
2142
Selim Cinek2627d722018-01-19 12:16:49 -08002143 @Override
2144 protected boolean shouldClipToActualHeight() {
Selim Cinek53328492018-12-05 14:58:44 -08002145 return super.shouldClipToActualHeight() && !mExpandAnimationRunning;
Selim Cinek2627d722018-01-19 12:16:49 -08002146 }
2147
2148 @Override
2149 public boolean isExpandAnimationRunning() {
2150 return mExpandAnimationRunning;
2151 }
2152
Lucas Dupincecc7c22017-09-12 16:02:45 -07002153 /**
2154 * Tap sounds should not be played when we're unlocking.
2155 * Doing so would cause audio collision and the system would feel unpolished.
2156 */
2157 @Override
2158 public boolean isSoundEffectsEnabled() {
Selim Cinekc3fec682019-06-06 18:11:07 -07002159 final boolean mute = mStatusbarStateController != null
2160 && mStatusbarStateController.isDozing()
2161 && mSecureStateProvider != null &&
Lucas Dupincecc7c22017-09-12 16:02:45 -07002162 !mSecureStateProvider.getAsBoolean();
2163 return !mute && super.isSoundEffectsEnabled();
2164 }
2165
Chris Wren51c75102013-07-16 20:49:17 -04002166 public boolean isExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002167 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek388df6d2015-10-22 13:25:11 -07002168 return !mChildrenExpanded;
2169 }
Anthony Chen6bf88a02017-04-10 14:41:44 -07002170 return mEnableNonGroupedNotificationExpand && mExpandable;
Chris Wren51c75102013-07-16 20:49:17 -04002171 }
2172
2173 public void setExpandable(boolean expandable) {
2174 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002175 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04002176 }
2177
Selim Cinek4ffd6362015-12-29 15:12:23 +01002178 @Override
2179 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08002180 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
2181 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01002182 }
2183
Selim Cinek1685e632014-04-08 02:27:49 +02002184 /**
2185 * @return whether the user has changed the expansion state
2186 */
2187 public boolean hasUserChangedExpansion() {
2188 return mHasUserChangedExpansion;
2189 }
2190
Chris Wren51c75102013-07-16 20:49:17 -04002191 public boolean isUserExpanded() {
2192 return mUserExpanded;
2193 }
2194
Selim Cinek1685e632014-04-08 02:27:49 +02002195 /**
2196 * Set this notification to be expanded by the user
2197 *
2198 * @param userExpanded whether the user wants this notification to be expanded
2199 */
Chris Wren51c75102013-07-16 20:49:17 -04002200 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07002201 setUserExpanded(userExpanded, false /* allowChildExpansion */);
2202 }
2203
2204 /**
2205 * Set this notification to be expanded by the user
2206 *
2207 * @param userExpanded whether the user wants this notification to be expanded
2208 * @param allowChildExpansion whether a call to this method allows expanding children
2209 */
2210 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07002211 mFalsingManager.setNotificationExpanded();
Selim Cinek0b9cf462017-12-07 16:31:03 -08002212 if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
Selim Cinek414ad332017-02-24 19:06:12 -08002213 && !mChildrenContainer.showingAsLowPriority()) {
Chris Wren698b1702016-05-23 11:16:32 -04002214 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07002215 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -08002216 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07002217 return;
2218 }
Christoph Studera7fe6312014-06-27 19:32:44 +02002219 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01002220 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02002221 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04002222 mUserExpanded = userExpanded;
Selim Cinek414ad332017-02-24 19:06:12 -08002223 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002224 if (!wasExpanded && isExpanded()
2225 && getActualHeight() != getIntrinsicHeight()) {
2226 notifyHeightChanged(true /* needsAnimation */);
2227 }
Chris Wren51c75102013-07-16 20:49:17 -04002228 }
2229
Selim Cinekccd14fb2014-08-12 18:53:24 +02002230 public void resetUserExpansion() {
Selim Cinekf2495a72019-03-11 19:58:15 -07002231 boolean wasExpanded = isExpanded();
Selim Cinekccd14fb2014-08-12 18:53:24 +02002232 mHasUserChangedExpansion = false;
2233 mUserExpanded = false;
Selim Cinekf2495a72019-03-11 19:58:15 -07002234 if (wasExpanded != isExpanded()) {
2235 if (mIsSummaryWithChildren) {
2236 mChildrenContainer.onExpansionChanged();
2237 }
2238 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek414ad332017-02-24 19:06:12 -08002239 }
2240 updateShelfIconColor();
Selim Cinekccd14fb2014-08-12 18:53:24 +02002241 }
2242
Chris Wren51c75102013-07-16 20:49:17 -04002243 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07002244 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04002245 }
2246
2247 public void setUserLocked(boolean userLocked) {
2248 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08002249 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07002250 // This is intentionally not guarded with mIsSummaryWithChildren since we might have had
2251 // children but not anymore.
2252 if (mChildrenContainer != null) {
Selim Cinek42357e02016-02-24 18:48:01 -08002253 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07002254 if (mIsSummaryWithChildren && (userLocked || !isGroupExpanded())) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002255 updateBackgroundForGroupState();
2256 }
Selim Cinek42357e02016-02-24 18:48:01 -08002257 }
Chris Wren51c75102013-07-16 20:49:17 -04002258 }
2259
Selim Cinek1685e632014-04-08 02:27:49 +02002260 /**
2261 * @return has the system set this notification to be expanded
2262 */
2263 public boolean isSystemExpanded() {
2264 return mIsSystemExpanded;
2265 }
2266
2267 /**
2268 * Set this notification to be expanded by the system.
2269 *
2270 * @param expand whether the system wants this notification to be expanded.
2271 */
2272 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02002273 if (expand != mIsSystemExpanded) {
2274 final boolean wasExpanded = isExpanded();
2275 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01002276 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek414ad332017-02-24 19:06:12 -08002277 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07002278 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07002279 mChildrenContainer.updateGroupOverflow();
2280 }
Selim Cinek31094df2014-08-14 19:28:15 +02002281 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02002282 }
2283
2284 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07002285 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02002286 */
Selim Cinek83bc7832015-10-22 13:26:54 -07002287 public void setOnKeyguard(boolean onKeyguard) {
2288 if (onKeyguard != mOnKeyguard) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07002289 boolean wasAboveShelf = isAboveShelf();
Selim Cinek31094df2014-08-14 19:28:15 +02002290 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07002291 mOnKeyguard = onKeyguard;
Selim Cinek414ad332017-02-24 19:06:12 -08002292 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cinek31094df2014-08-14 19:28:15 +02002293 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07002294 if (mIsSummaryWithChildren) {
2295 mChildrenContainer.updateGroupOverflow();
2296 }
Mady Mellor4b80b102016-01-22 08:03:58 -08002297 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02002298 }
Selim Cinek5cf1d052017-06-01 17:36:46 -07002299 if (isAboveShelf() != wasAboveShelf) {
2300 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
2301 }
Selim Cinek31094df2014-08-14 19:28:15 +02002302 }
Selim Cinekfe24fb72018-02-13 14:34:55 -08002303 updateRippleAllowed();
2304 }
2305
2306 private void updateRippleAllowed() {
2307 boolean allowed = isOnKeyguard()
2308 || mEntry.notification.getNotification().contentIntent == null;
2309 setRippleAllowed(allowed);
Selim Cinek1685e632014-04-08 02:27:49 +02002310 }
2311
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02002312 @Override
2313 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02002314 if (isUserLocked()) {
2315 return getActualHeight();
2316 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002317 if (mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07002318 return mGuts.getIntrinsicHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08002319 } else if ((isChildInGroup() && !isGroupExpanded())) {
2320 return mPrivateLayout.getMinHeight();
2321 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
2322 return getMinHeight();
Selim Cinekc3fec682019-06-06 18:11:07 -07002323 } else if (mIsSummaryWithChildren) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002324 return mChildrenContainer.getIntrinsicHeight();
Selim Cinekc3fec682019-06-06 18:11:07 -07002325 } else if (canShowHeadsUp() && isHeadsUpState()) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07002326 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08002327 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
2328 } else if (isExpanded()) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002329 return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
Selim Cinek8d490d42015-04-10 00:05:50 -07002330 } else {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002331 return Math.max(getCollapsedHeight(), getHeadsUpHeight());
Selim Cinek8d490d42015-04-10 00:05:50 -07002332 }
Selim Cinek31aada42015-12-18 17:51:15 -08002333 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07002334 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08002335 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07002336 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02002337 }
Selim Cinekb5605e52015-02-20 18:21:41 +01002338 }
Selim Cinek1685e632014-04-08 02:27:49 +02002339
Selim Cinekc3fec682019-06-06 18:11:07 -07002340 /**
2341 * @return {@code true} if the notification can show it's heads up layout. This is mostly true
2342 * except for legacy use cases.
2343 */
2344 public boolean canShowHeadsUp() {
2345 if (mOnKeyguard && !isDozing() && !isBypassEnabled()) {
2346 return false;
2347 }
2348 return true;
2349 }
2350
2351 private boolean isBypassEnabled() {
2352 return mBypassController == null || mBypassController.getBypassEnabled();
2353 }
2354
2355 private boolean isDozing() {
2356 return mStatusbarStateController != null && mStatusbarStateController.isDozing();
Adrian Roos6f6e1592017-05-02 16:22:53 -07002357 }
2358
Mady Mellor43c2cd12016-12-12 21:05:13 -08002359 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07002360 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07002361 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01002362 }
2363
Selim Cinek263398f2015-10-21 17:40:23 -07002364 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05002365 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07002366 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
2367 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
Selim Cinek414ad332017-02-24 19:06:12 -08002368 mChildrenContainer.recreateNotificationHeader(mExpandClickListener
2369 );
Selim Cinek263398f2015-10-21 17:40:23 -07002370 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07002371 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002372 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08002373 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08002374 updateChildrenVisibility();
Selim Cinek2871bef2017-11-22 08:40:00 -08002375 applyChildrenRoundness();
Selim Cinek263398f2015-10-21 17:40:23 -07002376 }
Rohan Shah63411fc2018-03-28 19:05:52 -07002377 /**
2378 * Returns the number of channels covered by the notification row (including its children if
2379 * it's a summary notification).
2380 */
2381 public int getNumUniqueChannels() {
Evan Laird47dc4542019-04-24 15:10:52 -04002382 return getUniqueChannels().size();
2383 }
2384
2385 /**
2386 * Returns the channels covered by the notification row (including its children if
2387 * it's a summary notification).
2388 */
2389 public ArraySet<NotificationChannel> getUniqueChannels() {
Rohan Shah63411fc2018-03-28 19:05:52 -07002390 ArraySet<NotificationChannel> channels = new ArraySet<>();
2391
2392 channels.add(mEntry.channel);
2393
2394 // If this is a summary, then add in the children notification channels for the
2395 // same user and pkg.
2396 if (mIsSummaryWithChildren) {
2397 final List<ExpandableNotificationRow> childrenRows = getNotificationChildren();
2398 final int numChildren = childrenRows.size();
2399 for (int i = 0; i < numChildren; i++) {
2400 final ExpandableNotificationRow childRow = childrenRows.get(i);
2401 final NotificationChannel childChannel = childRow.getEntry().channel;
2402 final StatusBarNotification childSbn = childRow.getStatusBarNotification();
2403 if (childSbn.getUser().equals(mStatusBarNotification.getUser()) &&
2404 childSbn.getPackageName().equals(mStatusBarNotification.getPackageName())) {
2405 channels.add(childChannel);
2406 }
2407 }
2408 }
Evan Laird47dc4542019-04-24 15:10:52 -04002409
2410 return channels;
Rohan Shah63411fc2018-03-28 19:05:52 -07002411 }
Selim Cinek263398f2015-10-21 17:40:23 -07002412
Mady Mellorb0a82462016-04-30 17:31:02 -07002413 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07002414 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002415 mChildrenContainer.updateChildrenHeaderAppearance();
2416 }
2417 }
2418
Selim Cinek1685e632014-04-08 02:27:49 +02002419 /**
2420 * Check whether the view state is currently expanded. This is given by the system in {@link
2421 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
2422 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
2423 * view can differ from this state, if layout params are modified from outside.
2424 *
2425 * @return whether the view state is currently expanded.
2426 */
Selim Cinek83bc7832015-10-22 13:26:54 -07002427 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08002428 return isExpanded(false /* allowOnKeyguard */);
2429 }
2430
2431 public boolean isExpanded(boolean allowOnKeyguard) {
2432 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01002433 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
2434 || isUserExpanded());
2435 }
2436
2437 private boolean isSystemChildExpanded() {
2438 return mIsSystemChildExpanded;
2439 }
2440
2441 public void setSystemChildExpanded(boolean expanded) {
2442 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02002443 }
2444
Mady Mellor035badd2017-04-04 18:45:30 -07002445 public void setLayoutListener(LayoutListener listener) {
2446 mLayoutListener = listener;
2447 }
2448
2449 public void removeListener() {
2450 mLayoutListener = null;
2451 }
2452
Selim Cinek1685e632014-04-08 02:27:49 +02002453 @Override
2454 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002455 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02002456 super.onLayout(changed, left, top, right, bottom);
Selim Cinek15af9762019-03-19 18:32:37 -07002457 if (intrinsicBefore != getIntrinsicHeight() && intrinsicBefore != 0) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002458 notifyHeightChanged(true /* needsAnimation */);
2459 }
Evan Lairde55c6012019-03-13 12:54:37 -04002460 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Aaron Heuckroth266cb342018-09-07 14:52:04 -04002461 mMenuRow.onParentHeightUpdate();
Mady Mellora6edc872016-04-26 11:01:03 -07002462 }
Selim Cinek875a3a12016-11-18 17:52:16 -08002463 updateContentShiftHeight();
Mady Mellor035badd2017-04-04 18:45:30 -07002464 if (mLayoutListener != null) {
2465 mLayoutListener.onLayout();
2466 }
Selim Cinek875a3a12016-11-18 17:52:16 -08002467 }
2468
2469 /**
2470 * Updates the content shift height such that the header is completely hidden when coming from
2471 * the top.
2472 */
2473 private void updateContentShiftHeight() {
Selim Cinek414ad332017-02-24 19:06:12 -08002474 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek875a3a12016-11-18 17:52:16 -08002475 if (notificationHeader != null) {
2476 CachingIconView icon = notificationHeader.getIcon();
2477 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
2478 } else {
2479 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
2480 }
Selim Cinek1685e632014-04-08 02:27:49 +02002481 }
2482
Selim Cinekfa0a2d32016-01-14 13:02:21 -08002483 @Override
2484 public void notifyHeightChanged(boolean needsAnimation) {
2485 super.notifyHeightChanged(needsAnimation);
2486 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
2487 }
2488
Selim Cinek3c76d502016-02-19 15:16:33 -08002489 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02002490 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08002491 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02002492 }
2493
Mady Mellor43c2cd12016-12-12 21:05:13 -08002494 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02002495 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07002496 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08002497 if (mIsSummaryWithChildren) {
2498 List<ExpandableNotificationRow> notificationChildren =
2499 mChildrenContainer.getNotificationChildren();
2500 for (int i = 0; i < notificationChildren.size(); i++) {
2501 ExpandableNotificationRow child = notificationChildren.get(i);
2502 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
2503 }
2504 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002505 }
2506
Mady Mellor43c2cd12016-12-12 21:05:13 -08002507 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02002508 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
2509 long duration) {
Selim Cinek69594fb2018-05-18 12:06:10 -07002510 if (getVisibility() == GONE) {
2511 // If we are GONE, the hideSensitive parameter will not be calculated and always be
2512 // false, which is incorrect, let's wait until a real call comes in later.
2513 return;
2514 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002515 boolean oldShowingPublic = mShowingPublic;
2516 mShowingPublic = mSensitive && hideSensitive;
2517 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
2518 return;
2519 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05002520
2521 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02002522 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002523
Jorim Jaggiae441282014-08-01 02:45:18 +02002524 if (!animated) {
2525 mPublicLayout.animate().cancel();
2526 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07002527 if (mChildrenContainer != null) {
2528 mChildrenContainer.animate().cancel();
2529 mChildrenContainer.setAlpha(1f);
2530 }
Jorim Jaggiae441282014-08-01 02:45:18 +02002531 mPublicLayout.setAlpha(1f);
2532 mPrivateLayout.setAlpha(1f);
2533 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08002534 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02002535 } else {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002536 animateShowingPublic(delay, duration, mShowingPublic);
Jorim Jaggiae441282014-08-01 02:45:18 +02002537 }
Selim Cinekc3179332016-03-04 14:44:56 -08002538 NotificationContentView showingLayout = getShowingLayout();
2539 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002540 mPrivateLayout.updateExpandButtons(isExpandable());
Lucas Dupinb6ed63b2017-05-30 16:17:42 -07002541 updateShelfIconColor();
Jorim Jaggiae441282014-08-01 02:45:18 +02002542 mShowingPublicInitialized = true;
2543 }
2544
Selim Cinek0b9cf462017-12-07 16:31:03 -08002545 private void animateShowingPublic(long delay, long duration, boolean showingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -07002546 View[] privateViews = mIsSummaryWithChildren
2547 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08002548 : new View[] {mPrivateLayout};
2549 View[] publicViews = new View[] {mPublicLayout};
Selim Cinek0b9cf462017-12-07 16:31:03 -08002550 View[] hiddenChildren = showingPublic ? privateViews : publicViews;
2551 View[] shownChildren = showingPublic ? publicViews : privateViews;
Selim Cinekd84a5932015-12-15 11:45:36 -08002552 for (final View hiddenView : hiddenChildren) {
2553 hiddenView.setVisibility(View.VISIBLE);
2554 hiddenView.animate().cancel();
2555 hiddenView.animate()
2556 .alpha(0f)
2557 .setStartDelay(delay)
2558 .setDuration(duration)
2559 .withEndAction(new Runnable() {
2560 @Override
2561 public void run() {
2562 hiddenView.setVisibility(View.INVISIBLE);
2563 }
2564 });
2565 }
2566 for (View showView : shownChildren) {
2567 showView.setVisibility(View.VISIBLE);
2568 showView.setAlpha(0f);
2569 showView.animate().cancel();
2570 showView.animate()
2571 .alpha(1f)
2572 .setStartDelay(delay)
2573 .setDuration(duration);
2574 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04002575 }
2576
Mady Mellor43c2cd12016-12-12 21:05:13 -08002577 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08002578 public boolean mustStayOnScreen() {
Selim Cinek9b9d6e12017-11-30 12:29:47 +01002579 return mIsHeadsUp && mMustStayOnScreen;
Selim Cinek3776fe02016-02-04 13:32:43 -08002580 }
2581
Selim Cinek9e624e72016-07-20 13:46:49 -07002582 /**
2583 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
2584 * otherwise some state might not be updated. To request about the general clearability
Ned Burnsf81c4c42019-01-07 14:10:43 -05002585 * see {@link NotificationEntry#isClearable()}.
Selim Cinek9e624e72016-07-20 13:46:49 -07002586 */
2587 public boolean canViewBeDismissed() {
Evan Laird94492852018-10-25 13:43:01 -04002588 return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
Selim Cinek0b9cf462017-12-07 16:31:03 -08002589 }
2590
2591 private boolean shouldShowPublic() {
2592 return mSensitive && mHideSensitiveForIntrinsicHeight;
Dan Sandlera5e0f412014-01-23 15:11:54 -05002593 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02002594
Ricky Waicd35def2016-05-03 11:07:07 +01002595 public void makeActionsVisibile() {
2596 setUserExpanded(true, true);
2597 if (isChildInGroup()) {
2598 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
2599 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07002600 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01002601 }
2602
Selim Cinekb5605e52015-02-20 18:21:41 +01002603 public void setChildrenExpanded(boolean expanded, boolean animate) {
2604 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07002605 if (mChildrenContainer != null) {
2606 mChildrenContainer.setChildrenExpanded(expanded);
2607 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07002608 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07002609 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01002610 }
2611
Selim Cinekb5605e52015-02-20 18:21:41 +01002612 public static void applyTint(View v, int color) {
2613 int alpha;
2614 if (color != 0) {
2615 alpha = COLORED_DIVIDER_ALPHA;
2616 } else {
2617 color = 0xff000000;
2618 alpha = DEFAULT_DIVIDER_ALPHA;
2619 }
2620 if (v.getBackground() instanceof ColorDrawable) {
2621 ColorDrawable background = (ColorDrawable) v.getBackground();
2622 background.mutate();
2623 background.setColor(color);
2624 background.setAlpha(alpha);
2625 }
2626 }
2627
Selim Cinek1685e632014-04-08 02:27:49 +02002628 public int getMaxExpandHeight() {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002629 return mPrivateLayout.getExpandHeight();
2630 }
2631
2632
2633 private int getHeadsUpHeight() {
Selim Cinekc7e4cb52019-06-20 15:41:45 -07002634 return getShowingLayout().getHeadsUpHeight(false /* forceNoHeader */);
Chris Wren51c75102013-07-16 20:49:17 -04002635 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02002636
Mady Mellor34958fa2016-02-23 09:52:17 -08002637 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002638 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08002639 }
2640
Jorim Jaggibe565df2014-04-28 17:51:23 +02002641 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002642 public boolean isContentExpandable() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002643 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002644 return true;
2645 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002646 NotificationContentView showingLayout = getShowingLayout();
2647 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002648 }
2649
2650 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07002651 protected View getContentView() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002652 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cineka5703182016-05-11 21:23:16 -04002653 return mChildrenContainer;
2654 }
Selim Cinek560e64d2015-06-09 19:58:11 -07002655 return getShowingLayout();
2656 }
2657
2658 @Override
Gus Prevas211181532018-12-13 14:49:33 -05002659 public long performRemoveAnimation(long duration, long delay, float translationDirection,
2660 boolean isHeadsUpAnimation, float endLocation, Runnable onFinishedRunnable,
2661 AnimatorListenerAdapter animationListener) {
Evan Lairde55c6012019-03-13 12:54:37 -04002662 if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Gus Prevas211181532018-12-13 14:49:33 -05002663 Animator anim = getTranslateViewAnimator(0f, null /* listener */);
2664 if (anim != null) {
2665 anim.addListener(new AnimatorListenerAdapter() {
2666 @Override
2667 public void onAnimationEnd(Animator animation) {
2668 ExpandableNotificationRow.super.performRemoveAnimation(
2669 duration, delay, translationDirection, isHeadsUpAnimation,
2670 endLocation, onFinishedRunnable, animationListener);
2671 }
2672 });
2673 anim.start();
2674 return anim.getDuration();
2675 }
2676 }
2677 return super.performRemoveAnimation(duration, delay, translationDirection,
2678 isHeadsUpAnimation, endLocation, onFinishedRunnable, animationListener);
2679 }
2680
2681 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07002682 protected void onAppearAnimationFinished(boolean wasAppearing) {
2683 super.onAppearAnimationFinished(wasAppearing);
2684 if (wasAppearing) {
2685 // During the animation the visible view might have changed, so let's make sure all
2686 // alphas are reset
2687 if (mChildrenContainer != null) {
2688 mChildrenContainer.setAlpha(1.0f);
2689 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
2690 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08002691 for (NotificationContentView l : mLayouts) {
2692 l.setAlpha(1.0f);
2693 l.setLayerType(LAYER_TYPE_NONE, null);
2694 }
Selim Cineke3c6e462019-06-24 19:37:06 -07002695 } else {
2696 setHeadsUpAnimatingAway(false);
Selim Cinekaa3901a2016-08-05 11:04:37 -07002697 }
2698 }
2699
2700 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07002701 public int getExtraBottomPadding() {
2702 if (mIsSummaryWithChildren && isGroupExpanded()) {
2703 return mIncreasedPaddingBetweenElements;
2704 }
2705 return 0;
2706 }
2707
2708 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02002709 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinek4ca6c632017-02-23 18:03:37 -08002710 boolean changed = height != getActualHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +01002711 super.setActualHeight(height, notifyListeners);
Selim Cinek4ca6c632017-02-23 18:03:37 -08002712 if (changed && isRemoved()) {
2713 // TODO: remove this once we found the gfx bug for this.
2714 // This is a hack since a removed view sometimes would just stay blank. it occured
2715 // when sending yourself a message and then clicking on it.
2716 ViewGroup parent = (ViewGroup) getParent();
2717 if (parent != null) {
2718 parent.invalidate();
2719 }
2720 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002721 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08002722 mGuts.setActualHeight(height);
2723 return;
2724 }
Selim Cinekeef84282015-10-30 16:28:00 -07002725 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002726 for (NotificationContentView l : mLayouts) {
2727 l.setContentHeight(contentHeight);
2728 }
Selim Cinek42357e02016-02-24 18:48:01 -08002729 if (mIsSummaryWithChildren) {
2730 mChildrenContainer.setActualHeight(height);
2731 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002732 if (mGuts != null) {
2733 mGuts.setActualHeight(height);
2734 }
Evan Lairde55c6012019-03-13 12:54:37 -04002735 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Aaron Heuckroth266cb342018-09-07 14:52:04 -04002736 mMenuRow.onParentHeightUpdate();
Mady Mellor54540972017-06-07 11:55:36 -07002737 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002738 }
2739
2740 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01002741 public int getMaxContentHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002742 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08002743 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002744 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002745 NotificationContentView showingLayout = getShowingLayout();
2746 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02002747 }
2748
2749 @Override
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002750 public int getMinHeight(boolean ignoreTemporaryStates) {
2751 if (!ignoreTemporaryStates && mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07002752 return mGuts.getIntrinsicHeight();
Selim Cinekc3fec682019-06-06 18:11:07 -07002753 } else if (!ignoreTemporaryStates && canShowHeadsUp() && mIsHeadsUp
Selim Cinekeb3fc3d2017-09-15 13:37:14 -07002754 && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08002755 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
Selim Cinek0b9cf462017-12-07 16:31:03 -08002756 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !shouldShowPublic()) {
Selim Cinekb55386d2015-12-16 17:26:49 -08002757 return mChildrenContainer.getMinHeight();
Selim Cinekc3fec682019-06-06 18:11:07 -07002758 } else if (!ignoreTemporaryStates && canShowHeadsUp() && mIsHeadsUp) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -08002759 return getHeadsUpHeight();
Selim Cinekb55386d2015-12-16 17:26:49 -08002760 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002761 NotificationContentView showingLayout = getShowingLayout();
2762 return showingLayout.getMinHeight();
2763 }
2764
2765 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07002766 public int getCollapsedHeight() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002767 if (mIsSummaryWithChildren && !shouldShowPublic()) {
Selim Cinek567e8452016-03-24 10:54:56 -07002768 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07002769 }
Selim Cinek816c8e42015-11-19 12:00:45 -08002770 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02002771 }
2772
2773 @Override
Selim Cinekc7e4cb52019-06-20 15:41:45 -07002774 public int getHeadsUpHeightWithoutHeader() {
2775 if (!canShowHeadsUp() || !mIsHeadsUp) {
2776 return getCollapsedHeight();
2777 }
2778 if (mIsSummaryWithChildren && !shouldShowPublic()) {
2779 return mChildrenContainer.getCollapsedHeightWithoutHeader();
2780 }
2781 return getShowingLayout().getHeadsUpHeight(true /* forceNoHeader */);
2782 }
2783
2784 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02002785 public void setClipTopAmount(int clipTopAmount) {
2786 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002787 for (NotificationContentView l : mLayouts) {
2788 l.setClipTopAmount(clipTopAmount);
2789 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02002790 if (mGuts != null) {
2791 mGuts.setClipTopAmount(clipTopAmount);
2792 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02002793 }
2794
Selim Cineka686b2c2016-10-26 13:58:27 -07002795 @Override
2796 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek2627d722018-01-19 12:16:49 -08002797 if (mExpandAnimationRunning) {
2798 return;
2799 }
Selim Cinek65d418e2016-11-29 15:42:34 -08002800 if (clipBottomAmount != mClipBottomAmount) {
2801 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002802 for (NotificationContentView l : mLayouts) {
2803 l.setClipBottomAmount(clipBottomAmount);
2804 }
Selim Cinek65d418e2016-11-29 15:42:34 -08002805 if (mGuts != null) {
2806 mGuts.setClipBottomAmount(clipBottomAmount);
2807 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002808 }
Selim Cinekc25989e2018-02-16 16:42:14 -08002809 if (mChildrenContainer != null && !mChildIsExpanding) {
Selim Cinek65d418e2016-11-29 15:42:34 -08002810 // We have to update this even if it hasn't changed, since the children locations can
2811 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08002812 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
2813 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002814 }
2815
Selim Cinek42357e02016-02-24 18:48:01 -08002816 public NotificationContentView getShowingLayout() {
Selim Cinek0b9cf462017-12-07 16:31:03 -08002817 return shouldShowPublic() ? mPublicLayout : mPrivateLayout;
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002818 }
Chris Wren78403d72014-07-28 10:23:24 +01002819
Kevind4660b22018-09-27 10:57:35 -07002820 public View getExpandedContentView() {
2821 return getPrivateLayout().getExpandedChild();
2822 }
2823
Selim Cinek1a48bab2017-02-17 19:38:40 -08002824 public void setLegacy(boolean legacy) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08002825 for (NotificationContentView l : mLayouts) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08002826 l.setLegacy(legacy);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002827 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07002828 }
2829
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002830 @Override
2831 protected void updateBackgroundTint() {
2832 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07002833 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002834 if (mIsSummaryWithChildren) {
2835 List<ExpandableNotificationRow> notificationChildren =
2836 mChildrenContainer.getNotificationChildren();
2837 for (int i = 0; i < notificationChildren.size(); i++) {
2838 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07002839 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002840 }
2841 }
2842 }
2843
Mady Mellorb0a82462016-04-30 17:31:02 -07002844 /**
2845 * Called when a group has finished animating from collapsed or expanded state.
2846 */
2847 public void onFinishedExpansionChange() {
2848 mGroupExpansionChanging = false;
2849 updateBackgroundForGroupState();
2850 }
2851
2852 /**
2853 * Updates the parent and children backgrounds in a group based on the expansion state.
2854 */
2855 public void updateBackgroundForGroupState() {
2856 if (mIsSummaryWithChildren) {
2857 // Only when the group has finished expanding do we hide its background.
Anthony Chen6bf88a02017-04-10 14:41:44 -07002858 mShowNoBackground = !mShowGroupBackgroundWhenExpanded && isGroupExpanded()
2859 && !isGroupExpansionChanging() && !isUserLocked();
Mady Mellorb0a82462016-04-30 17:31:02 -07002860 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
2861 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
2862 for (int i = 0; i < children.size(); i++) {
2863 children.get(i).updateBackgroundForGroupState();
2864 }
2865 } else if (isChildInGroup()) {
2866 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
2867 // Only show a background if the group is expanded OR if it is expanding / collapsing
Anthony Chen6bf88a02017-04-10 14:41:44 -07002868 // and has a custom background color.
Mady Mellorb0a82462016-04-30 17:31:02 -07002869 final boolean showBackground = isGroupExpanded()
2870 || ((mNotificationParent.isGroupExpansionChanging()
Anthony Chen6bf88a02017-04-10 14:41:44 -07002871 || mNotificationParent.isUserLocked()) && childColor != 0);
Mady Mellorb0a82462016-04-30 17:31:02 -07002872 mShowNoBackground = !showBackground;
2873 } else {
2874 // Only children or parents ever need no background.
2875 mShowNoBackground = false;
2876 }
2877 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002878 updateBackground();
2879 }
2880
Adrian Roos4a579672016-05-24 16:54:37 -07002881 public int getPositionOfChild(ExpandableNotificationRow childRow) {
2882 if (mIsSummaryWithChildren) {
2883 return mChildrenContainer.getPositionInLinearLayout(childRow);
2884 }
2885 return 0;
2886 }
2887
Chris Wren78403d72014-07-28 10:23:24 +01002888 public void setExpansionLogger(ExpansionLogger logger, String key) {
2889 mLogger = logger;
2890 mLoggingKey = key;
2891 }
2892
Chris Wren6abeeb92016-05-26 14:44:38 -04002893 public void onExpandedByGesture(boolean userExpanded) {
2894 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
2895 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
2896 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
2897 }
2898 MetricsLogger.action(mContext, event, userExpanded);
2899 }
2900
Selim Cinek6183d122016-01-14 18:48:41 -08002901 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08002902 public float getIncreasedPaddingAmount() {
2903 if (mIsSummaryWithChildren) {
2904 if (isGroupExpanded()) {
2905 return 1.0f;
2906 } else if (isUserLocked()) {
Selim Cinek414ad332017-02-24 19:06:12 -08002907 return mChildrenContainer.getIncreasedPaddingAmount();
Selim Cinek42357e02016-02-24 18:48:01 -08002908 }
Selim Cinek99104832017-01-25 14:47:33 -08002909 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08002910 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08002911 }
2912 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08002913 }
2914
Selim Cineka7ed2c12017-01-23 20:47:24 -08002915 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08002916 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08002917 }
2918
Selim Cinek61633a82016-01-25 15:54:10 -08002919 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08002920 protected boolean disallowSingleClick(MotionEvent event) {
dongwan0605.kimc4ddef42018-05-06 17:40:23 +09002921 if (areGutsExposed()) {
2922 return false;
2923 }
Selim Cinek6183d122016-01-14 18:48:41 -08002924 float x = event.getX();
2925 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08002926 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002927 if (header != null && header.isInTouchRect(x - getTranslation(), y)) {
2928 return true;
2929 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002930 if ((!mIsSummaryWithChildren || shouldShowPublic())
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002931 && getShowingLayout().disallowSingleClick(x, y)) {
2932 return true;
Selim Cinek6183d122016-01-14 18:48:41 -08002933 }
2934 return super.disallowSingleClick(event);
2935 }
2936
Selim Cinek414ad332017-02-24 19:06:12 -08002937 private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04002938 boolean nowExpanded = isExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08002939 if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
Chris Wren698b1702016-05-23 11:16:32 -04002940 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
2941 }
Selim Cinek414ad332017-02-24 19:06:12 -08002942 if (nowExpanded != wasExpanded) {
2943 updateShelfIconColor();
2944 if (mLogger != null) {
2945 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded);
2946 }
2947 if (mIsSummaryWithChildren) {
2948 mChildrenContainer.onExpansionChanged();
2949 }
Chris Wren78403d72014-07-28 10:23:24 +01002950 }
2951 }
Selim Cinek570981d2015-12-01 11:37:01 -08002952
Selim Cineke9bad242016-06-15 11:46:37 -07002953 @Override
2954 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2955 super.onInitializeAccessibilityNodeInfoInternal(info);
Geoffrey Pitsch409db272017-08-28 14:51:52 +00002956 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
Selim Cineke9bad242016-06-15 11:46:37 -07002957 if (canViewBeDismissed()) {
2958 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
2959 }
Selim Cinek0b9cf462017-12-07 16:31:03 -08002960 boolean expandable = shouldShowPublic();
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002961 boolean isExpanded = false;
2962 if (!expandable) {
2963 if (mIsSummaryWithChildren) {
2964 expandable = true;
2965 if (!mIsLowPriority || isExpanded()) {
2966 isExpanded = isGroupExpanded();
2967 }
2968 } else {
2969 expandable = mPrivateLayout.isContentExpandable();
2970 isExpanded = isExpanded();
2971 }
2972 }
2973 if (expandable) {
2974 if (isExpanded) {
2975 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
2976 } else {
2977 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
2978 }
2979 }
Mady Mellorb3a6aed2018-05-11 13:24:07 -07002980 NotificationMenuRowPlugin provider = getProvider();
2981 if (provider != null) {
2982 MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
2983 if (snoozeMenu != null) {
2984 AccessibilityAction action = new AccessibilityAction(R.id.action_snooze,
2985 getContext().getResources()
2986 .getString(R.string.notification_menu_snooze_action));
2987 info.addAction(action);
2988 }
2989 }
Selim Cineke9bad242016-06-15 11:46:37 -07002990 }
2991
2992 @Override
2993 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
2994 if (super.performAccessibilityActionInternal(action, arguments)) {
2995 return true;
2996 }
2997 switch (action) {
2998 case AccessibilityNodeInfo.ACTION_DISMISS:
Rohan Shah524cf7b2018-03-15 14:40:02 -07002999 performDismissWithBlockingHelper(true /* fromAccessibility */);
Selim Cineke9bad242016-06-15 11:46:37 -07003000 return true;
Selim Cinekc0ac4af2017-03-03 15:13:48 -08003001 case AccessibilityNodeInfo.ACTION_COLLAPSE:
3002 case AccessibilityNodeInfo.ACTION_EXPAND:
3003 mExpandClickListener.onClick(this);
3004 return true;
Geoffrey Pitsch409db272017-08-28 14:51:52 +00003005 case AccessibilityNodeInfo.ACTION_LONG_CLICK:
3006 doLongClickCallback();
3007 return true;
Jason Monk05dd5672018-08-09 09:38:21 -04003008 default:
3009 if (action == R.id.action_snooze) {
3010 NotificationMenuRowPlugin provider = getProvider();
Evan Lairde55c6012019-03-13 12:54:37 -04003011 if (provider == null && mMenuRow != null) {
Jason Monk05dd5672018-08-09 09:38:21 -04003012 provider = createMenu();
Evan Lairde55c6012019-03-13 12:54:37 -04003013 } else {
3014 return false;
Jason Monk05dd5672018-08-09 09:38:21 -04003015 }
3016 MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
3017 if (snoozeMenu != null) {
3018 doLongClickCallback(getWidth() / 2, getHeight() / 2, snoozeMenu);
3019 }
3020 return true;
Mady Mellorb3a6aed2018-05-11 13:24:07 -07003021 }
Selim Cineke9bad242016-06-15 11:46:37 -07003022 }
3023 return false;
3024 }
3025
3026 public boolean shouldRefocusOnDismiss() {
3027 return mRefocusOnDismiss || isAccessibilityFocused();
3028 }
3029
Selim Cinek570981d2015-12-01 11:37:01 -08003030 public interface OnExpandClickListener {
Ned Burnsf81c4c42019-01-07 14:10:43 -05003031 void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08003032 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08003033
3034 @Override
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003035 public ExpandableViewState createExpandableViewState() {
3036 return new NotificationViewState();
Selim Cinekf93bf3e2018-05-08 14:43:21 -07003037 }
3038
Selim Cinekd127d792016-11-01 19:11:41 -07003039 @Override
3040 public boolean isAboveShelf() {
Selim Cinekc3fec682019-06-06 18:11:07 -07003041 return (canShowHeadsUp()
Selim Cinek2627d722018-01-19 12:16:49 -08003042 && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf)
Selim Cinek5040f2e2019-02-14 18:22:42 -08003043 || mExpandAnimationRunning || mChildIsExpanding));
Selim Cinekd127d792016-11-01 19:11:41 -07003044 }
3045
Selim Cinek0fe07392017-11-09 13:26:34 -08003046 @Override
Tony Huangc092c432018-05-18 17:38:54 +08003047 public boolean topAmountNeedsClipping() {
3048 if (isGroupExpanded()) {
3049 return true;
3050 }
3051 if (isGroupExpansionChanging()) {
3052 return true;
3053 }
3054 if (getShowingLayout().shouldClipToRounding(true /* topRounded */,
3055 false /* bottomRounded */)) {
3056 return true;
3057 }
3058 if (mGuts != null && mGuts.getAlpha() != 0.0f) {
3059 return true;
3060 }
3061 return false;
3062 }
3063
3064 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08003065 protected boolean childNeedsClipping(View child) {
3066 if (child instanceof NotificationContentView) {
3067 NotificationContentView contentView = (NotificationContentView) child;
3068 if (isClippingNeeded()) {
3069 return true;
Selim Cinek86bfcee2018-01-17 11:00:47 -08003070 } else if (!hasNoRounding()
3071 && contentView.shouldClipToRounding(getCurrentTopRoundness() != 0.0f,
3072 getCurrentBottomRoundness() != 0.0f)) {
Selim Cinek515b2032017-11-15 10:20:19 -08003073 return true;
3074 }
3075 } else if (child == mChildrenContainer) {
Selim Cinek6487ebf2018-11-28 18:57:40 -08003076 if (isClippingNeeded() || !hasNoRounding()) {
Selim Cinek515b2032017-11-15 10:20:19 -08003077 return true;
3078 }
3079 } else if (child instanceof NotificationGuts) {
Selim Cinekb95fd182017-12-21 13:03:32 -08003080 return !hasNoRounding();
Selim Cinek515b2032017-11-15 10:20:19 -08003081 }
3082 return super.childNeedsClipping(child);
3083 }
3084
3085 @Override
Selim Cinek2871bef2017-11-22 08:40:00 -08003086 protected void applyRoundness() {
3087 super.applyRoundness();
3088 applyChildrenRoundness();
3089 }
3090
3091 private void applyChildrenRoundness() {
3092 if (mIsSummaryWithChildren) {
3093 mChildrenContainer.setCurrentBottomRoundness(getCurrentBottomRoundness());
3094 }
3095 }
3096
3097 @Override
Selim Cinek515b2032017-11-15 10:20:19 -08003098 public Path getCustomClipPath(View child) {
3099 if (child instanceof NotificationGuts) {
Selim Cinekdefd46f2018-05-30 11:47:08 -07003100 return getClipPath(true /* ignoreTranslation */);
Selim Cinek515b2032017-11-15 10:20:19 -08003101 }
3102 return super.getCustomClipPath(child);
3103 }
3104
Selim Cinekb95fd182017-12-21 13:03:32 -08003105 private boolean hasNoRounding() {
3106 return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f;
Selim Cinek0fe07392017-11-09 13:26:34 -08003107 }
3108
Evan Laird94492852018-10-25 13:43:01 -04003109 //TODO: this logic can't depend on layout if we are recycling!
3110 public boolean isMediaRow() {
3111 return getExpandedContentView() != null
3112 && getExpandedContentView().findViewById(
3113 com.android.internal.R.id.media_actions) != null;
3114 }
3115
3116 public boolean isTopLevelChild() {
3117 return getParent() instanceof NotificationStackScrollLayout;
3118 }
3119
3120 public boolean isGroupNotFullyVisible() {
3121 return getClipTopAmount() > 0 || getTranslationY() < 0;
3122 }
3123
Selim Cinekd127d792016-11-01 19:11:41 -07003124 public void setAboveShelf(boolean aboveShelf) {
Selim Cinek5cf1d052017-06-01 17:36:46 -07003125 boolean wasAboveShelf = isAboveShelf();
Selim Cinekd127d792016-11-01 19:11:41 -07003126 mAboveShelf = aboveShelf;
Selim Cinek5cf1d052017-06-01 17:36:46 -07003127 if (isAboveShelf() != wasAboveShelf) {
3128 mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
3129 }
Selim Cinekd127d792016-11-01 19:11:41 -07003130 }
3131
Gus Prevasa18dc572019-01-14 16:11:22 -05003132 /** Sets whether dismiss gestures are right-to-left (instead of left-to-right). */
3133 public void setDismissRtl(boolean dismissRtl) {
Evan Lairde55c6012019-03-13 12:54:37 -04003134 if (mMenuRow != null) {
3135 mMenuRow.setDismissRtl(dismissRtl);
3136 }
Gus Prevasa18dc572019-01-14 16:11:22 -05003137 }
3138
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003139 private static class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08003140
3141 @Override
3142 public void applyToView(View view) {
Selim Cinekbbcebde2016-11-09 18:28:20 -08003143 if (view instanceof ExpandableNotificationRow) {
3144 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinek2627d722018-01-19 12:16:49 -08003145 if (row.isExpandAnimationRunning()) {
3146 return;
3147 }
Selim Cinekc25989e2018-02-16 16:42:14 -08003148 handleFixedTranslationZ(row);
Selim Cinek2627d722018-01-19 12:16:49 -08003149 super.applyToView(view);
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003150 row.applyChildrenState();
Selim Cinekbbcebde2016-11-09 18:28:20 -08003151 }
3152 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08003153
Selim Cinekc25989e2018-02-16 16:42:14 -08003154 private void handleFixedTranslationZ(ExpandableNotificationRow row) {
3155 if (row.hasExpandingChild()) {
3156 zTranslation = row.getTranslationZ();
3157 clipTopAmount = row.getClipTopAmount();
3158 }
3159 }
3160
Selim Cinek0cfbef42016-11-09 19:06:36 -08003161 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08003162 protected void onYTranslationAnimationFinished(View view) {
3163 super.onYTranslationAnimationFinished(view);
Selim Cinekd4776a52017-02-14 18:50:16 -08003164 if (view instanceof ExpandableNotificationRow) {
3165 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
3166 if (row.isHeadsUpAnimatingAway()) {
3167 row.setHeadsUpAnimatingAway(false);
3168 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08003169 }
3170 }
3171
3172 @Override
3173 public void animateTo(View child, AnimationProperties properties) {
Selim Cinek0cfbef42016-11-09 19:06:36 -08003174 if (child instanceof ExpandableNotificationRow) {
3175 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
Selim Cinek2627d722018-01-19 12:16:49 -08003176 if (row.isExpandAnimationRunning()) {
3177 return;
3178 }
Selim Cinekc25989e2018-02-16 16:42:14 -08003179 handleFixedTranslationZ(row);
Selim Cinek2627d722018-01-19 12:16:49 -08003180 super.animateTo(child, properties);
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003181 row.startChildAnimation(properties);
Selim Cinek0cfbef42016-11-09 19:06:36 -08003182 }
3183 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08003184 }
Selim Cinek817abe72017-05-24 11:08:55 -07003185
Gustav Sennton8a52dc32019-04-15 12:48:23 +01003186 /**
3187 * Returns the Smart Suggestions backing the smart suggestion buttons in the notification.
3188 */
3189 public SmartRepliesAndActions getExistingSmartRepliesAndActions() {
3190 return mPrivateLayout.getCurrentSmartRepliesAndActions();
3191 }
3192
Selim Cinek817abe72017-05-24 11:08:55 -07003193 @VisibleForTesting
3194 protected void setChildrenContainer(NotificationChildrenContainer childrenContainer) {
3195 mChildrenContainer = childrenContainer;
3196 }
Geoffrey Pitsch409db272017-08-28 14:51:52 +00003197
Julia Reynoldsfc640012018-02-21 12:25:27 -05003198 @VisibleForTesting
3199 protected void setPrivateLayout(NotificationContentView privateLayout) {
3200 mPrivateLayout = privateLayout;
3201 }
3202
3203 @VisibleForTesting
3204 protected void setPublicLayout(NotificationContentView publicLayout) {
3205 mPublicLayout = publicLayout;
3206 }
3207
Geoffrey Pitsch409db272017-08-28 14:51:52 +00003208 /**
3209 * Equivalent to View.OnLongClickListener with coordinates
3210 */
3211 public interface LongPressListener {
3212 /**
3213 * Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
3214 * @return whether the longpress was handled
3215 */
3216 boolean onLongPress(View v, int x, int y, MenuItem item);
3217 }
Julia Reynoldsb5867452018-02-28 16:31:35 -05003218
3219 /**
3220 * Equivalent to View.OnClickListener with coordinates
3221 */
3222 public interface OnAppOpsClickListener {
3223 /**
3224 * Equivalent to {@link View.OnClickListener#onClick(View)} with coordinates
3225 * @return whether the click was handled
3226 */
3227 boolean onClick(View v, int x, int y, MenuItem item);
3228 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07003229
Selim Cinek30887662018-10-15 17:37:21 -07003230 @Override
3231 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3232 super.dump(fd, pw, args);
3233 pw.println(" Notification: " + getStatusBarNotification().getKey());
3234 pw.print(" visibility: " + getVisibility());
3235 pw.print(", alpha: " + getAlpha());
3236 pw.print(", translation: " + getTranslation());
3237 pw.print(", removed: " + isRemoved());
Selim Cinek0db74592018-12-05 17:42:51 -08003238 pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
Selim Cinek85a8f9f2018-11-21 13:58:27 -08003239 NotificationContentView showingLayout = getShowingLayout();
3240 pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
Selim Cinek30887662018-10-15 17:37:21 -07003241 pw.println();
Selim Cinek85a8f9f2018-11-21 13:58:27 -08003242 showingLayout.dump(fd, pw, args);
Selim Cinek30887662018-10-15 17:37:21 -07003243 pw.print(" ");
Dave Mankoffa4d195d2018-11-16 13:33:27 -05003244 if (getViewState() != null) {
3245 getViewState().dump(fd, pw, args);
Selim Cinek30887662018-10-15 17:37:21 -07003246 } else {
3247 pw.print("no viewState!!!");
3248 }
3249 pw.println();
3250 pw.println();
3251 if (mIsSummaryWithChildren) {
Selim Cinek0db74592018-12-05 17:42:51 -08003252 pw.print(" ChildrenContainer");
3253 pw.print(" visibility: " + mChildrenContainer.getVisibility());
3254 pw.print(", alpha: " + mChildrenContainer.getAlpha());
3255 pw.print(", translationY: " + mChildrenContainer.getTranslationY());
3256 pw.println();
Selim Cinek30887662018-10-15 17:37:21 -07003257 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
3258 pw.println(" Children: " + notificationChildren.size());
3259 pw.println(" {");
3260 for(ExpandableNotificationRow child : notificationChildren) {
3261 child.dump(fd, pw, args);
3262 }
3263 pw.println(" }");
3264 pw.println();
3265 }
3266 }
3267
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07003268 /**
3269 * Background task for executing IPCs to check if the notification is a system notification. The
3270 * output is used for both the blocking helper and the notification info.
3271 */
3272 private class SystemNotificationAsyncTask extends AsyncTask<Void, Void, Boolean> {
3273
3274 @Override
3275 protected Boolean doInBackground(Void... voids) {
3276 return isSystemNotification(mContext, mStatusBarNotification);
3277 }
3278
3279 @Override
3280 protected void onPostExecute(Boolean result) {
Julia Reynoldsaa96cf32018-04-17 09:09:04 -04003281 if (mEntry != null) {
3282 mEntry.mIsSystemNotification = result;
3283 }
Rohan Shah4ed1b2a2018-03-30 13:26:01 -07003284 }
3285 }
Chris Wren51c75102013-07-16 20:49:17 -04003286}