blob: 013554c16f9a30bc6b2655aada19f481e7d4e06f [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
Mady Mellor4b80b102016-01-22 08:03:58 -080019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
Mady Mellor4b80b102016-01-22 08:03:58 -080021import android.animation.ObjectAnimator;
Mady Mellor4b80b102016-01-22 08:03:58 -080022import android.animation.ValueAnimator.AnimatorUpdateListener;
Selim Cinekddf1b392016-05-27 16:33:10 -070023import android.annotation.Nullable;
Chris Wren51c75102013-07-16 20:49:17 -040024import android.content.Context;
Selim Cinek6743c0b2017-01-18 18:24:01 -080025import android.content.res.ColorStateList;
Selim Cinekcab4a602014-09-03 14:47:57 +020026import android.graphics.drawable.AnimatedVectorDrawable;
27import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010028import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020029import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080030import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070031import android.os.Bundle;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020032import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040033import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070034import android.util.FloatProperty;
35import android.util.Property;
Selim Cinek01af3342016-02-09 19:25:31 -080036import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080037import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080038import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050039import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080040import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020041import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020042import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070043import android.view.accessibility.AccessibilityNodeInfo;
Selim Cinek98713a42015-09-21 15:47:20 +020044import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020045import android.widget.ImageView;
Selim Cinekb5605e52015-02-20 18:21:41 +010046
Chris Wren698b1702016-05-23 11:16:32 -040047import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010048import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070049import com.android.internal.util.NotificationColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080050import com.android.internal.widget.CachingIconView;
Selim Cinek0242fbb2016-10-19 13:38:32 -070051import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050052import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070053import com.android.systemui.classifier.FalsingManager;
Selim Cinekc897bd32016-03-18 17:32:31 -070054import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinek6743c0b2017-01-18 18:24:01 -080055import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cineka7d4f822016-12-06 14:34:47 -080056import com.android.systemui.statusbar.notification.VisualStabilityManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010057import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinek31aada42015-12-18 17:51:15 -080058import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek0cfbef42016-11-09 19:06:36 -080059import com.android.systemui.statusbar.stack.AnimationProperties;
60import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010061import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070062import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010063import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010064
Mady Mellor4b80b102016-01-22 08:03:58 -080065import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010066import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050067
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020068public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010069
70 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
71 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Selim Cinek0242fbb2016-10-19 13:38:32 -070072 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -080073 private int mIconTransformContentShiftNoIcon;
Selim Cinek01af3342016-02-09 19:25:31 -080074 private int mNotificationMinHeightLegacy;
75 private int mMaxHeadsUpHeightLegacy;
76 private int mMaxHeadsUpHeight;
77 private int mNotificationMinHeight;
78 private int mNotificationMaxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -080079 private int mNotificationAmbientHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -070080 private int mIncreasedPaddingBetweenElements;
Chris Wren51c75102013-07-16 20:49:17 -040081
Selim Cinek1685e632014-04-08 02:27:49 +020082 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040083 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020084 /** Has the user actively changed the expansion state of this row */
85 private boolean mHasUserChangedExpansion;
86 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040087 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -080088
89 /**
90 * Has this notification been expanded while it was pinned
91 */
92 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +020093 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040094 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020095 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050096 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020097 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -080098 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +020099 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700100 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400101
Selim Cinek1685e632014-04-08 02:27:49 +0200102 /**
103 * Is this notification expanded by the system. The expansion state can be overridden by the
104 * user expansion.
105 */
106 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200107
108 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700109 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200110 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700111 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200112
Mady Mellorb0a82462016-04-30 17:31:02 -0700113 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800114 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200115 private NotificationContentView mPublicLayout;
116 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800117 private NotificationContentView[] mLayouts;
Selim Cinek1685e632014-04-08 02:27:49 +0200118 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700119 private int mHeadsUpHeight;
Selim Cinek4bb59342016-04-08 19:29:35 -0700120 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100121 private ExpansionLogger mLogger;
122 private String mLoggingKey;
Mady Mellor4b80b102016-01-22 08:03:58 -0800123 private NotificationSettingsIconRow mSettingsIconRow;
Selim Cinek8d490d42015-04-10 00:05:50 -0700124 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800125 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200126 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700127 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100128 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200129 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100130 private ViewStub mChildrenContainerStub;
131 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100132 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700133 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100134 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor4b80b102016-01-22 08:03:58 -0800135 private ViewStub mSettingsIconRowStub;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100136 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100137 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700138 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700139 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800140 private HeadsUpManager mHeadsUpManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200141
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700142 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800143 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700144 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700145 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800146 private OnExpandClickListener mOnExpandClickListener;
Mady Mellorb0a82462016-04-30 17:31:02 -0700147 private boolean mGroupExpansionChanging;
148
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800149 private OnClickListener mExpandClickListener = new OnClickListener() {
150 @Override
151 public void onClick(View v) {
Selim Cinek624c02db2015-12-14 21:00:02 -0800152 if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700153 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400154 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
155 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
156 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400157 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
158 nowExpanded);
159 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800160 } else {
Selim Cineke9bad242016-06-15 11:46:37 -0700161 if (v.isAccessibilityFocused()) {
162 mPrivateLayout.setFocusOnVisibilityChange();
163 }
Selim Cinek31aada42015-12-18 17:51:15 -0800164 boolean nowExpanded;
165 if (isPinned()) {
166 nowExpanded = !mExpandedWhenPinned;
167 mExpandedWhenPinned = nowExpanded;
168 } else {
169 nowExpanded = !isExpanded();
170 setUserExpanded(nowExpanded);
171 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800172 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800173 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400174 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
175 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800176 }
177 }
178 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700179 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700180 private boolean mDismissed;
181 private boolean mKeepInParent;
182 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700183 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
184 new FloatProperty<ExpandableNotificationRow>("translate") {
185 @Override
186 public void setValue(ExpandableNotificationRow object, float value) {
187 object.setTranslation(value);
188 }
189
190 @Override
191 public Float get(ExpandableNotificationRow object) {
192 return object.getTranslation();
193 }
194 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700195 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700196 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700197 private View mChildAfterViewWhenDismissed;
198 private View mGroupParentWhenDismissed;
199 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800200 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700201 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700202 private boolean mAboveShelf;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800203 private boolean mShowAmbient;
Selim Cinek875a3a12016-11-18 17:52:16 -0800204 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800205 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800206 private boolean mIsLowPriority;
Mady Mellorb0a82462016-04-30 17:31:02 -0700207
208 public boolean isGroupExpansionChanging() {
209 if (isChildInGroup()) {
210 return mNotificationParent.isGroupExpansionChanging();
211 }
212 return mGroupExpansionChanging;
213 }
214
215 public void setGroupExpansionChanging(boolean changing) {
216 mGroupExpansionChanging = changing;
217 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700218
Adrian Roos599be342016-06-13 14:54:39 -0700219 @Override
220 public void setActualHeightAnimating(boolean animating) {
221 if (mPrivateLayout != null) {
222 mPrivateLayout.setContentHeightAnimating(animating);
223 }
224 }
225
Selim Cinek8d490d42015-04-10 00:05:50 -0700226 public NotificationContentView getPrivateLayout() {
227 return mPrivateLayout;
228 }
229
230 public NotificationContentView getPublicLayout() {
231 return mPublicLayout;
232 }
233
Selim Cinekcab4a602014-09-03 14:47:57 +0200234 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800235 for (NotificationContentView l : mLayouts) {
236 setIconAnimationRunning(running, l);
237 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800238 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700239 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800240 List<ExpandableNotificationRow> notificationChildren =
241 mChildrenContainer.getNotificationChildren();
242 for (int i = 0; i < notificationChildren.size(); i++) {
243 ExpandableNotificationRow child = notificationChildren.get(i);
244 child.setIconAnimationRunning(running);
245 }
246 }
247 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200248 }
249
250 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
251 if (layout != null) {
252 View contractedChild = layout.getContractedChild();
253 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700254 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200255 setIconAnimationRunningForChild(running, contractedChild);
256 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700257 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200258 }
259 }
260
261 private void setIconAnimationRunningForChild(boolean running, View child) {
262 if (child != null) {
263 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
264 setIconRunning(icon, running);
265 ImageView rightIcon = (ImageView) child.findViewById(
266 com.android.internal.R.id.right_icon);
267 setIconRunning(rightIcon, running);
268 }
269 }
270
271 private void setIconRunning(ImageView imageView, boolean running) {
272 if (imageView != null) {
273 Drawable drawable = imageView.getDrawable();
274 if (drawable instanceof AnimationDrawable) {
275 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
276 if (running) {
277 animationDrawable.start();
278 } else {
279 animationDrawable.stop();
280 }
281 } else if (drawable instanceof AnimatedVectorDrawable) {
282 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
283 if (running) {
284 animationDrawable.start();
285 } else {
286 animationDrawable.stop();
287 }
288 }
289 }
290 }
291
Selim Cinekda42d652015-12-04 15:51:16 -0800292 public void onNotificationUpdated(NotificationData.Entry entry) {
293 mEntry = entry;
294 mStatusBarNotification = entry.notification;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800295 for (NotificationContentView l : mLayouts) {
296 l.onNotificationUpdated(entry);
297 }
Selim Cinek757d8792016-01-28 16:21:08 -0800298 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700299 updateNotificationColor();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800300 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700301 mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
Selim Cinekc897bd32016-03-18 17:32:31 -0700302 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800303 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800304 if (mIconAnimationRunning) {
305 setIconAnimationRunning(true);
306 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800307 if (mNotificationParent != null) {
308 mNotificationParent.updateChildrenHeaderAppearance();
309 }
Selim Cinek263398f2015-10-21 17:40:23 -0700310 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800311 // The public layouts expand button is always visible
312 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800313 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700314 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800315 updateShelfIconColor();
316 }
317
318 private void updateShelfIconColor() {
319 StatusBarIconView expandedIcon = mEntry.expandedIcon;
320 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
321 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
322 NotificationColorUtil.getInstance(mContext));
323 if (colorize) {
324 int color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded());
325 expandedIcon.setImageTintList(ColorStateList.valueOf(color));
326 }
Selim Cinekda42d652015-12-04 15:51:16 -0800327 }
328
329 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800330 for (NotificationContentView l : mLayouts) {
331 updateLimitsForView(l);
332 }
Selim Cineka1744872016-03-11 15:36:06 -0800333 }
334
335 private void updateLimitsForView(NotificationContentView layout) {
336 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800337 != com.android.internal.R.id.status_bar_latest_event_content;
338 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
339 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
340 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800341 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
342 layout.getHeadsUpChild().getId()
343 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek77019c72015-12-09 10:18:02 -0800344 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
345 : mMaxHeadsUpHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800346 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
347 mNotificationAmbientHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200348 }
349
350 public StatusBarNotification getStatusBarNotification() {
351 return mStatusBarNotification;
352 }
353
Selim Cinek281c2022016-10-13 19:14:43 -0700354 public NotificationData.Entry getEntry() {
355 return mEntry;
356 }
357
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700358 public boolean isHeadsUp() {
359 return mIsHeadsUp;
360 }
361
Selim Cinek1a521f32014-11-03 17:39:29 +0100362 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700363 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100364 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700365 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700366 if (mIsSummaryWithChildren) {
367 // The overflow might change since we allow more lines as HUN.
368 mChildrenContainer.updateGroupOverflow();
369 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700370 if (intrinsicBefore != getIntrinsicHeight()) {
371 notifyHeightChanged(false /* needsAnimation */);
372 }
Selim Cinekd127d792016-11-01 19:11:41 -0700373 if (isHeadsUp) {
374 setAboveShelf(true);
375 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100376 }
377
Selim Cinekb5605e52015-02-20 18:21:41 +0100378 public void setGroupManager(NotificationGroupManager groupManager) {
379 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700380 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100381 }
382
Adrian Roosb88b1a12015-12-09 18:51:05 -0800383 public void setRemoteInputController(RemoteInputController r) {
384 mPrivateLayout.setRemoteInputController(r);
385 }
386
Mady Mellor3fd273e2016-03-15 21:08:14 -0700387 public void setAppName(String appName) {
388 mAppName = appName;
389 if (mSettingsIconRow != null) {
390 mSettingsIconRow.setAppName(mAppName);
391 }
392 }
393
Selim Cinekb5605e52015-02-20 18:21:41 +0100394 public void addChildNotification(ExpandableNotificationRow row) {
395 addChildNotification(row, -1);
396 }
397
398 /**
399 * Add a child notification to this view.
400 *
401 * @param row the row to add
402 * @param childIndex the index to add it at, if -1 it will be added at the end
403 */
404 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
405 if (mChildrenContainer == null) {
406 mChildrenContainerStub.inflate();
407 }
408 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700409 onChildrenCountChanged();
410 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100411 }
412
413 public void removeChildNotification(ExpandableNotificationRow row) {
414 if (mChildrenContainer != null) {
415 mChildrenContainer.removeNotification(row);
416 }
Selim Cinek263398f2015-10-21 17:40:23 -0700417 onChildrenCountChanged();
418 row.setIsChildInGroup(false, null);
419 }
420
421 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700422 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700423 }
424
Selim Cinek388df6d2015-10-22 13:25:11 -0700425 public ExpandableNotificationRow getNotificationParent() {
426 return mNotificationParent;
427 }
428
Selim Cinek263398f2015-10-21 17:40:23 -0700429 /**
430 * @param isChildInGroup Is this notification now in a group
431 * @param parent the new parent notification
432 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700433 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
434 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
435 mNotificationParent = childInGroup ? parent : null;
436 mPrivateLayout.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400437 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700438 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700439 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700440 if (mNotificationParent != null) {
441 mNotificationParent.updateBackgroundForGroupState();
442 }
Selim Cinekdb167372016-11-17 15:41:17 -0800443 updateIconVisibilities();
Selim Cinek34d93b02015-10-22 12:30:38 -0700444 }
445
446 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800447 public boolean onTouchEvent(MotionEvent event) {
448 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
449 || !isChildInGroup() || isGroupExpanded()) {
450 return super.onTouchEvent(event);
451 } else {
452 return false;
453 }
454 }
455
456 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800457 protected boolean handleSlideBack() {
458 if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
459 animateTranslateNotification(0 /* targetLeft */);
460 return true;
461 }
462 return false;
463 }
464
465 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700466 protected boolean shouldHideBackground() {
467 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700468 }
469
470 @Override
471 public boolean isSummaryWithChildren() {
472 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100473 }
474
475 @Override
476 public boolean areChildrenExpanded() {
477 return mChildrenExpanded;
478 }
479
480 public List<ExpandableNotificationRow> getNotificationChildren() {
481 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
482 }
483
Selim Cinekeef84282015-10-30 16:28:00 -0700484 public int getNumberOfNotificationChildren() {
485 if (mChildrenContainer == null) {
486 return 0;
487 }
488 return mChildrenContainer.getNotificationChildren().size();
489 }
490
Selim Cinekb5605e52015-02-20 18:21:41 +0100491 /**
492 * Apply the order given in the list to the children.
493 *
494 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800495 * @param visualStabilityManager
496 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100497 * @return whether the list order has changed
498 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800499 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
500 VisualStabilityManager visualStabilityManager,
501 VisualStabilityManager.Callback callback) {
502 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
503 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100504 }
505
506 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700507 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800508 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100509 mChildrenContainer.getState(resultState, parentState);
510 }
511 }
512
513 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700514 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100515 mChildrenContainer.applyState(state);
516 }
517 }
518
519 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700520 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100521 mChildrenContainer.prepareExpansionChanged(state);
522 }
523 }
524
Selim Cinek0cfbef42016-11-09 19:06:36 -0800525 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700526 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800527 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100528 }
529 }
530
531 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800532 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100533 return this;
534 } else {
535 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
536 return view == null ? this : view;
537 }
538 }
539
Selim Cinekab29aeb2015-02-20 18:18:32 +0100540 public NotificationGuts getGuts() {
541 return mGuts;
542 }
543
Selim Cinek684a4422015-04-15 16:18:39 -0700544 /**
545 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
546 * the notification will be rendered on top of the screen.
547 *
548 * @param pinned whether it is pinned
549 */
550 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700551 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700552 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700553 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700554 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700555 }
Selim Cinek31aada42015-12-18 17:51:15 -0800556 if (pinned) {
557 setIconAnimationRunning(true);
558 mExpandedWhenPinned = false;
559 } else if (mExpandedWhenPinned) {
560 setUserExpanded(true);
561 }
Selim Cinek98713a42015-09-21 15:47:20 +0200562 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700563 }
564
Selim Cinek684a4422015-04-15 16:18:39 -0700565 public boolean isPinned() {
566 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700567 }
568
Selim Cinekd127d792016-11-01 19:11:41 -0700569 @Override
570 public int getPinnedHeadsUpHeight() {
571 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
572 }
573
Selim Cinek31aada42015-12-18 17:51:15 -0800574 /**
575 * @param atLeastMinHeight should the value returned be at least the minimum height.
576 * Used to avoid cyclic calls
577 * @return the height of the heads up notification when pinned
578 */
Selim Cinekd127d792016-11-01 19:11:41 -0700579 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800580 if (mIsSummaryWithChildren) {
581 return mChildrenContainer.getIntrinsicHeight();
582 }
Selim Cinek31aada42015-12-18 17:51:15 -0800583 if(mExpandedWhenPinned) {
584 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
585 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700586 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800587 } else {
588 return mHeadsUpHeight;
589 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700590 }
591
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700592 /**
593 * Mark whether this notification was just clicked, i.e. the user has just clicked this
594 * notification in this frame.
595 */
596 public void setJustClicked(boolean justClicked) {
597 mJustClicked = justClicked;
598 }
599
600 /**
601 * @return true if this notification has been clicked in this frame, false otherwise
602 */
603 public boolean wasJustClicked() {
604 return mJustClicked;
605 }
606
Selim Cinek98713a42015-09-21 15:47:20 +0200607 public void setChronometerRunning(boolean running) {
608 mLastChronometerRunning = running;
609 setChronometerRunning(running, mPrivateLayout);
610 setChronometerRunning(running, mPublicLayout);
611 if (mChildrenContainer != null) {
612 List<ExpandableNotificationRow> notificationChildren =
613 mChildrenContainer.getNotificationChildren();
614 for (int i = 0; i < notificationChildren.size(); i++) {
615 ExpandableNotificationRow child = notificationChildren.get(i);
616 child.setChronometerRunning(running);
617 }
618 }
619 }
620
621 private void setChronometerRunning(boolean running, NotificationContentView layout) {
622 if (layout != null) {
623 running = running || isPinned();
624 View contractedChild = layout.getContractedChild();
625 View expandedChild = layout.getExpandedChild();
626 View headsUpChild = layout.getHeadsUpChild();
627 setChronometerRunningForChild(running, contractedChild);
628 setChronometerRunningForChild(running, expandedChild);
629 setChronometerRunningForChild(running, headsUpChild);
630 }
631 }
632
633 private void setChronometerRunningForChild(boolean running, View child) {
634 if (child != null) {
635 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
636 if (chronometer instanceof Chronometer) {
637 ((Chronometer) chronometer).setStarted(running);
638 }
639 }
640 }
641
Selim Cinekea4bef72015-12-02 15:51:10 -0800642 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700643 if (mIsSummaryWithChildren) {
644 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700645 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800646 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700647 }
648
Selim Cinek34eda5e2016-02-18 17:10:43 -0800649 private NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700650 if (mIsSummaryWithChildren && !mShowingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700651 return mChildrenContainer.getHeaderView();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800652 }
653 return getShowingLayout().getVisibleNotificationHeader();
654 }
655
Selim Cinek570981d2015-12-01 11:37:01 -0800656 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
657 mOnExpandClickListener = onExpandClickListener;
658 }
659
Selim Cinekddf1b392016-05-27 16:33:10 -0700660 @Override
661 public void setOnClickListener(@Nullable OnClickListener l) {
662 super.setOnClickListener(l);
663 mOnClickListener = l;
664 updateClickAndFocus();
665 }
666
667 private void updateClickAndFocus() {
668 boolean normalChild = !isChildInGroup() || isGroupExpanded();
669 boolean clickable = mOnClickListener != null && normalChild;
670 if (isFocusable() != normalChild) {
671 setFocusable(normalChild);
672 }
673 if (isClickable() != clickable) {
674 setClickable(clickable);
675 }
676 }
677
Selim Cinek31aada42015-12-18 17:51:15 -0800678 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
679 mHeadsUpManager = headsUpManager;
680 }
681
Selim Cinek01af3342016-02-09 19:25:31 -0800682 public void reInflateViews() {
683 initDimens();
684 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800685 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700686 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800687 }
688 }
689 if (mGuts != null) {
690 View oldGuts = mGuts;
691 int index = indexOfChild(oldGuts);
692 removeView(oldGuts);
693 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
694 R.layout.notification_guts, this, false);
695 mGuts.setVisibility(oldGuts.getVisibility());
696 addView(mGuts, index);
697 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800698 if (mSettingsIconRow != null) {
699 View oldSettings = mSettingsIconRow;
700 int settingsIndex = indexOfChild(oldSettings);
701 removeView(oldSettings);
702 mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
703 R.layout.notification_settings_icon_row, this, false);
704 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700705 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800706 mSettingsIconRow.setVisibility(oldSettings.getVisibility());
707 addView(mSettingsIconRow, settingsIndex);
708
709 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800710 for (NotificationContentView l : mLayouts) {
711 l.reInflateViews();
712 }
Selim Cinek01af3342016-02-09 19:25:31 -0800713 }
714
Selim Cinekc3179332016-03-04 14:44:56 -0800715 public void setContentBackground(int customBackgroundColor, boolean animate,
716 NotificationContentView notificationContentView) {
717 if (getShowingLayout() == notificationContentView) {
718 setTintColor(customBackgroundColor, animate);
719 }
720 }
721
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700722 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800723 for (NotificationContentView l : mLayouts) {
724 l.closeRemoteInput();
725 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700726 }
727
Selim Cinekc897bd32016-03-18 17:32:31 -0700728 /**
729 * Set by how much the single line view should be indented.
730 */
731 public void setSingleLineWidthIndention(int indention) {
732 mPrivateLayout.setSingleLineWidthIndention(indention);
733 }
734
735 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700736 return mNotificationColor;
737 }
738
739 private void updateNotificationColor() {
740 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
741 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700742 }
743
744 public HybridNotificationView getSingleLineView() {
745 return mPrivateLayout.getSingleLineView();
746 }
747
Selim Cinekf07d0622016-03-21 19:52:52 -0700748 public boolean isOnKeyguard() {
749 return mOnKeyguard;
750 }
751
Selim Cinekc1e389d2016-04-07 11:02:57 -0700752 public void removeAllChildren() {
753 List<ExpandableNotificationRow> notificationChildren
754 = mChildrenContainer.getNotificationChildren();
755 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
756 for (int i = 0; i < clonedList.size(); i++) {
757 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700758 if (row.keepInParent()) {
759 continue;
760 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700761 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700762 row.setIsChildInGroup(false, null);
763 }
764 onChildrenCountChanged();
765 }
766
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700767 public void setForceUnlocked(boolean forceUnlocked) {
768 mForceUnlocked = forceUnlocked;
769 if (mIsSummaryWithChildren) {
770 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
771 for (ExpandableNotificationRow child : notificationChildren) {
772 child.setForceUnlocked(forceUnlocked);
773 }
774 }
775 }
776
Selim Cineke9bad242016-06-15 11:46:37 -0700777 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700778 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700779 mGroupParentWhenDismissed = mNotificationParent;
780 mRefocusOnDismiss = fromAccessibility;
781 mChildAfterViewWhenDismissed = null;
782 if (isChildInGroup()) {
783 List<ExpandableNotificationRow> notificationChildren =
784 mNotificationParent.getNotificationChildren();
785 int i = notificationChildren.indexOf(this);
786 if (i != -1 && i < notificationChildren.size() - 1) {
787 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
788 }
789 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700790 }
791
792 public boolean isDismissed() {
793 return mDismissed;
794 }
795
796 public boolean keepInParent() {
797 return mKeepInParent;
798 }
799
800 public void setKeepInParent(boolean keepInParent) {
801 mKeepInParent = keepInParent;
802 }
803
804 public boolean isRemoved() {
805 return mRemoved;
806 }
807
Adrian Roosd009ab12016-05-20 17:58:53 -0700808 public void setRemoved() {
809 mRemoved = true;
810
811 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700812 }
813
Selim Cinekd1395642016-04-28 12:22:42 -0700814 public NotificationChildrenContainer getChildrenContainer() {
815 return mChildrenContainer;
816 }
817
Selim Cinekcafa87f2016-10-26 17:00:17 -0700818 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
819 mHeadsupDisappearRunning = headsUpAnimatingAway;
820 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
821 }
822
823 /**
824 * @return if the view was just heads upped and is now animating away. During such a time the
825 * layout needs to be kept consistent
826 */
827 public boolean isHeadsUpAnimatingAway() {
828 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700829 }
830
Selim Cineke9bad242016-06-15 11:46:37 -0700831 public View getChildAfterViewWhenDismissed() {
832 return mChildAfterViewWhenDismissed;
833 }
834
835 public View getGroupParentWhenDismissed() {
836 return mGroupParentWhenDismissed;
837 }
838
Selim Cinek9e624e72016-07-20 13:46:49 -0700839 public void performDismiss() {
Selim Cineke9079112016-12-14 14:41:01 -0800840 if (mOnDismissRunnable != null) {
841 mOnDismissRunnable.run();
842 }
Selim Cinek9e624e72016-07-20 13:46:49 -0700843 }
844
Selim Cineke9079112016-12-14 14:41:01 -0800845 public void setOnDismissRunnable(Runnable onDismissRunnable) {
846 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -0700847 }
848
Selim Cinek281c2022016-10-13 19:14:43 -0700849 public View getNotificationIcon() {
850 NotificationHeaderView notificationHeader = getNotificationHeader();
851 if (notificationHeader != null) {
852 return notificationHeader.getIcon();
853 }
854 return null;
855 }
856
857 /**
858 * @return whether the notification is currently showing a view with an icon.
859 */
860 public boolean isShowingIcon() {
861 if (mIsSummaryWithChildren) {
862 return true;
863 }
864 NotificationContentView showingLayout = getShowingLayout();
865 NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
866 return notificationHeader != null;
867 }
868
Selim Cinek0242fbb2016-10-19 13:38:32 -0700869 /**
870 * Set how much this notification is transformed into an icon.
871 *
Selim Cinek2b549f42016-11-22 16:38:51 -0800872 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
873 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -0800874 * @param isLastChild is this the last child in the list. If true, then the transformation is
875 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -0700876 */
Selim Cinek2b549f42016-11-22 16:38:51 -0800877 public void setContentTransformationAmount(float contentTransformationAmount,
878 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -0800879 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800880 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800881 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800882 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800883 if (changeTransformation) {
884 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -0800885 }
886 }
887
888 /**
889 * Set the icons to be visible of this notification.
890 */
891 public void setIconsVisible(boolean iconsVisible) {
892 if (iconsVisible != mIconsVisible) {
893 mIconsVisible = iconsVisible;
894 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700895 }
896 }
897
Selim Cinekdb167372016-11-17 15:41:17 -0800898 @Override
899 protected void onBelowSpeedBumpChanged() {
900 updateIconVisibilities();
901 }
902
Selim Cinek875a3a12016-11-18 17:52:16 -0800903 private void updateContentTransformation() {
904 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -0800905 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800906 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -0800907 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800908 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700909 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -0800910 translationY *= 0.4f;
911 } else {
912 contentAlpha = 1.0f;
913 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800914 for (NotificationContentView l : mLayouts) {
915 l.setAlpha(contentAlpha);
916 l.setTranslationY(translationY);
917 }
Selim Cinek875a3a12016-11-18 17:52:16 -0800918 if (mChildrenContainer != null) {
919 mChildrenContainer.setAlpha(contentAlpha);
920 mChildrenContainer.setTranslationY(translationY);
921 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -0700922 }
923 }
924
925 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -0800926 boolean visible = isChildInGroup()
927 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
928 || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800929 for (NotificationContentView l : mLayouts) {
930 l.setIconsVisible(visible);
931 }
Selim Cinekdb167372016-11-17 15:41:17 -0800932 if (mChildrenContainer != null) {
933 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700934 }
935 }
936
Selim Cinek875a3a12016-11-18 17:52:16 -0800937 /**
938 * Get the relative top padding of a view relative to this view. This recursively walks up the
939 * hierarchy and does the corresponding measuring.
940 *
941 * @param view the view to the the padding for. The requested view has to be a child of this
942 * notification.
943 * @return the toppadding
944 */
945 public int getRelativeTopPadding(View view) {
946 int topPadding = 0;
947 while (view.getParent() instanceof ViewGroup) {
948 topPadding += view.getTop();
949 view = (View) view.getParent();
950 if (view instanceof ExpandableNotificationRow) {
951 return topPadding;
952 }
953 }
954 return topPadding;
955 }
956
Selim Cineka1d97902016-12-14 16:31:40 -0800957 public float getContentTranslation() {
958 return mPrivateLayout.getTranslationY();
959 }
960
Selim Cinek6743c0b2017-01-18 18:24:01 -0800961 public void setIsLowPriority(boolean isLowPriority) {
962 mIsLowPriority = isLowPriority;
963 mPrivateLayout.setIsLowPriority(isLowPriority);
964 if (mChildrenContainer != null) {
965 mChildrenContainer.setIsLowPriority(isLowPriority);
966 }
967 }
968
Chris Wren78403d72014-07-28 10:23:24 +0100969 public interface ExpansionLogger {
970 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
971 }
Selim Cinek1685e632014-04-08 02:27:49 +0200972
Chris Wren51c75102013-07-16 20:49:17 -0400973 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
974 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700975 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -0800976 initDimens();
977 }
978
979 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800980 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
981 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
982 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
Adrian Roos0aac04f2016-12-08 15:59:29 -0800983 mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800984 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -0800985 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800986 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Mady Mellorb0a82462016-04-30 17:31:02 -0700987 mIncreasedPaddingBetweenElements = getResources()
988 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinek875a3a12016-11-18 17:52:16 -0800989 mIconTransformContentShiftNoIcon = getResources().getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -0700990 R.dimen.notification_icon_transform_content_shift);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800991 }
992
993 /**
994 * @param dimenId the dimen to look up
995 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
996 */
997 private int getFontScaledHeight(int dimenId) {
998 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
999 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
1000 getResources().getDisplayMetrics().density);
1001 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -04001002 }
1003
Christoph Studera7fe6312014-06-27 19:32:44 +02001004 /**
1005 * Resets this view so it can be re-used for an updated notification.
1006 */
Christoph Studer22f2ee52014-07-29 22:57:21 +02001007 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +02001008 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +02001009 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +01001010 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +02001011 mExpandable = false;
1012 mHasUserChangedExpansion = false;
1013 mUserLocked = false;
1014 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +02001015 mSensitive = false;
1016 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +02001017 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -07001018 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -08001019 mPublicLayout.reset();
1020 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +02001021 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -08001022 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +02001023 logExpansionEvent(false, wasExpanded);
1024 }
1025
1026 public void resetHeight() {
Selim Cinek31094df2014-08-14 19:28:15 +02001027 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001028 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001029 }
1030
Jorim Jaggi251957d2014-04-09 04:24:09 +02001031 @Override
1032 protected void onFinishInflate() {
1033 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001034 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1035 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001036
1037 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1038
1039 for (NotificationContentView l : mLayouts) {
1040 l.setExpandClickListener(mExpandClickListener);
1041 l.setContainingNotification(this);
1042 }
1043
Mady Mellor4b80b102016-01-22 08:03:58 -08001044 mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
1045 mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1046 @Override
1047 public void onInflate(ViewStub stub, View inflated) {
1048 mSettingsIconRow = (NotificationSettingsIconRow) inflated;
1049 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -07001050 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -08001051 }
1052 });
Selim Cinekab29aeb2015-02-20 18:18:32 +01001053 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1054 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001055 @Override
1056 public void onInflate(ViewStub stub, View inflated) {
1057 mGuts = (NotificationGuts) inflated;
1058 mGuts.setClipTopAmount(getClipTopAmount());
1059 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001060 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001061 }
1062 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001063 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1064 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1065
1066 @Override
1067 public void onInflate(ViewStub stub, View inflated) {
1068 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001069 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek388df6d2015-10-22 13:25:11 -07001070 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001071 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -08001072 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +01001073 }
1074 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001075
1076 // Add the views that we translate to reveal the gear
1077 mTranslateableViews = new ArrayList<View>();
1078 for (int i = 0; i < getChildCount(); i++) {
1079 mTranslateableViews.add(getChildAt(i));
1080 }
1081 // Remove views that don't translate
Mady Mellor4b80b102016-01-22 08:03:58 -08001082 mTranslateableViews.remove(mSettingsIconRowStub);
1083 mTranslateableViews.remove(mChildrenContainerStub);
1084 mTranslateableViews.remove(mGutsStub);
1085 }
1086
Mady Mellor4b80b102016-01-22 08:03:58 -08001087 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001088 if (mTranslateAnim != null) {
1089 mTranslateAnim.cancel();
1090 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001091 if (mTranslateableViews != null) {
1092 for (int i = 0; i < mTranslateableViews.size(); i++) {
1093 mTranslateableViews.get(i).setTranslationX(0);
1094 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001095 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001096 invalidateOutline();
Mady Mellor4b80b102016-01-22 08:03:58 -08001097 if (mSettingsIconRow != null) {
1098 mSettingsIconRow.resetState();
1099 }
1100 }
1101
1102 public void animateTranslateNotification(final float leftTarget) {
1103 if (mTranslateAnim != null) {
1104 mTranslateAnim.cancel();
1105 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001106 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001107 if (mTranslateAnim != null) {
1108 mTranslateAnim.start();
1109 }
1110 }
1111
1112 @Override
1113 public void setTranslation(float translationX) {
1114 if (areGutsExposed()) {
1115 // Don't translate if guts are showing.
1116 return;
1117 }
1118 // Translate the group of views
1119 for (int i = 0; i < mTranslateableViews.size(); i++) {
1120 if (mTranslateableViews.get(i) != null) {
1121 mTranslateableViews.get(i).setTranslationX(translationX);
1122 }
1123 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001124 invalidateOutline();
Mady Mellor34958fa2016-02-23 09:52:17 -08001125 if (mSettingsIconRow != null) {
1126 mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
1127 }
1128 }
1129
1130 @Override
1131 public float getTranslation() {
1132 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1133 // All of the views in the list should have same translation, just use first one.
1134 return mTranslateableViews.get(0).getTranslationX();
1135 }
1136 return 0;
1137 }
1138
1139 public Animator getTranslateViewAnimator(final float leftTarget,
1140 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001141 if (mTranslateAnim != null) {
1142 mTranslateAnim.cancel();
1143 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001144 if (areGutsExposed()) {
1145 // No translation if guts are exposed.
1146 return null;
1147 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001148 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1149 leftTarget);
1150 if (listener != null) {
1151 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001152 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001153 translateAnim.addListener(new AnimatorListenerAdapter() {
1154 boolean cancelled = false;
1155
1156 @Override
1157 public void onAnimationCancel(Animator anim) {
1158 cancelled = true;
1159 }
1160
1161 @Override
1162 public void onAnimationEnd(Animator anim) {
1163 if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
1164 mSettingsIconRow.resetState();
1165 mTranslateAnim = null;
1166 }
1167 }
1168 });
1169 mTranslateAnim = translateAnim;
1170 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001171 }
1172
1173 public float getSpaceForGear() {
1174 if (mSettingsIconRow != null) {
1175 return mSettingsIconRow.getSpaceForGear();
1176 }
1177 return 0;
1178 }
1179
1180 public NotificationSettingsIconRow getSettingsRow() {
1181 if (mSettingsIconRow == null) {
1182 mSettingsIconRowStub.inflate();
1183 }
1184 return mSettingsIconRow;
1185 }
1186
Selim Cinekab29aeb2015-02-20 18:18:32 +01001187 public void inflateGuts() {
1188 if (mGuts == null) {
1189 mGutsStub.inflate();
1190 }
1191 }
1192
Selim Cinekda42d652015-12-04 15:51:16 -08001193 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001194 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1195 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001196 if (mChildrenContainer != null) {
1197 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1198 : INVISIBLE);
Mady Mellorb0a82462016-04-30 17:31:02 -07001199 mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
1200 ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001201 : INVISIBLE);
1202 }
Selim Cinekda42d652015-12-04 15:51:16 -08001203 // The limits might have changed if the view suddenly became a group or vice versa
1204 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001205 }
1206
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001207 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001208 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1209 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001210 // Add a record for the entire layout since its content is somehow small.
1211 // The event comes from a leaf view that is interacted with.
1212 AccessibilityEvent record = AccessibilityEvent.obtain();
1213 onInitializeAccessibilityEvent(record);
1214 dispatchPopulateAccessibilityEvent(record);
1215 event.appendRecord(record);
1216 return true;
1217 }
1218 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001219 }
Chris Wren51c75102013-07-16 20:49:17 -04001220
John Spurlocke15452b2014-08-21 09:44:39 -04001221 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001222 public void setDark(boolean dark, boolean fade, long delay) {
1223 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001224 final NotificationContentView showing = getShowingLayout();
1225 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001226 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001227 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001228 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001229 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001230 }
John Spurlocke15452b2014-08-21 09:44:39 -04001231 }
1232
Chris Wren51c75102013-07-16 20:49:17 -04001233 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001234 if (mIsSummaryWithChildren && !mShowingPublic) {
1235 return !mChildrenExpanded;
1236 }
Chris Wren51c75102013-07-16 20:49:17 -04001237 return mExpandable;
1238 }
1239
1240 public void setExpandable(boolean expandable) {
1241 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001242 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001243 }
1244
Selim Cinek4ffd6362015-12-29 15:12:23 +01001245 @Override
1246 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001247 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1248 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001249 }
1250
Selim Cinek1685e632014-04-08 02:27:49 +02001251 /**
1252 * @return whether the user has changed the expansion state
1253 */
1254 public boolean hasUserChangedExpansion() {
1255 return mHasUserChangedExpansion;
1256 }
1257
Chris Wren51c75102013-07-16 20:49:17 -04001258 public boolean isUserExpanded() {
1259 return mUserExpanded;
1260 }
1261
Selim Cinek1685e632014-04-08 02:27:49 +02001262 /**
1263 * Set this notification to be expanded by the user
1264 *
1265 * @param userExpanded whether the user wants this notification to be expanded
1266 */
Chris Wren51c75102013-07-16 20:49:17 -04001267 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001268 setUserExpanded(userExpanded, false /* allowChildExpansion */);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001269 updateShelfIconColor();
Selim Cinek388df6d2015-10-22 13:25:11 -07001270 }
1271
1272 /**
1273 * Set this notification to be expanded by the user
1274 *
1275 * @param userExpanded whether the user wants this notification to be expanded
1276 * @param allowChildExpansion whether a call to this method allows expanding children
1277 */
1278 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001279 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -07001280 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
Chris Wren698b1702016-05-23 11:16:32 -04001281 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001282 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Chris Wren698b1702016-05-23 11:16:32 -04001283 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001284 return;
1285 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001286 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001287 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001288 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001289 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001290 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001291 }
1292
Selim Cinekccd14fb2014-08-12 18:53:24 +02001293 public void resetUserExpansion() {
1294 mHasUserChangedExpansion = false;
1295 mUserExpanded = false;
1296 }
1297
Chris Wren51c75102013-07-16 20:49:17 -04001298 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001299 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001300 }
1301
1302 public void setUserLocked(boolean userLocked) {
1303 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001304 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001305 if (mIsSummaryWithChildren) {
1306 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek7baaa9e2016-07-21 17:21:09 -07001307 if (userLocked || !isGroupExpanded()) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001308 updateBackgroundForGroupState();
1309 }
Selim Cinek42357e02016-02-24 18:48:01 -08001310 }
Chris Wren51c75102013-07-16 20:49:17 -04001311 }
1312
Selim Cinek1685e632014-04-08 02:27:49 +02001313 /**
1314 * @return has the system set this notification to be expanded
1315 */
1316 public boolean isSystemExpanded() {
1317 return mIsSystemExpanded;
1318 }
1319
1320 /**
1321 * Set this notification to be expanded by the system.
1322 *
1323 * @param expand whether the system wants this notification to be expanded.
1324 */
1325 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001326 if (expand != mIsSystemExpanded) {
1327 final boolean wasExpanded = isExpanded();
1328 mIsSystemExpanded = expand;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001329 updateShelfIconColor();
Selim Cinekb5605e52015-02-20 18:21:41 +01001330 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001331 logExpansionEvent(false, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001332 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001333 mChildrenContainer.updateGroupOverflow();
1334 }
Selim Cinek31094df2014-08-14 19:28:15 +02001335 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001336 }
1337
1338 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001339 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001340 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001341 public void setOnKeyguard(boolean onKeyguard) {
1342 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001343 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001344 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001345 logExpansionEvent(false, wasExpanded);
1346 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001347 if (mIsSummaryWithChildren) {
1348 mChildrenContainer.updateGroupOverflow();
1349 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001350 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001351 }
1352 }
Selim Cinek1685e632014-04-08 02:27:49 +02001353 }
1354
1355 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001356 * @return Can the underlying notification be cleared? This can be different from whether the
1357 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1358 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001359 */
1360 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001361 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1362 return false;
1363 }
1364 if (mIsSummaryWithChildren) {
1365 List<ExpandableNotificationRow> notificationChildren =
1366 mChildrenContainer.getNotificationChildren();
1367 for (int i = 0; i < notificationChildren.size(); i++) {
1368 ExpandableNotificationRow child = notificationChildren.get(i);
1369 if (!child.isClearable()) {
1370 return false;
1371 }
1372 }
1373 }
1374 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001375 }
1376
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001377 @Override
1378 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001379 if (isUserLocked()) {
1380 return getActualHeight();
1381 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001382 if (mGuts != null && mGuts.isExposed()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001383 return mGuts.getHeight();
1384 } else if ((isChildInGroup() && !isGroupExpanded())) {
1385 return mPrivateLayout.getMinHeight();
Adrian Roos0aac04f2016-12-08 15:59:29 -08001386 } else if (mShowAmbient) {
1387 return getAmbientHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001388 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1389 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001390 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001391 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001392 } else if (!mOnKeyguard && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07001393 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001394 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1395 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001396 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001397 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001398 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001399 }
Selim Cinek31aada42015-12-18 17:51:15 -08001400 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001401 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001402 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001403 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001404 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001405 }
Selim Cinek1685e632014-04-08 02:27:49 +02001406
Mady Mellorb0a82462016-04-30 17:31:02 -07001407 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001408 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001409 }
1410
Selim Cinek263398f2015-10-21 17:40:23 -07001411 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001412 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001413 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1414 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
1415 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
1416 mEntry.notification);
Selim Cinek263398f2015-10-21 17:40:23 -07001417 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001418 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001419 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001420 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001421 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001422 }
1423
Mady Mellorb0a82462016-04-30 17:31:02 -07001424 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001425 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001426 mChildrenContainer.updateChildrenHeaderAppearance();
1427 }
1428 }
1429
Selim Cinek1685e632014-04-08 02:27:49 +02001430 /**
1431 * Check whether the view state is currently expanded. This is given by the system in {@link
1432 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1433 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1434 * view can differ from this state, if layout params are modified from outside.
1435 *
1436 * @return whether the view state is currently expanded.
1437 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001438 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001439 return isExpanded(false /* allowOnKeyguard */);
1440 }
1441
1442 public boolean isExpanded(boolean allowOnKeyguard) {
1443 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001444 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1445 || isUserExpanded());
1446 }
1447
1448 private boolean isSystemChildExpanded() {
1449 return mIsSystemChildExpanded;
1450 }
1451
1452 public void setSystemChildExpanded(boolean expanded) {
1453 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001454 }
1455
1456 @Override
1457 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1458 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001459 updateMaxHeights();
Mady Mellora6edc872016-04-26 11:01:03 -07001460 if (mSettingsIconRow != null) {
1461 mSettingsIconRow.updateVerticalLocation();
1462 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001463 updateContentShiftHeight();
1464 }
1465
1466 /**
1467 * Updates the content shift height such that the header is completely hidden when coming from
1468 * the top.
1469 */
1470 private void updateContentShiftHeight() {
1471 NotificationHeaderView notificationHeader = getNotificationHeader();
1472 if (notificationHeader != null) {
1473 CachingIconView icon = notificationHeader.getIcon();
1474 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1475 } else {
1476 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1477 }
Selim Cinek1685e632014-04-08 02:27:49 +02001478 }
1479
Selim Cinek8d490d42015-04-10 00:05:50 -07001480 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001481 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001482 View expandedChild = mPrivateLayout.getExpandedChild();
1483 if (expandedChild == null) {
1484 expandedChild = mPrivateLayout.getContractedChild();
1485 }
1486 mMaxExpandHeight = expandedChild.getHeight();
1487 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001488 if (headsUpChild == null) {
1489 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001490 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001491 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001492 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001493 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001494 }
1495 }
1496
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001497 @Override
1498 public void notifyHeightChanged(boolean needsAnimation) {
1499 super.notifyHeightChanged(needsAnimation);
1500 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1501 }
1502
Selim Cinek3c76d502016-02-19 15:16:33 -08001503 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001504 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001505 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001506 }
1507
1508 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001509 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001510 if (mIsSummaryWithChildren) {
1511 List<ExpandableNotificationRow> notificationChildren =
1512 mChildrenContainer.getNotificationChildren();
1513 for (int i = 0; i < notificationChildren.size(); i++) {
1514 ExpandableNotificationRow child = notificationChildren.get(i);
1515 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1516 }
1517 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001518 }
1519
1520 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1521 long duration) {
1522 boolean oldShowingPublic = mShowingPublic;
1523 mShowingPublic = mSensitive && hideSensitive;
1524 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1525 return;
1526 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001527
1528 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001529 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001530
Jorim Jaggiae441282014-08-01 02:45:18 +02001531 if (!animated) {
1532 mPublicLayout.animate().cancel();
1533 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001534 if (mChildrenContainer != null) {
1535 mChildrenContainer.animate().cancel();
1536 mChildrenContainer.setAlpha(1f);
1537 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001538 mPublicLayout.setAlpha(1f);
1539 mPrivateLayout.setAlpha(1f);
1540 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001541 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001542 } else {
1543 animateShowingPublic(delay, duration);
1544 }
Selim Cinekc3179332016-03-04 14:44:56 -08001545 NotificationContentView showingLayout = getShowingLayout();
1546 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001547 mPrivateLayout.updateExpandButtons(isExpandable());
Adrian Roose5726a22016-12-19 14:26:51 -08001548 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02001549 mShowingPublicInitialized = true;
1550 }
1551
1552 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001553 View[] privateViews = mIsSummaryWithChildren
1554 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001555 : new View[] {mPrivateLayout};
1556 View[] publicViews = new View[] {mPublicLayout};
1557 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1558 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1559 for (final View hiddenView : hiddenChildren) {
1560 hiddenView.setVisibility(View.VISIBLE);
1561 hiddenView.animate().cancel();
1562 hiddenView.animate()
1563 .alpha(0f)
1564 .setStartDelay(delay)
1565 .setDuration(duration)
1566 .withEndAction(new Runnable() {
1567 @Override
1568 public void run() {
1569 hiddenView.setVisibility(View.INVISIBLE);
1570 }
1571 });
1572 }
1573 for (View showView : shownChildren) {
1574 showView.setVisibility(View.VISIBLE);
1575 showView.setAlpha(0f);
1576 showView.animate().cancel();
1577 showView.animate()
1578 .alpha(1f)
1579 .setStartDelay(delay)
1580 .setDuration(duration);
1581 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001582 }
1583
Selim Cinek3776fe02016-02-04 13:32:43 -08001584 public boolean mustStayOnScreen() {
1585 return mIsHeadsUp;
1586 }
1587
Selim Cinek9e624e72016-07-20 13:46:49 -07001588 /**
1589 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1590 * otherwise some state might not be updated. To request about the general clearability
1591 * see {@link #isClearable()}.
1592 */
1593 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001594 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001595 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001596
Ricky Waicd35def2016-05-03 11:07:07 +01001597 public void makeActionsVisibile() {
1598 setUserExpanded(true, true);
1599 if (isChildInGroup()) {
1600 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1601 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001602 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001603 }
1604
Selim Cinekb5605e52015-02-20 18:21:41 +01001605 public void setChildrenExpanded(boolean expanded, boolean animate) {
1606 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001607 if (mChildrenContainer != null) {
1608 mChildrenContainer.setChildrenExpanded(expanded);
1609 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001610 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001611 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001612 }
1613
Selim Cinekb5605e52015-02-20 18:21:41 +01001614 public static void applyTint(View v, int color) {
1615 int alpha;
1616 if (color != 0) {
1617 alpha = COLORED_DIVIDER_ALPHA;
1618 } else {
1619 color = 0xff000000;
1620 alpha = DEFAULT_DIVIDER_ALPHA;
1621 }
1622 if (v.getBackground() instanceof ColorDrawable) {
1623 ColorDrawable background = (ColorDrawable) v.getBackground();
1624 background.mutate();
1625 background.setColor(color);
1626 background.setAlpha(alpha);
1627 }
1628 }
1629
Selim Cinek1685e632014-04-08 02:27:49 +02001630 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001631 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001632 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001633
Mady Mellor34958fa2016-02-23 09:52:17 -08001634 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001635 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08001636 }
1637
Jorim Jaggibe565df2014-04-28 17:51:23 +02001638 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001639 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001640 NotificationContentView showingLayout = getShowingLayout();
1641 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001642 }
1643
1644 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001645 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001646 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001647 return mChildrenContainer;
1648 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001649 return getShowingLayout();
1650 }
1651
1652 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001653 protected void onAppearAnimationFinished(boolean wasAppearing) {
1654 super.onAppearAnimationFinished(wasAppearing);
1655 if (wasAppearing) {
1656 // During the animation the visible view might have changed, so let's make sure all
1657 // alphas are reset
1658 if (mChildrenContainer != null) {
1659 mChildrenContainer.setAlpha(1.0f);
1660 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1661 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001662 for (NotificationContentView l : mLayouts) {
1663 l.setAlpha(1.0f);
1664 l.setLayerType(LAYER_TYPE_NONE, null);
1665 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07001666 }
1667 }
1668
1669 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001670 public int getExtraBottomPadding() {
1671 if (mIsSummaryWithChildren && isGroupExpanded()) {
1672 return mIncreasedPaddingBetweenElements;
1673 }
1674 return 0;
1675 }
1676
1677 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001678 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001679 super.setActualHeight(height, notifyListeners);
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001680 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08001681 mGuts.setActualHeight(height);
1682 return;
1683 }
Selim Cinekeef84282015-10-30 16:28:00 -07001684 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001685 for (NotificationContentView l : mLayouts) {
1686 l.setContentHeight(contentHeight);
1687 }
Selim Cinek42357e02016-02-24 18:48:01 -08001688 if (mIsSummaryWithChildren) {
1689 mChildrenContainer.setActualHeight(height);
1690 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001691 if (mGuts != null) {
1692 mGuts.setActualHeight(height);
1693 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001694 }
1695
1696 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001697 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001698 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001699 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001700 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001701 NotificationContentView showingLayout = getShowingLayout();
1702 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001703 }
1704
1705 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001706 public int getMinHeight() {
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001707 if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08001708 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1709 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001710 return mChildrenContainer.getMinHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001711 } else if (!mOnKeyguard && mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001712 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001713 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001714 NotificationContentView showingLayout = getShowingLayout();
1715 return showingLayout.getMinHeight();
1716 }
1717
Adrian Roos0aac04f2016-12-08 15:59:29 -08001718 private int getAmbientHeight() {
1719 NotificationContentView showingLayout = getShowingLayout();
1720 return showingLayout.getAmbientChild() != null
1721 ? showingLayout.getAmbientChild().getHeight()
1722 : getCollapsedHeight();
1723 }
1724
Selim Cinek816c8e42015-11-19 12:00:45 -08001725 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001726 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001727 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001728 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001729 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001730 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001731 }
1732
1733 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001734 public void setClipTopAmount(int clipTopAmount) {
1735 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001736 for (NotificationContentView l : mLayouts) {
1737 l.setClipTopAmount(clipTopAmount);
1738 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001739 if (mGuts != null) {
1740 mGuts.setClipTopAmount(clipTopAmount);
1741 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001742 }
1743
Selim Cineka686b2c2016-10-26 13:58:27 -07001744 @Override
1745 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001746 if (clipBottomAmount != mClipBottomAmount) {
1747 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001748 for (NotificationContentView l : mLayouts) {
1749 l.setClipBottomAmount(clipBottomAmount);
1750 }
Selim Cinek65d418e2016-11-29 15:42:34 -08001751 if (mGuts != null) {
1752 mGuts.setClipBottomAmount(clipBottomAmount);
1753 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001754 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001755 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001756 // We have to update this even if it hasn't changed, since the children locations can
1757 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001758 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
1759 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001760 }
1761
Selim Cinek31094df2014-08-14 19:28:15 +02001762 public boolean isMaxExpandHeightInitialized() {
1763 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001764 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001765
Selim Cinek42357e02016-02-24 18:48:01 -08001766 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001767 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1768 }
Chris Wren78403d72014-07-28 10:23:24 +01001769
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001770 @Override
1771 public void setShowingLegacyBackground(boolean showing) {
1772 super.setShowingLegacyBackground(showing);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001773 for (NotificationContentView l : mLayouts) {
1774 l.setShowingLegacyBackground(showing);
1775 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001776 }
1777
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001778 @Override
1779 protected void updateBackgroundTint() {
1780 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001781 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001782 if (mIsSummaryWithChildren) {
1783 List<ExpandableNotificationRow> notificationChildren =
1784 mChildrenContainer.getNotificationChildren();
1785 for (int i = 0; i < notificationChildren.size(); i++) {
1786 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001787 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001788 }
1789 }
1790 }
1791
Mady Mellorb0a82462016-04-30 17:31:02 -07001792 /**
1793 * Called when a group has finished animating from collapsed or expanded state.
1794 */
1795 public void onFinishedExpansionChange() {
1796 mGroupExpansionChanging = false;
1797 updateBackgroundForGroupState();
1798 }
1799
1800 /**
1801 * Updates the parent and children backgrounds in a group based on the expansion state.
1802 */
1803 public void updateBackgroundForGroupState() {
1804 if (mIsSummaryWithChildren) {
1805 // Only when the group has finished expanding do we hide its background.
1806 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1807 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1808 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1809 for (int i = 0; i < children.size(); i++) {
1810 children.get(i).updateBackgroundForGroupState();
1811 }
1812 } else if (isChildInGroup()) {
1813 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
1814 // Only show a background if the group is expanded OR if it is expanding / collapsing
1815 // and has a custom background color
1816 final boolean showBackground = isGroupExpanded()
1817 || ((mNotificationParent.isGroupExpansionChanging()
1818 || mNotificationParent.isUserLocked()) && childColor != 0);
1819 mShowNoBackground = !showBackground;
1820 } else {
1821 // Only children or parents ever need no background.
1822 mShowNoBackground = false;
1823 }
1824 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001825 updateBackground();
1826 }
1827
Adrian Roos4a579672016-05-24 16:54:37 -07001828 public int getPositionOfChild(ExpandableNotificationRow childRow) {
1829 if (mIsSummaryWithChildren) {
1830 return mChildrenContainer.getPositionInLinearLayout(childRow);
1831 }
1832 return 0;
1833 }
1834
Chris Wren78403d72014-07-28 10:23:24 +01001835 public void setExpansionLogger(ExpansionLogger logger, String key) {
1836 mLogger = logger;
1837 mLoggingKey = key;
1838 }
1839
Chris Wren6abeeb92016-05-26 14:44:38 -04001840 public void onExpandedByGesture(boolean userExpanded) {
1841 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
1842 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
1843 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
1844 }
1845 MetricsLogger.action(mContext, event, userExpanded);
1846 }
1847
Selim Cinek6183d122016-01-14 18:48:41 -08001848 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001849 public float getIncreasedPaddingAmount() {
1850 if (mIsSummaryWithChildren) {
1851 if (isGroupExpanded()) {
1852 return 1.0f;
1853 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001854 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001855 }
1856 }
1857 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001858 }
1859
1860 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001861 protected boolean disallowSingleClick(MotionEvent event) {
1862 float x = event.getX();
1863 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001864 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001865 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001866 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001867 }
1868 return super.disallowSingleClick(event);
1869 }
1870
Chris Wren78403d72014-07-28 10:23:24 +01001871 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04001872 boolean nowExpanded = isExpanded();
1873 if (mIsSummaryWithChildren) {
1874 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
1875 }
Chris Wren78403d72014-07-28 10:23:24 +01001876 if (wasExpanded != nowExpanded && mLogger != null) {
1877 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1878 }
1879 }
Selim Cinek570981d2015-12-01 11:37:01 -08001880
Selim Cineke9bad242016-06-15 11:46:37 -07001881 @Override
1882 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1883 super.onInitializeAccessibilityNodeInfoInternal(info);
1884 if (canViewBeDismissed()) {
1885 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
1886 }
1887 }
1888
1889 @Override
1890 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
1891 if (super.performAccessibilityActionInternal(action, arguments)) {
1892 return true;
1893 }
1894 switch (action) {
1895 case AccessibilityNodeInfo.ACTION_DISMISS:
1896 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
1897 true /* fromAccessibility */);
1898 return true;
1899 }
1900 return false;
1901 }
1902
1903 public boolean shouldRefocusOnDismiss() {
1904 return mRefocusOnDismiss || isAccessibilityFocused();
1905 }
1906
Selim Cinek570981d2015-12-01 11:37:01 -08001907 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001908 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001909 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001910
1911 @Override
1912 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
1913 return new NotificationViewState(stackScrollState);
1914 }
1915
Selim Cinekd127d792016-11-01 19:11:41 -07001916 @Override
1917 public boolean isAboveShelf() {
1918 return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
1919 }
1920
Adrian Roos0aac04f2016-12-08 15:59:29 -08001921 public void setShowAmbient(boolean showAmbient) {
1922 if (showAmbient != mShowAmbient) {
1923 mShowAmbient = showAmbient;
1924 notifyHeightChanged(false /* needsAnimation */);
1925 }
1926 }
1927
Selim Cinekd127d792016-11-01 19:11:41 -07001928 public void setAboveShelf(boolean aboveShelf) {
1929 mAboveShelf = aboveShelf;
1930 }
1931
Selim Cinek0cfbef42016-11-09 19:06:36 -08001932 public class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08001933
1934 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07001935
Selim Cinekbbcebde2016-11-09 18:28:20 -08001936
1937 private NotificationViewState(StackScrollState stackScrollState) {
1938 mOverallState = stackScrollState;
1939 }
1940
1941 @Override
1942 public void applyToView(View view) {
1943 super.applyToView(view);
1944 if (view instanceof ExpandableNotificationRow) {
1945 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinekbbcebde2016-11-09 18:28:20 -08001946 row.applyChildrenState(mOverallState);
1947 }
1948 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08001949
1950 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08001951 protected void onYTranslationAnimationFinished(View view) {
1952 super.onYTranslationAnimationFinished(view);
Selim Cinek0cfbef42016-11-09 19:06:36 -08001953 if (mHeadsupDisappearRunning) {
Selim Cinekcafa87f2016-10-26 17:00:17 -07001954 setHeadsUpAnimatingAway(false);
Selim Cinek0cfbef42016-11-09 19:06:36 -08001955 }
1956 }
1957
1958 @Override
1959 public void animateTo(View child, AnimationProperties properties) {
1960 super.animateTo(child, properties);
1961 if (child instanceof ExpandableNotificationRow) {
1962 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
1963 row.startChildAnimation(mOverallState, properties);
1964 }
1965 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001966 }
Chris Wren51c75102013-07-16 20:49:17 -04001967}