blob: a81b140e57536e57a2ac95656bfd36f9f933d398 [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 Cinek2630dc72017-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;
Mady Mellord9c2232c2017-04-04 18:45:30 -070027import android.content.res.Resources;
28import 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 Cinek2630dc72017-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 Mellord9c2232c2017-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
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800174 private OnClickListener mExpandClickListener = new OnClickListener() {
175 @Override
176 public void onClick(View v) {
Selim Cinek414ad332017-02-24 19:06:12 -0800177 if (!mShowingPublic && (!mIsLowPriority || isExpanded())
178 && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700179 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400180 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
181 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
182 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400183 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
184 nowExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -0800185 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800186 } else {
Selim Cineke9bad242016-06-15 11:46:37 -0700187 if (v.isAccessibilityFocused()) {
188 mPrivateLayout.setFocusOnVisibilityChange();
189 }
Selim Cinek31aada42015-12-18 17:51:15 -0800190 boolean nowExpanded;
191 if (isPinned()) {
192 nowExpanded = !mExpandedWhenPinned;
193 mExpandedWhenPinned = nowExpanded;
194 } else {
195 nowExpanded = !isExpanded();
196 setUserExpanded(nowExpanded);
197 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800198 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800199 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400200 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
201 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800202 }
203 }
204 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700205 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700206 private boolean mDismissed;
207 private boolean mKeepInParent;
208 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700209 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
210 new FloatProperty<ExpandableNotificationRow>("translate") {
211 @Override
212 public void setValue(ExpandableNotificationRow object, float value) {
213 object.setTranslation(value);
214 }
215
216 @Override
217 public Float get(ExpandableNotificationRow object) {
218 return object.getTranslation();
219 }
220 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700221 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700222 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700223 private View mChildAfterViewWhenDismissed;
224 private View mGroupParentWhenDismissed;
225 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800226 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700227 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700228 private boolean mAboveShelf;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800229 private boolean mShowAmbient;
Selim Cinek875a3a12016-11-18 17:52:16 -0800230 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800231 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800232 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800233 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800234 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800235 private boolean mUseIncreasedHeadsUpHeight;
Selim Cinekef8c2252017-02-10 14:52:18 -0800236 private float mTranslationWhenRemoved;
237 private boolean mWasChildInGroupWhenRemoved;
Adrian Roos6f6e1592017-05-02 16:22:53 -0700238 private int mNotificationColorAmbient;
Mady Mellorb0a82462016-04-30 17:31:02 -0700239
Mady Mellor43c2cd12016-12-12 21:05:13 -0800240 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700241 public boolean isGroupExpansionChanging() {
242 if (isChildInGroup()) {
243 return mNotificationParent.isGroupExpansionChanging();
244 }
245 return mGroupExpansionChanging;
246 }
247
248 public void setGroupExpansionChanging(boolean changing) {
249 mGroupExpansionChanging = changing;
250 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700251
Adrian Roos599be342016-06-13 14:54:39 -0700252 @Override
253 public void setActualHeightAnimating(boolean animating) {
254 if (mPrivateLayout != null) {
255 mPrivateLayout.setContentHeightAnimating(animating);
256 }
257 }
258
Selim Cinek8d490d42015-04-10 00:05:50 -0700259 public NotificationContentView getPrivateLayout() {
260 return mPrivateLayout;
261 }
262
263 public NotificationContentView getPublicLayout() {
264 return mPublicLayout;
265 }
266
Selim Cinekcab4a602014-09-03 14:47:57 +0200267 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800268 for (NotificationContentView l : mLayouts) {
269 setIconAnimationRunning(running, l);
270 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800271 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700272 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek414ad332017-02-24 19:06:12 -0800273 setIconAnimationRunningForChild(running, mChildrenContainer.getLowPriorityHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800274 List<ExpandableNotificationRow> notificationChildren =
275 mChildrenContainer.getNotificationChildren();
276 for (int i = 0; i < notificationChildren.size(); i++) {
277 ExpandableNotificationRow child = notificationChildren.get(i);
278 child.setIconAnimationRunning(running);
279 }
280 }
281 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200282 }
283
284 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
285 if (layout != null) {
286 View contractedChild = layout.getContractedChild();
287 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700288 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200289 setIconAnimationRunningForChild(running, contractedChild);
290 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700291 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200292 }
293 }
294
295 private void setIconAnimationRunningForChild(boolean running, View child) {
296 if (child != null) {
297 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
298 setIconRunning(icon, running);
299 ImageView rightIcon = (ImageView) child.findViewById(
300 com.android.internal.R.id.right_icon);
301 setIconRunning(rightIcon, running);
302 }
303 }
304
305 private void setIconRunning(ImageView imageView, boolean running) {
306 if (imageView != null) {
307 Drawable drawable = imageView.getDrawable();
308 if (drawable instanceof AnimationDrawable) {
309 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
310 if (running) {
311 animationDrawable.start();
312 } else {
313 animationDrawable.stop();
314 }
315 } else if (drawable instanceof AnimatedVectorDrawable) {
316 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
317 if (running) {
318 animationDrawable.start();
319 } else {
320 animationDrawable.stop();
321 }
322 }
323 }
324 }
325
Selim Cinek2630dc72017-04-20 15:16:10 -0700326 public void updateNotification(NotificationData.Entry entry) {
Selim Cinekda42d652015-12-04 15:51:16 -0800327 mEntry = entry;
328 mStatusBarNotification = entry.notification;
Selim Cinek1a48bab2017-02-17 19:38:40 -0800329 mNotificationInflater.inflateNotificationViews();
Selim Cinekc478f902017-02-22 20:55:44 -0800330 }
331
Selim Cinek2630dc72017-04-20 15:16:10 -0700332 public void onNotificationUpdated() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800333 for (NotificationContentView l : mLayouts) {
Selim Cinekc478f902017-02-22 20:55:44 -0800334 l.onNotificationUpdated(mEntry);
Adrian Rooseb434ff2017-01-11 11:18:48 -0800335 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800336 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800337 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700338 updateNotificationColor();
Mady Mellor4c197602017-04-10 17:57:52 -0700339 if (mMenuRow != null) {
340 mMenuRow.onNotificationUpdated();
341 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800342 if (mIsSummaryWithChildren) {
Selim Cinek414ad332017-02-24 19:06:12 -0800343 mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
Selim Cinekc897bd32016-03-18 17:32:31 -0700344 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800345 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800346 if (mIconAnimationRunning) {
347 setIconAnimationRunning(true);
348 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800349 if (mNotificationParent != null) {
350 mNotificationParent.updateChildrenHeaderAppearance();
351 }
Selim Cinek263398f2015-10-21 17:40:23 -0700352 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800353 // The public layouts expand button is always visible
354 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800355 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700356 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800357 updateShelfIconColor();
358 }
359
360 private void updateShelfIconColor() {
361 StatusBarIconView expandedIcon = mEntry.expandedIcon;
362 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
363 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
364 NotificationColorUtil.getInstance(mContext));
Selim Cinek875ba9b2017-02-13 16:20:17 -0800365 int color = StatusBarIconView.NO_COLOR;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800366 if (colorize) {
Selim Cinekac5f0272017-05-02 16:05:41 -0700367 color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
368 getBackgroundColorWithoutTint());
Selim Cinek6743c0b2017-01-18 18:24:01 -0800369 }
Selim Cinek875ba9b2017-02-13 16:20:17 -0800370 expandedIcon.setStaticDrawableColor(color);
Selim Cinekda42d652015-12-04 15:51:16 -0800371 }
372
Selim Cinek63edaf22017-04-24 22:18:48 -0700373 @Override
374 public boolean isDimmable() {
375 if (!getShowingLayout().isDimmable()) {
376 return false;
377 }
378 return super.isDimmable();
379 }
380
Selim Cinekda42d652015-12-04 15:51:16 -0800381 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800382 for (NotificationContentView l : mLayouts) {
383 updateLimitsForView(l);
384 }
Selim Cineka1744872016-03-11 15:36:06 -0800385 }
386
387 private void updateLimitsForView(NotificationContentView layout) {
388 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800389 != com.android.internal.R.id.status_bar_latest_event_content;
390 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800391 int minHeight;
392 if (customView && beforeN && !mIsSummaryWithChildren) {
393 minHeight = mNotificationMinHeightLegacy;
394 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
395 minHeight = mNotificationMinHeightLarge;
396 } else {
397 minHeight = mNotificationMinHeight;
398 }
Selim Cineka1744872016-03-11 15:36:06 -0800399 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
400 layout.getHeadsUpChild().getId()
401 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800402 int headsUpheight;
403 if (headsUpCustom && beforeN) {
404 headsUpheight = mMaxHeadsUpHeightLegacy;
405 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
406 headsUpheight = mMaxHeadsUpHeightIncreased;
407 } else {
408 headsUpheight = mMaxHeadsUpHeight;
409 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800410 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
411 mNotificationAmbientHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200412 }
413
414 public StatusBarNotification getStatusBarNotification() {
415 return mStatusBarNotification;
416 }
417
Selim Cinek281c2022016-10-13 19:14:43 -0700418 public NotificationData.Entry getEntry() {
419 return mEntry;
420 }
421
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700422 public boolean isHeadsUp() {
423 return mIsHeadsUp;
424 }
425
Selim Cinek1a521f32014-11-03 17:39:29 +0100426 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700427 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100428 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700429 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700430 if (mIsSummaryWithChildren) {
431 // The overflow might change since we allow more lines as HUN.
432 mChildrenContainer.updateGroupOverflow();
433 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700434 if (intrinsicBefore != getIntrinsicHeight()) {
435 notifyHeightChanged(false /* needsAnimation */);
436 }
Selim Cinekd127d792016-11-01 19:11:41 -0700437 if (isHeadsUp) {
438 setAboveShelf(true);
439 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100440 }
441
Selim Cinekb5605e52015-02-20 18:21:41 +0100442 public void setGroupManager(NotificationGroupManager groupManager) {
443 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700444 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100445 }
446
Adrian Roosb88b1a12015-12-09 18:51:05 -0800447 public void setRemoteInputController(RemoteInputController r) {
448 mPrivateLayout.setRemoteInputController(r);
449 }
450
Mady Mellor3fd273e2016-03-15 21:08:14 -0700451 public void setAppName(String appName) {
452 mAppName = appName;
Mady Mellor95d743c2017-01-10 12:05:27 -0800453 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800454 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700455 }
456 }
457
Selim Cinekb5605e52015-02-20 18:21:41 +0100458 public void addChildNotification(ExpandableNotificationRow row) {
459 addChildNotification(row, -1);
460 }
461
462 /**
463 * Add a child notification to this view.
464 *
465 * @param row the row to add
466 * @param childIndex the index to add it at, if -1 it will be added at the end
467 */
468 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
469 if (mChildrenContainer == null) {
470 mChildrenContainerStub.inflate();
471 }
472 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700473 onChildrenCountChanged();
474 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100475 }
476
477 public void removeChildNotification(ExpandableNotificationRow row) {
478 if (mChildrenContainer != null) {
479 mChildrenContainer.removeNotification(row);
480 }
Selim Cinek263398f2015-10-21 17:40:23 -0700481 onChildrenCountChanged();
482 row.setIsChildInGroup(false, null);
483 }
484
Mady Mellor43c2cd12016-12-12 21:05:13 -0800485 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700486 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700487 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700488 }
489
Selim Cinek388df6d2015-10-22 13:25:11 -0700490 public ExpandableNotificationRow getNotificationParent() {
491 return mNotificationParent;
492 }
493
Selim Cinek263398f2015-10-21 17:40:23 -0700494 /**
495 * @param isChildInGroup Is this notification now in a group
496 * @param parent the new parent notification
497 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700498 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500499 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700500 mNotificationParent = childInGroup ? parent : null;
501 mPrivateLayout.setIsChildInGroup(childInGroup);
Selim Cinek2630dc72017-04-20 15:16:10 -0700502 mNotificationInflater.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400503 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700504 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700505 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700506 if (mNotificationParent != null) {
Selim Cinek9ce32852017-02-15 16:21:10 -0800507 setOverrideTintColor(NO_COLOR, 0.0f);
Mady Mellorb0a82462016-04-30 17:31:02 -0700508 mNotificationParent.updateBackgroundForGroupState();
509 }
Selim Cinekdb167372016-11-17 15:41:17 -0800510 updateIconVisibilities();
Selim Cinek34d93b02015-10-22 12:30:38 -0700511 }
512
513 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800514 public boolean onTouchEvent(MotionEvent event) {
515 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
516 || !isChildInGroup() || isGroupExpanded()) {
517 return super.onTouchEvent(event);
518 } else {
519 return false;
520 }
521 }
522
523 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800524 protected boolean handleSlideBack() {
Mady Mellor95d743c2017-01-10 12:05:27 -0800525 if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800526 animateTranslateNotification(0 /* targetLeft */);
527 return true;
528 }
529 return false;
530 }
531
532 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700533 protected boolean shouldHideBackground() {
534 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700535 }
536
537 @Override
538 public boolean isSummaryWithChildren() {
539 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100540 }
541
542 @Override
543 public boolean areChildrenExpanded() {
544 return mChildrenExpanded;
545 }
546
547 public List<ExpandableNotificationRow> getNotificationChildren() {
548 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
549 }
550
Selim Cinekeef84282015-10-30 16:28:00 -0700551 public int getNumberOfNotificationChildren() {
552 if (mChildrenContainer == null) {
553 return 0;
554 }
555 return mChildrenContainer.getNotificationChildren().size();
556 }
557
Selim Cinekb5605e52015-02-20 18:21:41 +0100558 /**
559 * Apply the order given in the list to the children.
560 *
561 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800562 * @param visualStabilityManager
563 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100564 * @return whether the list order has changed
565 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800566 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
567 VisualStabilityManager visualStabilityManager,
568 VisualStabilityManager.Callback callback) {
569 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
570 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100571 }
572
573 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700574 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800575 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100576 mChildrenContainer.getState(resultState, parentState);
577 }
578 }
579
580 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700581 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100582 mChildrenContainer.applyState(state);
583 }
584 }
585
586 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700587 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100588 mChildrenContainer.prepareExpansionChanged(state);
589 }
590 }
591
Selim Cinek0cfbef42016-11-09 19:06:36 -0800592 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700593 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800594 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100595 }
596 }
597
598 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800599 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100600 return this;
601 } else {
602 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
603 return view == null ? this : view;
604 }
605 }
606
Selim Cinekab29aeb2015-02-20 18:18:32 +0100607 public NotificationGuts getGuts() {
608 return mGuts;
609 }
610
Selim Cinek684a4422015-04-15 16:18:39 -0700611 /**
612 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
613 * the notification will be rendered on top of the screen.
614 *
615 * @param pinned whether it is pinned
616 */
617 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700618 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700619 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700620 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700621 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700622 }
Selim Cinek31aada42015-12-18 17:51:15 -0800623 if (pinned) {
624 setIconAnimationRunning(true);
625 mExpandedWhenPinned = false;
626 } else if (mExpandedWhenPinned) {
627 setUserExpanded(true);
628 }
Selim Cinek98713a42015-09-21 15:47:20 +0200629 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700630 }
631
Selim Cinek684a4422015-04-15 16:18:39 -0700632 public boolean isPinned() {
633 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700634 }
635
Selim Cinekd127d792016-11-01 19:11:41 -0700636 @Override
637 public int getPinnedHeadsUpHeight() {
638 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
639 }
640
Selim Cinek31aada42015-12-18 17:51:15 -0800641 /**
642 * @param atLeastMinHeight should the value returned be at least the minimum height.
643 * Used to avoid cyclic calls
644 * @return the height of the heads up notification when pinned
645 */
Selim Cinekd127d792016-11-01 19:11:41 -0700646 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800647 if (mIsSummaryWithChildren) {
648 return mChildrenContainer.getIntrinsicHeight();
649 }
Selim Cinek31aada42015-12-18 17:51:15 -0800650 if(mExpandedWhenPinned) {
651 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
652 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700653 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800654 } else {
655 return mHeadsUpHeight;
656 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700657 }
658
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700659 /**
660 * Mark whether this notification was just clicked, i.e. the user has just clicked this
661 * notification in this frame.
662 */
663 public void setJustClicked(boolean justClicked) {
664 mJustClicked = justClicked;
665 }
666
667 /**
668 * @return true if this notification has been clicked in this frame, false otherwise
669 */
670 public boolean wasJustClicked() {
671 return mJustClicked;
672 }
673
Selim Cinek98713a42015-09-21 15:47:20 +0200674 public void setChronometerRunning(boolean running) {
675 mLastChronometerRunning = running;
676 setChronometerRunning(running, mPrivateLayout);
677 setChronometerRunning(running, mPublicLayout);
678 if (mChildrenContainer != null) {
679 List<ExpandableNotificationRow> notificationChildren =
680 mChildrenContainer.getNotificationChildren();
681 for (int i = 0; i < notificationChildren.size(); i++) {
682 ExpandableNotificationRow child = notificationChildren.get(i);
683 child.setChronometerRunning(running);
684 }
685 }
686 }
687
688 private void setChronometerRunning(boolean running, NotificationContentView layout) {
689 if (layout != null) {
690 running = running || isPinned();
691 View contractedChild = layout.getContractedChild();
692 View expandedChild = layout.getExpandedChild();
693 View headsUpChild = layout.getHeadsUpChild();
694 setChronometerRunningForChild(running, contractedChild);
695 setChronometerRunningForChild(running, expandedChild);
696 setChronometerRunningForChild(running, headsUpChild);
697 }
698 }
699
700 private void setChronometerRunningForChild(boolean running, View child) {
701 if (child != null) {
702 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
703 if (chronometer instanceof Chronometer) {
704 ((Chronometer) chronometer).setStarted(running);
705 }
706 }
707 }
708
Selim Cinekea4bef72015-12-02 15:51:10 -0800709 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700710 if (mIsSummaryWithChildren) {
711 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700712 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800713 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700714 }
715
Selim Cinek414ad332017-02-24 19:06:12 -0800716 /**
717 * @return the currently visible notification header. This can be different from
718 * {@link #getNotificationHeader()} in case it is a low-priority group.
719 */
720 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700721 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek414ad332017-02-24 19:06:12 -0800722 return mChildrenContainer.getVisibleHeader();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800723 }
724 return getShowingLayout().getVisibleNotificationHeader();
725 }
726
Selim Cinek570981d2015-12-01 11:37:01 -0800727 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
728 mOnExpandClickListener = onExpandClickListener;
729 }
730
Selim Cinekddf1b392016-05-27 16:33:10 -0700731 @Override
732 public void setOnClickListener(@Nullable OnClickListener l) {
733 super.setOnClickListener(l);
734 mOnClickListener = l;
735 updateClickAndFocus();
736 }
737
738 private void updateClickAndFocus() {
739 boolean normalChild = !isChildInGroup() || isGroupExpanded();
740 boolean clickable = mOnClickListener != null && normalChild;
741 if (isFocusable() != normalChild) {
742 setFocusable(normalChild);
743 }
744 if (isClickable() != clickable) {
745 setClickable(clickable);
746 }
747 }
748
Selim Cinek31aada42015-12-18 17:51:15 -0800749 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
750 mHeadsUpManager = headsUpManager;
751 }
752
Mady Mellor87d79452017-01-10 11:52:52 -0800753 public void setGutsView(MenuItem item) {
Mady Mellor95d743c2017-01-10 12:05:27 -0800754 if (mGuts != null && item.getGutsView() instanceof GutsContent) {
755 ((GutsContent) item.getGutsView()).setGutsParent(mGuts);
756 mGuts.setGutsContent((GutsContent) item.getGutsView());
Mady Mellor87d79452017-01-10 11:52:52 -0800757 }
758 }
759
Mady Mellor95d743c2017-01-10 12:05:27 -0800760 @Override
761 protected void onAttachedToWindow() {
762 super.onAttachedToWindow();
763 Dependency.get(PluginManager.class).addPluginListener(this,
764 NotificationMenuRowPlugin.class, false /* Allow multiple */);
765 }
766
767 @Override
768 protected void onDetachedFromWindow() {
769 super.onDetachedFromWindow();
770 Dependency.get(PluginManager.class).removePluginListener(this);
771 }
772
773 @Override
774 public void onPluginConnected(NotificationMenuRowPlugin plugin, Context pluginContext) {
775 boolean existed = mMenuRow.getMenuView() != null;
776 if (existed) {
777 removeView(mMenuRow.getMenuView());
778 }
779 mMenuRow = plugin;
780 if (mMenuRow.useDefaultMenuItems()) {
Mady Mellor4c197602017-04-10 17:57:52 -0700781 ArrayList<MenuItem> items = new ArrayList<>();
782 items.add(NotificationMenuRow.createInfoItem(mContext));
783 items.add(NotificationMenuRow.createSnoozeItem(mContext));
784 mMenuRow.setMenuItems(items);
Mady Mellor95d743c2017-01-10 12:05:27 -0800785 }
786 if (existed) {
787 createMenu();
788 }
789 }
790
791 @Override
792 public void onPluginDisconnected(NotificationMenuRowPlugin plugin) {
793 boolean existed = mMenuRow.getMenuView() != null;
794 mMenuRow = new NotificationMenuRow(mContext); // Back to default
795 if (existed) {
796 createMenu();
797 }
798 }
799
800 public NotificationMenuRowPlugin createMenu() {
801 if (mMenuRow.getMenuView() == null) {
802 mMenuRow.createMenu(this);
803 mMenuRow.setAppName(mAppName);
804 FrameLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
805 LayoutParams.MATCH_PARENT);
806 addView(mMenuRow.getMenuView(), MENU_VIEW_INDEX, lp);
807 }
808 return mMenuRow;
809 }
810
Mady Mellor95d743c2017-01-10 12:05:27 -0800811 public NotificationMenuRowPlugin getProvider() {
812 return mMenuRow;
813 }
814
Selim Cinek1a48bab2017-02-17 19:38:40 -0800815 public void onDensityOrFontScaleChanged() {
Selim Cinek01af3342016-02-09 19:25:31 -0800816 initDimens();
Selim Cinek91f41ce2017-05-24 11:08:55 -0700817 // Let's update our childrencontainer. This is intentionally not guarded with
818 // mIsSummaryWithChildren since we might have had children but not anymore.
819 if (mChildrenContainer != null) {
820 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800821 }
822 if (mGuts != null) {
823 View oldGuts = mGuts;
824 int index = indexOfChild(oldGuts);
825 removeView(oldGuts);
826 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
827 R.layout.notification_guts, this, false);
828 mGuts.setVisibility(oldGuts.getVisibility());
829 addView(mGuts, index);
830 }
Mady Mellor95d743c2017-01-10 12:05:27 -0800831 View oldMenu = mMenuRow.getMenuView();
832 if (oldMenu != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800833 int menuIndex = indexOfChild(oldMenu);
834 removeView(oldMenu);
Mady Mellor95d743c2017-01-10 12:05:27 -0800835 mMenuRow.createMenu(ExpandableNotificationRow.this);
Mady Mellor761cde12017-01-10 11:36:39 -0800836 mMenuRow.setAppName(mAppName);
Mady Mellor95d743c2017-01-10 12:05:27 -0800837 addView(mMenuRow.getMenuView(), menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -0800838 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800839 for (NotificationContentView l : mLayouts) {
840 l.reInflateViews();
841 }
Selim Cinek1a48bab2017-02-17 19:38:40 -0800842 mNotificationInflater.onDensityOrFontScaleChanged();
843 onNotificationUpdated();
Selim Cinek01af3342016-02-09 19:25:31 -0800844 }
845
Mady Mellord9c2232c2017-04-04 18:45:30 -0700846 @Override
847 public void onConfigurationChanged(Configuration newConfig) {
848 if (mMenuRow.getMenuView() != null) {
849 mMenuRow.onConfigurationChanged();
850 }
851 }
852
Selim Cinekc3179332016-03-04 14:44:56 -0800853 public void setContentBackground(int customBackgroundColor, boolean animate,
854 NotificationContentView notificationContentView) {
855 if (getShowingLayout() == notificationContentView) {
856 setTintColor(customBackgroundColor, animate);
857 }
858 }
859
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700860 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800861 for (NotificationContentView l : mLayouts) {
862 l.closeRemoteInput();
863 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700864 }
865
Selim Cinekc897bd32016-03-18 17:32:31 -0700866 /**
867 * Set by how much the single line view should be indented.
868 */
869 public void setSingleLineWidthIndention(int indention) {
870 mPrivateLayout.setSingleLineWidthIndention(indention);
871 }
872
873 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700874 return mNotificationColor;
875 }
876
877 private void updateNotificationColor() {
878 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
Selim Cinekac5f0272017-05-02 16:05:41 -0700879 getStatusBarNotification().getNotification().color,
880 getBackgroundColorWithoutTint());
Adrian Roos6f6e1592017-05-02 16:22:53 -0700881 mNotificationColorAmbient = NotificationColorUtil.resolveAmbientColor(mContext,
882 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700883 }
884
885 public HybridNotificationView getSingleLineView() {
886 return mPrivateLayout.getSingleLineView();
887 }
888
Adrian Roos6f6e1592017-05-02 16:22:53 -0700889 public HybridNotificationView getAmbientSingleLineView() {
890 return getShowingLayout().getAmbientSingleLineChild();
891 }
892
Selim Cinekf07d0622016-03-21 19:52:52 -0700893 public boolean isOnKeyguard() {
894 return mOnKeyguard;
895 }
896
Selim Cinekc1e389d2016-04-07 11:02:57 -0700897 public void removeAllChildren() {
898 List<ExpandableNotificationRow> notificationChildren
899 = mChildrenContainer.getNotificationChildren();
900 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
901 for (int i = 0; i < clonedList.size(); i++) {
902 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700903 if (row.keepInParent()) {
904 continue;
905 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700906 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700907 row.setIsChildInGroup(false, null);
908 }
909 onChildrenCountChanged();
910 }
911
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700912 public void setForceUnlocked(boolean forceUnlocked) {
913 mForceUnlocked = forceUnlocked;
914 if (mIsSummaryWithChildren) {
915 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
916 for (ExpandableNotificationRow child : notificationChildren) {
917 child.setForceUnlocked(forceUnlocked);
918 }
919 }
920 }
921
Selim Cineke9bad242016-06-15 11:46:37 -0700922 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700923 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700924 mGroupParentWhenDismissed = mNotificationParent;
925 mRefocusOnDismiss = fromAccessibility;
926 mChildAfterViewWhenDismissed = null;
927 if (isChildInGroup()) {
928 List<ExpandableNotificationRow> notificationChildren =
929 mNotificationParent.getNotificationChildren();
930 int i = notificationChildren.indexOf(this);
931 if (i != -1 && i < notificationChildren.size() - 1) {
932 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
933 }
934 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700935 }
936
937 public boolean isDismissed() {
938 return mDismissed;
939 }
940
941 public boolean keepInParent() {
942 return mKeepInParent;
943 }
944
945 public void setKeepInParent(boolean keepInParent) {
946 mKeepInParent = keepInParent;
947 }
948
949 public boolean isRemoved() {
950 return mRemoved;
951 }
952
Adrian Roosd009ab12016-05-20 17:58:53 -0700953 public void setRemoved() {
954 mRemoved = true;
Selim Cinekef8c2252017-02-10 14:52:18 -0800955 mTranslationWhenRemoved = getTranslationY();
956 mWasChildInGroupWhenRemoved = isChildInGroup();
957 if (isChildInGroup()) {
958 mTranslationWhenRemoved += getNotificationParent().getTranslationY();
959 }
Adrian Roosd009ab12016-05-20 17:58:53 -0700960 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700961 }
962
Selim Cinekef8c2252017-02-10 14:52:18 -0800963 public boolean wasChildInGroupWhenRemoved() {
964 return mWasChildInGroupWhenRemoved;
965 }
966
967 public float getTranslationWhenRemoved() {
968 return mTranslationWhenRemoved;
969 }
970
Selim Cinekd1395642016-04-28 12:22:42 -0700971 public NotificationChildrenContainer getChildrenContainer() {
972 return mChildrenContainer;
973 }
974
Selim Cinekcafa87f2016-10-26 17:00:17 -0700975 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
976 mHeadsupDisappearRunning = headsUpAnimatingAway;
977 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
978 }
979
980 /**
981 * @return if the view was just heads upped and is now animating away. During such a time the
982 * layout needs to be kept consistent
983 */
984 public boolean isHeadsUpAnimatingAway() {
985 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700986 }
987
Selim Cineke9bad242016-06-15 11:46:37 -0700988 public View getChildAfterViewWhenDismissed() {
989 return mChildAfterViewWhenDismissed;
990 }
991
992 public View getGroupParentWhenDismissed() {
993 return mGroupParentWhenDismissed;
994 }
995
Selim Cinek9e624e72016-07-20 13:46:49 -0700996 public void performDismiss() {
Selim Cineke9079112016-12-14 14:41:01 -0800997 if (mOnDismissRunnable != null) {
998 mOnDismissRunnable.run();
999 }
Selim Cinek9e624e72016-07-20 13:46:49 -07001000 }
1001
Selim Cineke9079112016-12-14 14:41:01 -08001002 public void setOnDismissRunnable(Runnable onDismissRunnable) {
1003 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -07001004 }
1005
Selim Cinek281c2022016-10-13 19:14:43 -07001006 public View getNotificationIcon() {
Selim Cinek414ad332017-02-24 19:06:12 -08001007 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek281c2022016-10-13 19:14:43 -07001008 if (notificationHeader != null) {
1009 return notificationHeader.getIcon();
1010 }
1011 return null;
1012 }
1013
1014 /**
1015 * @return whether the notification is currently showing a view with an icon.
1016 */
1017 public boolean isShowingIcon() {
Mady Mellor434180c2017-02-13 11:29:42 -08001018 if (areGutsExposed()) {
1019 return false;
1020 }
Selim Cinek2ffa02f2017-03-06 15:56:37 -08001021 return getVisibleNotificationHeader() != null;
Selim Cinek281c2022016-10-13 19:14:43 -07001022 }
1023
Selim Cinek0242fbb2016-10-19 13:38:32 -07001024 /**
1025 * Set how much this notification is transformed into an icon.
1026 *
Selim Cinek2b549f42016-11-22 16:38:51 -08001027 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
1028 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -08001029 * @param isLastChild is this the last child in the list. If true, then the transformation is
1030 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -07001031 */
Selim Cinek2b549f42016-11-22 16:38:51 -08001032 public void setContentTransformationAmount(float contentTransformationAmount,
1033 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -08001034 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001035 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001036 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001037 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001038 if (changeTransformation) {
1039 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -08001040 }
1041 }
1042
1043 /**
1044 * Set the icons to be visible of this notification.
1045 */
1046 public void setIconsVisible(boolean iconsVisible) {
1047 if (iconsVisible != mIconsVisible) {
1048 mIconsVisible = iconsVisible;
1049 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -07001050 }
1051 }
1052
Selim Cinekdb167372016-11-17 15:41:17 -08001053 @Override
1054 protected void onBelowSpeedBumpChanged() {
1055 updateIconVisibilities();
1056 }
1057
Selim Cinek875a3a12016-11-18 17:52:16 -08001058 private void updateContentTransformation() {
1059 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -08001060 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -08001061 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -08001062 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001063 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001064 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -08001065 translationY *= 0.4f;
1066 } else {
1067 contentAlpha = 1.0f;
1068 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001069 for (NotificationContentView l : mLayouts) {
1070 l.setAlpha(contentAlpha);
1071 l.setTranslationY(translationY);
1072 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001073 if (mChildrenContainer != null) {
1074 mChildrenContainer.setAlpha(contentAlpha);
1075 mChildrenContainer.setTranslationY(translationY);
1076 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -07001077 }
1078 }
1079
1080 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -08001081 boolean visible = isChildInGroup()
1082 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
1083 || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -08001084 for (NotificationContentView l : mLayouts) {
1085 l.setIconsVisible(visible);
1086 }
Selim Cinekdb167372016-11-17 15:41:17 -08001087 if (mChildrenContainer != null) {
1088 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001089 }
1090 }
1091
Selim Cinek875a3a12016-11-18 17:52:16 -08001092 /**
1093 * Get the relative top padding of a view relative to this view. This recursively walks up the
1094 * hierarchy and does the corresponding measuring.
1095 *
1096 * @param view the view to the the padding for. The requested view has to be a child of this
1097 * notification.
1098 * @return the toppadding
1099 */
1100 public int getRelativeTopPadding(View view) {
1101 int topPadding = 0;
1102 while (view.getParent() instanceof ViewGroup) {
1103 topPadding += view.getTop();
1104 view = (View) view.getParent();
1105 if (view instanceof ExpandableNotificationRow) {
1106 return topPadding;
1107 }
1108 }
1109 return topPadding;
1110 }
1111
Selim Cineka1d97902016-12-14 16:31:40 -08001112 public float getContentTranslation() {
1113 return mPrivateLayout.getTranslationY();
1114 }
1115
Selim Cinek6743c0b2017-01-18 18:24:01 -08001116 public void setIsLowPriority(boolean isLowPriority) {
1117 mIsLowPriority = isLowPriority;
1118 mPrivateLayout.setIsLowPriority(isLowPriority);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001119 mNotificationInflater.setIsLowPriority(mIsLowPriority);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001120 if (mChildrenContainer != null) {
1121 mChildrenContainer.setIsLowPriority(isLowPriority);
1122 }
1123 }
1124
Selim Cinek55a3e732017-05-25 18:30:10 -07001125
1126 public void setLowPriorityStateUpdated(boolean lowPriorityStateUpdated) {
1127 mLowPriorityStateUpdated = lowPriorityStateUpdated;
1128 }
1129
1130 public boolean hasLowPriorityStateUpdated() {
1131 return mLowPriorityStateUpdated;
1132 }
1133
Selim Cinek414ad332017-02-24 19:06:12 -08001134 public boolean isLowPriority() {
1135 return mIsLowPriority;
1136 }
1137
Selim Cinek7d1009b2017-01-25 15:28:28 -08001138 public void setUseIncreasedCollapsedHeight(boolean use) {
1139 mUseIncreasedCollapsedHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001140 mNotificationInflater.setUsesIncreasedHeight(use);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001141 }
1142
Selim Cinek87ed69b2017-02-09 15:59:43 -08001143 public void setUseIncreasedHeadsUpHeight(boolean use) {
1144 mUseIncreasedHeadsUpHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001145 mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
1146 }
1147
1148 public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
1149 mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001150 }
1151
Selim Cinek2630dc72017-04-20 15:16:10 -07001152 public void setInflationCallback(InflationCallback callback) {
1153 mNotificationInflater.setInflationCallback(callback);
Selim Cinekc478f902017-02-22 20:55:44 -08001154 }
1155
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001156 public void setNeedsRedaction(boolean needsRedaction) {
1157 mNotificationInflater.setRedactAmbient(needsRedaction);
1158 }
1159
Selim Cinek2630dc72017-04-20 15:16:10 -07001160 @VisibleForTesting
1161 public NotificationInflater getNotificationInflater() {
1162 return mNotificationInflater;
1163 }
1164
Adrian Roos6f6e1592017-05-02 16:22:53 -07001165 public int getNotificationColorAmbient() {
1166 return mNotificationColorAmbient;
1167 }
1168
Chris Wren78403d72014-07-28 10:23:24 +01001169 public interface ExpansionLogger {
1170 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
1171 }
Selim Cinek1685e632014-04-08 02:27:49 +02001172
Chris Wren51c75102013-07-16 20:49:17 -04001173 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1174 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001175 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001176 mNotificationInflater = new NotificationInflater(this);
Mady Mellor95d743c2017-01-10 12:05:27 -08001177 mMenuRow = new NotificationMenuRow(mContext);
Selim Cinek01af3342016-02-09 19:25:31 -08001178 initDimens();
1179 }
1180
1181 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -08001182 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
1183 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001184 mNotificationMinHeightLarge = getFontScaledHeight(
Selim Cinek87ed69b2017-02-09 15:59:43 -08001185 R.dimen.notification_min_height_increased);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001186 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
Adrian Roos0aac04f2016-12-08 15:59:29 -08001187 mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001188 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -08001189 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001190 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001191 mMaxHeadsUpHeightIncreased = getFontScaledHeight(
1192 R.dimen.notification_max_heads_up_height_increased);
Mady Mellorb0a82462016-04-30 17:31:02 -07001193 mIncreasedPaddingBetweenElements = getResources()
1194 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinek875a3a12016-11-18 17:52:16 -08001195 mIconTransformContentShiftNoIcon = getResources().getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001196 R.dimen.notification_icon_transform_content_shift);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001197 }
1198
1199 /**
1200 * @param dimenId the dimen to look up
1201 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
1202 */
1203 private int getFontScaledHeight(int dimenId) {
1204 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
1205 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
1206 getResources().getDisplayMetrics().density);
1207 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -04001208 }
1209
Christoph Studera7fe6312014-06-27 19:32:44 +02001210 /**
1211 * Resets this view so it can be re-used for an updated notification.
1212 */
1213 public void reset() {
Jorim Jaggiae441282014-08-01 02:45:18 +02001214 mShowingPublicInitialized = false;
Selim Cinek31094df2014-08-14 19:28:15 +02001215 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001216 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001217 }
1218
Jorim Jaggi251957d2014-04-09 04:24:09 +02001219 @Override
1220 protected void onFinishInflate() {
1221 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001222 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1223 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001224 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1225
1226 for (NotificationContentView l : mLayouts) {
1227 l.setExpandClickListener(mExpandClickListener);
1228 l.setContainingNotification(this);
1229 }
Selim Cinekab29aeb2015-02-20 18:18:32 +01001230 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1231 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001232 @Override
1233 public void onInflate(ViewStub stub, View inflated) {
1234 mGuts = (NotificationGuts) inflated;
1235 mGuts.setClipTopAmount(getClipTopAmount());
1236 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001237 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001238 }
1239 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001240 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1241 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1242
1243 @Override
1244 public void onInflate(ViewStub stub, View inflated) {
1245 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001246 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek414ad332017-02-24 19:06:12 -08001247 mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001248 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -08001249 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +01001250 }
1251 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001252
Mady Mellor95d743c2017-01-10 12:05:27 -08001253 // Add the views that we translate to reveal the menu
Mady Mellor4b80b102016-01-22 08:03:58 -08001254 mTranslateableViews = new ArrayList<View>();
1255 for (int i = 0; i < getChildCount(); i++) {
1256 mTranslateableViews.add(getChildAt(i));
1257 }
1258 // Remove views that don't translate
Mady Mellor4b80b102016-01-22 08:03:58 -08001259 mTranslateableViews.remove(mChildrenContainerStub);
1260 mTranslateableViews.remove(mGutsStub);
1261 }
1262
Mady Mellor4b80b102016-01-22 08:03:58 -08001263 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001264 if (mTranslateAnim != null) {
1265 mTranslateAnim.cancel();
1266 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001267 if (mTranslateableViews != null) {
1268 for (int i = 0; i < mTranslateableViews.size(); i++) {
1269 mTranslateableViews.get(i).setTranslationX(0);
1270 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001271 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001272 invalidateOutline();
Mady Mellor95d743c2017-01-10 12:05:27 -08001273 mMenuRow.resetMenu();
Mady Mellor4b80b102016-01-22 08:03:58 -08001274 }
1275
1276 public void animateTranslateNotification(final float leftTarget) {
1277 if (mTranslateAnim != null) {
1278 mTranslateAnim.cancel();
1279 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001280 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001281 if (mTranslateAnim != null) {
1282 mTranslateAnim.start();
1283 }
1284 }
1285
1286 @Override
1287 public void setTranslation(float translationX) {
1288 if (areGutsExposed()) {
1289 // Don't translate if guts are showing.
1290 return;
1291 }
1292 // Translate the group of views
1293 for (int i = 0; i < mTranslateableViews.size(); i++) {
1294 if (mTranslateableViews.get(i) != null) {
1295 mTranslateableViews.get(i).setTranslationX(translationX);
1296 }
1297 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001298 invalidateOutline();
Mady Mellor95d743c2017-01-10 12:05:27 -08001299 if (mMenuRow.getMenuView() != null) {
1300 mMenuRow.onTranslationUpdate(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001301 }
1302 }
1303
1304 @Override
1305 public float getTranslation() {
1306 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1307 // All of the views in the list should have same translation, just use first one.
1308 return mTranslateableViews.get(0).getTranslationX();
1309 }
1310 return 0;
1311 }
1312
1313 public Animator getTranslateViewAnimator(final float leftTarget,
1314 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001315 if (mTranslateAnim != null) {
1316 mTranslateAnim.cancel();
1317 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001318 if (areGutsExposed()) {
1319 // No translation if guts are exposed.
1320 return null;
1321 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001322 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1323 leftTarget);
1324 if (listener != null) {
1325 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001326 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001327 translateAnim.addListener(new AnimatorListenerAdapter() {
1328 boolean cancelled = false;
1329
1330 @Override
1331 public void onAnimationCancel(Animator anim) {
1332 cancelled = true;
1333 }
1334
1335 @Override
1336 public void onAnimationEnd(Animator anim) {
Mady Mellor95d743c2017-01-10 12:05:27 -08001337 if (!cancelled && leftTarget == 0) {
1338 mMenuRow.resetMenu();
Mady Mellorb0a82462016-04-30 17:31:02 -07001339 mTranslateAnim = null;
1340 }
1341 }
1342 });
1343 mTranslateAnim = translateAnim;
1344 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001345 }
1346
Selim Cinekab29aeb2015-02-20 18:18:32 +01001347 public void inflateGuts() {
1348 if (mGuts == null) {
1349 mGutsStub.inflate();
1350 }
1351 }
1352
Selim Cinekda42d652015-12-04 15:51:16 -08001353 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001354 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1355 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001356 if (mChildrenContainer != null) {
1357 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1358 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001359 }
Selim Cinekda42d652015-12-04 15:51:16 -08001360 // The limits might have changed if the view suddenly became a group or vice versa
1361 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001362 }
1363
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001364 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001365 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1366 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001367 // Add a record for the entire layout since its content is somehow small.
1368 // The event comes from a leaf view that is interacted with.
1369 AccessibilityEvent record = AccessibilityEvent.obtain();
1370 onInitializeAccessibilityEvent(record);
1371 dispatchPopulateAccessibilityEvent(record);
1372 event.appendRecord(record);
1373 return true;
1374 }
1375 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001376 }
Chris Wren51c75102013-07-16 20:49:17 -04001377
John Spurlocke15452b2014-08-21 09:44:39 -04001378 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001379 public void setDark(boolean dark, boolean fade, long delay) {
1380 super.setDark(dark, fade, delay);
Adrian Roos28f90c72017-05-08 17:24:26 -07001381 if (!mIsHeadsUp) {
1382 // Only fade the showing view of the pulsing notification.
1383 fade = false;
1384 }
John Spurlocke15452b2014-08-21 09:44:39 -04001385 final NotificationContentView showing = getShowingLayout();
1386 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001387 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001388 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001389 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001390 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001391 }
John Spurlocke15452b2014-08-21 09:44:39 -04001392 }
1393
Chris Wren51c75102013-07-16 20:49:17 -04001394 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001395 if (mIsSummaryWithChildren && !mShowingPublic) {
1396 return !mChildrenExpanded;
1397 }
Chris Wren51c75102013-07-16 20:49:17 -04001398 return mExpandable;
1399 }
1400
1401 public void setExpandable(boolean expandable) {
1402 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001403 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001404 }
1405
Selim Cinek4ffd6362015-12-29 15:12:23 +01001406 @Override
1407 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001408 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1409 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001410 }
1411
Selim Cinek1685e632014-04-08 02:27:49 +02001412 /**
1413 * @return whether the user has changed the expansion state
1414 */
1415 public boolean hasUserChangedExpansion() {
1416 return mHasUserChangedExpansion;
1417 }
1418
Chris Wren51c75102013-07-16 20:49:17 -04001419 public boolean isUserExpanded() {
1420 return mUserExpanded;
1421 }
1422
Selim Cinek1685e632014-04-08 02:27:49 +02001423 /**
1424 * Set this notification to be expanded by the user
1425 *
1426 * @param userExpanded whether the user wants this notification to be expanded
1427 */
Chris Wren51c75102013-07-16 20:49:17 -04001428 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001429 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1430 }
1431
1432 /**
1433 * Set this notification to be expanded by the user
1434 *
1435 * @param userExpanded whether the user wants this notification to be expanded
1436 * @param allowChildExpansion whether a call to this method allows expanding children
1437 */
1438 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001439 mFalsingManager.setNotificationExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08001440 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion
1441 && !mChildrenContainer.showingAsLowPriority()) {
Chris Wren698b1702016-05-23 11:16:32 -04001442 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001443 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -08001444 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001445 return;
1446 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001447 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001448 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001449 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001450 mUserExpanded = userExpanded;
Selim Cinek414ad332017-02-24 19:06:12 -08001451 onExpansionChanged(true /* userAction */, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001452 }
1453
Selim Cinekccd14fb2014-08-12 18:53:24 +02001454 public void resetUserExpansion() {
Selim Cinek414ad332017-02-24 19:06:12 -08001455 boolean changed = mUserExpanded;
Selim Cinekccd14fb2014-08-12 18:53:24 +02001456 mHasUserChangedExpansion = false;
1457 mUserExpanded = false;
Selim Cinek414ad332017-02-24 19:06:12 -08001458 if (changed && mIsSummaryWithChildren) {
1459 mChildrenContainer.onExpansionChanged();
1460 }
1461 updateShelfIconColor();
Selim Cinekccd14fb2014-08-12 18:53:24 +02001462 }
1463
Chris Wren51c75102013-07-16 20:49:17 -04001464 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001465 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001466 }
1467
1468 public void setUserLocked(boolean userLocked) {
1469 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001470 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek91f41ce2017-05-24 11:08:55 -07001471 // This is intentionally not guarded with mIsSummaryWithChildren since we might have had
1472 // children but not anymore.
1473 if (mChildrenContainer != null) {
Selim Cinek42357e02016-02-24 18:48:01 -08001474 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek91f41ce2017-05-24 11:08:55 -07001475 if (mIsSummaryWithChildren && (userLocked || !isGroupExpanded())) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001476 updateBackgroundForGroupState();
1477 }
Selim Cinek42357e02016-02-24 18:48:01 -08001478 }
Chris Wren51c75102013-07-16 20:49:17 -04001479 }
1480
Selim Cinek1685e632014-04-08 02:27:49 +02001481 /**
1482 * @return has the system set this notification to be expanded
1483 */
1484 public boolean isSystemExpanded() {
1485 return mIsSystemExpanded;
1486 }
1487
1488 /**
1489 * Set this notification to be expanded by the system.
1490 *
1491 * @param expand whether the system wants this notification to be expanded.
1492 */
1493 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001494 if (expand != mIsSystemExpanded) {
1495 final boolean wasExpanded = isExpanded();
1496 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001497 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek414ad332017-02-24 19:06:12 -08001498 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001499 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001500 mChildrenContainer.updateGroupOverflow();
1501 }
Selim Cinek31094df2014-08-14 19:28:15 +02001502 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001503 }
1504
1505 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001506 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001507 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001508 public void setOnKeyguard(boolean onKeyguard) {
1509 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001510 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001511 mOnKeyguard = onKeyguard;
Selim Cinek414ad332017-02-24 19:06:12 -08001512 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cinek31094df2014-08-14 19:28:15 +02001513 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001514 if (mIsSummaryWithChildren) {
1515 mChildrenContainer.updateGroupOverflow();
1516 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001517 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001518 }
1519 }
Selim Cinek1685e632014-04-08 02:27:49 +02001520 }
1521
1522 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001523 * @return Can the underlying notification be cleared? This can be different from whether the
1524 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1525 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001526 */
1527 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001528 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1529 return false;
1530 }
1531 if (mIsSummaryWithChildren) {
1532 List<ExpandableNotificationRow> notificationChildren =
1533 mChildrenContainer.getNotificationChildren();
1534 for (int i = 0; i < notificationChildren.size(); i++) {
1535 ExpandableNotificationRow child = notificationChildren.get(i);
1536 if (!child.isClearable()) {
1537 return false;
1538 }
1539 }
1540 }
1541 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001542 }
1543
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001544 @Override
1545 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001546 if (isUserLocked()) {
1547 return getActualHeight();
1548 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001549 if (mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07001550 return mGuts.getIntrinsicHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001551 } else if ((isChildInGroup() && !isGroupExpanded())) {
1552 return mPrivateLayout.getMinHeight();
1553 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1554 return getMinHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07001555 } else if (mIsSummaryWithChildren && (!mOnKeyguard || mShowAmbient)) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001556 return mChildrenContainer.getIntrinsicHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07001557 } else if (isHeadsUpAllowed() && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07001558 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001559 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1560 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001561 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001562 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001563 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001564 }
Selim Cinek31aada42015-12-18 17:51:15 -08001565 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001566 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001567 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001568 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001569 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001570 }
Selim Cinek1685e632014-04-08 02:27:49 +02001571
Adrian Roos6f6e1592017-05-02 16:22:53 -07001572 private boolean isHeadsUpAllowed() {
1573 return !mOnKeyguard && !mShowAmbient;
1574 }
1575
Mady Mellor43c2cd12016-12-12 21:05:13 -08001576 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001577 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001578 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001579 }
1580
Selim Cinek263398f2015-10-21 17:40:23 -07001581 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05001582 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001583 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1584 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
Selim Cinek414ad332017-02-24 19:06:12 -08001585 mChildrenContainer.recreateNotificationHeader(mExpandClickListener
1586 );
Selim Cinek263398f2015-10-21 17:40:23 -07001587 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001588 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001589 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001590 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001591 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001592 }
1593
Mady Mellorb0a82462016-04-30 17:31:02 -07001594 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001595 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001596 mChildrenContainer.updateChildrenHeaderAppearance();
1597 }
1598 }
1599
Selim Cinek1685e632014-04-08 02:27:49 +02001600 /**
1601 * Check whether the view state is currently expanded. This is given by the system in {@link
1602 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1603 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1604 * view can differ from this state, if layout params are modified from outside.
1605 *
1606 * @return whether the view state is currently expanded.
1607 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001608 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001609 return isExpanded(false /* allowOnKeyguard */);
1610 }
1611
1612 public boolean isExpanded(boolean allowOnKeyguard) {
1613 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001614 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1615 || isUserExpanded());
1616 }
1617
1618 private boolean isSystemChildExpanded() {
1619 return mIsSystemChildExpanded;
1620 }
1621
1622 public void setSystemChildExpanded(boolean expanded) {
1623 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001624 }
1625
Mady Mellord9c2232c2017-04-04 18:45:30 -07001626 public void setLayoutListener(LayoutListener listener) {
1627 mLayoutListener = listener;
1628 }
1629
1630 public void removeListener() {
1631 mLayoutListener = null;
1632 }
1633
Selim Cinek1685e632014-04-08 02:27:49 +02001634 @Override
1635 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1636 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001637 updateMaxHeights();
Mady Mellor95d743c2017-01-10 12:05:27 -08001638 if (mMenuRow.getMenuView() != null) {
1639 mMenuRow.onHeightUpdate();
Mady Mellora6edc872016-04-26 11:01:03 -07001640 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001641 updateContentShiftHeight();
Mady Mellord9c2232c2017-04-04 18:45:30 -07001642 if (mLayoutListener != null) {
1643 mLayoutListener.onLayout();
1644 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001645 }
1646
1647 /**
1648 * Updates the content shift height such that the header is completely hidden when coming from
1649 * the top.
1650 */
1651 private void updateContentShiftHeight() {
Selim Cinek414ad332017-02-24 19:06:12 -08001652 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek875a3a12016-11-18 17:52:16 -08001653 if (notificationHeader != null) {
1654 CachingIconView icon = notificationHeader.getIcon();
1655 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1656 } else {
1657 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1658 }
Selim Cinek1685e632014-04-08 02:27:49 +02001659 }
1660
Selim Cinek8d490d42015-04-10 00:05:50 -07001661 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001662 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001663 View expandedChild = mPrivateLayout.getExpandedChild();
1664 if (expandedChild == null) {
1665 expandedChild = mPrivateLayout.getContractedChild();
1666 }
1667 mMaxExpandHeight = expandedChild.getHeight();
1668 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001669 if (headsUpChild == null) {
1670 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001671 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001672 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001673 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001674 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001675 }
1676 }
1677
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001678 @Override
1679 public void notifyHeightChanged(boolean needsAnimation) {
1680 super.notifyHeightChanged(needsAnimation);
1681 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1682 }
1683
Selim Cinek3c76d502016-02-19 15:16:33 -08001684 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001685 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001686 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001687 }
1688
Mady Mellor43c2cd12016-12-12 21:05:13 -08001689 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001690 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001691 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001692 if (mIsSummaryWithChildren) {
1693 List<ExpandableNotificationRow> notificationChildren =
1694 mChildrenContainer.getNotificationChildren();
1695 for (int i = 0; i < notificationChildren.size(); i++) {
1696 ExpandableNotificationRow child = notificationChildren.get(i);
1697 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1698 }
1699 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001700 }
1701
Mady Mellor43c2cd12016-12-12 21:05:13 -08001702 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001703 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1704 long duration) {
1705 boolean oldShowingPublic = mShowingPublic;
1706 mShowingPublic = mSensitive && hideSensitive;
1707 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1708 return;
1709 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001710
1711 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001712 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001713
Jorim Jaggiae441282014-08-01 02:45:18 +02001714 if (!animated) {
1715 mPublicLayout.animate().cancel();
1716 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001717 if (mChildrenContainer != null) {
1718 mChildrenContainer.animate().cancel();
1719 mChildrenContainer.setAlpha(1f);
1720 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001721 mPublicLayout.setAlpha(1f);
1722 mPrivateLayout.setAlpha(1f);
1723 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001724 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001725 } else {
1726 animateShowingPublic(delay, duration);
1727 }
Selim Cinekc3179332016-03-04 14:44:56 -08001728 NotificationContentView showingLayout = getShowingLayout();
1729 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001730 mPrivateLayout.updateExpandButtons(isExpandable());
Adrian Roose5726a22016-12-19 14:26:51 -08001731 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02001732 mShowingPublicInitialized = true;
1733 }
1734
1735 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001736 View[] privateViews = mIsSummaryWithChildren
1737 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001738 : new View[] {mPrivateLayout};
1739 View[] publicViews = new View[] {mPublicLayout};
1740 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1741 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1742 for (final View hiddenView : hiddenChildren) {
1743 hiddenView.setVisibility(View.VISIBLE);
1744 hiddenView.animate().cancel();
1745 hiddenView.animate()
1746 .alpha(0f)
1747 .setStartDelay(delay)
1748 .setDuration(duration)
1749 .withEndAction(new Runnable() {
1750 @Override
1751 public void run() {
1752 hiddenView.setVisibility(View.INVISIBLE);
1753 }
1754 });
1755 }
1756 for (View showView : shownChildren) {
1757 showView.setVisibility(View.VISIBLE);
1758 showView.setAlpha(0f);
1759 showView.animate().cancel();
1760 showView.animate()
1761 .alpha(1f)
1762 .setStartDelay(delay)
1763 .setDuration(duration);
1764 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001765 }
1766
Mady Mellor43c2cd12016-12-12 21:05:13 -08001767 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08001768 public boolean mustStayOnScreen() {
1769 return mIsHeadsUp;
1770 }
1771
Selim Cinek9e624e72016-07-20 13:46:49 -07001772 /**
1773 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1774 * otherwise some state might not be updated. To request about the general clearability
1775 * see {@link #isClearable()}.
1776 */
1777 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001778 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001779 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001780
Ricky Waicd35def2016-05-03 11:07:07 +01001781 public void makeActionsVisibile() {
1782 setUserExpanded(true, true);
1783 if (isChildInGroup()) {
1784 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1785 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001786 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001787 }
1788
Selim Cinekb5605e52015-02-20 18:21:41 +01001789 public void setChildrenExpanded(boolean expanded, boolean animate) {
1790 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001791 if (mChildrenContainer != null) {
1792 mChildrenContainer.setChildrenExpanded(expanded);
1793 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001794 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001795 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001796 }
1797
Selim Cinekb5605e52015-02-20 18:21:41 +01001798 public static void applyTint(View v, int color) {
1799 int alpha;
1800 if (color != 0) {
1801 alpha = COLORED_DIVIDER_ALPHA;
1802 } else {
1803 color = 0xff000000;
1804 alpha = DEFAULT_DIVIDER_ALPHA;
1805 }
1806 if (v.getBackground() instanceof ColorDrawable) {
1807 ColorDrawable background = (ColorDrawable) v.getBackground();
1808 background.mutate();
1809 background.setColor(color);
1810 background.setAlpha(alpha);
1811 }
1812 }
1813
Selim Cinek1685e632014-04-08 02:27:49 +02001814 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001815 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001816 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001817
Mady Mellor34958fa2016-02-23 09:52:17 -08001818 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001819 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08001820 }
1821
Jorim Jaggibe565df2014-04-28 17:51:23 +02001822 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001823 public boolean isContentExpandable() {
Selim Cinekc0ac4af2017-03-03 15:13:48 -08001824 if (mIsSummaryWithChildren && !mShowingPublic) {
1825 return true;
1826 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001827 NotificationContentView showingLayout = getShowingLayout();
1828 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001829 }
1830
1831 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001832 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001833 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001834 return mChildrenContainer;
1835 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001836 return getShowingLayout();
1837 }
1838
1839 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001840 protected void onAppearAnimationFinished(boolean wasAppearing) {
1841 super.onAppearAnimationFinished(wasAppearing);
1842 if (wasAppearing) {
1843 // During the animation the visible view might have changed, so let's make sure all
1844 // alphas are reset
1845 if (mChildrenContainer != null) {
1846 mChildrenContainer.setAlpha(1.0f);
1847 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1848 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001849 for (NotificationContentView l : mLayouts) {
1850 l.setAlpha(1.0f);
1851 l.setLayerType(LAYER_TYPE_NONE, null);
1852 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07001853 }
1854 }
1855
1856 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001857 public int getExtraBottomPadding() {
1858 if (mIsSummaryWithChildren && isGroupExpanded()) {
1859 return mIncreasedPaddingBetweenElements;
1860 }
1861 return 0;
1862 }
1863
1864 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001865 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinek4ca6c632017-02-23 18:03:37 -08001866 boolean changed = height != getActualHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +01001867 super.setActualHeight(height, notifyListeners);
Selim Cinek4ca6c632017-02-23 18:03:37 -08001868 if (changed && isRemoved()) {
1869 // TODO: remove this once we found the gfx bug for this.
1870 // This is a hack since a removed view sometimes would just stay blank. it occured
1871 // when sending yourself a message and then clicking on it.
1872 ViewGroup parent = (ViewGroup) getParent();
1873 if (parent != null) {
1874 parent.invalidate();
1875 }
1876 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001877 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08001878 mGuts.setActualHeight(height);
1879 return;
1880 }
Selim Cinekeef84282015-10-30 16:28:00 -07001881 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001882 for (NotificationContentView l : mLayouts) {
1883 l.setContentHeight(contentHeight);
1884 }
Selim Cinek42357e02016-02-24 18:48:01 -08001885 if (mIsSummaryWithChildren) {
1886 mChildrenContainer.setActualHeight(height);
1887 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001888 if (mGuts != null) {
1889 mGuts.setActualHeight(height);
1890 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001891 }
1892
1893 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001894 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001895 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001896 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001897 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001898 NotificationContentView showingLayout = getShowingLayout();
1899 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001900 }
1901
1902 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001903 public int getMinHeight() {
Mady Mellore09fb702017-03-30 13:23:29 -07001904 if (mGuts != null && mGuts.isExposed()) {
1905 return mGuts.getIntrinsicHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07001906 } else if (isHeadsUpAllowed() && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08001907 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1908 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001909 return mChildrenContainer.getMinHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -07001910 } else if (isHeadsUpAllowed() && mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001911 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001912 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001913 NotificationContentView showingLayout = getShowingLayout();
1914 return showingLayout.getMinHeight();
1915 }
1916
1917 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001918 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001919 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001920 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001921 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001922 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001923 }
1924
1925 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001926 public void setClipTopAmount(int clipTopAmount) {
1927 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001928 for (NotificationContentView l : mLayouts) {
1929 l.setClipTopAmount(clipTopAmount);
1930 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001931 if (mGuts != null) {
1932 mGuts.setClipTopAmount(clipTopAmount);
1933 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001934 }
1935
Selim Cineka686b2c2016-10-26 13:58:27 -07001936 @Override
1937 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001938 if (clipBottomAmount != mClipBottomAmount) {
1939 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001940 for (NotificationContentView l : mLayouts) {
1941 l.setClipBottomAmount(clipBottomAmount);
1942 }
Selim Cinek65d418e2016-11-29 15:42:34 -08001943 if (mGuts != null) {
1944 mGuts.setClipBottomAmount(clipBottomAmount);
1945 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001946 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001947 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001948 // We have to update this even if it hasn't changed, since the children locations can
1949 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001950 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
1951 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001952 }
1953
Selim Cinek31094df2014-08-14 19:28:15 +02001954 public boolean isMaxExpandHeightInitialized() {
1955 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001956 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001957
Selim Cinek42357e02016-02-24 18:48:01 -08001958 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001959 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1960 }
Chris Wren78403d72014-07-28 10:23:24 +01001961
Selim Cinek1a48bab2017-02-17 19:38:40 -08001962 public void setLegacy(boolean legacy) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08001963 for (NotificationContentView l : mLayouts) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08001964 l.setLegacy(legacy);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001965 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001966 }
1967
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001968 @Override
1969 protected void updateBackgroundTint() {
1970 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001971 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001972 if (mIsSummaryWithChildren) {
1973 List<ExpandableNotificationRow> notificationChildren =
1974 mChildrenContainer.getNotificationChildren();
1975 for (int i = 0; i < notificationChildren.size(); i++) {
1976 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001977 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001978 }
1979 }
1980 }
1981
Mady Mellorb0a82462016-04-30 17:31:02 -07001982 /**
1983 * Called when a group has finished animating from collapsed or expanded state.
1984 */
1985 public void onFinishedExpansionChange() {
1986 mGroupExpansionChanging = false;
1987 updateBackgroundForGroupState();
1988 }
1989
1990 /**
1991 * Updates the parent and children backgrounds in a group based on the expansion state.
1992 */
1993 public void updateBackgroundForGroupState() {
1994 if (mIsSummaryWithChildren) {
1995 // Only when the group has finished expanding do we hide its background.
1996 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1997 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1998 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1999 for (int i = 0; i < children.size(); i++) {
2000 children.get(i).updateBackgroundForGroupState();
2001 }
2002 } else if (isChildInGroup()) {
2003 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
2004 // Only show a background if the group is expanded OR if it is expanding / collapsing
2005 // and has a custom background color
2006 final boolean showBackground = isGroupExpanded()
2007 || ((mNotificationParent.isGroupExpansionChanging()
2008 || mNotificationParent.isUserLocked()) && childColor != 0);
2009 mShowNoBackground = !showBackground;
2010 } else {
2011 // Only children or parents ever need no background.
2012 mShowNoBackground = false;
2013 }
2014 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002015 updateBackground();
2016 }
2017
Adrian Roos4a579672016-05-24 16:54:37 -07002018 public int getPositionOfChild(ExpandableNotificationRow childRow) {
2019 if (mIsSummaryWithChildren) {
2020 return mChildrenContainer.getPositionInLinearLayout(childRow);
2021 }
2022 return 0;
2023 }
2024
Chris Wren78403d72014-07-28 10:23:24 +01002025 public void setExpansionLogger(ExpansionLogger logger, String key) {
2026 mLogger = logger;
2027 mLoggingKey = key;
2028 }
2029
Chris Wren6abeeb92016-05-26 14:44:38 -04002030 public void onExpandedByGesture(boolean userExpanded) {
2031 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
2032 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
2033 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
2034 }
2035 MetricsLogger.action(mContext, event, userExpanded);
2036 }
2037
Selim Cinek6183d122016-01-14 18:48:41 -08002038 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08002039 public float getIncreasedPaddingAmount() {
2040 if (mIsSummaryWithChildren) {
2041 if (isGroupExpanded()) {
2042 return 1.0f;
2043 } else if (isUserLocked()) {
Selim Cinek414ad332017-02-24 19:06:12 -08002044 return mChildrenContainer.getIncreasedPaddingAmount();
Selim Cinek42357e02016-02-24 18:48:01 -08002045 }
Selim Cinek99104832017-01-25 14:47:33 -08002046 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08002047 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08002048 }
2049 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08002050 }
2051
Selim Cineka7ed2c12017-01-23 20:47:24 -08002052 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08002053 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08002054 }
2055
Selim Cinek61633a82016-01-25 15:54:10 -08002056 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08002057 protected boolean disallowSingleClick(MotionEvent event) {
2058 float x = event.getX();
2059 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08002060 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08002061 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08002062 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08002063 }
2064 return super.disallowSingleClick(event);
2065 }
2066
Selim Cinek414ad332017-02-24 19:06:12 -08002067 private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04002068 boolean nowExpanded = isExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08002069 if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
Chris Wren698b1702016-05-23 11:16:32 -04002070 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
2071 }
Selim Cinek414ad332017-02-24 19:06:12 -08002072 if (nowExpanded != wasExpanded) {
2073 updateShelfIconColor();
2074 if (mLogger != null) {
2075 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded);
2076 }
2077 if (mIsSummaryWithChildren) {
2078 mChildrenContainer.onExpansionChanged();
2079 }
Chris Wren78403d72014-07-28 10:23:24 +01002080 }
2081 }
Selim Cinek570981d2015-12-01 11:37:01 -08002082
Selim Cineke9bad242016-06-15 11:46:37 -07002083 @Override
2084 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2085 super.onInitializeAccessibilityNodeInfoInternal(info);
2086 if (canViewBeDismissed()) {
2087 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
2088 }
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002089 boolean expandable = mShowingPublic;
2090 boolean isExpanded = false;
2091 if (!expandable) {
2092 if (mIsSummaryWithChildren) {
2093 expandable = true;
2094 if (!mIsLowPriority || isExpanded()) {
2095 isExpanded = isGroupExpanded();
2096 }
2097 } else {
2098 expandable = mPrivateLayout.isContentExpandable();
2099 isExpanded = isExpanded();
2100 }
2101 }
2102 if (expandable) {
2103 if (isExpanded) {
2104 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
2105 } else {
2106 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
2107 }
2108 }
Selim Cineke9bad242016-06-15 11:46:37 -07002109 }
2110
2111 @Override
2112 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
2113 if (super.performAccessibilityActionInternal(action, arguments)) {
2114 return true;
2115 }
2116 switch (action) {
2117 case AccessibilityNodeInfo.ACTION_DISMISS:
2118 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
2119 true /* fromAccessibility */);
2120 return true;
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002121 case AccessibilityNodeInfo.ACTION_COLLAPSE:
2122 case AccessibilityNodeInfo.ACTION_EXPAND:
2123 mExpandClickListener.onClick(this);
2124 return true;
Selim Cineke9bad242016-06-15 11:46:37 -07002125 }
2126 return false;
2127 }
2128
2129 public boolean shouldRefocusOnDismiss() {
2130 return mRefocusOnDismiss || isAccessibilityFocused();
2131 }
2132
Selim Cinek570981d2015-12-01 11:37:01 -08002133 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08002134 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08002135 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002136
2137 @Override
2138 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
2139 return new NotificationViewState(stackScrollState);
2140 }
2141
Selim Cinekd127d792016-11-01 19:11:41 -07002142 @Override
2143 public boolean isAboveShelf() {
Selim Cinekc8007c52017-02-28 16:09:56 -08002144 return !isOnKeyguard()
2145 && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf));
Selim Cinekd127d792016-11-01 19:11:41 -07002146 }
2147
Adrian Roos0aac04f2016-12-08 15:59:29 -08002148 public void setShowAmbient(boolean showAmbient) {
2149 if (showAmbient != mShowAmbient) {
2150 mShowAmbient = showAmbient;
Adrian Roos6f6e1592017-05-02 16:22:53 -07002151 if (mChildrenContainer != null) {
2152 mChildrenContainer.notifyShowAmbientChanged();
2153 }
Adrian Roos0aac04f2016-12-08 15:59:29 -08002154 notifyHeightChanged(false /* needsAnimation */);
2155 }
2156 }
2157
Adrian Roos6f6e1592017-05-02 16:22:53 -07002158 public boolean isShowingAmbient() {
2159 return mShowAmbient;
2160 }
2161
Selim Cinekd127d792016-11-01 19:11:41 -07002162 public void setAboveShelf(boolean aboveShelf) {
2163 mAboveShelf = aboveShelf;
2164 }
2165
Selim Cinekd4776a52017-02-14 18:50:16 -08002166 public static class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08002167
2168 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07002169
Selim Cinekbbcebde2016-11-09 18:28:20 -08002170
2171 private NotificationViewState(StackScrollState stackScrollState) {
2172 mOverallState = stackScrollState;
2173 }
2174
2175 @Override
2176 public void applyToView(View view) {
2177 super.applyToView(view);
2178 if (view instanceof ExpandableNotificationRow) {
2179 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinekbbcebde2016-11-09 18:28:20 -08002180 row.applyChildrenState(mOverallState);
2181 }
2182 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002183
2184 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08002185 protected void onYTranslationAnimationFinished(View view) {
2186 super.onYTranslationAnimationFinished(view);
Selim Cinekd4776a52017-02-14 18:50:16 -08002187 if (view instanceof ExpandableNotificationRow) {
2188 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
2189 if (row.isHeadsUpAnimatingAway()) {
2190 row.setHeadsUpAnimatingAway(false);
2191 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002192 }
2193 }
2194
2195 @Override
2196 public void animateTo(View child, AnimationProperties properties) {
2197 super.animateTo(child, properties);
2198 if (child instanceof ExpandableNotificationRow) {
2199 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
2200 row.startChildAnimation(mOverallState, properties);
2201 }
2202 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002203 }
Selim Cinek91f41ce2017-05-24 11:08:55 -07002204
2205 @VisibleForTesting
2206 protected void setChildrenContainer(NotificationChildrenContainer childrenContainer) {
2207 mChildrenContainer = childrenContainer;
2208 }
Chris Wren51c75102013-07-16 20:49:17 -04002209}