blob: 713f91b12e3b73d480ce58ce9145b1abc5e04114 [file] [log] [blame]
Chris Wren51c75102013-07-16 20:49:17 -04001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar;
18
Selim Cinek5ba22542017-04-20 15:16:10 -070019import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;
Selim Cinekc478f902017-02-22 20:55:44 -080020
Mady Mellor4b80b102016-01-22 08:03:58 -080021import android.animation.Animator;
22import android.animation.AnimatorListenerAdapter;
Mady Mellor4b80b102016-01-22 08:03:58 -080023import android.animation.ObjectAnimator;
Mady Mellor4b80b102016-01-22 08:03:58 -080024import android.animation.ValueAnimator.AnimatorUpdateListener;
Selim Cinekddf1b392016-05-27 16:33:10 -070025import android.annotation.Nullable;
Chris Wren51c75102013-07-16 20:49:17 -040026import android.content.Context;
Anthony Chen7acbb772017-04-07 16:45:25 -070027import android.content.res.Resources;
Mady Mellor9d03a522017-04-04 18:45:30 -070028import android.content.res.Configuration;
Selim Cinekcab4a602014-09-03 14:47:57 +020029import android.graphics.drawable.AnimatedVectorDrawable;
30import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010031import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020032import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080033import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070034import android.os.Bundle;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020035import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040036import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070037import android.util.FloatProperty;
38import android.util.Property;
Selim Cinek01af3342016-02-09 19:25:31 -080039import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080040import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080041import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050042import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080043import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020044import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020045import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070046import android.view.accessibility.AccessibilityNodeInfo;
Selim Cinek98713a42015-09-21 15:47:20 +020047import android.widget.Chronometer;
Mady Mellor95d743c2017-01-10 12:05:27 -080048import android.widget.FrameLayout;
Selim Cinekcab4a602014-09-03 14:47:57 +020049import android.widget.ImageView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080050import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010051
Selim Cinek5ba22542017-04-20 15:16:10 -070052import com.android.internal.annotations.VisibleForTesting;
Chris Wren698b1702016-05-23 11:16:32 -040053import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010054import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070055import com.android.internal.util.NotificationColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080056import com.android.internal.widget.CachingIconView;
Mady Mellor95d743c2017-01-10 12:05:27 -080057import com.android.systemui.Dependency;
Selim Cinek0242fbb2016-10-19 13:38:32 -070058import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050059import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070060import com.android.systemui.classifier.FalsingManager;
Mady Mellor95d743c2017-01-10 12:05:27 -080061import com.android.systemui.plugins.PluginListener;
62import com.android.systemui.plugins.PluginManager;
63import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
64import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
65import com.android.systemui.statusbar.NotificationGuts.GutsContent;
Selim Cinekc897bd32016-03-18 17:32:31 -070066import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080067import com.android.systemui.statusbar.notification.NotificationInflater;
Selim Cinek6743c0b2017-01-18 18:24:01 -080068import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cineka7d4f822016-12-06 14:34:47 -080069import com.android.systemui.statusbar.notification.VisualStabilityManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010070import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050071import com.android.systemui.statusbar.phone.StatusBar;
Selim Cinek31aada42015-12-18 17:51:15 -080072import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek0cfbef42016-11-09 19:06:36 -080073import com.android.systemui.statusbar.stack.AnimationProperties;
74import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010075import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070076import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010077import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010078
Mady Mellor4b80b102016-01-22 08:03:58 -080079import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010080import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050081
Mady Mellor95d743c2017-01-10 12:05:27 -080082public class ExpandableNotificationRow extends ActivatableNotificationView
83 implements PluginListener<NotificationMenuRowPlugin> {
Selim Cinekb5605e52015-02-20 18:21:41 +010084
85 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
86 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Mady Mellor95d743c2017-01-10 12:05:27 -080087 private static final int MENU_VIEW_INDEX = 0;
88
Mady Mellor035badd2017-04-04 18:45:30 -070089 public interface LayoutListener {
90 public void onLayout();
91 }
92
93 private LayoutListener mLayoutListener;
Selim Cinek55a3e732017-05-25 18:30:10 -070094 private boolean mLowPriorityStateUpdated;
Selim Cinek1a48bab2017-02-17 19:38:40 -080095 private final NotificationInflater mNotificationInflater;
Selim Cinek0242fbb2016-10-19 13:38:32 -070096 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -080097 private int mIconTransformContentShiftNoIcon;
Selim Cinek01af3342016-02-09 19:25:31 -080098 private int mNotificationMinHeightLegacy;
99 private int mMaxHeadsUpHeightLegacy;
100 private int mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800101 private int mMaxHeadsUpHeightIncreased;
Selim Cinek01af3342016-02-09 19:25:31 -0800102 private int mNotificationMinHeight;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800103 private int mNotificationMinHeightLarge;
Selim Cinek01af3342016-02-09 19:25:31 -0800104 private int mNotificationMaxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800105 private int mNotificationAmbientHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -0700106 private int mIncreasedPaddingBetweenElements;
Chris Wren51c75102013-07-16 20:49:17 -0400107
Selim Cinek1685e632014-04-08 02:27:49 +0200108 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -0400109 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +0200110 /** Has the user actively changed the expansion state of this row */
111 private boolean mHasUserChangedExpansion;
112 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -0400113 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -0800114
115 /**
116 * Has this notification been expanded while it was pinned
117 */
118 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +0200119 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -0400120 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +0200121 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -0500122 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +0200123 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -0800124 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +0200125 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700126 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400127
Selim Cinek1685e632014-04-08 02:27:49 +0200128 /**
129 * Is this notification expanded by the system. The expansion state can be overridden by the
130 * user expansion.
131 */
132 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200133
134 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700135 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200136 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700137 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200138
Mady Mellorb0a82462016-04-30 17:31:02 -0700139 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800140 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200141 private NotificationContentView mPublicLayout;
142 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800143 private NotificationContentView[] mLayouts;
Selim Cinek1685e632014-04-08 02:27:49 +0200144 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700145 private int mHeadsUpHeight;
Selim Cinek4bb59342016-04-08 19:29:35 -0700146 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100147 private ExpansionLogger mLogger;
148 private String mLoggingKey;
Selim Cinek8d490d42015-04-10 00:05:50 -0700149 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800150 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200151 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700152 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100153 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200154 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100155 private ViewStub mChildrenContainerStub;
156 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100157 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700158 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100159 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor95d743c2017-01-10 12:05:27 -0800160 private NotificationMenuRowPlugin mMenuRow;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100161 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100162 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700163 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700164 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800165 private HeadsUpManager mHeadsUpManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200166
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700167 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800168 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700169 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700170 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800171 private OnExpandClickListener mOnExpandClickListener;
Mady Mellorb0a82462016-04-30 17:31:02 -0700172 private boolean mGroupExpansionChanging;
173
Anthony Chen6bf88a02017-04-10 14:41:44 -0700174 /**
175 * Whether or not a notification that is not part of a group of notifications can be manually
176 * expanded by the user.
177 */
178 private boolean mEnableNonGroupedNotificationExpand;
179
180 /**
181 * Whether or not to update the background of the header of the notification when its expanded.
182 * If {@code true}, the header background will disappear when expanded.
183 */
184 private boolean mShowGroupBackgroundWhenExpanded;
185
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800186 private OnClickListener mExpandClickListener = new OnClickListener() {
187 @Override
188 public void onClick(View v) {
Selim Cinek414ad332017-02-24 19:06:12 -0800189 if (!mShowingPublic && (!mIsLowPriority || isExpanded())
190 && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700191 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400192 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
193 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
194 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400195 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
196 nowExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -0800197 onExpansionChanged(true /* userAction */, wasExpanded);
Anthony Chen6bf88a02017-04-10 14:41:44 -0700198 } else if (mEnableNonGroupedNotificationExpand) {
Selim Cineke9bad242016-06-15 11:46:37 -0700199 if (v.isAccessibilityFocused()) {
200 mPrivateLayout.setFocusOnVisibilityChange();
201 }
Selim Cinek31aada42015-12-18 17:51:15 -0800202 boolean nowExpanded;
203 if (isPinned()) {
204 nowExpanded = !mExpandedWhenPinned;
205 mExpandedWhenPinned = nowExpanded;
206 } else {
207 nowExpanded = !isExpanded();
208 setUserExpanded(nowExpanded);
209 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800210 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800211 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400212 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
213 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800214 }
215 }
216 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700217 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700218 private boolean mDismissed;
219 private boolean mKeepInParent;
220 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700221 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
222 new FloatProperty<ExpandableNotificationRow>("translate") {
223 @Override
224 public void setValue(ExpandableNotificationRow object, float value) {
225 object.setTranslation(value);
226 }
227
228 @Override
229 public Float get(ExpandableNotificationRow object) {
230 return object.getTranslation();
231 }
232 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700233 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700234 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700235 private View mChildAfterViewWhenDismissed;
236 private View mGroupParentWhenDismissed;
237 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800238 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700239 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700240 private boolean mAboveShelf;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800241 private boolean mShowAmbient;
Selim Cinek875a3a12016-11-18 17:52:16 -0800242 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800243 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800244 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800245 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800246 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800247 private boolean mUseIncreasedHeadsUpHeight;
Selim Cinekef8c2252017-02-10 14:52:18 -0800248 private float mTranslationWhenRemoved;
249 private boolean mWasChildInGroupWhenRemoved;
Adrian Roos6f6e1592017-05-02 16:22:53 -0700250 private int mNotificationColorAmbient;
Mady Mellorb0a82462016-04-30 17:31:02 -0700251
Mady Mellor43c2cd12016-12-12 21:05:13 -0800252 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700253 public boolean isGroupExpansionChanging() {
254 if (isChildInGroup()) {
255 return mNotificationParent.isGroupExpansionChanging();
256 }
257 return mGroupExpansionChanging;
258 }
259
260 public void setGroupExpansionChanging(boolean changing) {
261 mGroupExpansionChanging = changing;
262 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700263
Adrian Roos599be342016-06-13 14:54:39 -0700264 @Override
265 public void setActualHeightAnimating(boolean animating) {
266 if (mPrivateLayout != null) {
267 mPrivateLayout.setContentHeightAnimating(animating);
268 }
269 }
270
Selim Cinek8d490d42015-04-10 00:05:50 -0700271 public NotificationContentView getPrivateLayout() {
272 return mPrivateLayout;
273 }
274
275 public NotificationContentView getPublicLayout() {
276 return mPublicLayout;
277 }
278
Selim Cinekcab4a602014-09-03 14:47:57 +0200279 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800280 for (NotificationContentView l : mLayouts) {
281 setIconAnimationRunning(running, l);
282 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800283 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700284 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek414ad332017-02-24 19:06:12 -0800285 setIconAnimationRunningForChild(running, mChildrenContainer.getLowPriorityHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800286 List<ExpandableNotificationRow> notificationChildren =
287 mChildrenContainer.getNotificationChildren();
288 for (int i = 0; i < notificationChildren.size(); i++) {
289 ExpandableNotificationRow child = notificationChildren.get(i);
290 child.setIconAnimationRunning(running);
291 }
292 }
293 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200294 }
295
296 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
297 if (layout != null) {
298 View contractedChild = layout.getContractedChild();
299 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700300 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200301 setIconAnimationRunningForChild(running, contractedChild);
302 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700303 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200304 }
305 }
306
307 private void setIconAnimationRunningForChild(boolean running, View child) {
308 if (child != null) {
309 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
310 setIconRunning(icon, running);
311 ImageView rightIcon = (ImageView) child.findViewById(
312 com.android.internal.R.id.right_icon);
313 setIconRunning(rightIcon, running);
314 }
315 }
316
317 private void setIconRunning(ImageView imageView, boolean running) {
318 if (imageView != null) {
319 Drawable drawable = imageView.getDrawable();
320 if (drawable instanceof AnimationDrawable) {
321 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
322 if (running) {
323 animationDrawable.start();
324 } else {
325 animationDrawable.stop();
326 }
327 } else if (drawable instanceof AnimatedVectorDrawable) {
328 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
329 if (running) {
330 animationDrawable.start();
331 } else {
332 animationDrawable.stop();
333 }
334 }
335 }
336 }
337
Selim Cinek5ba22542017-04-20 15:16:10 -0700338 public void updateNotification(NotificationData.Entry entry) {
Selim Cinekda42d652015-12-04 15:51:16 -0800339 mEntry = entry;
340 mStatusBarNotification = entry.notification;
Selim Cinek1a48bab2017-02-17 19:38:40 -0800341 mNotificationInflater.inflateNotificationViews();
Selim Cinekc478f902017-02-22 20:55:44 -0800342 }
343
Selim Cinek5ba22542017-04-20 15:16:10 -0700344 public void onNotificationUpdated() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800345 for (NotificationContentView l : mLayouts) {
Selim Cinekc478f902017-02-22 20:55:44 -0800346 l.onNotificationUpdated(mEntry);
Adrian Rooseb434ff2017-01-11 11:18:48 -0800347 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800348 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800349 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700350 updateNotificationColor();
Mady Mellor4c197602017-04-10 17:57:52 -0700351 if (mMenuRow != null) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700352 mMenuRow.onNotificationUpdated(mStatusBarNotification);
Mady Mellor4c197602017-04-10 17:57:52 -0700353 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800354 if (mIsSummaryWithChildren) {
Selim Cinek414ad332017-02-24 19:06:12 -0800355 mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
Selim Cinekc897bd32016-03-18 17:32:31 -0700356 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800357 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800358 if (mIconAnimationRunning) {
359 setIconAnimationRunning(true);
360 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800361 if (mNotificationParent != null) {
362 mNotificationParent.updateChildrenHeaderAppearance();
363 }
Selim Cinek263398f2015-10-21 17:40:23 -0700364 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800365 // The public layouts expand button is always visible
366 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800367 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700368 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800369 updateShelfIconColor();
370 }
371
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700372 @VisibleForTesting
373 void updateShelfIconColor() {
Selim Cinek6743c0b2017-01-18 18:24:01 -0800374 StatusBarIconView expandedIcon = mEntry.expandedIcon;
375 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
376 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
377 NotificationColorUtil.getInstance(mContext));
Selim Cinek875ba9b2017-02-13 16:20:17 -0800378 int color = StatusBarIconView.NO_COLOR;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800379 if (colorize) {
Lucas Dupinb6ed63b2017-05-30 16:17:42 -0700380 NotificationHeaderView header = getVisibleNotificationHeader();
381 if (header != null) {
382 color = header.getOriginalIconColor();
383 } else {
384 color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
385 getBackgroundColorWithoutTint());
386 }
Selim Cinek6743c0b2017-01-18 18:24:01 -0800387 }
Selim Cinek875ba9b2017-02-13 16:20:17 -0800388 expandedIcon.setStaticDrawableColor(color);
Selim Cinekda42d652015-12-04 15:51:16 -0800389 }
390
Selim Cinek4705f292017-04-24 22:18:48 -0700391 @Override
392 public boolean isDimmable() {
393 if (!getShowingLayout().isDimmable()) {
394 return false;
395 }
396 return super.isDimmable();
397 }
398
Selim Cinekda42d652015-12-04 15:51:16 -0800399 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800400 for (NotificationContentView l : mLayouts) {
401 updateLimitsForView(l);
402 }
Selim Cineka1744872016-03-11 15:36:06 -0800403 }
404
405 private void updateLimitsForView(NotificationContentView layout) {
406 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800407 != com.android.internal.R.id.status_bar_latest_event_content;
408 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800409 int minHeight;
410 if (customView && beforeN && !mIsSummaryWithChildren) {
411 minHeight = mNotificationMinHeightLegacy;
412 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
413 minHeight = mNotificationMinHeightLarge;
414 } else {
415 minHeight = mNotificationMinHeight;
416 }
Selim Cineka1744872016-03-11 15:36:06 -0800417 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
418 layout.getHeadsUpChild().getId()
419 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800420 int headsUpheight;
421 if (headsUpCustom && beforeN) {
422 headsUpheight = mMaxHeadsUpHeightLegacy;
423 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
424 headsUpheight = mMaxHeadsUpHeightIncreased;
425 } else {
426 headsUpheight = mMaxHeadsUpHeight;
427 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800428 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
429 mNotificationAmbientHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200430 }
431
432 public StatusBarNotification getStatusBarNotification() {
433 return mStatusBarNotification;
434 }
435
Selim Cinek281c2022016-10-13 19:14:43 -0700436 public NotificationData.Entry getEntry() {
437 return mEntry;
438 }
439
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700440 public boolean isHeadsUp() {
441 return mIsHeadsUp;
442 }
443
Selim Cinek1a521f32014-11-03 17:39:29 +0100444 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700445 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100446 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700447 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700448 if (mIsSummaryWithChildren) {
449 // The overflow might change since we allow more lines as HUN.
450 mChildrenContainer.updateGroupOverflow();
451 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700452 if (intrinsicBefore != getIntrinsicHeight()) {
453 notifyHeightChanged(false /* needsAnimation */);
454 }
Selim Cinekd127d792016-11-01 19:11:41 -0700455 if (isHeadsUp) {
456 setAboveShelf(true);
457 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100458 }
459
Selim Cinekb5605e52015-02-20 18:21:41 +0100460 public void setGroupManager(NotificationGroupManager groupManager) {
461 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700462 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100463 }
464
Adrian Roosb88b1a12015-12-09 18:51:05 -0800465 public void setRemoteInputController(RemoteInputController r) {
466 mPrivateLayout.setRemoteInputController(r);
467 }
468
Mady Mellor3fd273e2016-03-15 21:08:14 -0700469 public void setAppName(String appName) {
470 mAppName = appName;
Mady Mellor95d743c2017-01-10 12:05:27 -0800471 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800472 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700473 }
474 }
475
Selim Cinekb5605e52015-02-20 18:21:41 +0100476 public void addChildNotification(ExpandableNotificationRow row) {
477 addChildNotification(row, -1);
478 }
479
480 /**
481 * Add a child notification to this view.
482 *
483 * @param row the row to add
484 * @param childIndex the index to add it at, if -1 it will be added at the end
485 */
486 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
487 if (mChildrenContainer == null) {
488 mChildrenContainerStub.inflate();
489 }
490 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700491 onChildrenCountChanged();
492 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100493 }
494
495 public void removeChildNotification(ExpandableNotificationRow row) {
496 if (mChildrenContainer != null) {
497 mChildrenContainer.removeNotification(row);
498 }
Selim Cinek263398f2015-10-21 17:40:23 -0700499 onChildrenCountChanged();
500 row.setIsChildInGroup(false, null);
501 }
502
Mady Mellor43c2cd12016-12-12 21:05:13 -0800503 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700504 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700505 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700506 }
507
Selim Cinek388df6d2015-10-22 13:25:11 -0700508 public ExpandableNotificationRow getNotificationParent() {
509 return mNotificationParent;
510 }
511
Selim Cinek263398f2015-10-21 17:40:23 -0700512 /**
513 * @param isChildInGroup Is this notification now in a group
514 * @param parent the new parent notification
515 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700516 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500517 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700518 mNotificationParent = childInGroup ? parent : null;
519 mPrivateLayout.setIsChildInGroup(childInGroup);
Selim Cinek5ba22542017-04-20 15:16:10 -0700520 mNotificationInflater.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400521 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700522 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700523 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700524 if (mNotificationParent != null) {
Selim Cinek9ce32852017-02-15 16:21:10 -0800525 setOverrideTintColor(NO_COLOR, 0.0f);
Mady Mellorb0a82462016-04-30 17:31:02 -0700526 mNotificationParent.updateBackgroundForGroupState();
527 }
Selim Cinekdb167372016-11-17 15:41:17 -0800528 updateIconVisibilities();
Selim Cinek34d93b02015-10-22 12:30:38 -0700529 }
530
531 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800532 public boolean onTouchEvent(MotionEvent event) {
533 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
534 || !isChildInGroup() || isGroupExpanded()) {
535 return super.onTouchEvent(event);
536 } else {
537 return false;
538 }
539 }
540
541 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800542 protected boolean handleSlideBack() {
Mady Mellor95d743c2017-01-10 12:05:27 -0800543 if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800544 animateTranslateNotification(0 /* targetLeft */);
545 return true;
546 }
547 return false;
548 }
549
550 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700551 protected boolean shouldHideBackground() {
552 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700553 }
554
555 @Override
556 public boolean isSummaryWithChildren() {
557 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100558 }
559
560 @Override
561 public boolean areChildrenExpanded() {
562 return mChildrenExpanded;
563 }
564
565 public List<ExpandableNotificationRow> getNotificationChildren() {
566 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
567 }
568
Selim Cinekeef84282015-10-30 16:28:00 -0700569 public int getNumberOfNotificationChildren() {
570 if (mChildrenContainer == null) {
571 return 0;
572 }
573 return mChildrenContainer.getNotificationChildren().size();
574 }
575
Selim Cinekb5605e52015-02-20 18:21:41 +0100576 /**
577 * Apply the order given in the list to the children.
578 *
579 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800580 * @param visualStabilityManager
581 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100582 * @return whether the list order has changed
583 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800584 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
585 VisualStabilityManager visualStabilityManager,
586 VisualStabilityManager.Callback callback) {
587 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
588 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100589 }
590
591 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700592 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800593 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100594 mChildrenContainer.getState(resultState, parentState);
595 }
596 }
597
598 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700599 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100600 mChildrenContainer.applyState(state);
601 }
602 }
603
604 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700605 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100606 mChildrenContainer.prepareExpansionChanged(state);
607 }
608 }
609
Selim Cinek0cfbef42016-11-09 19:06:36 -0800610 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700611 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800612 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100613 }
614 }
615
616 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800617 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100618 return this;
619 } else {
620 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
621 return view == null ? this : view;
622 }
623 }
624
Selim Cinekab29aeb2015-02-20 18:18:32 +0100625 public NotificationGuts getGuts() {
626 return mGuts;
627 }
628
Selim Cinek684a4422015-04-15 16:18:39 -0700629 /**
630 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
631 * the notification will be rendered on top of the screen.
632 *
633 * @param pinned whether it is pinned
634 */
635 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700636 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700637 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700638 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700639 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700640 }
Selim Cinek31aada42015-12-18 17:51:15 -0800641 if (pinned) {
642 setIconAnimationRunning(true);
643 mExpandedWhenPinned = false;
644 } else if (mExpandedWhenPinned) {
645 setUserExpanded(true);
646 }
Selim Cinek98713a42015-09-21 15:47:20 +0200647 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700648 }
649
Selim Cinek684a4422015-04-15 16:18:39 -0700650 public boolean isPinned() {
651 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700652 }
653
Selim Cinekd127d792016-11-01 19:11:41 -0700654 @Override
655 public int getPinnedHeadsUpHeight() {
656 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
657 }
658
Selim Cinek31aada42015-12-18 17:51:15 -0800659 /**
660 * @param atLeastMinHeight should the value returned be at least the minimum height.
661 * Used to avoid cyclic calls
662 * @return the height of the heads up notification when pinned
663 */
Selim Cinekd127d792016-11-01 19:11:41 -0700664 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800665 if (mIsSummaryWithChildren) {
666 return mChildrenContainer.getIntrinsicHeight();
667 }
Selim Cinek31aada42015-12-18 17:51:15 -0800668 if(mExpandedWhenPinned) {
669 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
670 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700671 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800672 } else {
673 return mHeadsUpHeight;
674 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700675 }
676
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700677 /**
678 * Mark whether this notification was just clicked, i.e. the user has just clicked this
679 * notification in this frame.
680 */
681 public void setJustClicked(boolean justClicked) {
682 mJustClicked = justClicked;
683 }
684
685 /**
686 * @return true if this notification has been clicked in this frame, false otherwise
687 */
688 public boolean wasJustClicked() {
689 return mJustClicked;
690 }
691
Selim Cinek98713a42015-09-21 15:47:20 +0200692 public void setChronometerRunning(boolean running) {
693 mLastChronometerRunning = running;
694 setChronometerRunning(running, mPrivateLayout);
695 setChronometerRunning(running, mPublicLayout);
696 if (mChildrenContainer != null) {
697 List<ExpandableNotificationRow> notificationChildren =
698 mChildrenContainer.getNotificationChildren();
699 for (int i = 0; i < notificationChildren.size(); i++) {
700 ExpandableNotificationRow child = notificationChildren.get(i);
701 child.setChronometerRunning(running);
702 }
703 }
704 }
705
706 private void setChronometerRunning(boolean running, NotificationContentView layout) {
707 if (layout != null) {
708 running = running || isPinned();
709 View contractedChild = layout.getContractedChild();
710 View expandedChild = layout.getExpandedChild();
711 View headsUpChild = layout.getHeadsUpChild();
712 setChronometerRunningForChild(running, contractedChild);
713 setChronometerRunningForChild(running, expandedChild);
714 setChronometerRunningForChild(running, headsUpChild);
715 }
716 }
717
718 private void setChronometerRunningForChild(boolean running, View child) {
719 if (child != null) {
720 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
721 if (chronometer instanceof Chronometer) {
722 ((Chronometer) chronometer).setStarted(running);
723 }
724 }
725 }
726
Selim Cinekea4bef72015-12-02 15:51:10 -0800727 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700728 if (mIsSummaryWithChildren) {
729 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700730 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800731 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700732 }
733
Selim Cinek414ad332017-02-24 19:06:12 -0800734 /**
735 * @return the currently visible notification header. This can be different from
736 * {@link #getNotificationHeader()} in case it is a low-priority group.
737 */
738 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700739 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek414ad332017-02-24 19:06:12 -0800740 return mChildrenContainer.getVisibleHeader();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800741 }
742 return getShowingLayout().getVisibleNotificationHeader();
743 }
744
Selim Cinek570981d2015-12-01 11:37:01 -0800745 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
746 mOnExpandClickListener = onExpandClickListener;
747 }
748
Selim Cinekddf1b392016-05-27 16:33:10 -0700749 @Override
750 public void setOnClickListener(@Nullable OnClickListener l) {
751 super.setOnClickListener(l);
752 mOnClickListener = l;
753 updateClickAndFocus();
754 }
755
756 private void updateClickAndFocus() {
757 boolean normalChild = !isChildInGroup() || isGroupExpanded();
758 boolean clickable = mOnClickListener != null && normalChild;
759 if (isFocusable() != normalChild) {
760 setFocusable(normalChild);
761 }
762 if (isClickable() != clickable) {
763 setClickable(clickable);
764 }
765 }
766
Selim Cinek31aada42015-12-18 17:51:15 -0800767 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
768 mHeadsUpManager = headsUpManager;
769 }
770
Mady Mellor87d79452017-01-10 11:52:52 -0800771 public void setGutsView(MenuItem item) {
Mady Mellor95d743c2017-01-10 12:05:27 -0800772 if (mGuts != null && item.getGutsView() instanceof GutsContent) {
773 ((GutsContent) item.getGutsView()).setGutsParent(mGuts);
774 mGuts.setGutsContent((GutsContent) item.getGutsView());
Mady Mellor87d79452017-01-10 11:52:52 -0800775 }
776 }
777
Mady Mellor95d743c2017-01-10 12:05:27 -0800778 @Override
779 protected void onAttachedToWindow() {
780 super.onAttachedToWindow();
781 Dependency.get(PluginManager.class).addPluginListener(this,
782 NotificationMenuRowPlugin.class, false /* Allow multiple */);
783 }
784
785 @Override
786 protected void onDetachedFromWindow() {
787 super.onDetachedFromWindow();
788 Dependency.get(PluginManager.class).removePluginListener(this);
789 }
790
791 @Override
792 public void onPluginConnected(NotificationMenuRowPlugin plugin, Context pluginContext) {
793 boolean existed = mMenuRow.getMenuView() != null;
794 if (existed) {
795 removeView(mMenuRow.getMenuView());
796 }
797 mMenuRow = plugin;
798 if (mMenuRow.useDefaultMenuItems()) {
Mady Mellor4c197602017-04-10 17:57:52 -0700799 ArrayList<MenuItem> items = new ArrayList<>();
800 items.add(NotificationMenuRow.createInfoItem(mContext));
801 items.add(NotificationMenuRow.createSnoozeItem(mContext));
802 mMenuRow.setMenuItems(items);
Mady Mellor95d743c2017-01-10 12:05:27 -0800803 }
804 if (existed) {
805 createMenu();
806 }
807 }
808
809 @Override
810 public void onPluginDisconnected(NotificationMenuRowPlugin plugin) {
811 boolean existed = mMenuRow.getMenuView() != null;
812 mMenuRow = new NotificationMenuRow(mContext); // Back to default
813 if (existed) {
814 createMenu();
815 }
816 }
817
818 public NotificationMenuRowPlugin createMenu() {
819 if (mMenuRow.getMenuView() == null) {
Mady Mellor4ab28202017-06-06 11:42:50 -0700820 mMenuRow.createMenu(this, mStatusBarNotification);
Mady Mellor95d743c2017-01-10 12:05:27 -0800821 mMenuRow.setAppName(mAppName);
822 FrameLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
823 LayoutParams.MATCH_PARENT);
824 addView(mMenuRow.getMenuView(), MENU_VIEW_INDEX, lp);
825 }
826 return mMenuRow;
827 }
828
Mady Mellor95d743c2017-01-10 12:05:27 -0800829 public NotificationMenuRowPlugin getProvider() {
830 return mMenuRow;
831 }
832
Anthony Chen9fe1ee72017-04-07 13:53:37 -0700833 @Override
Selim Cinek1a48bab2017-02-17 19:38:40 -0800834 public void onDensityOrFontScaleChanged() {
Anthony Chen9fe1ee72017-04-07 13:53:37 -0700835 super.onDensityOrFontScaleChanged();
Selim Cinek01af3342016-02-09 19:25:31 -0800836 initDimens();
Selim Cinek817abe72017-05-24 11:08:55 -0700837 // Let's update our childrencontainer. This is intentionally not guarded with
838 // mIsSummaryWithChildren since we might have had children but not anymore.
839 if (mChildrenContainer != null) {
840 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800841 }
842 if (mGuts != null) {
843 View oldGuts = mGuts;
844 int index = indexOfChild(oldGuts);
845 removeView(oldGuts);
846 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
847 R.layout.notification_guts, this, false);
848 mGuts.setVisibility(oldGuts.getVisibility());
849 addView(mGuts, index);
850 }
Mady Mellor95d743c2017-01-10 12:05:27 -0800851 View oldMenu = mMenuRow.getMenuView();
852 if (oldMenu != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800853 int menuIndex = indexOfChild(oldMenu);
854 removeView(oldMenu);
Mady Mellor4ab28202017-06-06 11:42:50 -0700855 mMenuRow.createMenu(ExpandableNotificationRow.this, mStatusBarNotification);
Mady Mellor761cde12017-01-10 11:36:39 -0800856 mMenuRow.setAppName(mAppName);
Mady Mellor95d743c2017-01-10 12:05:27 -0800857 addView(mMenuRow.getMenuView(), menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -0800858 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800859 for (NotificationContentView l : mLayouts) {
860 l.reInflateViews();
861 }
Selim Cinek1a48bab2017-02-17 19:38:40 -0800862 mNotificationInflater.onDensityOrFontScaleChanged();
863 onNotificationUpdated();
Selim Cinek01af3342016-02-09 19:25:31 -0800864 }
865
Mady Mellor9d03a522017-04-04 18:45:30 -0700866 @Override
867 public void onConfigurationChanged(Configuration newConfig) {
868 if (mMenuRow.getMenuView() != null) {
869 mMenuRow.onConfigurationChanged();
870 }
871 }
872
Selim Cinekc3179332016-03-04 14:44:56 -0800873 public void setContentBackground(int customBackgroundColor, boolean animate,
874 NotificationContentView notificationContentView) {
875 if (getShowingLayout() == notificationContentView) {
876 setTintColor(customBackgroundColor, animate);
877 }
878 }
879
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700880 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800881 for (NotificationContentView l : mLayouts) {
882 l.closeRemoteInput();
883 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700884 }
885
Selim Cinekc897bd32016-03-18 17:32:31 -0700886 /**
887 * Set by how much the single line view should be indented.
888 */
889 public void setSingleLineWidthIndention(int indention) {
890 mPrivateLayout.setSingleLineWidthIndention(indention);
891 }
892
893 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700894 return mNotificationColor;
895 }
896
897 private void updateNotificationColor() {
898 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
Selim Cinekac5f0272017-05-02 16:05:41 -0700899 getStatusBarNotification().getNotification().color,
900 getBackgroundColorWithoutTint());
Adrian Roos6f6e1592017-05-02 16:22:53 -0700901 mNotificationColorAmbient = NotificationColorUtil.resolveAmbientColor(mContext,
902 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700903 }
904
905 public HybridNotificationView getSingleLineView() {
906 return mPrivateLayout.getSingleLineView();
907 }
908
Adrian Roos6f6e1592017-05-02 16:22:53 -0700909 public HybridNotificationView getAmbientSingleLineView() {
910 return getShowingLayout().getAmbientSingleLineChild();
911 }
912
Selim Cinekf07d0622016-03-21 19:52:52 -0700913 public boolean isOnKeyguard() {
914 return mOnKeyguard;
915 }
916
Selim Cinekc1e389d2016-04-07 11:02:57 -0700917 public void removeAllChildren() {
918 List<ExpandableNotificationRow> notificationChildren
919 = mChildrenContainer.getNotificationChildren();
920 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
921 for (int i = 0; i < clonedList.size(); i++) {
922 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700923 if (row.keepInParent()) {
924 continue;
925 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700926 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700927 row.setIsChildInGroup(false, null);
928 }
929 onChildrenCountChanged();
930 }
931
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700932 public void setForceUnlocked(boolean forceUnlocked) {
933 mForceUnlocked = forceUnlocked;
934 if (mIsSummaryWithChildren) {
935 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
936 for (ExpandableNotificationRow child : notificationChildren) {
937 child.setForceUnlocked(forceUnlocked);
938 }
939 }
940 }
941
Selim Cineke9bad242016-06-15 11:46:37 -0700942 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700943 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700944 mGroupParentWhenDismissed = mNotificationParent;
945 mRefocusOnDismiss = fromAccessibility;
946 mChildAfterViewWhenDismissed = null;
947 if (isChildInGroup()) {
948 List<ExpandableNotificationRow> notificationChildren =
949 mNotificationParent.getNotificationChildren();
950 int i = notificationChildren.indexOf(this);
951 if (i != -1 && i < notificationChildren.size() - 1) {
952 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
953 }
954 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700955 }
956
957 public boolean isDismissed() {
958 return mDismissed;
959 }
960
961 public boolean keepInParent() {
962 return mKeepInParent;
963 }
964
965 public void setKeepInParent(boolean keepInParent) {
966 mKeepInParent = keepInParent;
967 }
968
969 public boolean isRemoved() {
970 return mRemoved;
971 }
972
Adrian Roosd009ab12016-05-20 17:58:53 -0700973 public void setRemoved() {
974 mRemoved = true;
Selim Cinekef8c2252017-02-10 14:52:18 -0800975 mTranslationWhenRemoved = getTranslationY();
976 mWasChildInGroupWhenRemoved = isChildInGroup();
977 if (isChildInGroup()) {
978 mTranslationWhenRemoved += getNotificationParent().getTranslationY();
979 }
Adrian Roosd009ab12016-05-20 17:58:53 -0700980 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700981 }
982
Selim Cinekef8c2252017-02-10 14:52:18 -0800983 public boolean wasChildInGroupWhenRemoved() {
984 return mWasChildInGroupWhenRemoved;
985 }
986
987 public float getTranslationWhenRemoved() {
988 return mTranslationWhenRemoved;
989 }
990
Selim Cinekd1395642016-04-28 12:22:42 -0700991 public NotificationChildrenContainer getChildrenContainer() {
992 return mChildrenContainer;
993 }
994
Selim Cinekcafa87f2016-10-26 17:00:17 -0700995 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
996 mHeadsupDisappearRunning = headsUpAnimatingAway;
997 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
998 }
999
1000 /**
1001 * @return if the view was just heads upped and is now animating away. During such a time the
1002 * layout needs to be kept consistent
1003 */
1004 public boolean isHeadsUpAnimatingAway() {
1005 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -07001006 }
1007
Selim Cineke9bad242016-06-15 11:46:37 -07001008 public View getChildAfterViewWhenDismissed() {
1009 return mChildAfterViewWhenDismissed;
1010 }
1011
1012 public View getGroupParentWhenDismissed() {
1013 return mGroupParentWhenDismissed;
1014 }
1015
Selim Cinek9e624e72016-07-20 13:46:49 -07001016 public void performDismiss() {
Selim Cineke9079112016-12-14 14:41:01 -08001017 if (mOnDismissRunnable != null) {
1018 mOnDismissRunnable.run();
1019 }
Selim Cinek9e624e72016-07-20 13:46:49 -07001020 }
1021
Selim Cineke9079112016-12-14 14:41:01 -08001022 public void setOnDismissRunnable(Runnable onDismissRunnable) {
1023 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -07001024 }
1025
Selim Cinek281c2022016-10-13 19:14:43 -07001026 public View getNotificationIcon() {
Selim Cinek414ad332017-02-24 19:06:12 -08001027 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek281c2022016-10-13 19:14:43 -07001028 if (notificationHeader != null) {
1029 return notificationHeader.getIcon();
1030 }
1031 return null;
1032 }
1033
1034 /**
1035 * @return whether the notification is currently showing a view with an icon.
1036 */
1037 public boolean isShowingIcon() {
Mady Mellor434180c2017-02-13 11:29:42 -08001038 if (areGutsExposed()) {
1039 return false;
1040 }
Selim Cinek2ffa02f2017-03-06 15:56:37 -08001041 return getVisibleNotificationHeader() != null;
Selim Cinek281c2022016-10-13 19:14:43 -07001042 }
1043
Selim Cinek0242fbb2016-10-19 13:38:32 -07001044 /**
1045 * Set how much this notification is transformed into an icon.
1046 *
Selim Cinek2b549f42016-11-22 16:38:51 -08001047 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
1048 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -08001049 * @param isLastChild is this the last child in the list. If true, then the transformation is
1050 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -07001051 */
Selim Cinek2b549f42016-11-22 16:38:51 -08001052 public void setContentTransformationAmount(float contentTransformationAmount,
1053 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -08001054 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001055 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001056 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001057 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001058 if (changeTransformation) {
1059 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -08001060 }
1061 }
1062
1063 /**
1064 * Set the icons to be visible of this notification.
1065 */
1066 public void setIconsVisible(boolean iconsVisible) {
1067 if (iconsVisible != mIconsVisible) {
1068 mIconsVisible = iconsVisible;
1069 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -07001070 }
1071 }
1072
Selim Cinekdb167372016-11-17 15:41:17 -08001073 @Override
1074 protected void onBelowSpeedBumpChanged() {
1075 updateIconVisibilities();
1076 }
1077
Selim Cinek875a3a12016-11-18 17:52:16 -08001078 private void updateContentTransformation() {
1079 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -08001080 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -08001081 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -08001082 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001083 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001084 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -08001085 translationY *= 0.4f;
1086 } else {
1087 contentAlpha = 1.0f;
1088 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001089 for (NotificationContentView l : mLayouts) {
1090 l.setAlpha(contentAlpha);
1091 l.setTranslationY(translationY);
1092 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001093 if (mChildrenContainer != null) {
1094 mChildrenContainer.setAlpha(contentAlpha);
1095 mChildrenContainer.setTranslationY(translationY);
1096 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -07001097 }
1098 }
1099
1100 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -08001101 boolean visible = isChildInGroup()
1102 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
1103 || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -08001104 for (NotificationContentView l : mLayouts) {
1105 l.setIconsVisible(visible);
1106 }
Selim Cinekdb167372016-11-17 15:41:17 -08001107 if (mChildrenContainer != null) {
1108 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001109 }
1110 }
1111
Selim Cinek875a3a12016-11-18 17:52:16 -08001112 /**
1113 * Get the relative top padding of a view relative to this view. This recursively walks up the
1114 * hierarchy and does the corresponding measuring.
1115 *
1116 * @param view the view to the the padding for. The requested view has to be a child of this
1117 * notification.
1118 * @return the toppadding
1119 */
1120 public int getRelativeTopPadding(View view) {
1121 int topPadding = 0;
1122 while (view.getParent() instanceof ViewGroup) {
1123 topPadding += view.getTop();
1124 view = (View) view.getParent();
1125 if (view instanceof ExpandableNotificationRow) {
1126 return topPadding;
1127 }
1128 }
1129 return topPadding;
1130 }
1131
Selim Cineka1d97902016-12-14 16:31:40 -08001132 public float getContentTranslation() {
1133 return mPrivateLayout.getTranslationY();
1134 }
1135
Selim Cinek6743c0b2017-01-18 18:24:01 -08001136 public void setIsLowPriority(boolean isLowPriority) {
1137 mIsLowPriority = isLowPriority;
1138 mPrivateLayout.setIsLowPriority(isLowPriority);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001139 mNotificationInflater.setIsLowPriority(mIsLowPriority);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001140 if (mChildrenContainer != null) {
1141 mChildrenContainer.setIsLowPriority(isLowPriority);
1142 }
1143 }
1144
Selim Cinek55a3e732017-05-25 18:30:10 -07001145
1146 public void setLowPriorityStateUpdated(boolean lowPriorityStateUpdated) {
1147 mLowPriorityStateUpdated = lowPriorityStateUpdated;
1148 }
1149
1150 public boolean hasLowPriorityStateUpdated() {
1151 return mLowPriorityStateUpdated;
1152 }
1153
Selim Cinek414ad332017-02-24 19:06:12 -08001154 public boolean isLowPriority() {
1155 return mIsLowPriority;
1156 }
1157
Selim Cinek7d1009b2017-01-25 15:28:28 -08001158 public void setUseIncreasedCollapsedHeight(boolean use) {
1159 mUseIncreasedCollapsedHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001160 mNotificationInflater.setUsesIncreasedHeight(use);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001161 }
1162
Selim Cinek87ed69b2017-02-09 15:59:43 -08001163 public void setUseIncreasedHeadsUpHeight(boolean use) {
1164 mUseIncreasedHeadsUpHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001165 mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
1166 }
1167
1168 public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
1169 mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001170 }
1171
Selim Cinek5ba22542017-04-20 15:16:10 -07001172 public void setInflationCallback(InflationCallback callback) {
1173 mNotificationInflater.setInflationCallback(callback);
Selim Cinekc478f902017-02-22 20:55:44 -08001174 }
1175
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001176 public void setNeedsRedaction(boolean needsRedaction) {
1177 mNotificationInflater.setRedactAmbient(needsRedaction);
1178 }
1179
Selim Cinek5ba22542017-04-20 15:16:10 -07001180 @VisibleForTesting
1181 public NotificationInflater getNotificationInflater() {
1182 return mNotificationInflater;
1183 }
1184
Adrian Roos6f6e1592017-05-02 16:22:53 -07001185 public int getNotificationColorAmbient() {
1186 return mNotificationColorAmbient;
1187 }
1188
Chris Wren78403d72014-07-28 10:23:24 +01001189 public interface ExpansionLogger {
Anthony Chen6bf88a02017-04-10 14:41:44 -07001190 void logNotificationExpansion(String key, boolean userAction, boolean expanded);
Chris Wren78403d72014-07-28 10:23:24 +01001191 }
Selim Cinek1685e632014-04-08 02:27:49 +02001192
Chris Wren51c75102013-07-16 20:49:17 -04001193 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1194 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001195 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001196 mNotificationInflater = new NotificationInflater(this);
Mady Mellor95d743c2017-01-10 12:05:27 -08001197 mMenuRow = new NotificationMenuRow(mContext);
Selim Cinek01af3342016-02-09 19:25:31 -08001198 initDimens();
1199 }
1200
1201 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -08001202 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
1203 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001204 mNotificationMinHeightLarge = getFontScaledHeight(
Selim Cinek87ed69b2017-02-09 15:59:43 -08001205 R.dimen.notification_min_height_increased);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001206 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
Adrian Roos0aac04f2016-12-08 15:59:29 -08001207 mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001208 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -08001209 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001210 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001211 mMaxHeadsUpHeightIncreased = getFontScaledHeight(
1212 R.dimen.notification_max_heads_up_height_increased);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001213
Anthony Chen7acbb772017-04-07 16:45:25 -07001214 Resources res = getResources();
1215 mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
1216 R.dimen.notification_divider_height_increased);
1217 mIconTransformContentShiftNoIcon = res.getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001218 R.dimen.notification_icon_transform_content_shift);
Anthony Chen6bf88a02017-04-10 14:41:44 -07001219 mEnableNonGroupedNotificationExpand =
1220 res.getBoolean(R.bool.config_enableNonGroupedNotificationExpand);
1221 mShowGroupBackgroundWhenExpanded =
1222 res.getBoolean(R.bool.config_showGroupNotificationBgWhenExpanded);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001223 }
1224
1225 /**
1226 * @param dimenId the dimen to look up
1227 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
1228 */
1229 private int getFontScaledHeight(int dimenId) {
1230 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
1231 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
1232 getResources().getDisplayMetrics().density);
1233 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -04001234 }
1235
Christoph Studera7fe6312014-06-27 19:32:44 +02001236 /**
1237 * Resets this view so it can be re-used for an updated notification.
1238 */
1239 public void reset() {
Jorim Jaggiae441282014-08-01 02:45:18 +02001240 mShowingPublicInitialized = false;
Selim Cinek31094df2014-08-14 19:28:15 +02001241 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001242 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001243 }
1244
Jorim Jaggi251957d2014-04-09 04:24:09 +02001245 @Override
1246 protected void onFinishInflate() {
1247 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001248 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1249 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001250 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1251
1252 for (NotificationContentView l : mLayouts) {
1253 l.setExpandClickListener(mExpandClickListener);
1254 l.setContainingNotification(this);
1255 }
Selim Cinekab29aeb2015-02-20 18:18:32 +01001256 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1257 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001258 @Override
1259 public void onInflate(ViewStub stub, View inflated) {
1260 mGuts = (NotificationGuts) inflated;
1261 mGuts.setClipTopAmount(getClipTopAmount());
1262 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001263 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001264 }
1265 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001266 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1267 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1268
1269 @Override
1270 public void onInflate(ViewStub stub, View inflated) {
1271 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001272 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek414ad332017-02-24 19:06:12 -08001273 mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001274 mChildrenContainer.onNotificationUpdated();
Anthony Chen7acbb772017-04-07 16:45:25 -07001275
1276 if (mShouldTranslateContents) {
1277 mTranslateableViews.add(mChildrenContainer);
1278 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001279 }
1280 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001281
Anthony Chen7acbb772017-04-07 16:45:25 -07001282 if (mShouldTranslateContents) {
1283 // Add the views that we translate to reveal the menu
1284 mTranslateableViews = new ArrayList<>();
1285 for (int i = 0; i < getChildCount(); i++) {
1286 mTranslateableViews.add(getChildAt(i));
1287 }
1288 // Remove views that don't translate
1289 mTranslateableViews.remove(mChildrenContainerStub);
1290 mTranslateableViews.remove(mGutsStub);
Mady Mellor4b80b102016-01-22 08:03:58 -08001291 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001292 }
1293
Mady Mellor4b80b102016-01-22 08:03:58 -08001294 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001295 if (mTranslateAnim != null) {
1296 mTranslateAnim.cancel();
1297 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001298
1299 if (!mShouldTranslateContents) {
1300 setTranslationX(0);
1301 } else if (mTranslateableViews != null) {
Mady Mellor4b80b102016-01-22 08:03:58 -08001302 for (int i = 0; i < mTranslateableViews.size(); i++) {
1303 mTranslateableViews.get(i).setTranslationX(0);
1304 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001305 invalidateOutline();
Mady Mellor4b80b102016-01-22 08:03:58 -08001306 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001307
Mady Mellor95d743c2017-01-10 12:05:27 -08001308 mMenuRow.resetMenu();
Mady Mellor4b80b102016-01-22 08:03:58 -08001309 }
1310
1311 public void animateTranslateNotification(final float leftTarget) {
1312 if (mTranslateAnim != null) {
1313 mTranslateAnim.cancel();
1314 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001315 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001316 if (mTranslateAnim != null) {
1317 mTranslateAnim.start();
1318 }
1319 }
1320
1321 @Override
1322 public void setTranslation(float translationX) {
1323 if (areGutsExposed()) {
1324 // Don't translate if guts are showing.
1325 return;
1326 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001327 if (!mShouldTranslateContents) {
1328 setTranslationX(translationX);
1329 } else if (mTranslateableViews != null) {
1330 // Translate the group of views
1331 for (int i = 0; i < mTranslateableViews.size(); i++) {
1332 if (mTranslateableViews.get(i) != null) {
1333 mTranslateableViews.get(i).setTranslationX(translationX);
1334 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001335 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001336 invalidateOutline();
Mady Mellor34958fa2016-02-23 09:52:17 -08001337 }
Mady Mellor95d743c2017-01-10 12:05:27 -08001338 if (mMenuRow.getMenuView() != null) {
1339 mMenuRow.onTranslationUpdate(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001340 }
1341 }
1342
1343 @Override
1344 public float getTranslation() {
Anthony Chene04afcb2017-04-21 13:51:32 -07001345 if (!mShouldTranslateContents) {
Anthony Chen7acbb772017-04-07 16:45:25 -07001346 return getTranslationX();
1347 }
1348
Mady Mellor34958fa2016-02-23 09:52:17 -08001349 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1350 // All of the views in the list should have same translation, just use first one.
1351 return mTranslateableViews.get(0).getTranslationX();
1352 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001353
Mady Mellor34958fa2016-02-23 09:52:17 -08001354 return 0;
1355 }
1356
1357 public Animator getTranslateViewAnimator(final float leftTarget,
1358 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001359 if (mTranslateAnim != null) {
1360 mTranslateAnim.cancel();
1361 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001362 if (areGutsExposed()) {
1363 // No translation if guts are exposed.
1364 return null;
1365 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001366 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1367 leftTarget);
1368 if (listener != null) {
1369 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001370 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001371 translateAnim.addListener(new AnimatorListenerAdapter() {
1372 boolean cancelled = false;
1373
1374 @Override
1375 public void onAnimationCancel(Animator anim) {
1376 cancelled = true;
1377 }
1378
1379 @Override
1380 public void onAnimationEnd(Animator anim) {
Mady Mellor95d743c2017-01-10 12:05:27 -08001381 if (!cancelled && leftTarget == 0) {
1382 mMenuRow.resetMenu();
Mady Mellorb0a82462016-04-30 17:31:02 -07001383 mTranslateAnim = null;
1384 }
1385 }
1386 });
1387 mTranslateAnim = translateAnim;
1388 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001389 }
1390
Selim Cinekab29aeb2015-02-20 18:18:32 +01001391 public void inflateGuts() {
1392 if (mGuts == null) {
1393 mGutsStub.inflate();
1394 }
1395 }
1396
Selim Cinekda42d652015-12-04 15:51:16 -08001397 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001398 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1399 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001400 if (mChildrenContainer != null) {
1401 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1402 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001403 }
Selim Cinekda42d652015-12-04 15:51:16 -08001404 // The limits might have changed if the view suddenly became a group or vice versa
1405 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001406 }
1407
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001408 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001409 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1410 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001411 // Add a record for the entire layout since its content is somehow small.
1412 // The event comes from a leaf view that is interacted with.
1413 AccessibilityEvent record = AccessibilityEvent.obtain();
1414 onInitializeAccessibilityEvent(record);
1415 dispatchPopulateAccessibilityEvent(record);
1416 event.appendRecord(record);
1417 return true;
1418 }
1419 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001420 }
Chris Wren51c75102013-07-16 20:49:17 -04001421
John Spurlocke15452b2014-08-21 09:44:39 -04001422 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001423 public void setDark(boolean dark, boolean fade, long delay) {
1424 super.setDark(dark, fade, delay);
Adrian Roos28f90c72017-05-08 17:24:26 -07001425 if (!mIsHeadsUp) {
1426 // Only fade the showing view of the pulsing notification.
1427 fade = false;
1428 }
John Spurlocke15452b2014-08-21 09:44:39 -04001429 final NotificationContentView showing = getShowingLayout();
1430 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001431 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001432 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001433 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001434 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001435 }
John Spurlocke15452b2014-08-21 09:44:39 -04001436 }
1437
Chris Wren51c75102013-07-16 20:49:17 -04001438 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001439 if (mIsSummaryWithChildren && !mShowingPublic) {
1440 return !mChildrenExpanded;
1441 }
Anthony Chen6bf88a02017-04-10 14:41:44 -07001442 return mEnableNonGroupedNotificationExpand && mExpandable;
Chris Wren51c75102013-07-16 20:49:17 -04001443 }
1444
1445 public void setExpandable(boolean expandable) {
1446 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001447 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001448 }
1449
Selim Cinek4ffd6362015-12-29 15:12:23 +01001450 @Override
1451 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001452 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1453 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001454 }
1455
Selim Cinek1685e632014-04-08 02:27:49 +02001456 /**
1457 * @return whether the user has changed the expansion state
1458 */
1459 public boolean hasUserChangedExpansion() {
1460 return mHasUserChangedExpansion;
1461 }
1462
Chris Wren51c75102013-07-16 20:49:17 -04001463 public boolean isUserExpanded() {
1464 return mUserExpanded;
1465 }
1466
Selim Cinek1685e632014-04-08 02:27:49 +02001467 /**
1468 * Set this notification to be expanded by the user
1469 *
1470 * @param userExpanded whether the user wants this notification to be expanded
1471 */
Chris Wren51c75102013-07-16 20:49:17 -04001472 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001473 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1474 }
1475
1476 /**
1477 * Set this notification to be expanded by the user
1478 *
1479 * @param userExpanded whether the user wants this notification to be expanded
1480 * @param allowChildExpansion whether a call to this method allows expanding children
1481 */
1482 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001483 mFalsingManager.setNotificationExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08001484 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion
1485 && !mChildrenContainer.showingAsLowPriority()) {
Chris Wren698b1702016-05-23 11:16:32 -04001486 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001487 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -08001488 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001489 return;
1490 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001491 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001492 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001493 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001494 mUserExpanded = userExpanded;
Selim Cinek414ad332017-02-24 19:06:12 -08001495 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07001496 if (!wasExpanded && isExpanded()
1497 && getActualHeight() != getIntrinsicHeight()) {
1498 notifyHeightChanged(true /* needsAnimation */);
1499 }
Chris Wren51c75102013-07-16 20:49:17 -04001500 }
1501
Selim Cinekccd14fb2014-08-12 18:53:24 +02001502 public void resetUserExpansion() {
Selim Cinek414ad332017-02-24 19:06:12 -08001503 boolean changed = mUserExpanded;
Selim Cinekccd14fb2014-08-12 18:53:24 +02001504 mHasUserChangedExpansion = false;
1505 mUserExpanded = false;
Selim Cinek414ad332017-02-24 19:06:12 -08001506 if (changed && mIsSummaryWithChildren) {
1507 mChildrenContainer.onExpansionChanged();
1508 }
1509 updateShelfIconColor();
Selim Cinekccd14fb2014-08-12 18:53:24 +02001510 }
1511
Chris Wren51c75102013-07-16 20:49:17 -04001512 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001513 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001514 }
1515
1516 public void setUserLocked(boolean userLocked) {
1517 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001518 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07001519 // This is intentionally not guarded with mIsSummaryWithChildren since we might have had
1520 // children but not anymore.
1521 if (mChildrenContainer != null) {
Selim Cinek42357e02016-02-24 18:48:01 -08001522 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek817abe72017-05-24 11:08:55 -07001523 if (mIsSummaryWithChildren && (userLocked || !isGroupExpanded())) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001524 updateBackgroundForGroupState();
1525 }
Selim Cinek42357e02016-02-24 18:48:01 -08001526 }
Chris Wren51c75102013-07-16 20:49:17 -04001527 }
1528
Selim Cinek1685e632014-04-08 02:27:49 +02001529 /**
1530 * @return has the system set this notification to be expanded
1531 */
1532 public boolean isSystemExpanded() {
1533 return mIsSystemExpanded;
1534 }
1535
1536 /**
1537 * Set this notification to be expanded by the system.
1538 *
1539 * @param expand whether the system wants this notification to be expanded.
1540 */
1541 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001542 if (expand != mIsSystemExpanded) {
1543 final boolean wasExpanded = isExpanded();
1544 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001545 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek414ad332017-02-24 19:06:12 -08001546 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001547 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001548 mChildrenContainer.updateGroupOverflow();
1549 }
Selim Cinek31094df2014-08-14 19:28:15 +02001550 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001551 }
1552
1553 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001554 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001555 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001556 public void setOnKeyguard(boolean onKeyguard) {
1557 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001558 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001559 mOnKeyguard = onKeyguard;
Selim Cinek414ad332017-02-24 19:06:12 -08001560 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cinek31094df2014-08-14 19:28:15 +02001561 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001562 if (mIsSummaryWithChildren) {
1563 mChildrenContainer.updateGroupOverflow();
1564 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001565 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001566 }
1567 }
Selim Cinek1685e632014-04-08 02:27:49 +02001568 }
1569
1570 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001571 * @return Can the underlying notification be cleared? This can be different from whether the
1572 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1573 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001574 */
1575 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001576 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1577 return false;
1578 }
1579 if (mIsSummaryWithChildren) {
1580 List<ExpandableNotificationRow> notificationChildren =
1581 mChildrenContainer.getNotificationChildren();
1582 for (int i = 0; i < notificationChildren.size(); i++) {
1583 ExpandableNotificationRow child = notificationChildren.get(i);
1584 if (!child.isClearable()) {
1585 return false;
1586 }
1587 }
1588 }
1589 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001590 }
1591
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001592 @Override
1593 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001594 if (isUserLocked()) {
1595 return getActualHeight();
1596 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001597 if (mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07001598 return mGuts.getIntrinsicHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001599 } else if ((isChildInGroup() && !isGroupExpanded())) {
1600 return mPrivateLayout.getMinHeight();
1601 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1602 return getMinHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07001603 } else if (mIsSummaryWithChildren && (!mOnKeyguard || mShowAmbient)) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001604 return mChildrenContainer.getIntrinsicHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07001605 } else if (isHeadsUpAllowed() && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07001606 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001607 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1608 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001609 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001610 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001611 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001612 }
Selim Cinek31aada42015-12-18 17:51:15 -08001613 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001614 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001615 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001616 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001617 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001618 }
Selim Cinek1685e632014-04-08 02:27:49 +02001619
Adrian Roos6f6e1592017-05-02 16:22:53 -07001620 private boolean isHeadsUpAllowed() {
1621 return !mOnKeyguard && !mShowAmbient;
1622 }
1623
Mady Mellor43c2cd12016-12-12 21:05:13 -08001624 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001625 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001626 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001627 }
1628
Selim Cinek263398f2015-10-21 17:40:23 -07001629 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05001630 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001631 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1632 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
Selim Cinek414ad332017-02-24 19:06:12 -08001633 mChildrenContainer.recreateNotificationHeader(mExpandClickListener
1634 );
Selim Cinek263398f2015-10-21 17:40:23 -07001635 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001636 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001637 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001638 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001639 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001640 }
1641
Mady Mellorb0a82462016-04-30 17:31:02 -07001642 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001643 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001644 mChildrenContainer.updateChildrenHeaderAppearance();
1645 }
1646 }
1647
Selim Cinek1685e632014-04-08 02:27:49 +02001648 /**
1649 * Check whether the view state is currently expanded. This is given by the system in {@link
1650 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1651 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1652 * view can differ from this state, if layout params are modified from outside.
1653 *
1654 * @return whether the view state is currently expanded.
1655 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001656 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001657 return isExpanded(false /* allowOnKeyguard */);
1658 }
1659
1660 public boolean isExpanded(boolean allowOnKeyguard) {
1661 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001662 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1663 || isUserExpanded());
1664 }
1665
1666 private boolean isSystemChildExpanded() {
1667 return mIsSystemChildExpanded;
1668 }
1669
1670 public void setSystemChildExpanded(boolean expanded) {
1671 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001672 }
1673
Mady Mellor035badd2017-04-04 18:45:30 -07001674 public void setLayoutListener(LayoutListener listener) {
1675 mLayoutListener = listener;
1676 }
1677
1678 public void removeListener() {
1679 mLayoutListener = null;
1680 }
1681
Selim Cinek1685e632014-04-08 02:27:49 +02001682 @Override
1683 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1684 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001685 updateMaxHeights();
Mady Mellor95d743c2017-01-10 12:05:27 -08001686 if (mMenuRow.getMenuView() != null) {
1687 mMenuRow.onHeightUpdate();
Mady Mellora6edc872016-04-26 11:01:03 -07001688 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001689 updateContentShiftHeight();
Mady Mellor035badd2017-04-04 18:45:30 -07001690 if (mLayoutListener != null) {
1691 mLayoutListener.onLayout();
1692 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001693 }
1694
1695 /**
1696 * Updates the content shift height such that the header is completely hidden when coming from
1697 * the top.
1698 */
1699 private void updateContentShiftHeight() {
Selim Cinek414ad332017-02-24 19:06:12 -08001700 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek875a3a12016-11-18 17:52:16 -08001701 if (notificationHeader != null) {
1702 CachingIconView icon = notificationHeader.getIcon();
1703 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1704 } else {
1705 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1706 }
Selim Cinek1685e632014-04-08 02:27:49 +02001707 }
1708
Selim Cinek8d490d42015-04-10 00:05:50 -07001709 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001710 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001711 View expandedChild = mPrivateLayout.getExpandedChild();
1712 if (expandedChild == null) {
1713 expandedChild = mPrivateLayout.getContractedChild();
1714 }
1715 mMaxExpandHeight = expandedChild.getHeight();
1716 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001717 if (headsUpChild == null) {
1718 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001719 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001720 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001721 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001722 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001723 }
1724 }
1725
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001726 @Override
1727 public void notifyHeightChanged(boolean needsAnimation) {
1728 super.notifyHeightChanged(needsAnimation);
1729 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1730 }
1731
Selim Cinek3c76d502016-02-19 15:16:33 -08001732 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001733 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001734 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001735 }
1736
Mady Mellor43c2cd12016-12-12 21:05:13 -08001737 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001738 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001739 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001740 if (mIsSummaryWithChildren) {
1741 List<ExpandableNotificationRow> notificationChildren =
1742 mChildrenContainer.getNotificationChildren();
1743 for (int i = 0; i < notificationChildren.size(); i++) {
1744 ExpandableNotificationRow child = notificationChildren.get(i);
1745 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1746 }
1747 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001748 }
1749
Mady Mellor43c2cd12016-12-12 21:05:13 -08001750 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001751 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1752 long duration) {
1753 boolean oldShowingPublic = mShowingPublic;
1754 mShowingPublic = mSensitive && hideSensitive;
1755 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1756 return;
1757 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001758
1759 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001760 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001761
Jorim Jaggiae441282014-08-01 02:45:18 +02001762 if (!animated) {
1763 mPublicLayout.animate().cancel();
1764 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001765 if (mChildrenContainer != null) {
1766 mChildrenContainer.animate().cancel();
1767 mChildrenContainer.setAlpha(1f);
1768 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001769 mPublicLayout.setAlpha(1f);
1770 mPrivateLayout.setAlpha(1f);
1771 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001772 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001773 } else {
1774 animateShowingPublic(delay, duration);
1775 }
Selim Cinekc3179332016-03-04 14:44:56 -08001776 NotificationContentView showingLayout = getShowingLayout();
1777 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001778 mPrivateLayout.updateExpandButtons(isExpandable());
Lucas Dupinb6ed63b2017-05-30 16:17:42 -07001779 updateShelfIconColor();
Adrian Roose5726a22016-12-19 14:26:51 -08001780 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02001781 mShowingPublicInitialized = true;
1782 }
1783
1784 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001785 View[] privateViews = mIsSummaryWithChildren
1786 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001787 : new View[] {mPrivateLayout};
1788 View[] publicViews = new View[] {mPublicLayout};
1789 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1790 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1791 for (final View hiddenView : hiddenChildren) {
1792 hiddenView.setVisibility(View.VISIBLE);
1793 hiddenView.animate().cancel();
1794 hiddenView.animate()
1795 .alpha(0f)
1796 .setStartDelay(delay)
1797 .setDuration(duration)
1798 .withEndAction(new Runnable() {
1799 @Override
1800 public void run() {
1801 hiddenView.setVisibility(View.INVISIBLE);
1802 }
1803 });
1804 }
1805 for (View showView : shownChildren) {
1806 showView.setVisibility(View.VISIBLE);
1807 showView.setAlpha(0f);
1808 showView.animate().cancel();
1809 showView.animate()
1810 .alpha(1f)
1811 .setStartDelay(delay)
1812 .setDuration(duration);
1813 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001814 }
1815
Mady Mellor43c2cd12016-12-12 21:05:13 -08001816 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08001817 public boolean mustStayOnScreen() {
1818 return mIsHeadsUp;
1819 }
1820
Selim Cinek9e624e72016-07-20 13:46:49 -07001821 /**
1822 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1823 * otherwise some state might not be updated. To request about the general clearability
1824 * see {@link #isClearable()}.
1825 */
1826 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001827 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001828 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001829
Ricky Waicd35def2016-05-03 11:07:07 +01001830 public void makeActionsVisibile() {
1831 setUserExpanded(true, true);
1832 if (isChildInGroup()) {
1833 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1834 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001835 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001836 }
1837
Selim Cinekb5605e52015-02-20 18:21:41 +01001838 public void setChildrenExpanded(boolean expanded, boolean animate) {
1839 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001840 if (mChildrenContainer != null) {
1841 mChildrenContainer.setChildrenExpanded(expanded);
1842 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001843 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001844 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001845 }
1846
Selim Cinekb5605e52015-02-20 18:21:41 +01001847 public static void applyTint(View v, int color) {
1848 int alpha;
1849 if (color != 0) {
1850 alpha = COLORED_DIVIDER_ALPHA;
1851 } else {
1852 color = 0xff000000;
1853 alpha = DEFAULT_DIVIDER_ALPHA;
1854 }
1855 if (v.getBackground() instanceof ColorDrawable) {
1856 ColorDrawable background = (ColorDrawable) v.getBackground();
1857 background.mutate();
1858 background.setColor(color);
1859 background.setAlpha(alpha);
1860 }
1861 }
1862
Selim Cinek1685e632014-04-08 02:27:49 +02001863 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001864 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001865 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001866
Mady Mellor34958fa2016-02-23 09:52:17 -08001867 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001868 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08001869 }
1870
Jorim Jaggibe565df2014-04-28 17:51:23 +02001871 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001872 public boolean isContentExpandable() {
Selim Cinekc0ac4af2017-03-03 15:13:48 -08001873 if (mIsSummaryWithChildren && !mShowingPublic) {
1874 return true;
1875 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001876 NotificationContentView showingLayout = getShowingLayout();
1877 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001878 }
1879
1880 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001881 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001882 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001883 return mChildrenContainer;
1884 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001885 return getShowingLayout();
1886 }
1887
1888 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001889 protected void onAppearAnimationFinished(boolean wasAppearing) {
1890 super.onAppearAnimationFinished(wasAppearing);
1891 if (wasAppearing) {
1892 // During the animation the visible view might have changed, so let's make sure all
1893 // alphas are reset
1894 if (mChildrenContainer != null) {
1895 mChildrenContainer.setAlpha(1.0f);
1896 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1897 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001898 for (NotificationContentView l : mLayouts) {
1899 l.setAlpha(1.0f);
1900 l.setLayerType(LAYER_TYPE_NONE, null);
1901 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07001902 }
1903 }
1904
1905 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001906 public int getExtraBottomPadding() {
1907 if (mIsSummaryWithChildren && isGroupExpanded()) {
1908 return mIncreasedPaddingBetweenElements;
1909 }
1910 return 0;
1911 }
1912
1913 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001914 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinek4ca6c632017-02-23 18:03:37 -08001915 boolean changed = height != getActualHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +01001916 super.setActualHeight(height, notifyListeners);
Selim Cinek4ca6c632017-02-23 18:03:37 -08001917 if (changed && isRemoved()) {
1918 // TODO: remove this once we found the gfx bug for this.
1919 // This is a hack since a removed view sometimes would just stay blank. it occured
1920 // when sending yourself a message and then clicking on it.
1921 ViewGroup parent = (ViewGroup) getParent();
1922 if (parent != null) {
1923 parent.invalidate();
1924 }
1925 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001926 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08001927 mGuts.setActualHeight(height);
1928 return;
1929 }
Selim Cinekeef84282015-10-30 16:28:00 -07001930 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001931 for (NotificationContentView l : mLayouts) {
1932 l.setContentHeight(contentHeight);
1933 }
Selim Cinek42357e02016-02-24 18:48:01 -08001934 if (mIsSummaryWithChildren) {
1935 mChildrenContainer.setActualHeight(height);
1936 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001937 if (mGuts != null) {
1938 mGuts.setActualHeight(height);
1939 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001940 }
1941
1942 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001943 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001944 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001945 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001946 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001947 NotificationContentView showingLayout = getShowingLayout();
1948 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001949 }
1950
1951 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001952 public int getMinHeight() {
Mady Mellore09fb702017-03-30 13:23:29 -07001953 if (mGuts != null && mGuts.isExposed()) {
1954 return mGuts.getIntrinsicHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07001955 } else if (isHeadsUpAllowed() && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08001956 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1957 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001958 return mChildrenContainer.getMinHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07001959 } else if (isHeadsUpAllowed() && mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001960 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001961 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001962 NotificationContentView showingLayout = getShowingLayout();
1963 return showingLayout.getMinHeight();
1964 }
1965
1966 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001967 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001968 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001969 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001970 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001971 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001972 }
1973
1974 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001975 public void setClipTopAmount(int clipTopAmount) {
1976 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001977 for (NotificationContentView l : mLayouts) {
1978 l.setClipTopAmount(clipTopAmount);
1979 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001980 if (mGuts != null) {
1981 mGuts.setClipTopAmount(clipTopAmount);
1982 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001983 }
1984
Selim Cineka686b2c2016-10-26 13:58:27 -07001985 @Override
1986 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001987 if (clipBottomAmount != mClipBottomAmount) {
1988 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001989 for (NotificationContentView l : mLayouts) {
1990 l.setClipBottomAmount(clipBottomAmount);
1991 }
Selim Cinek65d418e2016-11-29 15:42:34 -08001992 if (mGuts != null) {
1993 mGuts.setClipBottomAmount(clipBottomAmount);
1994 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001995 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001996 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001997 // We have to update this even if it hasn't changed, since the children locations can
1998 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001999 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
2000 }
Selim Cineka686b2c2016-10-26 13:58:27 -07002001 }
2002
Selim Cinek31094df2014-08-14 19:28:15 +02002003 public boolean isMaxExpandHeightInitialized() {
2004 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02002005 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002006
Selim Cinek42357e02016-02-24 18:48:01 -08002007 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02002008 return mShowingPublic ? mPublicLayout : mPrivateLayout;
2009 }
Chris Wren78403d72014-07-28 10:23:24 +01002010
Selim Cinek1a48bab2017-02-17 19:38:40 -08002011 public void setLegacy(boolean legacy) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08002012 for (NotificationContentView l : mLayouts) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08002013 l.setLegacy(legacy);
Adrian Rooseb434ff2017-01-11 11:18:48 -08002014 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07002015 }
2016
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002017 @Override
2018 protected void updateBackgroundTint() {
2019 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07002020 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002021 if (mIsSummaryWithChildren) {
2022 List<ExpandableNotificationRow> notificationChildren =
2023 mChildrenContainer.getNotificationChildren();
2024 for (int i = 0; i < notificationChildren.size(); i++) {
2025 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07002026 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002027 }
2028 }
2029 }
2030
Mady Mellorb0a82462016-04-30 17:31:02 -07002031 /**
2032 * Called when a group has finished animating from collapsed or expanded state.
2033 */
2034 public void onFinishedExpansionChange() {
2035 mGroupExpansionChanging = false;
2036 updateBackgroundForGroupState();
2037 }
2038
2039 /**
2040 * Updates the parent and children backgrounds in a group based on the expansion state.
2041 */
2042 public void updateBackgroundForGroupState() {
2043 if (mIsSummaryWithChildren) {
2044 // Only when the group has finished expanding do we hide its background.
Anthony Chen6bf88a02017-04-10 14:41:44 -07002045 mShowNoBackground = !mShowGroupBackgroundWhenExpanded && isGroupExpanded()
2046 && !isGroupExpansionChanging() && !isUserLocked();
Mady Mellorb0a82462016-04-30 17:31:02 -07002047 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
2048 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
2049 for (int i = 0; i < children.size(); i++) {
2050 children.get(i).updateBackgroundForGroupState();
2051 }
2052 } else if (isChildInGroup()) {
2053 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
2054 // Only show a background if the group is expanded OR if it is expanding / collapsing
Anthony Chen6bf88a02017-04-10 14:41:44 -07002055 // and has a custom background color.
Mady Mellorb0a82462016-04-30 17:31:02 -07002056 final boolean showBackground = isGroupExpanded()
2057 || ((mNotificationParent.isGroupExpansionChanging()
Anthony Chen6bf88a02017-04-10 14:41:44 -07002058 || mNotificationParent.isUserLocked()) && childColor != 0);
Mady Mellorb0a82462016-04-30 17:31:02 -07002059 mShowNoBackground = !showBackground;
2060 } else {
2061 // Only children or parents ever need no background.
2062 mShowNoBackground = false;
2063 }
2064 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002065 updateBackground();
2066 }
2067
Adrian Roos4a579672016-05-24 16:54:37 -07002068 public int getPositionOfChild(ExpandableNotificationRow childRow) {
2069 if (mIsSummaryWithChildren) {
2070 return mChildrenContainer.getPositionInLinearLayout(childRow);
2071 }
2072 return 0;
2073 }
2074
Chris Wren78403d72014-07-28 10:23:24 +01002075 public void setExpansionLogger(ExpansionLogger logger, String key) {
2076 mLogger = logger;
2077 mLoggingKey = key;
2078 }
2079
Chris Wren6abeeb92016-05-26 14:44:38 -04002080 public void onExpandedByGesture(boolean userExpanded) {
2081 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
2082 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
2083 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
2084 }
2085 MetricsLogger.action(mContext, event, userExpanded);
2086 }
2087
Selim Cinek6183d122016-01-14 18:48:41 -08002088 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08002089 public float getIncreasedPaddingAmount() {
2090 if (mIsSummaryWithChildren) {
2091 if (isGroupExpanded()) {
2092 return 1.0f;
2093 } else if (isUserLocked()) {
Selim Cinek414ad332017-02-24 19:06:12 -08002094 return mChildrenContainer.getIncreasedPaddingAmount();
Selim Cinek42357e02016-02-24 18:48:01 -08002095 }
Selim Cinek99104832017-01-25 14:47:33 -08002096 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08002097 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08002098 }
2099 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08002100 }
2101
Selim Cineka7ed2c12017-01-23 20:47:24 -08002102 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08002103 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08002104 }
2105
Selim Cinek61633a82016-01-25 15:54:10 -08002106 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08002107 protected boolean disallowSingleClick(MotionEvent event) {
2108 float x = event.getX();
2109 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08002110 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07002111 if (header != null && header.isInTouchRect(x - getTranslation(), y)) {
2112 return true;
2113 }
2114 if ((!mIsSummaryWithChildren || mShowingPublic)
2115 && getShowingLayout().disallowSingleClick(x, y)) {
2116 return true;
Selim Cinek6183d122016-01-14 18:48:41 -08002117 }
2118 return super.disallowSingleClick(event);
2119 }
2120
Selim Cinek414ad332017-02-24 19:06:12 -08002121 private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04002122 boolean nowExpanded = isExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08002123 if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
Chris Wren698b1702016-05-23 11:16:32 -04002124 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
2125 }
Selim Cinek414ad332017-02-24 19:06:12 -08002126 if (nowExpanded != wasExpanded) {
2127 updateShelfIconColor();
2128 if (mLogger != null) {
2129 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded);
2130 }
2131 if (mIsSummaryWithChildren) {
2132 mChildrenContainer.onExpansionChanged();
2133 }
Chris Wren78403d72014-07-28 10:23:24 +01002134 }
2135 }
Selim Cinek570981d2015-12-01 11:37:01 -08002136
Selim Cineke9bad242016-06-15 11:46:37 -07002137 @Override
2138 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2139 super.onInitializeAccessibilityNodeInfoInternal(info);
2140 if (canViewBeDismissed()) {
2141 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
2142 }
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002143 boolean expandable = mShowingPublic;
2144 boolean isExpanded = false;
2145 if (!expandable) {
2146 if (mIsSummaryWithChildren) {
2147 expandable = true;
2148 if (!mIsLowPriority || isExpanded()) {
2149 isExpanded = isGroupExpanded();
2150 }
2151 } else {
2152 expandable = mPrivateLayout.isContentExpandable();
2153 isExpanded = isExpanded();
2154 }
2155 }
2156 if (expandable) {
2157 if (isExpanded) {
2158 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
2159 } else {
2160 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
2161 }
2162 }
Selim Cineke9bad242016-06-15 11:46:37 -07002163 }
2164
2165 @Override
2166 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
2167 if (super.performAccessibilityActionInternal(action, arguments)) {
2168 return true;
2169 }
2170 switch (action) {
2171 case AccessibilityNodeInfo.ACTION_DISMISS:
2172 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
2173 true /* fromAccessibility */);
2174 return true;
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002175 case AccessibilityNodeInfo.ACTION_COLLAPSE:
2176 case AccessibilityNodeInfo.ACTION_EXPAND:
2177 mExpandClickListener.onClick(this);
2178 return true;
Selim Cineke9bad242016-06-15 11:46:37 -07002179 }
2180 return false;
2181 }
2182
2183 public boolean shouldRefocusOnDismiss() {
2184 return mRefocusOnDismiss || isAccessibilityFocused();
2185 }
2186
Selim Cinek570981d2015-12-01 11:37:01 -08002187 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08002188 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08002189 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002190
2191 @Override
2192 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
2193 return new NotificationViewState(stackScrollState);
2194 }
2195
Selim Cinekd127d792016-11-01 19:11:41 -07002196 @Override
2197 public boolean isAboveShelf() {
Selim Cinekc8007c52017-02-28 16:09:56 -08002198 return !isOnKeyguard()
2199 && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf));
Selim Cinekd127d792016-11-01 19:11:41 -07002200 }
2201
Adrian Roos0aac04f2016-12-08 15:59:29 -08002202 public void setShowAmbient(boolean showAmbient) {
2203 if (showAmbient != mShowAmbient) {
2204 mShowAmbient = showAmbient;
Adrian Roos6f6e1592017-05-02 16:22:53 -07002205 if (mChildrenContainer != null) {
2206 mChildrenContainer.notifyShowAmbientChanged();
2207 }
Adrian Roos0aac04f2016-12-08 15:59:29 -08002208 notifyHeightChanged(false /* needsAnimation */);
2209 }
2210 }
2211
Adrian Roos6f6e1592017-05-02 16:22:53 -07002212 public boolean isShowingAmbient() {
2213 return mShowAmbient;
2214 }
2215
Selim Cinekd127d792016-11-01 19:11:41 -07002216 public void setAboveShelf(boolean aboveShelf) {
2217 mAboveShelf = aboveShelf;
2218 }
2219
Selim Cinekd4776a52017-02-14 18:50:16 -08002220 public static class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08002221
2222 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07002223
Selim Cinekbbcebde2016-11-09 18:28:20 -08002224
2225 private NotificationViewState(StackScrollState stackScrollState) {
2226 mOverallState = stackScrollState;
2227 }
2228
2229 @Override
2230 public void applyToView(View view) {
2231 super.applyToView(view);
2232 if (view instanceof ExpandableNotificationRow) {
2233 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinekbbcebde2016-11-09 18:28:20 -08002234 row.applyChildrenState(mOverallState);
2235 }
2236 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002237
2238 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08002239 protected void onYTranslationAnimationFinished(View view) {
2240 super.onYTranslationAnimationFinished(view);
Selim Cinekd4776a52017-02-14 18:50:16 -08002241 if (view instanceof ExpandableNotificationRow) {
2242 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
2243 if (row.isHeadsUpAnimatingAway()) {
2244 row.setHeadsUpAnimatingAway(false);
2245 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002246 }
2247 }
2248
2249 @Override
2250 public void animateTo(View child, AnimationProperties properties) {
2251 super.animateTo(child, properties);
2252 if (child instanceof ExpandableNotificationRow) {
2253 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
2254 row.startChildAnimation(mOverallState, properties);
2255 }
2256 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002257 }
Selim Cinek817abe72017-05-24 11:08:55 -07002258
2259 @VisibleForTesting
2260 protected void setChildrenContainer(NotificationChildrenContainer childrenContainer) {
2261 mChildrenContainer = childrenContainer;
2262 }
Chris Wren51c75102013-07-16 20:49:17 -04002263}