blob: 2b5ade3769fff2c115bb9fc02cd6e0e006247c3b [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;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800207 private boolean mIsColorized;
Mady Mellorb0a82462016-04-30 17:31:02 -0700208
209 public boolean isGroupExpansionChanging() {
210 if (isChildInGroup()) {
211 return mNotificationParent.isGroupExpansionChanging();
212 }
213 return mGroupExpansionChanging;
214 }
215
216 public void setGroupExpansionChanging(boolean changing) {
217 mGroupExpansionChanging = changing;
218 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700219
Adrian Roos599be342016-06-13 14:54:39 -0700220 @Override
221 public void setActualHeightAnimating(boolean animating) {
222 if (mPrivateLayout != null) {
223 mPrivateLayout.setContentHeightAnimating(animating);
224 }
225 }
226
Selim Cinek8d490d42015-04-10 00:05:50 -0700227 public NotificationContentView getPrivateLayout() {
228 return mPrivateLayout;
229 }
230
231 public NotificationContentView getPublicLayout() {
232 return mPublicLayout;
233 }
234
Selim Cinekcab4a602014-09-03 14:47:57 +0200235 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800236 for (NotificationContentView l : mLayouts) {
237 setIconAnimationRunning(running, l);
238 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800239 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700240 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800241 List<ExpandableNotificationRow> notificationChildren =
242 mChildrenContainer.getNotificationChildren();
243 for (int i = 0; i < notificationChildren.size(); i++) {
244 ExpandableNotificationRow child = notificationChildren.get(i);
245 child.setIconAnimationRunning(running);
246 }
247 }
248 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200249 }
250
251 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
252 if (layout != null) {
253 View contractedChild = layout.getContractedChild();
254 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700255 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200256 setIconAnimationRunningForChild(running, contractedChild);
257 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700258 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200259 }
260 }
261
262 private void setIconAnimationRunningForChild(boolean running, View child) {
263 if (child != null) {
264 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
265 setIconRunning(icon, running);
266 ImageView rightIcon = (ImageView) child.findViewById(
267 com.android.internal.R.id.right_icon);
268 setIconRunning(rightIcon, running);
269 }
270 }
271
272 private void setIconRunning(ImageView imageView, boolean running) {
273 if (imageView != null) {
274 Drawable drawable = imageView.getDrawable();
275 if (drawable instanceof AnimationDrawable) {
276 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
277 if (running) {
278 animationDrawable.start();
279 } else {
280 animationDrawable.stop();
281 }
282 } else if (drawable instanceof AnimatedVectorDrawable) {
283 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
284 if (running) {
285 animationDrawable.start();
286 } else {
287 animationDrawable.stop();
288 }
289 }
290 }
291 }
292
Selim Cinekda42d652015-12-04 15:51:16 -0800293 public void onNotificationUpdated(NotificationData.Entry entry) {
294 mEntry = entry;
295 mStatusBarNotification = entry.notification;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800296 for (NotificationContentView l : mLayouts) {
297 l.onNotificationUpdated(entry);
298 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800299 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800300 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700301 updateNotificationColor();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800302 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700303 mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
Selim Cinekc897bd32016-03-18 17:32:31 -0700304 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800305 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800306 if (mIconAnimationRunning) {
307 setIconAnimationRunning(true);
308 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800309 if (mNotificationParent != null) {
310 mNotificationParent.updateChildrenHeaderAppearance();
311 }
Selim Cinek263398f2015-10-21 17:40:23 -0700312 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800313 // The public layouts expand button is always visible
314 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800315 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700316 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800317 updateShelfIconColor();
318 }
319
320 private void updateShelfIconColor() {
321 StatusBarIconView expandedIcon = mEntry.expandedIcon;
322 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
323 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
324 NotificationColorUtil.getInstance(mContext));
325 if (colorize) {
326 int color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded());
327 expandedIcon.setImageTintList(ColorStateList.valueOf(color));
328 }
Selim Cinekda42d652015-12-04 15:51:16 -0800329 }
330
331 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800332 for (NotificationContentView l : mLayouts) {
333 updateLimitsForView(l);
334 }
Selim Cineka1744872016-03-11 15:36:06 -0800335 }
336
337 private void updateLimitsForView(NotificationContentView layout) {
338 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800339 != com.android.internal.R.id.status_bar_latest_event_content;
340 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
341 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
342 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800343 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
344 layout.getHeadsUpChild().getId()
345 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek77019c72015-12-09 10:18:02 -0800346 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
347 : mMaxHeadsUpHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800348 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
349 mNotificationAmbientHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200350 }
351
352 public StatusBarNotification getStatusBarNotification() {
353 return mStatusBarNotification;
354 }
355
Selim Cinek281c2022016-10-13 19:14:43 -0700356 public NotificationData.Entry getEntry() {
357 return mEntry;
358 }
359
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700360 public boolean isHeadsUp() {
361 return mIsHeadsUp;
362 }
363
Selim Cinek1a521f32014-11-03 17:39:29 +0100364 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700365 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100366 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700367 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700368 if (mIsSummaryWithChildren) {
369 // The overflow might change since we allow more lines as HUN.
370 mChildrenContainer.updateGroupOverflow();
371 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700372 if (intrinsicBefore != getIntrinsicHeight()) {
373 notifyHeightChanged(false /* needsAnimation */);
374 }
Selim Cinekd127d792016-11-01 19:11:41 -0700375 if (isHeadsUp) {
376 setAboveShelf(true);
377 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100378 }
379
Selim Cinekb5605e52015-02-20 18:21:41 +0100380 public void setGroupManager(NotificationGroupManager groupManager) {
381 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700382 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100383 }
384
Adrian Roosb88b1a12015-12-09 18:51:05 -0800385 public void setRemoteInputController(RemoteInputController r) {
386 mPrivateLayout.setRemoteInputController(r);
387 }
388
Mady Mellor3fd273e2016-03-15 21:08:14 -0700389 public void setAppName(String appName) {
390 mAppName = appName;
391 if (mSettingsIconRow != null) {
392 mSettingsIconRow.setAppName(mAppName);
393 }
394 }
395
Selim Cinekb5605e52015-02-20 18:21:41 +0100396 public void addChildNotification(ExpandableNotificationRow row) {
397 addChildNotification(row, -1);
398 }
399
400 /**
401 * Add a child notification to this view.
402 *
403 * @param row the row to add
404 * @param childIndex the index to add it at, if -1 it will be added at the end
405 */
406 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
407 if (mChildrenContainer == null) {
408 mChildrenContainerStub.inflate();
409 }
410 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700411 onChildrenCountChanged();
412 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100413 }
414
415 public void removeChildNotification(ExpandableNotificationRow row) {
416 if (mChildrenContainer != null) {
417 mChildrenContainer.removeNotification(row);
418 }
Selim Cinek263398f2015-10-21 17:40:23 -0700419 onChildrenCountChanged();
420 row.setIsChildInGroup(false, null);
421 }
422
423 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700424 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700425 }
426
Selim Cinek388df6d2015-10-22 13:25:11 -0700427 public ExpandableNotificationRow getNotificationParent() {
428 return mNotificationParent;
429 }
430
Selim Cinek263398f2015-10-21 17:40:23 -0700431 /**
432 * @param isChildInGroup Is this notification now in a group
433 * @param parent the new parent notification
434 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700435 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
436 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
437 mNotificationParent = childInGroup ? parent : null;
438 mPrivateLayout.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400439 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700440 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700441 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700442 if (mNotificationParent != null) {
443 mNotificationParent.updateBackgroundForGroupState();
444 }
Selim Cinekdb167372016-11-17 15:41:17 -0800445 updateIconVisibilities();
Selim Cinek34d93b02015-10-22 12:30:38 -0700446 }
447
448 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800449 public boolean onTouchEvent(MotionEvent event) {
450 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
451 || !isChildInGroup() || isGroupExpanded()) {
452 return super.onTouchEvent(event);
453 } else {
454 return false;
455 }
456 }
457
458 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800459 protected boolean handleSlideBack() {
460 if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
461 animateTranslateNotification(0 /* targetLeft */);
462 return true;
463 }
464 return false;
465 }
466
467 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700468 protected boolean shouldHideBackground() {
469 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700470 }
471
472 @Override
473 public boolean isSummaryWithChildren() {
474 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100475 }
476
477 @Override
478 public boolean areChildrenExpanded() {
479 return mChildrenExpanded;
480 }
481
482 public List<ExpandableNotificationRow> getNotificationChildren() {
483 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
484 }
485
Selim Cinekeef84282015-10-30 16:28:00 -0700486 public int getNumberOfNotificationChildren() {
487 if (mChildrenContainer == null) {
488 return 0;
489 }
490 return mChildrenContainer.getNotificationChildren().size();
491 }
492
Selim Cinekb5605e52015-02-20 18:21:41 +0100493 /**
494 * Apply the order given in the list to the children.
495 *
496 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800497 * @param visualStabilityManager
498 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100499 * @return whether the list order has changed
500 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800501 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
502 VisualStabilityManager visualStabilityManager,
503 VisualStabilityManager.Callback callback) {
504 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
505 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100506 }
507
508 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700509 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800510 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100511 mChildrenContainer.getState(resultState, parentState);
512 }
513 }
514
515 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700516 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100517 mChildrenContainer.applyState(state);
518 }
519 }
520
521 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700522 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100523 mChildrenContainer.prepareExpansionChanged(state);
524 }
525 }
526
Selim Cinek0cfbef42016-11-09 19:06:36 -0800527 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700528 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800529 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100530 }
531 }
532
533 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800534 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100535 return this;
536 } else {
537 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
538 return view == null ? this : view;
539 }
540 }
541
Selim Cinekab29aeb2015-02-20 18:18:32 +0100542 public NotificationGuts getGuts() {
543 return mGuts;
544 }
545
Selim Cinek684a4422015-04-15 16:18:39 -0700546 /**
547 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
548 * the notification will be rendered on top of the screen.
549 *
550 * @param pinned whether it is pinned
551 */
552 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700553 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700554 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700555 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700556 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700557 }
Selim Cinek31aada42015-12-18 17:51:15 -0800558 if (pinned) {
559 setIconAnimationRunning(true);
560 mExpandedWhenPinned = false;
561 } else if (mExpandedWhenPinned) {
562 setUserExpanded(true);
563 }
Selim Cinek98713a42015-09-21 15:47:20 +0200564 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700565 }
566
Selim Cinek684a4422015-04-15 16:18:39 -0700567 public boolean isPinned() {
568 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700569 }
570
Selim Cinekd127d792016-11-01 19:11:41 -0700571 @Override
572 public int getPinnedHeadsUpHeight() {
573 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
574 }
575
Selim Cinek31aada42015-12-18 17:51:15 -0800576 /**
577 * @param atLeastMinHeight should the value returned be at least the minimum height.
578 * Used to avoid cyclic calls
579 * @return the height of the heads up notification when pinned
580 */
Selim Cinekd127d792016-11-01 19:11:41 -0700581 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800582 if (mIsSummaryWithChildren) {
583 return mChildrenContainer.getIntrinsicHeight();
584 }
Selim Cinek31aada42015-12-18 17:51:15 -0800585 if(mExpandedWhenPinned) {
586 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
587 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700588 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800589 } else {
590 return mHeadsUpHeight;
591 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700592 }
593
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700594 /**
595 * Mark whether this notification was just clicked, i.e. the user has just clicked this
596 * notification in this frame.
597 */
598 public void setJustClicked(boolean justClicked) {
599 mJustClicked = justClicked;
600 }
601
602 /**
603 * @return true if this notification has been clicked in this frame, false otherwise
604 */
605 public boolean wasJustClicked() {
606 return mJustClicked;
607 }
608
Selim Cinek98713a42015-09-21 15:47:20 +0200609 public void setChronometerRunning(boolean running) {
610 mLastChronometerRunning = running;
611 setChronometerRunning(running, mPrivateLayout);
612 setChronometerRunning(running, mPublicLayout);
613 if (mChildrenContainer != null) {
614 List<ExpandableNotificationRow> notificationChildren =
615 mChildrenContainer.getNotificationChildren();
616 for (int i = 0; i < notificationChildren.size(); i++) {
617 ExpandableNotificationRow child = notificationChildren.get(i);
618 child.setChronometerRunning(running);
619 }
620 }
621 }
622
623 private void setChronometerRunning(boolean running, NotificationContentView layout) {
624 if (layout != null) {
625 running = running || isPinned();
626 View contractedChild = layout.getContractedChild();
627 View expandedChild = layout.getExpandedChild();
628 View headsUpChild = layout.getHeadsUpChild();
629 setChronometerRunningForChild(running, contractedChild);
630 setChronometerRunningForChild(running, expandedChild);
631 setChronometerRunningForChild(running, headsUpChild);
632 }
633 }
634
635 private void setChronometerRunningForChild(boolean running, View child) {
636 if (child != null) {
637 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
638 if (chronometer instanceof Chronometer) {
639 ((Chronometer) chronometer).setStarted(running);
640 }
641 }
642 }
643
Selim Cinekea4bef72015-12-02 15:51:10 -0800644 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700645 if (mIsSummaryWithChildren) {
646 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700647 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800648 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700649 }
650
Selim Cinek34eda5e2016-02-18 17:10:43 -0800651 private NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700652 if (mIsSummaryWithChildren && !mShowingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700653 return mChildrenContainer.getHeaderView();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800654 }
655 return getShowingLayout().getVisibleNotificationHeader();
656 }
657
Selim Cinek570981d2015-12-01 11:37:01 -0800658 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
659 mOnExpandClickListener = onExpandClickListener;
660 }
661
Selim Cinekddf1b392016-05-27 16:33:10 -0700662 @Override
663 public void setOnClickListener(@Nullable OnClickListener l) {
664 super.setOnClickListener(l);
665 mOnClickListener = l;
666 updateClickAndFocus();
667 }
668
669 private void updateClickAndFocus() {
670 boolean normalChild = !isChildInGroup() || isGroupExpanded();
671 boolean clickable = mOnClickListener != null && normalChild;
672 if (isFocusable() != normalChild) {
673 setFocusable(normalChild);
674 }
675 if (isClickable() != clickable) {
676 setClickable(clickable);
677 }
678 }
679
Selim Cinek31aada42015-12-18 17:51:15 -0800680 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
681 mHeadsUpManager = headsUpManager;
682 }
683
Selim Cinek01af3342016-02-09 19:25:31 -0800684 public void reInflateViews() {
685 initDimens();
686 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800687 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700688 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800689 }
690 }
691 if (mGuts != null) {
692 View oldGuts = mGuts;
693 int index = indexOfChild(oldGuts);
694 removeView(oldGuts);
695 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
696 R.layout.notification_guts, this, false);
697 mGuts.setVisibility(oldGuts.getVisibility());
698 addView(mGuts, index);
699 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800700 if (mSettingsIconRow != null) {
701 View oldSettings = mSettingsIconRow;
702 int settingsIndex = indexOfChild(oldSettings);
703 removeView(oldSettings);
704 mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
705 R.layout.notification_settings_icon_row, this, false);
706 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700707 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800708 mSettingsIconRow.setVisibility(oldSettings.getVisibility());
709 addView(mSettingsIconRow, settingsIndex);
710
711 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800712 for (NotificationContentView l : mLayouts) {
713 l.reInflateViews();
714 }
Selim Cinek01af3342016-02-09 19:25:31 -0800715 }
716
Selim Cinekc3179332016-03-04 14:44:56 -0800717 public void setContentBackground(int customBackgroundColor, boolean animate,
718 NotificationContentView notificationContentView) {
719 if (getShowingLayout() == notificationContentView) {
720 setTintColor(customBackgroundColor, animate);
721 }
722 }
723
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700724 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800725 for (NotificationContentView l : mLayouts) {
726 l.closeRemoteInput();
727 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700728 }
729
Selim Cinekc897bd32016-03-18 17:32:31 -0700730 /**
731 * Set by how much the single line view should be indented.
732 */
733 public void setSingleLineWidthIndention(int indention) {
734 mPrivateLayout.setSingleLineWidthIndention(indention);
735 }
736
737 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700738 return mNotificationColor;
739 }
740
741 private void updateNotificationColor() {
742 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
743 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700744 }
745
746 public HybridNotificationView getSingleLineView() {
747 return mPrivateLayout.getSingleLineView();
748 }
749
Selim Cinekf07d0622016-03-21 19:52:52 -0700750 public boolean isOnKeyguard() {
751 return mOnKeyguard;
752 }
753
Selim Cinekc1e389d2016-04-07 11:02:57 -0700754 public void removeAllChildren() {
755 List<ExpandableNotificationRow> notificationChildren
756 = mChildrenContainer.getNotificationChildren();
757 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
758 for (int i = 0; i < clonedList.size(); i++) {
759 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700760 if (row.keepInParent()) {
761 continue;
762 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700763 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700764 row.setIsChildInGroup(false, null);
765 }
766 onChildrenCountChanged();
767 }
768
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700769 public void setForceUnlocked(boolean forceUnlocked) {
770 mForceUnlocked = forceUnlocked;
771 if (mIsSummaryWithChildren) {
772 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
773 for (ExpandableNotificationRow child : notificationChildren) {
774 child.setForceUnlocked(forceUnlocked);
775 }
776 }
777 }
778
Selim Cineke9bad242016-06-15 11:46:37 -0700779 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700780 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700781 mGroupParentWhenDismissed = mNotificationParent;
782 mRefocusOnDismiss = fromAccessibility;
783 mChildAfterViewWhenDismissed = null;
784 if (isChildInGroup()) {
785 List<ExpandableNotificationRow> notificationChildren =
786 mNotificationParent.getNotificationChildren();
787 int i = notificationChildren.indexOf(this);
788 if (i != -1 && i < notificationChildren.size() - 1) {
789 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
790 }
791 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700792 }
793
794 public boolean isDismissed() {
795 return mDismissed;
796 }
797
798 public boolean keepInParent() {
799 return mKeepInParent;
800 }
801
802 public void setKeepInParent(boolean keepInParent) {
803 mKeepInParent = keepInParent;
804 }
805
806 public boolean isRemoved() {
807 return mRemoved;
808 }
809
Adrian Roosd009ab12016-05-20 17:58:53 -0700810 public void setRemoved() {
811 mRemoved = true;
812
813 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700814 }
815
Selim Cinekd1395642016-04-28 12:22:42 -0700816 public NotificationChildrenContainer getChildrenContainer() {
817 return mChildrenContainer;
818 }
819
Selim Cinekcafa87f2016-10-26 17:00:17 -0700820 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
821 mHeadsupDisappearRunning = headsUpAnimatingAway;
822 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
823 }
824
825 /**
826 * @return if the view was just heads upped and is now animating away. During such a time the
827 * layout needs to be kept consistent
828 */
829 public boolean isHeadsUpAnimatingAway() {
830 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700831 }
832
Selim Cineke9bad242016-06-15 11:46:37 -0700833 public View getChildAfterViewWhenDismissed() {
834 return mChildAfterViewWhenDismissed;
835 }
836
837 public View getGroupParentWhenDismissed() {
838 return mGroupParentWhenDismissed;
839 }
840
Selim Cinek9e624e72016-07-20 13:46:49 -0700841 public void performDismiss() {
Selim Cineke9079112016-12-14 14:41:01 -0800842 if (mOnDismissRunnable != null) {
843 mOnDismissRunnable.run();
844 }
Selim Cinek9e624e72016-07-20 13:46:49 -0700845 }
846
Selim Cineke9079112016-12-14 14:41:01 -0800847 public void setOnDismissRunnable(Runnable onDismissRunnable) {
848 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -0700849 }
850
Selim Cinek281c2022016-10-13 19:14:43 -0700851 public View getNotificationIcon() {
852 NotificationHeaderView notificationHeader = getNotificationHeader();
853 if (notificationHeader != null) {
854 return notificationHeader.getIcon();
855 }
856 return null;
857 }
858
859 /**
860 * @return whether the notification is currently showing a view with an icon.
861 */
862 public boolean isShowingIcon() {
863 if (mIsSummaryWithChildren) {
864 return true;
865 }
866 NotificationContentView showingLayout = getShowingLayout();
867 NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
868 return notificationHeader != null;
869 }
870
Selim Cinek0242fbb2016-10-19 13:38:32 -0700871 /**
872 * Set how much this notification is transformed into an icon.
873 *
Selim Cinek2b549f42016-11-22 16:38:51 -0800874 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
875 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -0800876 * @param isLastChild is this the last child in the list. If true, then the transformation is
877 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -0700878 */
Selim Cinek2b549f42016-11-22 16:38:51 -0800879 public void setContentTransformationAmount(float contentTransformationAmount,
880 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -0800881 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800882 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800883 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800884 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800885 if (changeTransformation) {
886 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -0800887 }
888 }
889
890 /**
891 * Set the icons to be visible of this notification.
892 */
893 public void setIconsVisible(boolean iconsVisible) {
894 if (iconsVisible != mIconsVisible) {
895 mIconsVisible = iconsVisible;
896 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700897 }
898 }
899
Selim Cinekdb167372016-11-17 15:41:17 -0800900 @Override
901 protected void onBelowSpeedBumpChanged() {
902 updateIconVisibilities();
903 }
904
Selim Cinek875a3a12016-11-18 17:52:16 -0800905 private void updateContentTransformation() {
906 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -0800907 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800908 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -0800909 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800910 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700911 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -0800912 translationY *= 0.4f;
913 } else {
914 contentAlpha = 1.0f;
915 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800916 for (NotificationContentView l : mLayouts) {
917 l.setAlpha(contentAlpha);
918 l.setTranslationY(translationY);
919 }
Selim Cinek875a3a12016-11-18 17:52:16 -0800920 if (mChildrenContainer != null) {
921 mChildrenContainer.setAlpha(contentAlpha);
922 mChildrenContainer.setTranslationY(translationY);
923 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -0700924 }
925 }
926
927 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -0800928 boolean visible = isChildInGroup()
929 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
930 || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800931 for (NotificationContentView l : mLayouts) {
932 l.setIconsVisible(visible);
933 }
Selim Cinekdb167372016-11-17 15:41:17 -0800934 if (mChildrenContainer != null) {
935 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700936 }
937 }
938
Selim Cinek875a3a12016-11-18 17:52:16 -0800939 /**
940 * Get the relative top padding of a view relative to this view. This recursively walks up the
941 * hierarchy and does the corresponding measuring.
942 *
943 * @param view the view to the the padding for. The requested view has to be a child of this
944 * notification.
945 * @return the toppadding
946 */
947 public int getRelativeTopPadding(View view) {
948 int topPadding = 0;
949 while (view.getParent() instanceof ViewGroup) {
950 topPadding += view.getTop();
951 view = (View) view.getParent();
952 if (view instanceof ExpandableNotificationRow) {
953 return topPadding;
954 }
955 }
956 return topPadding;
957 }
958
Selim Cineka1d97902016-12-14 16:31:40 -0800959 public float getContentTranslation() {
960 return mPrivateLayout.getTranslationY();
961 }
962
Selim Cinek6743c0b2017-01-18 18:24:01 -0800963 public void setIsLowPriority(boolean isLowPriority) {
964 mIsLowPriority = isLowPriority;
965 mPrivateLayout.setIsLowPriority(isLowPriority);
966 if (mChildrenContainer != null) {
967 mChildrenContainer.setIsLowPriority(isLowPriority);
968 }
969 }
970
Chris Wren78403d72014-07-28 10:23:24 +0100971 public interface ExpansionLogger {
972 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
973 }
Selim Cinek1685e632014-04-08 02:27:49 +0200974
Chris Wren51c75102013-07-16 20:49:17 -0400975 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
976 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700977 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -0800978 initDimens();
979 }
980
981 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800982 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
983 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
984 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
Adrian Roos0aac04f2016-12-08 15:59:29 -0800985 mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800986 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -0800987 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800988 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Mady Mellorb0a82462016-04-30 17:31:02 -0700989 mIncreasedPaddingBetweenElements = getResources()
990 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinek875a3a12016-11-18 17:52:16 -0800991 mIconTransformContentShiftNoIcon = getResources().getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -0700992 R.dimen.notification_icon_transform_content_shift);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800993 }
994
995 /**
996 * @param dimenId the dimen to look up
997 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
998 */
999 private int getFontScaledHeight(int dimenId) {
1000 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
1001 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
1002 getResources().getDisplayMetrics().density);
1003 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -04001004 }
1005
Christoph Studera7fe6312014-06-27 19:32:44 +02001006 /**
1007 * Resets this view so it can be re-used for an updated notification.
1008 */
Christoph Studer22f2ee52014-07-29 22:57:21 +02001009 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +02001010 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +02001011 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +01001012 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +02001013 mExpandable = false;
1014 mHasUserChangedExpansion = false;
1015 mUserLocked = false;
1016 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +02001017 mSensitive = false;
1018 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +02001019 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -07001020 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -08001021 mPublicLayout.reset();
1022 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +02001023 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -08001024 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +02001025 logExpansionEvent(false, wasExpanded);
1026 }
1027
1028 public void resetHeight() {
Selim Cinek31094df2014-08-14 19:28:15 +02001029 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001030 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001031 }
1032
Jorim Jaggi251957d2014-04-09 04:24:09 +02001033 @Override
1034 protected void onFinishInflate() {
1035 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001036 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1037 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001038
1039 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1040
1041 for (NotificationContentView l : mLayouts) {
1042 l.setExpandClickListener(mExpandClickListener);
1043 l.setContainingNotification(this);
1044 }
1045
Mady Mellor4b80b102016-01-22 08:03:58 -08001046 mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
1047 mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1048 @Override
1049 public void onInflate(ViewStub stub, View inflated) {
1050 mSettingsIconRow = (NotificationSettingsIconRow) inflated;
1051 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -07001052 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -08001053 }
1054 });
Selim Cinekab29aeb2015-02-20 18:18:32 +01001055 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1056 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001057 @Override
1058 public void onInflate(ViewStub stub, View inflated) {
1059 mGuts = (NotificationGuts) inflated;
1060 mGuts.setClipTopAmount(getClipTopAmount());
1061 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001062 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001063 }
1064 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001065 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1066 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1067
1068 @Override
1069 public void onInflate(ViewStub stub, View inflated) {
1070 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001071 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek388df6d2015-10-22 13:25:11 -07001072 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001073 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -08001074 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +01001075 }
1076 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001077
1078 // Add the views that we translate to reveal the gear
1079 mTranslateableViews = new ArrayList<View>();
1080 for (int i = 0; i < getChildCount(); i++) {
1081 mTranslateableViews.add(getChildAt(i));
1082 }
1083 // Remove views that don't translate
Mady Mellor4b80b102016-01-22 08:03:58 -08001084 mTranslateableViews.remove(mSettingsIconRowStub);
1085 mTranslateableViews.remove(mChildrenContainerStub);
1086 mTranslateableViews.remove(mGutsStub);
1087 }
1088
Mady Mellor4b80b102016-01-22 08:03:58 -08001089 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001090 if (mTranslateAnim != null) {
1091 mTranslateAnim.cancel();
1092 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001093 if (mTranslateableViews != null) {
1094 for (int i = 0; i < mTranslateableViews.size(); i++) {
1095 mTranslateableViews.get(i).setTranslationX(0);
1096 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001097 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001098 invalidateOutline();
Mady Mellor4b80b102016-01-22 08:03:58 -08001099 if (mSettingsIconRow != null) {
1100 mSettingsIconRow.resetState();
1101 }
1102 }
1103
1104 public void animateTranslateNotification(final float leftTarget) {
1105 if (mTranslateAnim != null) {
1106 mTranslateAnim.cancel();
1107 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001108 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001109 if (mTranslateAnim != null) {
1110 mTranslateAnim.start();
1111 }
1112 }
1113
1114 @Override
1115 public void setTranslation(float translationX) {
1116 if (areGutsExposed()) {
1117 // Don't translate if guts are showing.
1118 return;
1119 }
1120 // Translate the group of views
1121 for (int i = 0; i < mTranslateableViews.size(); i++) {
1122 if (mTranslateableViews.get(i) != null) {
1123 mTranslateableViews.get(i).setTranslationX(translationX);
1124 }
1125 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001126 invalidateOutline();
Mady Mellor34958fa2016-02-23 09:52:17 -08001127 if (mSettingsIconRow != null) {
1128 mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
1129 }
1130 }
1131
1132 @Override
1133 public float getTranslation() {
1134 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1135 // All of the views in the list should have same translation, just use first one.
1136 return mTranslateableViews.get(0).getTranslationX();
1137 }
1138 return 0;
1139 }
1140
1141 public Animator getTranslateViewAnimator(final float leftTarget,
1142 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001143 if (mTranslateAnim != null) {
1144 mTranslateAnim.cancel();
1145 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001146 if (areGutsExposed()) {
1147 // No translation if guts are exposed.
1148 return null;
1149 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001150 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1151 leftTarget);
1152 if (listener != null) {
1153 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001154 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001155 translateAnim.addListener(new AnimatorListenerAdapter() {
1156 boolean cancelled = false;
1157
1158 @Override
1159 public void onAnimationCancel(Animator anim) {
1160 cancelled = true;
1161 }
1162
1163 @Override
1164 public void onAnimationEnd(Animator anim) {
1165 if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
1166 mSettingsIconRow.resetState();
1167 mTranslateAnim = null;
1168 }
1169 }
1170 });
1171 mTranslateAnim = translateAnim;
1172 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001173 }
1174
1175 public float getSpaceForGear() {
1176 if (mSettingsIconRow != null) {
1177 return mSettingsIconRow.getSpaceForGear();
1178 }
1179 return 0;
1180 }
1181
1182 public NotificationSettingsIconRow getSettingsRow() {
1183 if (mSettingsIconRow == null) {
1184 mSettingsIconRowStub.inflate();
1185 }
1186 return mSettingsIconRow;
1187 }
1188
Selim Cinekab29aeb2015-02-20 18:18:32 +01001189 public void inflateGuts() {
1190 if (mGuts == null) {
1191 mGutsStub.inflate();
1192 }
1193 }
1194
Selim Cinekda42d652015-12-04 15:51:16 -08001195 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001196 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1197 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001198 if (mChildrenContainer != null) {
1199 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1200 : INVISIBLE);
Mady Mellorb0a82462016-04-30 17:31:02 -07001201 mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
1202 ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001203 : INVISIBLE);
1204 }
Selim Cinekda42d652015-12-04 15:51:16 -08001205 // The limits might have changed if the view suddenly became a group or vice versa
1206 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001207 }
1208
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001209 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001210 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1211 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001212 // Add a record for the entire layout since its content is somehow small.
1213 // The event comes from a leaf view that is interacted with.
1214 AccessibilityEvent record = AccessibilityEvent.obtain();
1215 onInitializeAccessibilityEvent(record);
1216 dispatchPopulateAccessibilityEvent(record);
1217 event.appendRecord(record);
1218 return true;
1219 }
1220 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001221 }
Chris Wren51c75102013-07-16 20:49:17 -04001222
John Spurlocke15452b2014-08-21 09:44:39 -04001223 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001224 public void setDark(boolean dark, boolean fade, long delay) {
1225 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001226 final NotificationContentView showing = getShowingLayout();
1227 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001228 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001229 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001230 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001231 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001232 }
John Spurlocke15452b2014-08-21 09:44:39 -04001233 }
1234
Chris Wren51c75102013-07-16 20:49:17 -04001235 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001236 if (mIsSummaryWithChildren && !mShowingPublic) {
1237 return !mChildrenExpanded;
1238 }
Chris Wren51c75102013-07-16 20:49:17 -04001239 return mExpandable;
1240 }
1241
1242 public void setExpandable(boolean expandable) {
1243 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001244 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001245 }
1246
Selim Cinek4ffd6362015-12-29 15:12:23 +01001247 @Override
1248 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001249 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1250 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001251 }
1252
Selim Cinek1685e632014-04-08 02:27:49 +02001253 /**
1254 * @return whether the user has changed the expansion state
1255 */
1256 public boolean hasUserChangedExpansion() {
1257 return mHasUserChangedExpansion;
1258 }
1259
Chris Wren51c75102013-07-16 20:49:17 -04001260 public boolean isUserExpanded() {
1261 return mUserExpanded;
1262 }
1263
Selim Cinek1685e632014-04-08 02:27:49 +02001264 /**
1265 * Set this notification to be expanded by the user
1266 *
1267 * @param userExpanded whether the user wants this notification to be expanded
1268 */
Chris Wren51c75102013-07-16 20:49:17 -04001269 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001270 setUserExpanded(userExpanded, false /* allowChildExpansion */);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001271 updateShelfIconColor();
Selim Cinek388df6d2015-10-22 13:25:11 -07001272 }
1273
1274 /**
1275 * Set this notification to be expanded by the user
1276 *
1277 * @param userExpanded whether the user wants this notification to be expanded
1278 * @param allowChildExpansion whether a call to this method allows expanding children
1279 */
1280 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001281 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -07001282 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
Chris Wren698b1702016-05-23 11:16:32 -04001283 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001284 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Chris Wren698b1702016-05-23 11:16:32 -04001285 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001286 return;
1287 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001288 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001289 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001290 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001291 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001292 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001293 }
1294
Selim Cinekccd14fb2014-08-12 18:53:24 +02001295 public void resetUserExpansion() {
1296 mHasUserChangedExpansion = false;
1297 mUserExpanded = false;
1298 }
1299
Chris Wren51c75102013-07-16 20:49:17 -04001300 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001301 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001302 }
1303
1304 public void setUserLocked(boolean userLocked) {
1305 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001306 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001307 if (mIsSummaryWithChildren) {
1308 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek7baaa9e2016-07-21 17:21:09 -07001309 if (userLocked || !isGroupExpanded()) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001310 updateBackgroundForGroupState();
1311 }
Selim Cinek42357e02016-02-24 18:48:01 -08001312 }
Chris Wren51c75102013-07-16 20:49:17 -04001313 }
1314
Selim Cinek1685e632014-04-08 02:27:49 +02001315 /**
1316 * @return has the system set this notification to be expanded
1317 */
1318 public boolean isSystemExpanded() {
1319 return mIsSystemExpanded;
1320 }
1321
1322 /**
1323 * Set this notification to be expanded by the system.
1324 *
1325 * @param expand whether the system wants this notification to be expanded.
1326 */
1327 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001328 if (expand != mIsSystemExpanded) {
1329 final boolean wasExpanded = isExpanded();
1330 mIsSystemExpanded = expand;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001331 updateShelfIconColor();
Selim Cinekb5605e52015-02-20 18:21:41 +01001332 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001333 logExpansionEvent(false, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001334 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001335 mChildrenContainer.updateGroupOverflow();
1336 }
Selim Cinek31094df2014-08-14 19:28:15 +02001337 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001338 }
1339
1340 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001341 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001342 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001343 public void setOnKeyguard(boolean onKeyguard) {
1344 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001345 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001346 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001347 logExpansionEvent(false, wasExpanded);
1348 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001349 if (mIsSummaryWithChildren) {
1350 mChildrenContainer.updateGroupOverflow();
1351 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001352 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001353 }
1354 }
Selim Cinek1685e632014-04-08 02:27:49 +02001355 }
1356
1357 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001358 * @return Can the underlying notification be cleared? This can be different from whether the
1359 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1360 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001361 */
1362 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001363 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1364 return false;
1365 }
1366 if (mIsSummaryWithChildren) {
1367 List<ExpandableNotificationRow> notificationChildren =
1368 mChildrenContainer.getNotificationChildren();
1369 for (int i = 0; i < notificationChildren.size(); i++) {
1370 ExpandableNotificationRow child = notificationChildren.get(i);
1371 if (!child.isClearable()) {
1372 return false;
1373 }
1374 }
1375 }
1376 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001377 }
1378
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001379 @Override
1380 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001381 if (isUserLocked()) {
1382 return getActualHeight();
1383 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001384 if (mGuts != null && mGuts.isExposed()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001385 return mGuts.getHeight();
1386 } else if ((isChildInGroup() && !isGroupExpanded())) {
1387 return mPrivateLayout.getMinHeight();
Adrian Roos0aac04f2016-12-08 15:59:29 -08001388 } else if (mShowAmbient) {
1389 return getAmbientHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001390 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1391 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001392 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001393 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001394 } else if (!mOnKeyguard && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07001395 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001396 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1397 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001398 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001399 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001400 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001401 }
Selim Cinek31aada42015-12-18 17:51:15 -08001402 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001403 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001404 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001405 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001406 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001407 }
Selim Cinek1685e632014-04-08 02:27:49 +02001408
Mady Mellorb0a82462016-04-30 17:31:02 -07001409 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001410 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001411 }
1412
Selim Cinek263398f2015-10-21 17:40:23 -07001413 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001414 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001415 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1416 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
1417 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
1418 mEntry.notification);
Selim Cinek263398f2015-10-21 17:40:23 -07001419 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001420 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001421 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001422 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001423 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001424 }
1425
Mady Mellorb0a82462016-04-30 17:31:02 -07001426 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001427 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001428 mChildrenContainer.updateChildrenHeaderAppearance();
1429 }
1430 }
1431
Selim Cinek1685e632014-04-08 02:27:49 +02001432 /**
1433 * Check whether the view state is currently expanded. This is given by the system in {@link
1434 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1435 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1436 * view can differ from this state, if layout params are modified from outside.
1437 *
1438 * @return whether the view state is currently expanded.
1439 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001440 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001441 return isExpanded(false /* allowOnKeyguard */);
1442 }
1443
1444 public boolean isExpanded(boolean allowOnKeyguard) {
1445 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001446 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1447 || isUserExpanded());
1448 }
1449
1450 private boolean isSystemChildExpanded() {
1451 return mIsSystemChildExpanded;
1452 }
1453
1454 public void setSystemChildExpanded(boolean expanded) {
1455 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001456 }
1457
1458 @Override
1459 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1460 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001461 updateMaxHeights();
Mady Mellora6edc872016-04-26 11:01:03 -07001462 if (mSettingsIconRow != null) {
1463 mSettingsIconRow.updateVerticalLocation();
1464 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001465 updateContentShiftHeight();
1466 }
1467
1468 /**
1469 * Updates the content shift height such that the header is completely hidden when coming from
1470 * the top.
1471 */
1472 private void updateContentShiftHeight() {
1473 NotificationHeaderView notificationHeader = getNotificationHeader();
1474 if (notificationHeader != null) {
1475 CachingIconView icon = notificationHeader.getIcon();
1476 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1477 } else {
1478 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1479 }
Selim Cinek1685e632014-04-08 02:27:49 +02001480 }
1481
Selim Cinek8d490d42015-04-10 00:05:50 -07001482 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001483 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001484 View expandedChild = mPrivateLayout.getExpandedChild();
1485 if (expandedChild == null) {
1486 expandedChild = mPrivateLayout.getContractedChild();
1487 }
1488 mMaxExpandHeight = expandedChild.getHeight();
1489 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001490 if (headsUpChild == null) {
1491 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001492 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001493 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001494 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001495 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001496 }
1497 }
1498
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001499 @Override
1500 public void notifyHeightChanged(boolean needsAnimation) {
1501 super.notifyHeightChanged(needsAnimation);
1502 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1503 }
1504
Selim Cinek3c76d502016-02-19 15:16:33 -08001505 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001506 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001507 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001508 }
1509
1510 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001511 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001512 if (mIsSummaryWithChildren) {
1513 List<ExpandableNotificationRow> notificationChildren =
1514 mChildrenContainer.getNotificationChildren();
1515 for (int i = 0; i < notificationChildren.size(); i++) {
1516 ExpandableNotificationRow child = notificationChildren.get(i);
1517 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1518 }
1519 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001520 }
1521
1522 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1523 long duration) {
1524 boolean oldShowingPublic = mShowingPublic;
1525 mShowingPublic = mSensitive && hideSensitive;
1526 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1527 return;
1528 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001529
1530 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001531 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001532
Jorim Jaggiae441282014-08-01 02:45:18 +02001533 if (!animated) {
1534 mPublicLayout.animate().cancel();
1535 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001536 if (mChildrenContainer != null) {
1537 mChildrenContainer.animate().cancel();
1538 mChildrenContainer.setAlpha(1f);
1539 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001540 mPublicLayout.setAlpha(1f);
1541 mPrivateLayout.setAlpha(1f);
1542 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001543 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001544 } else {
1545 animateShowingPublic(delay, duration);
1546 }
Selim Cinekc3179332016-03-04 14:44:56 -08001547 NotificationContentView showingLayout = getShowingLayout();
1548 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001549 mPrivateLayout.updateExpandButtons(isExpandable());
Adrian Roose5726a22016-12-19 14:26:51 -08001550 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02001551 mShowingPublicInitialized = true;
1552 }
1553
1554 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001555 View[] privateViews = mIsSummaryWithChildren
1556 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001557 : new View[] {mPrivateLayout};
1558 View[] publicViews = new View[] {mPublicLayout};
1559 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1560 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1561 for (final View hiddenView : hiddenChildren) {
1562 hiddenView.setVisibility(View.VISIBLE);
1563 hiddenView.animate().cancel();
1564 hiddenView.animate()
1565 .alpha(0f)
1566 .setStartDelay(delay)
1567 .setDuration(duration)
1568 .withEndAction(new Runnable() {
1569 @Override
1570 public void run() {
1571 hiddenView.setVisibility(View.INVISIBLE);
1572 }
1573 });
1574 }
1575 for (View showView : shownChildren) {
1576 showView.setVisibility(View.VISIBLE);
1577 showView.setAlpha(0f);
1578 showView.animate().cancel();
1579 showView.animate()
1580 .alpha(1f)
1581 .setStartDelay(delay)
1582 .setDuration(duration);
1583 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001584 }
1585
Selim Cinek3776fe02016-02-04 13:32:43 -08001586 public boolean mustStayOnScreen() {
1587 return mIsHeadsUp;
1588 }
1589
Selim Cinek9e624e72016-07-20 13:46:49 -07001590 /**
1591 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1592 * otherwise some state might not be updated. To request about the general clearability
1593 * see {@link #isClearable()}.
1594 */
1595 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001596 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001597 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001598
Ricky Waicd35def2016-05-03 11:07:07 +01001599 public void makeActionsVisibile() {
1600 setUserExpanded(true, true);
1601 if (isChildInGroup()) {
1602 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1603 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001604 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001605 }
1606
Selim Cinekb5605e52015-02-20 18:21:41 +01001607 public void setChildrenExpanded(boolean expanded, boolean animate) {
1608 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001609 if (mChildrenContainer != null) {
1610 mChildrenContainer.setChildrenExpanded(expanded);
1611 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001612 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001613 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001614 }
1615
Selim Cinekb5605e52015-02-20 18:21:41 +01001616 public static void applyTint(View v, int color) {
1617 int alpha;
1618 if (color != 0) {
1619 alpha = COLORED_DIVIDER_ALPHA;
1620 } else {
1621 color = 0xff000000;
1622 alpha = DEFAULT_DIVIDER_ALPHA;
1623 }
1624 if (v.getBackground() instanceof ColorDrawable) {
1625 ColorDrawable background = (ColorDrawable) v.getBackground();
1626 background.mutate();
1627 background.setColor(color);
1628 background.setAlpha(alpha);
1629 }
1630 }
1631
Selim Cinek1685e632014-04-08 02:27:49 +02001632 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001633 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001634 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001635
Mady Mellor34958fa2016-02-23 09:52:17 -08001636 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001637 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08001638 }
1639
Jorim Jaggibe565df2014-04-28 17:51:23 +02001640 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001641 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001642 NotificationContentView showingLayout = getShowingLayout();
1643 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001644 }
1645
1646 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001647 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001648 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001649 return mChildrenContainer;
1650 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001651 return getShowingLayout();
1652 }
1653
1654 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001655 protected void onAppearAnimationFinished(boolean wasAppearing) {
1656 super.onAppearAnimationFinished(wasAppearing);
1657 if (wasAppearing) {
1658 // During the animation the visible view might have changed, so let's make sure all
1659 // alphas are reset
1660 if (mChildrenContainer != null) {
1661 mChildrenContainer.setAlpha(1.0f);
1662 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1663 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001664 for (NotificationContentView l : mLayouts) {
1665 l.setAlpha(1.0f);
1666 l.setLayerType(LAYER_TYPE_NONE, null);
1667 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07001668 }
1669 }
1670
1671 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001672 public int getExtraBottomPadding() {
1673 if (mIsSummaryWithChildren && isGroupExpanded()) {
1674 return mIncreasedPaddingBetweenElements;
1675 }
1676 return 0;
1677 }
1678
1679 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001680 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001681 super.setActualHeight(height, notifyListeners);
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001682 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08001683 mGuts.setActualHeight(height);
1684 return;
1685 }
Selim Cinekeef84282015-10-30 16:28:00 -07001686 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001687 for (NotificationContentView l : mLayouts) {
1688 l.setContentHeight(contentHeight);
1689 }
Selim Cinek42357e02016-02-24 18:48:01 -08001690 if (mIsSummaryWithChildren) {
1691 mChildrenContainer.setActualHeight(height);
1692 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001693 if (mGuts != null) {
1694 mGuts.setActualHeight(height);
1695 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001696 }
1697
1698 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001699 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001700 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001701 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001702 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001703 NotificationContentView showingLayout = getShowingLayout();
1704 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001705 }
1706
1707 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001708 public int getMinHeight() {
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001709 if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08001710 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1711 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001712 return mChildrenContainer.getMinHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001713 } else if (!mOnKeyguard && mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001714 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001715 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001716 NotificationContentView showingLayout = getShowingLayout();
1717 return showingLayout.getMinHeight();
1718 }
1719
Adrian Roos0aac04f2016-12-08 15:59:29 -08001720 private int getAmbientHeight() {
1721 NotificationContentView showingLayout = getShowingLayout();
1722 return showingLayout.getAmbientChild() != null
1723 ? showingLayout.getAmbientChild().getHeight()
1724 : getCollapsedHeight();
1725 }
1726
Selim Cinek816c8e42015-11-19 12:00:45 -08001727 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001728 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001729 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001730 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001731 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001732 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001733 }
1734
1735 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001736 public void setClipTopAmount(int clipTopAmount) {
1737 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001738 for (NotificationContentView l : mLayouts) {
1739 l.setClipTopAmount(clipTopAmount);
1740 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001741 if (mGuts != null) {
1742 mGuts.setClipTopAmount(clipTopAmount);
1743 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001744 }
1745
Selim Cineka686b2c2016-10-26 13:58:27 -07001746 @Override
1747 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001748 if (clipBottomAmount != mClipBottomAmount) {
1749 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001750 for (NotificationContentView l : mLayouts) {
1751 l.setClipBottomAmount(clipBottomAmount);
1752 }
Selim Cinek65d418e2016-11-29 15:42:34 -08001753 if (mGuts != null) {
1754 mGuts.setClipBottomAmount(clipBottomAmount);
1755 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001756 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001757 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001758 // We have to update this even if it hasn't changed, since the children locations can
1759 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001760 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
1761 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001762 }
1763
Selim Cinek31094df2014-08-14 19:28:15 +02001764 public boolean isMaxExpandHeightInitialized() {
1765 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001766 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001767
Selim Cinek42357e02016-02-24 18:48:01 -08001768 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001769 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1770 }
Chris Wren78403d72014-07-28 10:23:24 +01001771
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001772 @Override
1773 public void setShowingLegacyBackground(boolean showing) {
1774 super.setShowingLegacyBackground(showing);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001775 for (NotificationContentView l : mLayouts) {
1776 l.setShowingLegacyBackground(showing);
1777 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001778 }
1779
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001780 @Override
1781 protected void updateBackgroundTint() {
1782 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001783 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001784 if (mIsSummaryWithChildren) {
1785 List<ExpandableNotificationRow> notificationChildren =
1786 mChildrenContainer.getNotificationChildren();
1787 for (int i = 0; i < notificationChildren.size(); i++) {
1788 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001789 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001790 }
1791 }
1792 }
1793
Mady Mellorb0a82462016-04-30 17:31:02 -07001794 /**
1795 * Called when a group has finished animating from collapsed or expanded state.
1796 */
1797 public void onFinishedExpansionChange() {
1798 mGroupExpansionChanging = false;
1799 updateBackgroundForGroupState();
1800 }
1801
1802 /**
1803 * Updates the parent and children backgrounds in a group based on the expansion state.
1804 */
1805 public void updateBackgroundForGroupState() {
1806 if (mIsSummaryWithChildren) {
1807 // Only when the group has finished expanding do we hide its background.
1808 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1809 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1810 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1811 for (int i = 0; i < children.size(); i++) {
1812 children.get(i).updateBackgroundForGroupState();
1813 }
1814 } else if (isChildInGroup()) {
1815 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
1816 // Only show a background if the group is expanded OR if it is expanding / collapsing
1817 // and has a custom background color
1818 final boolean showBackground = isGroupExpanded()
1819 || ((mNotificationParent.isGroupExpansionChanging()
1820 || mNotificationParent.isUserLocked()) && childColor != 0);
1821 mShowNoBackground = !showBackground;
1822 } else {
1823 // Only children or parents ever need no background.
1824 mShowNoBackground = false;
1825 }
1826 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001827 updateBackground();
1828 }
1829
Adrian Roos4a579672016-05-24 16:54:37 -07001830 public int getPositionOfChild(ExpandableNotificationRow childRow) {
1831 if (mIsSummaryWithChildren) {
1832 return mChildrenContainer.getPositionInLinearLayout(childRow);
1833 }
1834 return 0;
1835 }
1836
Chris Wren78403d72014-07-28 10:23:24 +01001837 public void setExpansionLogger(ExpansionLogger logger, String key) {
1838 mLogger = logger;
1839 mLoggingKey = key;
1840 }
1841
Chris Wren6abeeb92016-05-26 14:44:38 -04001842 public void onExpandedByGesture(boolean userExpanded) {
1843 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
1844 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
1845 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
1846 }
1847 MetricsLogger.action(mContext, event, userExpanded);
1848 }
1849
Selim Cinek6183d122016-01-14 18:48:41 -08001850 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001851 public float getIncreasedPaddingAmount() {
1852 if (mIsSummaryWithChildren) {
1853 if (isGroupExpanded()) {
1854 return 1.0f;
1855 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001856 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001857 }
Selim Cineka7ed2c12017-01-23 20:47:24 -08001858 } else if (isColorized()) {
1859 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08001860 }
1861 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001862 }
1863
Selim Cineka7ed2c12017-01-23 20:47:24 -08001864 private boolean isColorized() {
1865 return mIsColorized;
1866 }
1867
Selim Cinek61633a82016-01-25 15:54:10 -08001868 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001869 protected boolean disallowSingleClick(MotionEvent event) {
1870 float x = event.getX();
1871 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001872 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001873 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001874 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001875 }
1876 return super.disallowSingleClick(event);
1877 }
1878
Chris Wren78403d72014-07-28 10:23:24 +01001879 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04001880 boolean nowExpanded = isExpanded();
1881 if (mIsSummaryWithChildren) {
1882 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
1883 }
Chris Wren78403d72014-07-28 10:23:24 +01001884 if (wasExpanded != nowExpanded && mLogger != null) {
1885 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1886 }
1887 }
Selim Cinek570981d2015-12-01 11:37:01 -08001888
Selim Cineke9bad242016-06-15 11:46:37 -07001889 @Override
1890 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1891 super.onInitializeAccessibilityNodeInfoInternal(info);
1892 if (canViewBeDismissed()) {
1893 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
1894 }
1895 }
1896
1897 @Override
1898 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
1899 if (super.performAccessibilityActionInternal(action, arguments)) {
1900 return true;
1901 }
1902 switch (action) {
1903 case AccessibilityNodeInfo.ACTION_DISMISS:
1904 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
1905 true /* fromAccessibility */);
1906 return true;
1907 }
1908 return false;
1909 }
1910
1911 public boolean shouldRefocusOnDismiss() {
1912 return mRefocusOnDismiss || isAccessibilityFocused();
1913 }
1914
Selim Cinek570981d2015-12-01 11:37:01 -08001915 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001916 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001917 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001918
1919 @Override
1920 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
1921 return new NotificationViewState(stackScrollState);
1922 }
1923
Selim Cinekd127d792016-11-01 19:11:41 -07001924 @Override
1925 public boolean isAboveShelf() {
1926 return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
1927 }
1928
Adrian Roos0aac04f2016-12-08 15:59:29 -08001929 public void setShowAmbient(boolean showAmbient) {
1930 if (showAmbient != mShowAmbient) {
1931 mShowAmbient = showAmbient;
1932 notifyHeightChanged(false /* needsAnimation */);
1933 }
1934 }
1935
Selim Cinekd127d792016-11-01 19:11:41 -07001936 public void setAboveShelf(boolean aboveShelf) {
1937 mAboveShelf = aboveShelf;
1938 }
1939
Selim Cinek0cfbef42016-11-09 19:06:36 -08001940 public class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08001941
1942 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07001943
Selim Cinekbbcebde2016-11-09 18:28:20 -08001944
1945 private NotificationViewState(StackScrollState stackScrollState) {
1946 mOverallState = stackScrollState;
1947 }
1948
1949 @Override
1950 public void applyToView(View view) {
1951 super.applyToView(view);
1952 if (view instanceof ExpandableNotificationRow) {
1953 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinekbbcebde2016-11-09 18:28:20 -08001954 row.applyChildrenState(mOverallState);
1955 }
1956 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08001957
1958 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08001959 protected void onYTranslationAnimationFinished(View view) {
1960 super.onYTranslationAnimationFinished(view);
Selim Cinek0cfbef42016-11-09 19:06:36 -08001961 if (mHeadsupDisappearRunning) {
Selim Cinekcafa87f2016-10-26 17:00:17 -07001962 setHeadsUpAnimatingAway(false);
Selim Cinek0cfbef42016-11-09 19:06:36 -08001963 }
1964 }
1965
1966 @Override
1967 public void animateTo(View child, AnimationProperties properties) {
1968 super.animateTo(child, properties);
1969 if (child instanceof ExpandableNotificationRow) {
1970 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
1971 row.startChildAnimation(mOverallState, properties);
1972 }
1973 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001974 }
Chris Wren51c75102013-07-16 20:49:17 -04001975}