blob: 677642e53d6e6f590f160fbabea114b3b0e64ae1 [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 Cinekc478f902017-02-22 20:55:44 -080019import static com.android.systemui.statusbar.notification.NotificationInflater.InflationExceptionHandler;
20
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;
Selim Cinekcab4a602014-09-03 14:47:57 +020027import android.graphics.drawable.AnimatedVectorDrawable;
28import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010029import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020030import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080031import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070032import android.os.Bundle;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020033import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040034import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070035import android.util.FloatProperty;
36import android.util.Property;
Selim Cinek01af3342016-02-09 19:25:31 -080037import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080038import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080039import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050040import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080041import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020042import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020043import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070044import android.view.accessibility.AccessibilityNodeInfo;
Selim Cinek98713a42015-09-21 15:47:20 +020045import android.widget.Chronometer;
Mady Mellor95d743c2017-01-10 12:05:27 -080046import android.widget.FrameLayout;
Selim Cinekcab4a602014-09-03 14:47:57 +020047import android.widget.ImageView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080048import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010049
Chris Wren698b1702016-05-23 11:16:32 -040050import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010051import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070052import com.android.internal.util.NotificationColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080053import com.android.internal.widget.CachingIconView;
Mady Mellor95d743c2017-01-10 12:05:27 -080054import com.android.systemui.Dependency;
Selim Cinek0242fbb2016-10-19 13:38:32 -070055import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050056import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070057import com.android.systemui.classifier.FalsingManager;
Mady Mellor95d743c2017-01-10 12:05:27 -080058import com.android.systemui.plugins.PluginListener;
59import com.android.systemui.plugins.PluginManager;
60import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
61import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
62import com.android.systemui.statusbar.NotificationGuts.GutsContent;
Selim Cinekc897bd32016-03-18 17:32:31 -070063import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080064import com.android.systemui.statusbar.notification.InflationException;
65import com.android.systemui.statusbar.notification.NotificationInflater;
Selim Cinek6743c0b2017-01-18 18:24:01 -080066import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cineka7d4f822016-12-06 14:34:47 -080067import com.android.systemui.statusbar.notification.VisualStabilityManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010068import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050069import com.android.systemui.statusbar.phone.StatusBar;
Selim Cinek31aada42015-12-18 17:51:15 -080070import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek0cfbef42016-11-09 19:06:36 -080071import com.android.systemui.statusbar.stack.AnimationProperties;
72import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010073import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070074import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010075import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010076
Mady Mellor4b80b102016-01-22 08:03:58 -080077import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010078import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050079
Mady Mellor95d743c2017-01-10 12:05:27 -080080public class ExpandableNotificationRow extends ActivatableNotificationView
81 implements PluginListener<NotificationMenuRowPlugin> {
Selim Cinekb5605e52015-02-20 18:21:41 +010082
83 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
84 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Mady Mellor95d743c2017-01-10 12:05:27 -080085 private static final int MENU_VIEW_INDEX = 0;
86
Selim Cinek1a48bab2017-02-17 19:38:40 -080087 private final NotificationInflater mNotificationInflater;
Selim Cinek0242fbb2016-10-19 13:38:32 -070088 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -080089 private int mIconTransformContentShiftNoIcon;
Selim Cinek01af3342016-02-09 19:25:31 -080090 private int mNotificationMinHeightLegacy;
91 private int mMaxHeadsUpHeightLegacy;
92 private int mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -080093 private int mMaxHeadsUpHeightIncreased;
Selim Cinek01af3342016-02-09 19:25:31 -080094 private int mNotificationMinHeight;
Selim Cinek7d1009b2017-01-25 15:28:28 -080095 private int mNotificationMinHeightLarge;
Selim Cinek01af3342016-02-09 19:25:31 -080096 private int mNotificationMaxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -080097 private int mNotificationAmbientHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -070098 private int mIncreasedPaddingBetweenElements;
Chris Wren51c75102013-07-16 20:49:17 -040099
Selim Cinek1685e632014-04-08 02:27:49 +0200100 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -0400101 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +0200102 /** Has the user actively changed the expansion state of this row */
103 private boolean mHasUserChangedExpansion;
104 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -0400105 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -0800106
107 /**
108 * Has this notification been expanded while it was pinned
109 */
110 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +0200111 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -0400112 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +0200113 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -0500114 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +0200115 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -0800116 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +0200117 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700118 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400119
Selim Cinek1685e632014-04-08 02:27:49 +0200120 /**
121 * Is this notification expanded by the system. The expansion state can be overridden by the
122 * user expansion.
123 */
124 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200125
126 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700127 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200128 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700129 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200130
Mady Mellorb0a82462016-04-30 17:31:02 -0700131 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800132 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200133 private NotificationContentView mPublicLayout;
134 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800135 private NotificationContentView[] mLayouts;
Selim Cinek1685e632014-04-08 02:27:49 +0200136 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700137 private int mHeadsUpHeight;
Selim Cinek4bb59342016-04-08 19:29:35 -0700138 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100139 private ExpansionLogger mLogger;
140 private String mLoggingKey;
Selim Cinek8d490d42015-04-10 00:05:50 -0700141 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800142 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200143 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700144 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100145 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200146 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100147 private ViewStub mChildrenContainerStub;
148 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100149 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700150 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100151 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor95d743c2017-01-10 12:05:27 -0800152 private NotificationMenuRowPlugin mMenuRow;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100153 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100154 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700155 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700156 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800157 private HeadsUpManager mHeadsUpManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200158
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700159 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800160 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700161 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700162 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800163 private OnExpandClickListener mOnExpandClickListener;
Mady Mellorb0a82462016-04-30 17:31:02 -0700164 private boolean mGroupExpansionChanging;
165
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800166 private OnClickListener mExpandClickListener = new OnClickListener() {
167 @Override
168 public void onClick(View v) {
Selim Cinek414ad332017-02-24 19:06:12 -0800169 if (!mShowingPublic && (!mIsLowPriority || isExpanded())
170 && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700171 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400172 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
173 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
174 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400175 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
176 nowExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -0800177 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800178 } else {
Selim Cineke9bad242016-06-15 11:46:37 -0700179 if (v.isAccessibilityFocused()) {
180 mPrivateLayout.setFocusOnVisibilityChange();
181 }
Selim Cinek31aada42015-12-18 17:51:15 -0800182 boolean nowExpanded;
183 if (isPinned()) {
184 nowExpanded = !mExpandedWhenPinned;
185 mExpandedWhenPinned = nowExpanded;
186 } else {
187 nowExpanded = !isExpanded();
188 setUserExpanded(nowExpanded);
189 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800190 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800191 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400192 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
193 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800194 }
195 }
196 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700197 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700198 private boolean mDismissed;
199 private boolean mKeepInParent;
200 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700201 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
202 new FloatProperty<ExpandableNotificationRow>("translate") {
203 @Override
204 public void setValue(ExpandableNotificationRow object, float value) {
205 object.setTranslation(value);
206 }
207
208 @Override
209 public Float get(ExpandableNotificationRow object) {
210 return object.getTranslation();
211 }
212 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700213 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700214 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700215 private View mChildAfterViewWhenDismissed;
216 private View mGroupParentWhenDismissed;
217 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800218 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700219 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700220 private boolean mAboveShelf;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800221 private boolean mShowAmbient;
Selim Cinek875a3a12016-11-18 17:52:16 -0800222 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800223 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800224 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800225 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800226 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800227 private boolean mUseIncreasedHeadsUpHeight;
Selim Cinekef8c2252017-02-10 14:52:18 -0800228 private float mTranslationWhenRemoved;
229 private boolean mWasChildInGroupWhenRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700230
Mady Mellor43c2cd12016-12-12 21:05:13 -0800231 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700232 public boolean isGroupExpansionChanging() {
233 if (isChildInGroup()) {
234 return mNotificationParent.isGroupExpansionChanging();
235 }
236 return mGroupExpansionChanging;
237 }
238
239 public void setGroupExpansionChanging(boolean changing) {
240 mGroupExpansionChanging = changing;
241 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700242
Adrian Roos599be342016-06-13 14:54:39 -0700243 @Override
244 public void setActualHeightAnimating(boolean animating) {
245 if (mPrivateLayout != null) {
246 mPrivateLayout.setContentHeightAnimating(animating);
247 }
248 }
249
Selim Cinek8d490d42015-04-10 00:05:50 -0700250 public NotificationContentView getPrivateLayout() {
251 return mPrivateLayout;
252 }
253
254 public NotificationContentView getPublicLayout() {
255 return mPublicLayout;
256 }
257
Selim Cinekcab4a602014-09-03 14:47:57 +0200258 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800259 for (NotificationContentView l : mLayouts) {
260 setIconAnimationRunning(running, l);
261 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800262 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700263 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek414ad332017-02-24 19:06:12 -0800264 setIconAnimationRunningForChild(running, mChildrenContainer.getLowPriorityHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800265 List<ExpandableNotificationRow> notificationChildren =
266 mChildrenContainer.getNotificationChildren();
267 for (int i = 0; i < notificationChildren.size(); i++) {
268 ExpandableNotificationRow child = notificationChildren.get(i);
269 child.setIconAnimationRunning(running);
270 }
271 }
272 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200273 }
274
275 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
276 if (layout != null) {
277 View contractedChild = layout.getContractedChild();
278 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700279 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200280 setIconAnimationRunningForChild(running, contractedChild);
281 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700282 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200283 }
284 }
285
286 private void setIconAnimationRunningForChild(boolean running, View child) {
287 if (child != null) {
288 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
289 setIconRunning(icon, running);
290 ImageView rightIcon = (ImageView) child.findViewById(
291 com.android.internal.R.id.right_icon);
292 setIconRunning(rightIcon, running);
293 }
294 }
295
296 private void setIconRunning(ImageView imageView, boolean running) {
297 if (imageView != null) {
298 Drawable drawable = imageView.getDrawable();
299 if (drawable instanceof AnimationDrawable) {
300 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
301 if (running) {
302 animationDrawable.start();
303 } else {
304 animationDrawable.stop();
305 }
306 } else if (drawable instanceof AnimatedVectorDrawable) {
307 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
308 if (running) {
309 animationDrawable.start();
310 } else {
311 animationDrawable.stop();
312 }
313 }
314 }
315 }
316
Selim Cinek1a48bab2017-02-17 19:38:40 -0800317 public void updateNotification(NotificationData.Entry entry) throws InflationException {
Selim Cinekda42d652015-12-04 15:51:16 -0800318 mEntry = entry;
319 mStatusBarNotification = entry.notification;
Selim Cinek1a48bab2017-02-17 19:38:40 -0800320 mNotificationInflater.inflateNotificationViews();
Selim Cinekc478f902017-02-22 20:55:44 -0800321 onNotificationUpdated();
322 }
323
324 private void onNotificationUpdated() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800325 for (NotificationContentView l : mLayouts) {
Selim Cinekc478f902017-02-22 20:55:44 -0800326 l.onNotificationUpdated(mEntry);
Adrian Rooseb434ff2017-01-11 11:18:48 -0800327 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800328 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800329 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700330 updateNotificationColor();
Mady Mellor4c197602017-04-10 17:57:52 -0700331 if (mMenuRow != null) {
332 mMenuRow.onNotificationUpdated();
333 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800334 if (mIsSummaryWithChildren) {
Selim Cinek414ad332017-02-24 19:06:12 -0800335 mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
Selim Cinekc897bd32016-03-18 17:32:31 -0700336 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800337 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800338 if (mIconAnimationRunning) {
339 setIconAnimationRunning(true);
340 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800341 if (mNotificationParent != null) {
342 mNotificationParent.updateChildrenHeaderAppearance();
343 }
Selim Cinek263398f2015-10-21 17:40:23 -0700344 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800345 // The public layouts expand button is always visible
346 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800347 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700348 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800349 updateShelfIconColor();
350 }
351
352 private void updateShelfIconColor() {
353 StatusBarIconView expandedIcon = mEntry.expandedIcon;
354 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
355 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
356 NotificationColorUtil.getInstance(mContext));
Selim Cinek875ba9b2017-02-13 16:20:17 -0800357 int color = StatusBarIconView.NO_COLOR;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800358 if (colorize) {
Selim Cinek875ba9b2017-02-13 16:20:17 -0800359 color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded());
Selim Cinek6743c0b2017-01-18 18:24:01 -0800360 }
Selim Cinek875ba9b2017-02-13 16:20:17 -0800361 expandedIcon.setStaticDrawableColor(color);
Selim Cinekda42d652015-12-04 15:51:16 -0800362 }
363
364 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800365 for (NotificationContentView l : mLayouts) {
366 updateLimitsForView(l);
367 }
Selim Cineka1744872016-03-11 15:36:06 -0800368 }
369
370 private void updateLimitsForView(NotificationContentView layout) {
371 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800372 != com.android.internal.R.id.status_bar_latest_event_content;
373 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800374 int minHeight;
375 if (customView && beforeN && !mIsSummaryWithChildren) {
376 minHeight = mNotificationMinHeightLegacy;
377 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
378 minHeight = mNotificationMinHeightLarge;
379 } else {
380 minHeight = mNotificationMinHeight;
381 }
Selim Cineka1744872016-03-11 15:36:06 -0800382 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
383 layout.getHeadsUpChild().getId()
384 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800385 int headsUpheight;
386 if (headsUpCustom && beforeN) {
387 headsUpheight = mMaxHeadsUpHeightLegacy;
388 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
389 headsUpheight = mMaxHeadsUpHeightIncreased;
390 } else {
391 headsUpheight = mMaxHeadsUpHeight;
392 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800393 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
394 mNotificationAmbientHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200395 }
396
397 public StatusBarNotification getStatusBarNotification() {
398 return mStatusBarNotification;
399 }
400
Selim Cinek281c2022016-10-13 19:14:43 -0700401 public NotificationData.Entry getEntry() {
402 return mEntry;
403 }
404
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700405 public boolean isHeadsUp() {
406 return mIsHeadsUp;
407 }
408
Selim Cinek1a521f32014-11-03 17:39:29 +0100409 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700410 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100411 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700412 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700413 if (mIsSummaryWithChildren) {
414 // The overflow might change since we allow more lines as HUN.
415 mChildrenContainer.updateGroupOverflow();
416 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700417 if (intrinsicBefore != getIntrinsicHeight()) {
418 notifyHeightChanged(false /* needsAnimation */);
419 }
Selim Cinekd127d792016-11-01 19:11:41 -0700420 if (isHeadsUp) {
421 setAboveShelf(true);
422 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100423 }
424
Selim Cinekb5605e52015-02-20 18:21:41 +0100425 public void setGroupManager(NotificationGroupManager groupManager) {
426 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700427 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100428 }
429
Adrian Roosb88b1a12015-12-09 18:51:05 -0800430 public void setRemoteInputController(RemoteInputController r) {
431 mPrivateLayout.setRemoteInputController(r);
432 }
433
Mady Mellor3fd273e2016-03-15 21:08:14 -0700434 public void setAppName(String appName) {
435 mAppName = appName;
Mady Mellor95d743c2017-01-10 12:05:27 -0800436 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800437 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700438 }
439 }
440
Selim Cinekb5605e52015-02-20 18:21:41 +0100441 public void addChildNotification(ExpandableNotificationRow row) {
442 addChildNotification(row, -1);
443 }
444
445 /**
446 * Add a child notification to this view.
447 *
448 * @param row the row to add
449 * @param childIndex the index to add it at, if -1 it will be added at the end
450 */
451 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
452 if (mChildrenContainer == null) {
453 mChildrenContainerStub.inflate();
454 }
455 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700456 onChildrenCountChanged();
457 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100458 }
459
460 public void removeChildNotification(ExpandableNotificationRow row) {
461 if (mChildrenContainer != null) {
462 mChildrenContainer.removeNotification(row);
463 }
Selim Cinek263398f2015-10-21 17:40:23 -0700464 onChildrenCountChanged();
465 row.setIsChildInGroup(false, null);
466 }
467
Mady Mellor43c2cd12016-12-12 21:05:13 -0800468 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700469 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700470 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700471 }
472
Selim Cinek388df6d2015-10-22 13:25:11 -0700473 public ExpandableNotificationRow getNotificationParent() {
474 return mNotificationParent;
475 }
476
Selim Cinek263398f2015-10-21 17:40:23 -0700477 /**
478 * @param isChildInGroup Is this notification now in a group
479 * @param parent the new parent notification
480 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700481 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500482 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700483 mNotificationParent = childInGroup ? parent : null;
484 mPrivateLayout.setIsChildInGroup(childInGroup);
Selim Cinekc478f902017-02-22 20:55:44 -0800485 if (mNotificationInflater.setIsChildInGroup(childInGroup)) {
486 onNotificationUpdated();
487 }
Mady Mellorc7d65b42016-05-04 11:44:57 -0400488 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700489 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700490 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700491 if (mNotificationParent != null) {
Selim Cinek9ce32852017-02-15 16:21:10 -0800492 setOverrideTintColor(NO_COLOR, 0.0f);
Mady Mellorb0a82462016-04-30 17:31:02 -0700493 mNotificationParent.updateBackgroundForGroupState();
494 }
Selim Cinekdb167372016-11-17 15:41:17 -0800495 updateIconVisibilities();
Selim Cinek34d93b02015-10-22 12:30:38 -0700496 }
497
498 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800499 public boolean onTouchEvent(MotionEvent event) {
500 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
501 || !isChildInGroup() || isGroupExpanded()) {
502 return super.onTouchEvent(event);
503 } else {
504 return false;
505 }
506 }
507
508 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800509 protected boolean handleSlideBack() {
Mady Mellor95d743c2017-01-10 12:05:27 -0800510 if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800511 animateTranslateNotification(0 /* targetLeft */);
512 return true;
513 }
514 return false;
515 }
516
517 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700518 protected boolean shouldHideBackground() {
519 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700520 }
521
522 @Override
523 public boolean isSummaryWithChildren() {
524 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100525 }
526
527 @Override
528 public boolean areChildrenExpanded() {
529 return mChildrenExpanded;
530 }
531
532 public List<ExpandableNotificationRow> getNotificationChildren() {
533 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
534 }
535
Selim Cinekeef84282015-10-30 16:28:00 -0700536 public int getNumberOfNotificationChildren() {
537 if (mChildrenContainer == null) {
538 return 0;
539 }
540 return mChildrenContainer.getNotificationChildren().size();
541 }
542
Selim Cinekb5605e52015-02-20 18:21:41 +0100543 /**
544 * Apply the order given in the list to the children.
545 *
546 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800547 * @param visualStabilityManager
548 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100549 * @return whether the list order has changed
550 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800551 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
552 VisualStabilityManager visualStabilityManager,
553 VisualStabilityManager.Callback callback) {
554 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
555 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100556 }
557
558 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700559 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800560 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100561 mChildrenContainer.getState(resultState, parentState);
562 }
563 }
564
565 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700566 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100567 mChildrenContainer.applyState(state);
568 }
569 }
570
571 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700572 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100573 mChildrenContainer.prepareExpansionChanged(state);
574 }
575 }
576
Selim Cinek0cfbef42016-11-09 19:06:36 -0800577 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700578 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800579 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100580 }
581 }
582
583 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800584 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100585 return this;
586 } else {
587 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
588 return view == null ? this : view;
589 }
590 }
591
Selim Cinekab29aeb2015-02-20 18:18:32 +0100592 public NotificationGuts getGuts() {
593 return mGuts;
594 }
595
Selim Cinek684a4422015-04-15 16:18:39 -0700596 /**
597 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
598 * the notification will be rendered on top of the screen.
599 *
600 * @param pinned whether it is pinned
601 */
602 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700603 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700604 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700605 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700606 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700607 }
Selim Cinek31aada42015-12-18 17:51:15 -0800608 if (pinned) {
609 setIconAnimationRunning(true);
610 mExpandedWhenPinned = false;
611 } else if (mExpandedWhenPinned) {
612 setUserExpanded(true);
613 }
Selim Cinek98713a42015-09-21 15:47:20 +0200614 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700615 }
616
Selim Cinek684a4422015-04-15 16:18:39 -0700617 public boolean isPinned() {
618 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700619 }
620
Selim Cinekd127d792016-11-01 19:11:41 -0700621 @Override
622 public int getPinnedHeadsUpHeight() {
623 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
624 }
625
Selim Cinek31aada42015-12-18 17:51:15 -0800626 /**
627 * @param atLeastMinHeight should the value returned be at least the minimum height.
628 * Used to avoid cyclic calls
629 * @return the height of the heads up notification when pinned
630 */
Selim Cinekd127d792016-11-01 19:11:41 -0700631 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800632 if (mIsSummaryWithChildren) {
633 return mChildrenContainer.getIntrinsicHeight();
634 }
Selim Cinek31aada42015-12-18 17:51:15 -0800635 if(mExpandedWhenPinned) {
636 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
637 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700638 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800639 } else {
640 return mHeadsUpHeight;
641 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700642 }
643
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700644 /**
645 * Mark whether this notification was just clicked, i.e. the user has just clicked this
646 * notification in this frame.
647 */
648 public void setJustClicked(boolean justClicked) {
649 mJustClicked = justClicked;
650 }
651
652 /**
653 * @return true if this notification has been clicked in this frame, false otherwise
654 */
655 public boolean wasJustClicked() {
656 return mJustClicked;
657 }
658
Selim Cinek98713a42015-09-21 15:47:20 +0200659 public void setChronometerRunning(boolean running) {
660 mLastChronometerRunning = running;
661 setChronometerRunning(running, mPrivateLayout);
662 setChronometerRunning(running, mPublicLayout);
663 if (mChildrenContainer != null) {
664 List<ExpandableNotificationRow> notificationChildren =
665 mChildrenContainer.getNotificationChildren();
666 for (int i = 0; i < notificationChildren.size(); i++) {
667 ExpandableNotificationRow child = notificationChildren.get(i);
668 child.setChronometerRunning(running);
669 }
670 }
671 }
672
673 private void setChronometerRunning(boolean running, NotificationContentView layout) {
674 if (layout != null) {
675 running = running || isPinned();
676 View contractedChild = layout.getContractedChild();
677 View expandedChild = layout.getExpandedChild();
678 View headsUpChild = layout.getHeadsUpChild();
679 setChronometerRunningForChild(running, contractedChild);
680 setChronometerRunningForChild(running, expandedChild);
681 setChronometerRunningForChild(running, headsUpChild);
682 }
683 }
684
685 private void setChronometerRunningForChild(boolean running, View child) {
686 if (child != null) {
687 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
688 if (chronometer instanceof Chronometer) {
689 ((Chronometer) chronometer).setStarted(running);
690 }
691 }
692 }
693
Selim Cinekea4bef72015-12-02 15:51:10 -0800694 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700695 if (mIsSummaryWithChildren) {
696 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700697 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800698 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700699 }
700
Selim Cinek414ad332017-02-24 19:06:12 -0800701 /**
702 * @return the currently visible notification header. This can be different from
703 * {@link #getNotificationHeader()} in case it is a low-priority group.
704 */
705 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700706 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek414ad332017-02-24 19:06:12 -0800707 return mChildrenContainer.getVisibleHeader();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800708 }
709 return getShowingLayout().getVisibleNotificationHeader();
710 }
711
Selim Cinek570981d2015-12-01 11:37:01 -0800712 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
713 mOnExpandClickListener = onExpandClickListener;
714 }
715
Selim Cinekddf1b392016-05-27 16:33:10 -0700716 @Override
717 public void setOnClickListener(@Nullable OnClickListener l) {
718 super.setOnClickListener(l);
719 mOnClickListener = l;
720 updateClickAndFocus();
721 }
722
723 private void updateClickAndFocus() {
724 boolean normalChild = !isChildInGroup() || isGroupExpanded();
725 boolean clickable = mOnClickListener != null && normalChild;
726 if (isFocusable() != normalChild) {
727 setFocusable(normalChild);
728 }
729 if (isClickable() != clickable) {
730 setClickable(clickable);
731 }
732 }
733
Selim Cinek31aada42015-12-18 17:51:15 -0800734 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
735 mHeadsUpManager = headsUpManager;
736 }
737
Mady Mellor87d79452017-01-10 11:52:52 -0800738 public void setGutsView(MenuItem item) {
Mady Mellor95d743c2017-01-10 12:05:27 -0800739 if (mGuts != null && item.getGutsView() instanceof GutsContent) {
740 ((GutsContent) item.getGutsView()).setGutsParent(mGuts);
741 mGuts.setGutsContent((GutsContent) item.getGutsView());
Mady Mellor87d79452017-01-10 11:52:52 -0800742 }
743 }
744
Mady Mellor95d743c2017-01-10 12:05:27 -0800745 @Override
746 protected void onAttachedToWindow() {
747 super.onAttachedToWindow();
748 Dependency.get(PluginManager.class).addPluginListener(this,
749 NotificationMenuRowPlugin.class, false /* Allow multiple */);
750 }
751
752 @Override
753 protected void onDetachedFromWindow() {
754 super.onDetachedFromWindow();
755 Dependency.get(PluginManager.class).removePluginListener(this);
756 }
757
758 @Override
759 public void onPluginConnected(NotificationMenuRowPlugin plugin, Context pluginContext) {
760 boolean existed = mMenuRow.getMenuView() != null;
761 if (existed) {
762 removeView(mMenuRow.getMenuView());
763 }
764 mMenuRow = plugin;
765 if (mMenuRow.useDefaultMenuItems()) {
Mady Mellor4c197602017-04-10 17:57:52 -0700766 ArrayList<MenuItem> items = new ArrayList<>();
767 items.add(NotificationMenuRow.createInfoItem(mContext));
768 items.add(NotificationMenuRow.createSnoozeItem(mContext));
769 mMenuRow.setMenuItems(items);
Mady Mellor95d743c2017-01-10 12:05:27 -0800770 }
771 if (existed) {
772 createMenu();
773 }
774 }
775
776 @Override
777 public void onPluginDisconnected(NotificationMenuRowPlugin plugin) {
778 boolean existed = mMenuRow.getMenuView() != null;
779 mMenuRow = new NotificationMenuRow(mContext); // Back to default
780 if (existed) {
781 createMenu();
782 }
783 }
784
785 public NotificationMenuRowPlugin createMenu() {
786 if (mMenuRow.getMenuView() == null) {
787 mMenuRow.createMenu(this);
788 mMenuRow.setAppName(mAppName);
789 FrameLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
790 LayoutParams.MATCH_PARENT);
791 addView(mMenuRow.getMenuView(), MENU_VIEW_INDEX, lp);
792 }
793 return mMenuRow;
794 }
795
Mady Mellor95d743c2017-01-10 12:05:27 -0800796 public NotificationMenuRowPlugin getProvider() {
797 return mMenuRow;
798 }
799
Selim Cinek1a48bab2017-02-17 19:38:40 -0800800 public void onDensityOrFontScaleChanged() {
Selim Cinek01af3342016-02-09 19:25:31 -0800801 initDimens();
802 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800803 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700804 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800805 }
806 }
807 if (mGuts != null) {
808 View oldGuts = mGuts;
809 int index = indexOfChild(oldGuts);
810 removeView(oldGuts);
811 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
812 R.layout.notification_guts, this, false);
813 mGuts.setVisibility(oldGuts.getVisibility());
814 addView(mGuts, index);
815 }
Mady Mellor95d743c2017-01-10 12:05:27 -0800816 View oldMenu = mMenuRow.getMenuView();
817 if (oldMenu != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800818 int menuIndex = indexOfChild(oldMenu);
819 removeView(oldMenu);
Mady Mellor95d743c2017-01-10 12:05:27 -0800820 mMenuRow.createMenu(ExpandableNotificationRow.this);
Mady Mellor761cde12017-01-10 11:36:39 -0800821 mMenuRow.setAppName(mAppName);
Mady Mellor95d743c2017-01-10 12:05:27 -0800822 addView(mMenuRow.getMenuView(), menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -0800823 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800824 for (NotificationContentView l : mLayouts) {
825 l.reInflateViews();
826 }
Selim Cinek1a48bab2017-02-17 19:38:40 -0800827 mNotificationInflater.onDensityOrFontScaleChanged();
828 onNotificationUpdated();
Selim Cinek01af3342016-02-09 19:25:31 -0800829 }
830
Selim Cinekc3179332016-03-04 14:44:56 -0800831 public void setContentBackground(int customBackgroundColor, boolean animate,
832 NotificationContentView notificationContentView) {
833 if (getShowingLayout() == notificationContentView) {
834 setTintColor(customBackgroundColor, animate);
835 }
836 }
837
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700838 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800839 for (NotificationContentView l : mLayouts) {
840 l.closeRemoteInput();
841 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700842 }
843
Selim Cinekc897bd32016-03-18 17:32:31 -0700844 /**
845 * Set by how much the single line view should be indented.
846 */
847 public void setSingleLineWidthIndention(int indention) {
848 mPrivateLayout.setSingleLineWidthIndention(indention);
849 }
850
851 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700852 return mNotificationColor;
853 }
854
855 private void updateNotificationColor() {
856 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
857 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700858 }
859
860 public HybridNotificationView getSingleLineView() {
861 return mPrivateLayout.getSingleLineView();
862 }
863
Selim Cinekf07d0622016-03-21 19:52:52 -0700864 public boolean isOnKeyguard() {
865 return mOnKeyguard;
866 }
867
Selim Cinekc1e389d2016-04-07 11:02:57 -0700868 public void removeAllChildren() {
869 List<ExpandableNotificationRow> notificationChildren
870 = mChildrenContainer.getNotificationChildren();
871 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
872 for (int i = 0; i < clonedList.size(); i++) {
873 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700874 if (row.keepInParent()) {
875 continue;
876 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700877 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700878 row.setIsChildInGroup(false, null);
879 }
880 onChildrenCountChanged();
881 }
882
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700883 public void setForceUnlocked(boolean forceUnlocked) {
884 mForceUnlocked = forceUnlocked;
885 if (mIsSummaryWithChildren) {
886 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
887 for (ExpandableNotificationRow child : notificationChildren) {
888 child.setForceUnlocked(forceUnlocked);
889 }
890 }
891 }
892
Selim Cineke9bad242016-06-15 11:46:37 -0700893 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700894 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700895 mGroupParentWhenDismissed = mNotificationParent;
896 mRefocusOnDismiss = fromAccessibility;
897 mChildAfterViewWhenDismissed = null;
898 if (isChildInGroup()) {
899 List<ExpandableNotificationRow> notificationChildren =
900 mNotificationParent.getNotificationChildren();
901 int i = notificationChildren.indexOf(this);
902 if (i != -1 && i < notificationChildren.size() - 1) {
903 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
904 }
905 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700906 }
907
908 public boolean isDismissed() {
909 return mDismissed;
910 }
911
912 public boolean keepInParent() {
913 return mKeepInParent;
914 }
915
916 public void setKeepInParent(boolean keepInParent) {
917 mKeepInParent = keepInParent;
918 }
919
920 public boolean isRemoved() {
921 return mRemoved;
922 }
923
Adrian Roosd009ab12016-05-20 17:58:53 -0700924 public void setRemoved() {
925 mRemoved = true;
Selim Cinekef8c2252017-02-10 14:52:18 -0800926 mTranslationWhenRemoved = getTranslationY();
927 mWasChildInGroupWhenRemoved = isChildInGroup();
928 if (isChildInGroup()) {
929 mTranslationWhenRemoved += getNotificationParent().getTranslationY();
930 }
Adrian Roosd009ab12016-05-20 17:58:53 -0700931 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700932 }
933
Selim Cinekef8c2252017-02-10 14:52:18 -0800934 public boolean wasChildInGroupWhenRemoved() {
935 return mWasChildInGroupWhenRemoved;
936 }
937
938 public float getTranslationWhenRemoved() {
939 return mTranslationWhenRemoved;
940 }
941
Selim Cinekd1395642016-04-28 12:22:42 -0700942 public NotificationChildrenContainer getChildrenContainer() {
943 return mChildrenContainer;
944 }
945
Selim Cinekcafa87f2016-10-26 17:00:17 -0700946 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
947 mHeadsupDisappearRunning = headsUpAnimatingAway;
948 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
949 }
950
951 /**
952 * @return if the view was just heads upped and is now animating away. During such a time the
953 * layout needs to be kept consistent
954 */
955 public boolean isHeadsUpAnimatingAway() {
956 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700957 }
958
Selim Cineke9bad242016-06-15 11:46:37 -0700959 public View getChildAfterViewWhenDismissed() {
960 return mChildAfterViewWhenDismissed;
961 }
962
963 public View getGroupParentWhenDismissed() {
964 return mGroupParentWhenDismissed;
965 }
966
Selim Cinek9e624e72016-07-20 13:46:49 -0700967 public void performDismiss() {
Selim Cineke9079112016-12-14 14:41:01 -0800968 if (mOnDismissRunnable != null) {
969 mOnDismissRunnable.run();
970 }
Selim Cinek9e624e72016-07-20 13:46:49 -0700971 }
972
Selim Cineke9079112016-12-14 14:41:01 -0800973 public void setOnDismissRunnable(Runnable onDismissRunnable) {
974 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -0700975 }
976
Selim Cinek281c2022016-10-13 19:14:43 -0700977 public View getNotificationIcon() {
Selim Cinek414ad332017-02-24 19:06:12 -0800978 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek281c2022016-10-13 19:14:43 -0700979 if (notificationHeader != null) {
980 return notificationHeader.getIcon();
981 }
982 return null;
983 }
984
985 /**
986 * @return whether the notification is currently showing a view with an icon.
987 */
988 public boolean isShowingIcon() {
Mady Mellor434180c2017-02-13 11:29:42 -0800989 if (areGutsExposed()) {
990 return false;
991 }
Selim Cinek2ffa02f2017-03-06 15:56:37 -0800992 return getVisibleNotificationHeader() != null;
Selim Cinek281c2022016-10-13 19:14:43 -0700993 }
994
Selim Cinek0242fbb2016-10-19 13:38:32 -0700995 /**
996 * Set how much this notification is transformed into an icon.
997 *
Selim Cinek2b549f42016-11-22 16:38:51 -0800998 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
999 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -08001000 * @param isLastChild is this the last child in the list. If true, then the transformation is
1001 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -07001002 */
Selim Cinek2b549f42016-11-22 16:38:51 -08001003 public void setContentTransformationAmount(float contentTransformationAmount,
1004 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -08001005 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001006 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001007 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001008 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001009 if (changeTransformation) {
1010 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -08001011 }
1012 }
1013
1014 /**
1015 * Set the icons to be visible of this notification.
1016 */
1017 public void setIconsVisible(boolean iconsVisible) {
1018 if (iconsVisible != mIconsVisible) {
1019 mIconsVisible = iconsVisible;
1020 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -07001021 }
1022 }
1023
Selim Cinekdb167372016-11-17 15:41:17 -08001024 @Override
1025 protected void onBelowSpeedBumpChanged() {
1026 updateIconVisibilities();
1027 }
1028
Selim Cinek875a3a12016-11-18 17:52:16 -08001029 private void updateContentTransformation() {
1030 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -08001031 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -08001032 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -08001033 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001034 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001035 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -08001036 translationY *= 0.4f;
1037 } else {
1038 contentAlpha = 1.0f;
1039 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001040 for (NotificationContentView l : mLayouts) {
1041 l.setAlpha(contentAlpha);
1042 l.setTranslationY(translationY);
1043 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001044 if (mChildrenContainer != null) {
1045 mChildrenContainer.setAlpha(contentAlpha);
1046 mChildrenContainer.setTranslationY(translationY);
1047 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -07001048 }
1049 }
1050
1051 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -08001052 boolean visible = isChildInGroup()
1053 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
1054 || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -08001055 for (NotificationContentView l : mLayouts) {
1056 l.setIconsVisible(visible);
1057 }
Selim Cinekdb167372016-11-17 15:41:17 -08001058 if (mChildrenContainer != null) {
1059 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001060 }
1061 }
1062
Selim Cinek875a3a12016-11-18 17:52:16 -08001063 /**
1064 * Get the relative top padding of a view relative to this view. This recursively walks up the
1065 * hierarchy and does the corresponding measuring.
1066 *
1067 * @param view the view to the the padding for. The requested view has to be a child of this
1068 * notification.
1069 * @return the toppadding
1070 */
1071 public int getRelativeTopPadding(View view) {
1072 int topPadding = 0;
1073 while (view.getParent() instanceof ViewGroup) {
1074 topPadding += view.getTop();
1075 view = (View) view.getParent();
1076 if (view instanceof ExpandableNotificationRow) {
1077 return topPadding;
1078 }
1079 }
1080 return topPadding;
1081 }
1082
Selim Cineka1d97902016-12-14 16:31:40 -08001083 public float getContentTranslation() {
1084 return mPrivateLayout.getTranslationY();
1085 }
1086
Selim Cinek6743c0b2017-01-18 18:24:01 -08001087 public void setIsLowPriority(boolean isLowPriority) {
1088 mIsLowPriority = isLowPriority;
1089 mPrivateLayout.setIsLowPriority(isLowPriority);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001090 mNotificationInflater.setIsLowPriority(mIsLowPriority);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001091 if (mChildrenContainer != null) {
1092 mChildrenContainer.setIsLowPriority(isLowPriority);
1093 }
1094 }
1095
Selim Cinek414ad332017-02-24 19:06:12 -08001096 public boolean isLowPriority() {
1097 return mIsLowPriority;
1098 }
1099
Selim Cinek7d1009b2017-01-25 15:28:28 -08001100 public void setUseIncreasedCollapsedHeight(boolean use) {
1101 mUseIncreasedCollapsedHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001102 mNotificationInflater.setUsesIncreasedHeight(use);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001103 }
1104
Selim Cinek87ed69b2017-02-09 15:59:43 -08001105 public void setUseIncreasedHeadsUpHeight(boolean use) {
1106 mUseIncreasedHeadsUpHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001107 mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
1108 }
1109
1110 public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
1111 mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001112 }
1113
Selim Cinekc478f902017-02-22 20:55:44 -08001114 public void setInflateExceptionHandler(InflationExceptionHandler inflateExceptionHandler) {
1115 mNotificationInflater.setInflateExceptionHandler(inflateExceptionHandler);
1116 }
1117
Chris Wren78403d72014-07-28 10:23:24 +01001118 public interface ExpansionLogger {
1119 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
1120 }
Selim Cinek1685e632014-04-08 02:27:49 +02001121
Chris Wren51c75102013-07-16 20:49:17 -04001122 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1123 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001124 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001125 mNotificationInflater = new NotificationInflater(this);
Mady Mellor95d743c2017-01-10 12:05:27 -08001126 mMenuRow = new NotificationMenuRow(mContext);
Selim Cinek01af3342016-02-09 19:25:31 -08001127 initDimens();
1128 }
1129
1130 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -08001131 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
1132 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001133 mNotificationMinHeightLarge = getFontScaledHeight(
Selim Cinek87ed69b2017-02-09 15:59:43 -08001134 R.dimen.notification_min_height_increased);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001135 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
Adrian Roos0aac04f2016-12-08 15:59:29 -08001136 mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001137 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -08001138 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001139 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001140 mMaxHeadsUpHeightIncreased = getFontScaledHeight(
1141 R.dimen.notification_max_heads_up_height_increased);
Mady Mellorb0a82462016-04-30 17:31:02 -07001142 mIncreasedPaddingBetweenElements = getResources()
1143 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinek875a3a12016-11-18 17:52:16 -08001144 mIconTransformContentShiftNoIcon = getResources().getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001145 R.dimen.notification_icon_transform_content_shift);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001146 }
1147
1148 /**
1149 * @param dimenId the dimen to look up
1150 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
1151 */
1152 private int getFontScaledHeight(int dimenId) {
1153 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
1154 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
1155 getResources().getDisplayMetrics().density);
1156 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -04001157 }
1158
Christoph Studera7fe6312014-06-27 19:32:44 +02001159 /**
1160 * Resets this view so it can be re-used for an updated notification.
1161 */
1162 public void reset() {
Jorim Jaggiae441282014-08-01 02:45:18 +02001163 mShowingPublicInitialized = false;
Selim Cinek31094df2014-08-14 19:28:15 +02001164 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001165 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001166 }
1167
Jorim Jaggi251957d2014-04-09 04:24:09 +02001168 @Override
1169 protected void onFinishInflate() {
1170 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001171 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1172 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001173 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1174
1175 for (NotificationContentView l : mLayouts) {
1176 l.setExpandClickListener(mExpandClickListener);
1177 l.setContainingNotification(this);
1178 }
Selim Cinekab29aeb2015-02-20 18:18:32 +01001179 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1180 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001181 @Override
1182 public void onInflate(ViewStub stub, View inflated) {
1183 mGuts = (NotificationGuts) inflated;
1184 mGuts.setClipTopAmount(getClipTopAmount());
1185 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001186 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001187 }
1188 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001189 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1190 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1191
1192 @Override
1193 public void onInflate(ViewStub stub, View inflated) {
1194 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001195 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek414ad332017-02-24 19:06:12 -08001196 mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001197 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -08001198 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +01001199 }
1200 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001201
Mady Mellor95d743c2017-01-10 12:05:27 -08001202 // Add the views that we translate to reveal the menu
Mady Mellor4b80b102016-01-22 08:03:58 -08001203 mTranslateableViews = new ArrayList<View>();
1204 for (int i = 0; i < getChildCount(); i++) {
1205 mTranslateableViews.add(getChildAt(i));
1206 }
1207 // Remove views that don't translate
Mady Mellor4b80b102016-01-22 08:03:58 -08001208 mTranslateableViews.remove(mChildrenContainerStub);
1209 mTranslateableViews.remove(mGutsStub);
1210 }
1211
Mady Mellor4b80b102016-01-22 08:03:58 -08001212 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001213 if (mTranslateAnim != null) {
1214 mTranslateAnim.cancel();
1215 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001216 if (mTranslateableViews != null) {
1217 for (int i = 0; i < mTranslateableViews.size(); i++) {
1218 mTranslateableViews.get(i).setTranslationX(0);
1219 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001220 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001221 invalidateOutline();
Mady Mellor95d743c2017-01-10 12:05:27 -08001222 mMenuRow.resetMenu();
Mady Mellor4b80b102016-01-22 08:03:58 -08001223 }
1224
1225 public void animateTranslateNotification(final float leftTarget) {
1226 if (mTranslateAnim != null) {
1227 mTranslateAnim.cancel();
1228 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001229 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001230 if (mTranslateAnim != null) {
1231 mTranslateAnim.start();
1232 }
1233 }
1234
1235 @Override
1236 public void setTranslation(float translationX) {
1237 if (areGutsExposed()) {
1238 // Don't translate if guts are showing.
1239 return;
1240 }
1241 // Translate the group of views
1242 for (int i = 0; i < mTranslateableViews.size(); i++) {
1243 if (mTranslateableViews.get(i) != null) {
1244 mTranslateableViews.get(i).setTranslationX(translationX);
1245 }
1246 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001247 invalidateOutline();
Mady Mellor95d743c2017-01-10 12:05:27 -08001248 if (mMenuRow.getMenuView() != null) {
1249 mMenuRow.onTranslationUpdate(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001250 }
1251 }
1252
1253 @Override
1254 public float getTranslation() {
1255 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1256 // All of the views in the list should have same translation, just use first one.
1257 return mTranslateableViews.get(0).getTranslationX();
1258 }
1259 return 0;
1260 }
1261
1262 public Animator getTranslateViewAnimator(final float leftTarget,
1263 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001264 if (mTranslateAnim != null) {
1265 mTranslateAnim.cancel();
1266 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001267 if (areGutsExposed()) {
1268 // No translation if guts are exposed.
1269 return null;
1270 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001271 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1272 leftTarget);
1273 if (listener != null) {
1274 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001275 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001276 translateAnim.addListener(new AnimatorListenerAdapter() {
1277 boolean cancelled = false;
1278
1279 @Override
1280 public void onAnimationCancel(Animator anim) {
1281 cancelled = true;
1282 }
1283
1284 @Override
1285 public void onAnimationEnd(Animator anim) {
Mady Mellor95d743c2017-01-10 12:05:27 -08001286 if (!cancelled && leftTarget == 0) {
1287 mMenuRow.resetMenu();
Mady Mellorb0a82462016-04-30 17:31:02 -07001288 mTranslateAnim = null;
1289 }
1290 }
1291 });
1292 mTranslateAnim = translateAnim;
1293 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001294 }
1295
Selim Cinekab29aeb2015-02-20 18:18:32 +01001296 public void inflateGuts() {
1297 if (mGuts == null) {
1298 mGutsStub.inflate();
1299 }
1300 }
1301
Selim Cinekda42d652015-12-04 15:51:16 -08001302 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001303 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1304 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001305 if (mChildrenContainer != null) {
1306 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1307 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001308 }
Selim Cinekda42d652015-12-04 15:51:16 -08001309 // The limits might have changed if the view suddenly became a group or vice versa
1310 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001311 }
1312
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001313 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001314 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1315 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001316 // Add a record for the entire layout since its content is somehow small.
1317 // The event comes from a leaf view that is interacted with.
1318 AccessibilityEvent record = AccessibilityEvent.obtain();
1319 onInitializeAccessibilityEvent(record);
1320 dispatchPopulateAccessibilityEvent(record);
1321 event.appendRecord(record);
1322 return true;
1323 }
1324 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001325 }
Chris Wren51c75102013-07-16 20:49:17 -04001326
John Spurlocke15452b2014-08-21 09:44:39 -04001327 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001328 public void setDark(boolean dark, boolean fade, long delay) {
1329 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001330 final NotificationContentView showing = getShowingLayout();
1331 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001332 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001333 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001334 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001335 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001336 }
John Spurlocke15452b2014-08-21 09:44:39 -04001337 }
1338
Chris Wren51c75102013-07-16 20:49:17 -04001339 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001340 if (mIsSummaryWithChildren && !mShowingPublic) {
1341 return !mChildrenExpanded;
1342 }
Chris Wren51c75102013-07-16 20:49:17 -04001343 return mExpandable;
1344 }
1345
1346 public void setExpandable(boolean expandable) {
1347 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001348 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001349 }
1350
Selim Cinek4ffd6362015-12-29 15:12:23 +01001351 @Override
1352 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001353 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1354 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001355 }
1356
Selim Cinek1685e632014-04-08 02:27:49 +02001357 /**
1358 * @return whether the user has changed the expansion state
1359 */
1360 public boolean hasUserChangedExpansion() {
1361 return mHasUserChangedExpansion;
1362 }
1363
Chris Wren51c75102013-07-16 20:49:17 -04001364 public boolean isUserExpanded() {
1365 return mUserExpanded;
1366 }
1367
Selim Cinek1685e632014-04-08 02:27:49 +02001368 /**
1369 * Set this notification to be expanded by the user
1370 *
1371 * @param userExpanded whether the user wants this notification to be expanded
1372 */
Chris Wren51c75102013-07-16 20:49:17 -04001373 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001374 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1375 }
1376
1377 /**
1378 * Set this notification to be expanded by the user
1379 *
1380 * @param userExpanded whether the user wants this notification to be expanded
1381 * @param allowChildExpansion whether a call to this method allows expanding children
1382 */
1383 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001384 mFalsingManager.setNotificationExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08001385 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion
1386 && !mChildrenContainer.showingAsLowPriority()) {
Chris Wren698b1702016-05-23 11:16:32 -04001387 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001388 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -08001389 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001390 return;
1391 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001392 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001393 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001394 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001395 mUserExpanded = userExpanded;
Selim Cinek414ad332017-02-24 19:06:12 -08001396 onExpansionChanged(true /* userAction */, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001397 }
1398
Selim Cinekccd14fb2014-08-12 18:53:24 +02001399 public void resetUserExpansion() {
Selim Cinek414ad332017-02-24 19:06:12 -08001400 boolean changed = mUserExpanded;
Selim Cinekccd14fb2014-08-12 18:53:24 +02001401 mHasUserChangedExpansion = false;
1402 mUserExpanded = false;
Selim Cinek414ad332017-02-24 19:06:12 -08001403 if (changed && mIsSummaryWithChildren) {
1404 mChildrenContainer.onExpansionChanged();
1405 }
1406 updateShelfIconColor();
Selim Cinekccd14fb2014-08-12 18:53:24 +02001407 }
1408
Chris Wren51c75102013-07-16 20:49:17 -04001409 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001410 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001411 }
1412
1413 public void setUserLocked(boolean userLocked) {
1414 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001415 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001416 if (mIsSummaryWithChildren) {
1417 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek7baaa9e2016-07-21 17:21:09 -07001418 if (userLocked || !isGroupExpanded()) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001419 updateBackgroundForGroupState();
1420 }
Selim Cinek42357e02016-02-24 18:48:01 -08001421 }
Chris Wren51c75102013-07-16 20:49:17 -04001422 }
1423
Selim Cinek1685e632014-04-08 02:27:49 +02001424 /**
1425 * @return has the system set this notification to be expanded
1426 */
1427 public boolean isSystemExpanded() {
1428 return mIsSystemExpanded;
1429 }
1430
1431 /**
1432 * Set this notification to be expanded by the system.
1433 *
1434 * @param expand whether the system wants this notification to be expanded.
1435 */
1436 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001437 if (expand != mIsSystemExpanded) {
1438 final boolean wasExpanded = isExpanded();
1439 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001440 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek414ad332017-02-24 19:06:12 -08001441 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001442 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001443 mChildrenContainer.updateGroupOverflow();
1444 }
Selim Cinek31094df2014-08-14 19:28:15 +02001445 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001446 }
1447
1448 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001449 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001450 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001451 public void setOnKeyguard(boolean onKeyguard) {
1452 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001453 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001454 mOnKeyguard = onKeyguard;
Selim Cinek414ad332017-02-24 19:06:12 -08001455 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cinek31094df2014-08-14 19:28:15 +02001456 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001457 if (mIsSummaryWithChildren) {
1458 mChildrenContainer.updateGroupOverflow();
1459 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001460 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001461 }
1462 }
Selim Cinek1685e632014-04-08 02:27:49 +02001463 }
1464
1465 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001466 * @return Can the underlying notification be cleared? This can be different from whether the
1467 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1468 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001469 */
1470 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001471 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1472 return false;
1473 }
1474 if (mIsSummaryWithChildren) {
1475 List<ExpandableNotificationRow> notificationChildren =
1476 mChildrenContainer.getNotificationChildren();
1477 for (int i = 0; i < notificationChildren.size(); i++) {
1478 ExpandableNotificationRow child = notificationChildren.get(i);
1479 if (!child.isClearable()) {
1480 return false;
1481 }
1482 }
1483 }
1484 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001485 }
1486
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001487 @Override
1488 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001489 if (isUserLocked()) {
1490 return getActualHeight();
1491 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001492 if (mGuts != null && mGuts.isExposed()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001493 return mGuts.getHeight();
1494 } else if ((isChildInGroup() && !isGroupExpanded())) {
1495 return mPrivateLayout.getMinHeight();
Adrian Roos0aac04f2016-12-08 15:59:29 -08001496 } else if (mShowAmbient) {
1497 return getAmbientHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001498 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1499 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001500 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001501 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001502 } else if (!mOnKeyguard && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07001503 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001504 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1505 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001506 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001507 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001508 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001509 }
Selim Cinek31aada42015-12-18 17:51:15 -08001510 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001511 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001512 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001513 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001514 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001515 }
Selim Cinek1685e632014-04-08 02:27:49 +02001516
Mady Mellor43c2cd12016-12-12 21:05:13 -08001517 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001518 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001519 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001520 }
1521
Selim Cinek263398f2015-10-21 17:40:23 -07001522 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05001523 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001524 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1525 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
Selim Cinek414ad332017-02-24 19:06:12 -08001526 mChildrenContainer.recreateNotificationHeader(mExpandClickListener
1527 );
Selim Cinek263398f2015-10-21 17:40:23 -07001528 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001529 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001530 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001531 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001532 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001533 }
1534
Mady Mellorb0a82462016-04-30 17:31:02 -07001535 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001536 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001537 mChildrenContainer.updateChildrenHeaderAppearance();
1538 }
1539 }
1540
Selim Cinek1685e632014-04-08 02:27:49 +02001541 /**
1542 * Check whether the view state is currently expanded. This is given by the system in {@link
1543 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1544 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1545 * view can differ from this state, if layout params are modified from outside.
1546 *
1547 * @return whether the view state is currently expanded.
1548 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001549 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001550 return isExpanded(false /* allowOnKeyguard */);
1551 }
1552
1553 public boolean isExpanded(boolean allowOnKeyguard) {
1554 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001555 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1556 || isUserExpanded());
1557 }
1558
1559 private boolean isSystemChildExpanded() {
1560 return mIsSystemChildExpanded;
1561 }
1562
1563 public void setSystemChildExpanded(boolean expanded) {
1564 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001565 }
1566
1567 @Override
1568 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1569 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001570 updateMaxHeights();
Mady Mellor95d743c2017-01-10 12:05:27 -08001571 if (mMenuRow.getMenuView() != null) {
1572 mMenuRow.onHeightUpdate();
Mady Mellora6edc872016-04-26 11:01:03 -07001573 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001574 updateContentShiftHeight();
1575 }
1576
1577 /**
1578 * Updates the content shift height such that the header is completely hidden when coming from
1579 * the top.
1580 */
1581 private void updateContentShiftHeight() {
Selim Cinek414ad332017-02-24 19:06:12 -08001582 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek875a3a12016-11-18 17:52:16 -08001583 if (notificationHeader != null) {
1584 CachingIconView icon = notificationHeader.getIcon();
1585 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1586 } else {
1587 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1588 }
Selim Cinek1685e632014-04-08 02:27:49 +02001589 }
1590
Selim Cinek8d490d42015-04-10 00:05:50 -07001591 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001592 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001593 View expandedChild = mPrivateLayout.getExpandedChild();
1594 if (expandedChild == null) {
1595 expandedChild = mPrivateLayout.getContractedChild();
1596 }
1597 mMaxExpandHeight = expandedChild.getHeight();
1598 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001599 if (headsUpChild == null) {
1600 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001601 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001602 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001603 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001604 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001605 }
1606 }
1607
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001608 @Override
1609 public void notifyHeightChanged(boolean needsAnimation) {
1610 super.notifyHeightChanged(needsAnimation);
1611 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1612 }
1613
Selim Cinek3c76d502016-02-19 15:16:33 -08001614 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001615 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001616 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001617 }
1618
Mady Mellor43c2cd12016-12-12 21:05:13 -08001619 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001620 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001621 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001622 if (mIsSummaryWithChildren) {
1623 List<ExpandableNotificationRow> notificationChildren =
1624 mChildrenContainer.getNotificationChildren();
1625 for (int i = 0; i < notificationChildren.size(); i++) {
1626 ExpandableNotificationRow child = notificationChildren.get(i);
1627 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1628 }
1629 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001630 }
1631
Mady Mellor43c2cd12016-12-12 21:05:13 -08001632 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001633 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1634 long duration) {
1635 boolean oldShowingPublic = mShowingPublic;
1636 mShowingPublic = mSensitive && hideSensitive;
1637 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1638 return;
1639 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001640
1641 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001642 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001643
Jorim Jaggiae441282014-08-01 02:45:18 +02001644 if (!animated) {
1645 mPublicLayout.animate().cancel();
1646 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001647 if (mChildrenContainer != null) {
1648 mChildrenContainer.animate().cancel();
1649 mChildrenContainer.setAlpha(1f);
1650 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001651 mPublicLayout.setAlpha(1f);
1652 mPrivateLayout.setAlpha(1f);
1653 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001654 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001655 } else {
1656 animateShowingPublic(delay, duration);
1657 }
Selim Cinekc3179332016-03-04 14:44:56 -08001658 NotificationContentView showingLayout = getShowingLayout();
1659 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001660 mPrivateLayout.updateExpandButtons(isExpandable());
Adrian Roose5726a22016-12-19 14:26:51 -08001661 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02001662 mShowingPublicInitialized = true;
1663 }
1664
1665 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001666 View[] privateViews = mIsSummaryWithChildren
1667 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001668 : new View[] {mPrivateLayout};
1669 View[] publicViews = new View[] {mPublicLayout};
1670 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1671 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1672 for (final View hiddenView : hiddenChildren) {
1673 hiddenView.setVisibility(View.VISIBLE);
1674 hiddenView.animate().cancel();
1675 hiddenView.animate()
1676 .alpha(0f)
1677 .setStartDelay(delay)
1678 .setDuration(duration)
1679 .withEndAction(new Runnable() {
1680 @Override
1681 public void run() {
1682 hiddenView.setVisibility(View.INVISIBLE);
1683 }
1684 });
1685 }
1686 for (View showView : shownChildren) {
1687 showView.setVisibility(View.VISIBLE);
1688 showView.setAlpha(0f);
1689 showView.animate().cancel();
1690 showView.animate()
1691 .alpha(1f)
1692 .setStartDelay(delay)
1693 .setDuration(duration);
1694 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001695 }
1696
Mady Mellor43c2cd12016-12-12 21:05:13 -08001697 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08001698 public boolean mustStayOnScreen() {
1699 return mIsHeadsUp;
1700 }
1701
Selim Cinek9e624e72016-07-20 13:46:49 -07001702 /**
1703 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1704 * otherwise some state might not be updated. To request about the general clearability
1705 * see {@link #isClearable()}.
1706 */
1707 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001708 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001709 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001710
Ricky Waicd35def2016-05-03 11:07:07 +01001711 public void makeActionsVisibile() {
1712 setUserExpanded(true, true);
1713 if (isChildInGroup()) {
1714 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1715 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001716 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001717 }
1718
Selim Cinekb5605e52015-02-20 18:21:41 +01001719 public void setChildrenExpanded(boolean expanded, boolean animate) {
1720 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001721 if (mChildrenContainer != null) {
1722 mChildrenContainer.setChildrenExpanded(expanded);
1723 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001724 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001725 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001726 }
1727
Selim Cinekb5605e52015-02-20 18:21:41 +01001728 public static void applyTint(View v, int color) {
1729 int alpha;
1730 if (color != 0) {
1731 alpha = COLORED_DIVIDER_ALPHA;
1732 } else {
1733 color = 0xff000000;
1734 alpha = DEFAULT_DIVIDER_ALPHA;
1735 }
1736 if (v.getBackground() instanceof ColorDrawable) {
1737 ColorDrawable background = (ColorDrawable) v.getBackground();
1738 background.mutate();
1739 background.setColor(color);
1740 background.setAlpha(alpha);
1741 }
1742 }
1743
Selim Cinek1685e632014-04-08 02:27:49 +02001744 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001745 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001746 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001747
Mady Mellor34958fa2016-02-23 09:52:17 -08001748 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001749 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08001750 }
1751
Jorim Jaggibe565df2014-04-28 17:51:23 +02001752 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001753 public boolean isContentExpandable() {
Selim Cinekc0ac4af2017-03-03 15:13:48 -08001754 if (mIsSummaryWithChildren && !mShowingPublic) {
1755 return true;
1756 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001757 NotificationContentView showingLayout = getShowingLayout();
1758 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001759 }
1760
1761 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001762 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001763 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001764 return mChildrenContainer;
1765 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001766 return getShowingLayout();
1767 }
1768
1769 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001770 protected void onAppearAnimationFinished(boolean wasAppearing) {
1771 super.onAppearAnimationFinished(wasAppearing);
1772 if (wasAppearing) {
1773 // During the animation the visible view might have changed, so let's make sure all
1774 // alphas are reset
1775 if (mChildrenContainer != null) {
1776 mChildrenContainer.setAlpha(1.0f);
1777 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1778 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001779 for (NotificationContentView l : mLayouts) {
1780 l.setAlpha(1.0f);
1781 l.setLayerType(LAYER_TYPE_NONE, null);
1782 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07001783 }
1784 }
1785
1786 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001787 public int getExtraBottomPadding() {
1788 if (mIsSummaryWithChildren && isGroupExpanded()) {
1789 return mIncreasedPaddingBetweenElements;
1790 }
1791 return 0;
1792 }
1793
1794 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001795 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinek4ca6c632017-02-23 18:03:37 -08001796 boolean changed = height != getActualHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +01001797 super.setActualHeight(height, notifyListeners);
Selim Cinek4ca6c632017-02-23 18:03:37 -08001798 if (changed && isRemoved()) {
1799 // TODO: remove this once we found the gfx bug for this.
1800 // This is a hack since a removed view sometimes would just stay blank. it occured
1801 // when sending yourself a message and then clicking on it.
1802 ViewGroup parent = (ViewGroup) getParent();
1803 if (parent != null) {
1804 parent.invalidate();
1805 }
1806 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001807 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08001808 mGuts.setActualHeight(height);
1809 return;
1810 }
Selim Cinekeef84282015-10-30 16:28:00 -07001811 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001812 for (NotificationContentView l : mLayouts) {
1813 l.setContentHeight(contentHeight);
1814 }
Selim Cinek42357e02016-02-24 18:48:01 -08001815 if (mIsSummaryWithChildren) {
1816 mChildrenContainer.setActualHeight(height);
1817 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001818 if (mGuts != null) {
1819 mGuts.setActualHeight(height);
1820 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001821 }
1822
1823 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001824 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001825 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001826 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001827 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001828 NotificationContentView showingLayout = getShowingLayout();
1829 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001830 }
1831
1832 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001833 public int getMinHeight() {
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001834 if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08001835 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1836 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001837 return mChildrenContainer.getMinHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001838 } else if (!mOnKeyguard && mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001839 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001840 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001841 NotificationContentView showingLayout = getShowingLayout();
1842 return showingLayout.getMinHeight();
1843 }
1844
Adrian Roos0aac04f2016-12-08 15:59:29 -08001845 private int getAmbientHeight() {
1846 NotificationContentView showingLayout = getShowingLayout();
1847 return showingLayout.getAmbientChild() != null
1848 ? showingLayout.getAmbientChild().getHeight()
1849 : getCollapsedHeight();
1850 }
1851
Selim Cinek816c8e42015-11-19 12:00:45 -08001852 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001853 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001854 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001855 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001856 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001857 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001858 }
1859
1860 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001861 public void setClipTopAmount(int clipTopAmount) {
1862 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001863 for (NotificationContentView l : mLayouts) {
1864 l.setClipTopAmount(clipTopAmount);
1865 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001866 if (mGuts != null) {
1867 mGuts.setClipTopAmount(clipTopAmount);
1868 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001869 }
1870
Selim Cineka686b2c2016-10-26 13:58:27 -07001871 @Override
1872 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001873 if (clipBottomAmount != mClipBottomAmount) {
1874 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001875 for (NotificationContentView l : mLayouts) {
1876 l.setClipBottomAmount(clipBottomAmount);
1877 }
Selim Cinek65d418e2016-11-29 15:42:34 -08001878 if (mGuts != null) {
1879 mGuts.setClipBottomAmount(clipBottomAmount);
1880 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001881 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001882 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001883 // We have to update this even if it hasn't changed, since the children locations can
1884 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001885 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
1886 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001887 }
1888
Selim Cinek31094df2014-08-14 19:28:15 +02001889 public boolean isMaxExpandHeightInitialized() {
1890 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001891 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001892
Selim Cinek42357e02016-02-24 18:48:01 -08001893 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001894 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1895 }
Chris Wren78403d72014-07-28 10:23:24 +01001896
Selim Cinek1a48bab2017-02-17 19:38:40 -08001897 public void setLegacy(boolean legacy) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08001898 for (NotificationContentView l : mLayouts) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08001899 l.setLegacy(legacy);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001900 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001901 }
1902
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001903 @Override
1904 protected void updateBackgroundTint() {
1905 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001906 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001907 if (mIsSummaryWithChildren) {
1908 List<ExpandableNotificationRow> notificationChildren =
1909 mChildrenContainer.getNotificationChildren();
1910 for (int i = 0; i < notificationChildren.size(); i++) {
1911 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001912 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001913 }
1914 }
1915 }
1916
Mady Mellorb0a82462016-04-30 17:31:02 -07001917 /**
1918 * Called when a group has finished animating from collapsed or expanded state.
1919 */
1920 public void onFinishedExpansionChange() {
1921 mGroupExpansionChanging = false;
1922 updateBackgroundForGroupState();
1923 }
1924
1925 /**
1926 * Updates the parent and children backgrounds in a group based on the expansion state.
1927 */
1928 public void updateBackgroundForGroupState() {
1929 if (mIsSummaryWithChildren) {
1930 // Only when the group has finished expanding do we hide its background.
1931 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1932 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1933 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1934 for (int i = 0; i < children.size(); i++) {
1935 children.get(i).updateBackgroundForGroupState();
1936 }
1937 } else if (isChildInGroup()) {
1938 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
1939 // Only show a background if the group is expanded OR if it is expanding / collapsing
1940 // and has a custom background color
1941 final boolean showBackground = isGroupExpanded()
1942 || ((mNotificationParent.isGroupExpansionChanging()
1943 || mNotificationParent.isUserLocked()) && childColor != 0);
1944 mShowNoBackground = !showBackground;
1945 } else {
1946 // Only children or parents ever need no background.
1947 mShowNoBackground = false;
1948 }
1949 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001950 updateBackground();
1951 }
1952
Adrian Roos4a579672016-05-24 16:54:37 -07001953 public int getPositionOfChild(ExpandableNotificationRow childRow) {
1954 if (mIsSummaryWithChildren) {
1955 return mChildrenContainer.getPositionInLinearLayout(childRow);
1956 }
1957 return 0;
1958 }
1959
Chris Wren78403d72014-07-28 10:23:24 +01001960 public void setExpansionLogger(ExpansionLogger logger, String key) {
1961 mLogger = logger;
1962 mLoggingKey = key;
1963 }
1964
Chris Wren6abeeb92016-05-26 14:44:38 -04001965 public void onExpandedByGesture(boolean userExpanded) {
1966 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
1967 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
1968 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
1969 }
1970 MetricsLogger.action(mContext, event, userExpanded);
1971 }
1972
Selim Cinek6183d122016-01-14 18:48:41 -08001973 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001974 public float getIncreasedPaddingAmount() {
1975 if (mIsSummaryWithChildren) {
1976 if (isGroupExpanded()) {
1977 return 1.0f;
1978 } else if (isUserLocked()) {
Selim Cinek414ad332017-02-24 19:06:12 -08001979 return mChildrenContainer.getIncreasedPaddingAmount();
Selim Cinek42357e02016-02-24 18:48:01 -08001980 }
Selim Cinek99104832017-01-25 14:47:33 -08001981 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08001982 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08001983 }
1984 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001985 }
1986
Selim Cineka7ed2c12017-01-23 20:47:24 -08001987 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08001988 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08001989 }
1990
Selim Cinek61633a82016-01-25 15:54:10 -08001991 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001992 protected boolean disallowSingleClick(MotionEvent event) {
1993 float x = event.getX();
1994 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001995 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001996 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001997 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001998 }
1999 return super.disallowSingleClick(event);
2000 }
2001
Selim Cinek414ad332017-02-24 19:06:12 -08002002 private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04002003 boolean nowExpanded = isExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08002004 if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
Chris Wren698b1702016-05-23 11:16:32 -04002005 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
2006 }
Selim Cinek414ad332017-02-24 19:06:12 -08002007 if (nowExpanded != wasExpanded) {
2008 updateShelfIconColor();
2009 if (mLogger != null) {
2010 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded);
2011 }
2012 if (mIsSummaryWithChildren) {
2013 mChildrenContainer.onExpansionChanged();
2014 }
Chris Wren78403d72014-07-28 10:23:24 +01002015 }
2016 }
Selim Cinek570981d2015-12-01 11:37:01 -08002017
Selim Cineke9bad242016-06-15 11:46:37 -07002018 @Override
2019 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2020 super.onInitializeAccessibilityNodeInfoInternal(info);
2021 if (canViewBeDismissed()) {
2022 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
2023 }
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002024 boolean expandable = mShowingPublic;
2025 boolean isExpanded = false;
2026 if (!expandable) {
2027 if (mIsSummaryWithChildren) {
2028 expandable = true;
2029 if (!mIsLowPriority || isExpanded()) {
2030 isExpanded = isGroupExpanded();
2031 }
2032 } else {
2033 expandable = mPrivateLayout.isContentExpandable();
2034 isExpanded = isExpanded();
2035 }
2036 }
2037 if (expandable) {
2038 if (isExpanded) {
2039 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
2040 } else {
2041 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
2042 }
2043 }
Selim Cineke9bad242016-06-15 11:46:37 -07002044 }
2045
2046 @Override
2047 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
2048 if (super.performAccessibilityActionInternal(action, arguments)) {
2049 return true;
2050 }
2051 switch (action) {
2052 case AccessibilityNodeInfo.ACTION_DISMISS:
2053 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
2054 true /* fromAccessibility */);
2055 return true;
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002056 case AccessibilityNodeInfo.ACTION_COLLAPSE:
2057 case AccessibilityNodeInfo.ACTION_EXPAND:
2058 mExpandClickListener.onClick(this);
2059 return true;
Selim Cineke9bad242016-06-15 11:46:37 -07002060 }
2061 return false;
2062 }
2063
2064 public boolean shouldRefocusOnDismiss() {
2065 return mRefocusOnDismiss || isAccessibilityFocused();
2066 }
2067
Selim Cinek570981d2015-12-01 11:37:01 -08002068 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08002069 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08002070 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002071
2072 @Override
2073 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
2074 return new NotificationViewState(stackScrollState);
2075 }
2076
Selim Cinekd127d792016-11-01 19:11:41 -07002077 @Override
2078 public boolean isAboveShelf() {
Selim Cinekc8007c52017-02-28 16:09:56 -08002079 return !isOnKeyguard()
2080 && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf));
Selim Cinekd127d792016-11-01 19:11:41 -07002081 }
2082
Adrian Roos0aac04f2016-12-08 15:59:29 -08002083 public void setShowAmbient(boolean showAmbient) {
2084 if (showAmbient != mShowAmbient) {
2085 mShowAmbient = showAmbient;
2086 notifyHeightChanged(false /* needsAnimation */);
2087 }
2088 }
2089
Selim Cinekd127d792016-11-01 19:11:41 -07002090 public void setAboveShelf(boolean aboveShelf) {
2091 mAboveShelf = aboveShelf;
2092 }
2093
Selim Cinekd4776a52017-02-14 18:50:16 -08002094 public static class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08002095
2096 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07002097
Selim Cinekbbcebde2016-11-09 18:28:20 -08002098
2099 private NotificationViewState(StackScrollState stackScrollState) {
2100 mOverallState = stackScrollState;
2101 }
2102
2103 @Override
2104 public void applyToView(View view) {
2105 super.applyToView(view);
2106 if (view instanceof ExpandableNotificationRow) {
2107 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinekbbcebde2016-11-09 18:28:20 -08002108 row.applyChildrenState(mOverallState);
2109 }
2110 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002111
2112 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08002113 protected void onYTranslationAnimationFinished(View view) {
2114 super.onYTranslationAnimationFinished(view);
Selim Cinekd4776a52017-02-14 18:50:16 -08002115 if (view instanceof ExpandableNotificationRow) {
2116 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
2117 if (row.isHeadsUpAnimatingAway()) {
2118 row.setHeadsUpAnimatingAway(false);
2119 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002120 }
2121 }
2122
2123 @Override
2124 public void animateTo(View child, AnimationProperties properties) {
2125 super.animateTo(child, properties);
2126 if (child instanceof ExpandableNotificationRow) {
2127 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
2128 row.startChildAnimation(mOverallState, properties);
2129 }
2130 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002131 }
Chris Wren51c75102013-07-16 20:49:17 -04002132}