blob: a19978a9b6d6591167f1d641d8b76dfa78efa9fc [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 Cinekcab4a602014-09-03 14:47:57 +020025import android.graphics.drawable.AnimatedVectorDrawable;
26import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010027import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020028import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080029import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070030import android.os.Bundle;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020031import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040032import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070033import android.util.FloatProperty;
34import android.util.Property;
Selim Cinek01af3342016-02-09 19:25:31 -080035import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080036import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080037import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050038import android.view.View;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020039import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020040import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070041import android.view.accessibility.AccessibilityNodeInfo;
Selim Cinek98713a42015-09-21 15:47:20 +020042import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020043import android.widget.ImageView;
Selim Cinekb5605e52015-02-20 18:21:41 +010044
Chris Wren698b1702016-05-23 11:16:32 -040045import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010046import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070047import com.android.internal.util.NotificationColorUtil;
Selim Cinek0242fbb2016-10-19 13:38:32 -070048import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050049import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070050import com.android.systemui.classifier.FalsingManager;
Selim Cinekc897bd32016-03-18 17:32:31 -070051import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinekb5605e52015-02-20 18:21:41 +010052import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinek31aada42015-12-18 17:51:15 -080053import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek0cfbef42016-11-09 19:06:36 -080054import com.android.systemui.statusbar.stack.AnimationProperties;
55import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010056import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070057import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010058import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010059
Mady Mellor4b80b102016-01-22 08:03:58 -080060import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010061import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050062
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020063public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010064
65 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
66 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Selim Cinek0242fbb2016-10-19 13:38:32 -070067 private int mIconTransformContentShift;
Selim Cinek01af3342016-02-09 19:25:31 -080068 private int mNotificationMinHeightLegacy;
69 private int mMaxHeadsUpHeightLegacy;
70 private int mMaxHeadsUpHeight;
71 private int mNotificationMinHeight;
72 private int mNotificationMaxHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -070073 private int mIncreasedPaddingBetweenElements;
Chris Wren51c75102013-07-16 20:49:17 -040074
Selim Cinek1685e632014-04-08 02:27:49 +020075 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040076 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020077 /** Has the user actively changed the expansion state of this row */
78 private boolean mHasUserChangedExpansion;
79 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040080 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -080081
82 /**
83 * Has this notification been expanded while it was pinned
84 */
85 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +020086 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040087 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020088 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050089 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020090 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -080091 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +020092 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -070093 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -040094
Selim Cinek1685e632014-04-08 02:27:49 +020095 /**
96 * Is this notification expanded by the system. The expansion state can be overridden by the
97 * user expansion.
98 */
99 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200100
101 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700102 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200103 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700104 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200105
Mady Mellorb0a82462016-04-30 17:31:02 -0700106 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800107 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200108 private NotificationContentView mPublicLayout;
109 private NotificationContentView mPrivateLayout;
Selim Cinek1685e632014-04-08 02:27:49 +0200110 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700111 private int mHeadsUpHeight;
Selim Cinek863834b2014-05-20 04:20:25 +0200112 private View mVetoButton;
Selim Cinek4bb59342016-04-08 19:29:35 -0700113 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100114 private ExpansionLogger mLogger;
115 private String mLoggingKey;
Mady Mellor4b80b102016-01-22 08:03:58 -0800116 private NotificationSettingsIconRow mSettingsIconRow;
Selim Cinek8d490d42015-04-10 00:05:50 -0700117 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800118 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200119 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700120 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100121 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200122 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100123 private ViewStub mChildrenContainerStub;
124 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100125 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700126 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100127 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor4b80b102016-01-22 08:03:58 -0800128 private ViewStub mSettingsIconRowStub;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100129 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100130 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700131 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700132 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800133 private HeadsUpManager mHeadsUpManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200134
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700135 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800136 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700137 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700138 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800139 private OnExpandClickListener mOnExpandClickListener;
Mady Mellorb0a82462016-04-30 17:31:02 -0700140 private boolean mGroupExpansionChanging;
141
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800142 private OnClickListener mExpandClickListener = new OnClickListener() {
143 @Override
144 public void onClick(View v) {
Selim Cinek624c02db2015-12-14 21:00:02 -0800145 if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700146 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400147 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
148 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
149 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400150 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
151 nowExpanded);
152 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800153 } else {
Selim Cineke9bad242016-06-15 11:46:37 -0700154 if (v.isAccessibilityFocused()) {
155 mPrivateLayout.setFocusOnVisibilityChange();
156 }
Selim Cinek31aada42015-12-18 17:51:15 -0800157 boolean nowExpanded;
158 if (isPinned()) {
159 nowExpanded = !mExpandedWhenPinned;
160 mExpandedWhenPinned = nowExpanded;
161 } else {
162 nowExpanded = !isExpanded();
163 setUserExpanded(nowExpanded);
164 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800165 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800166 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400167 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
168 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800169 }
170 }
171 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700172 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700173 private boolean mDismissed;
174 private boolean mKeepInParent;
175 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700176 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
177 new FloatProperty<ExpandableNotificationRow>("translate") {
178 @Override
179 public void setValue(ExpandableNotificationRow object, float value) {
180 object.setTranslation(value);
181 }
182
183 @Override
184 public Float get(ExpandableNotificationRow object) {
185 return object.getTranslation();
186 }
187 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700188 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700189 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700190 private View mChildAfterViewWhenDismissed;
191 private View mGroupParentWhenDismissed;
192 private boolean mRefocusOnDismiss;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700193 private float mIconTransformationAmount;
194 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700195 private boolean mAboveShelf;
Mady Mellorb0a82462016-04-30 17:31:02 -0700196
197 public boolean isGroupExpansionChanging() {
198 if (isChildInGroup()) {
199 return mNotificationParent.isGroupExpansionChanging();
200 }
201 return mGroupExpansionChanging;
202 }
203
204 public void setGroupExpansionChanging(boolean changing) {
205 mGroupExpansionChanging = changing;
206 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700207
Adrian Roos599be342016-06-13 14:54:39 -0700208 @Override
209 public void setActualHeightAnimating(boolean animating) {
210 if (mPrivateLayout != null) {
211 mPrivateLayout.setContentHeightAnimating(animating);
212 }
213 }
214
Selim Cinek8d490d42015-04-10 00:05:50 -0700215 public NotificationContentView getPrivateLayout() {
216 return mPrivateLayout;
217 }
218
219 public NotificationContentView getPublicLayout() {
220 return mPublicLayout;
221 }
222
Selim Cinekcab4a602014-09-03 14:47:57 +0200223 public void setIconAnimationRunning(boolean running) {
224 setIconAnimationRunning(running, mPublicLayout);
225 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800226 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700227 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800228 List<ExpandableNotificationRow> notificationChildren =
229 mChildrenContainer.getNotificationChildren();
230 for (int i = 0; i < notificationChildren.size(); i++) {
231 ExpandableNotificationRow child = notificationChildren.get(i);
232 child.setIconAnimationRunning(running);
233 }
234 }
235 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200236 }
237
238 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
239 if (layout != null) {
240 View contractedChild = layout.getContractedChild();
241 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700242 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200243 setIconAnimationRunningForChild(running, contractedChild);
244 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700245 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200246 }
247 }
248
249 private void setIconAnimationRunningForChild(boolean running, View child) {
250 if (child != null) {
251 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
252 setIconRunning(icon, running);
253 ImageView rightIcon = (ImageView) child.findViewById(
254 com.android.internal.R.id.right_icon);
255 setIconRunning(rightIcon, running);
256 }
257 }
258
259 private void setIconRunning(ImageView imageView, boolean running) {
260 if (imageView != null) {
261 Drawable drawable = imageView.getDrawable();
262 if (drawable instanceof AnimationDrawable) {
263 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
264 if (running) {
265 animationDrawable.start();
266 } else {
267 animationDrawable.stop();
268 }
269 } else if (drawable instanceof AnimatedVectorDrawable) {
270 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
271 if (running) {
272 animationDrawable.start();
273 } else {
274 animationDrawable.stop();
275 }
276 }
277 }
278 }
279
Selim Cinekda42d652015-12-04 15:51:16 -0800280 public void onNotificationUpdated(NotificationData.Entry entry) {
281 mEntry = entry;
282 mStatusBarNotification = entry.notification;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800283 mPrivateLayout.onNotificationUpdated(entry);
284 mPublicLayout.onNotificationUpdated(entry);
Selim Cinek757d8792016-01-28 16:21:08 -0800285 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700286 updateNotificationColor();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800287 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700288 mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
Selim Cinekc897bd32016-03-18 17:32:31 -0700289 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800290 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800291 if (mIconAnimationRunning) {
292 setIconAnimationRunning(true);
293 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800294 if (mNotificationParent != null) {
295 mNotificationParent.updateChildrenHeaderAppearance();
296 }
Selim Cinek263398f2015-10-21 17:40:23 -0700297 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800298 // The public layouts expand button is always visible
299 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800300 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700301 updateIconVisibilities();
Selim Cinekda42d652015-12-04 15:51:16 -0800302 }
303
304 private void updateLimits() {
Selim Cineka1744872016-03-11 15:36:06 -0800305 updateLimitsForView(mPrivateLayout);
306 updateLimitsForView(mPublicLayout);
307 }
308
309 private void updateLimitsForView(NotificationContentView layout) {
310 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800311 != com.android.internal.R.id.status_bar_latest_event_content;
312 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
313 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
314 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800315 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
316 layout.getHeadsUpChild().getId()
317 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek77019c72015-12-09 10:18:02 -0800318 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
319 : mMaxHeadsUpHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800320 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200321 }
322
323 public StatusBarNotification getStatusBarNotification() {
324 return mStatusBarNotification;
325 }
326
Selim Cinek281c2022016-10-13 19:14:43 -0700327 public NotificationData.Entry getEntry() {
328 return mEntry;
329 }
330
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700331 public boolean isHeadsUp() {
332 return mIsHeadsUp;
333 }
334
Selim Cinek1a521f32014-11-03 17:39:29 +0100335 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700336 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100337 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700338 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700339 if (mIsSummaryWithChildren) {
340 // The overflow might change since we allow more lines as HUN.
341 mChildrenContainer.updateGroupOverflow();
342 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700343 if (intrinsicBefore != getIntrinsicHeight()) {
344 notifyHeightChanged(false /* needsAnimation */);
345 }
Selim Cinekd127d792016-11-01 19:11:41 -0700346 if (isHeadsUp) {
347 setAboveShelf(true);
348 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100349 }
350
Selim Cinekb5605e52015-02-20 18:21:41 +0100351 public void setGroupManager(NotificationGroupManager groupManager) {
352 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700353 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100354 }
355
Adrian Roosb88b1a12015-12-09 18:51:05 -0800356 public void setRemoteInputController(RemoteInputController r) {
357 mPrivateLayout.setRemoteInputController(r);
358 }
359
Mady Mellor3fd273e2016-03-15 21:08:14 -0700360 public void setAppName(String appName) {
361 mAppName = appName;
362 if (mSettingsIconRow != null) {
363 mSettingsIconRow.setAppName(mAppName);
364 }
365 }
366
Selim Cinekb5605e52015-02-20 18:21:41 +0100367 public void addChildNotification(ExpandableNotificationRow row) {
368 addChildNotification(row, -1);
369 }
370
371 /**
372 * Add a child notification to this view.
373 *
374 * @param row the row to add
375 * @param childIndex the index to add it at, if -1 it will be added at the end
376 */
377 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
378 if (mChildrenContainer == null) {
379 mChildrenContainerStub.inflate();
380 }
381 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700382 onChildrenCountChanged();
383 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100384 }
385
386 public void removeChildNotification(ExpandableNotificationRow row) {
387 if (mChildrenContainer != null) {
388 mChildrenContainer.removeNotification(row);
389 }
Selim Cinek263398f2015-10-21 17:40:23 -0700390 onChildrenCountChanged();
391 row.setIsChildInGroup(false, null);
392 }
393
394 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700395 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700396 }
397
Selim Cinek388df6d2015-10-22 13:25:11 -0700398 public ExpandableNotificationRow getNotificationParent() {
399 return mNotificationParent;
400 }
401
Selim Cinek263398f2015-10-21 17:40:23 -0700402 /**
403 * @param isChildInGroup Is this notification now in a group
404 * @param parent the new parent notification
405 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700406 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
407 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
408 mNotificationParent = childInGroup ? parent : null;
409 mPrivateLayout.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400410 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700411 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700412 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700413 if (mNotificationParent != null) {
414 mNotificationParent.updateBackgroundForGroupState();
415 }
Selim Cinek34d93b02015-10-22 12:30:38 -0700416 }
417
418 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800419 public boolean onTouchEvent(MotionEvent event) {
420 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
421 || !isChildInGroup() || isGroupExpanded()) {
422 return super.onTouchEvent(event);
423 } else {
424 return false;
425 }
426 }
427
428 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800429 protected boolean handleSlideBack() {
430 if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
431 animateTranslateNotification(0 /* targetLeft */);
432 return true;
433 }
434 return false;
435 }
436
437 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700438 protected boolean shouldHideBackground() {
439 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700440 }
441
442 @Override
443 public boolean isSummaryWithChildren() {
444 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100445 }
446
447 @Override
448 public boolean areChildrenExpanded() {
449 return mChildrenExpanded;
450 }
451
452 public List<ExpandableNotificationRow> getNotificationChildren() {
453 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
454 }
455
Selim Cinekeef84282015-10-30 16:28:00 -0700456 public int getNumberOfNotificationChildren() {
457 if (mChildrenContainer == null) {
458 return 0;
459 }
460 return mChildrenContainer.getNotificationChildren().size();
461 }
462
Selim Cinekb5605e52015-02-20 18:21:41 +0100463 /**
464 * Apply the order given in the list to the children.
465 *
466 * @param childOrder the new list order
467 * @return whether the list order has changed
468 */
469 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
470 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
471 }
472
473 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700474 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800475 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100476 mChildrenContainer.getState(resultState, parentState);
477 }
478 }
479
480 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700481 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100482 mChildrenContainer.applyState(state);
483 }
484 }
485
486 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700487 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100488 mChildrenContainer.prepareExpansionChanged(state);
489 }
490 }
491
Selim Cinek0cfbef42016-11-09 19:06:36 -0800492 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700493 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800494 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100495 }
496 }
497
498 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800499 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100500 return this;
501 } else {
502 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
503 return view == null ? this : view;
504 }
505 }
506
Selim Cinekab29aeb2015-02-20 18:18:32 +0100507 public NotificationGuts getGuts() {
508 return mGuts;
509 }
510
Selim Cinek684a4422015-04-15 16:18:39 -0700511 /**
512 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
513 * the notification will be rendered on top of the screen.
514 *
515 * @param pinned whether it is pinned
516 */
517 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700518 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700519 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700520 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700521 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700522 }
Selim Cinek31aada42015-12-18 17:51:15 -0800523 if (pinned) {
524 setIconAnimationRunning(true);
525 mExpandedWhenPinned = false;
526 } else if (mExpandedWhenPinned) {
527 setUserExpanded(true);
528 }
Selim Cinek98713a42015-09-21 15:47:20 +0200529 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700530 }
531
Selim Cinek684a4422015-04-15 16:18:39 -0700532 public boolean isPinned() {
533 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700534 }
535
Selim Cinekd127d792016-11-01 19:11:41 -0700536 @Override
537 public int getPinnedHeadsUpHeight() {
538 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
539 }
540
Selim Cinek31aada42015-12-18 17:51:15 -0800541 /**
542 * @param atLeastMinHeight should the value returned be at least the minimum height.
543 * Used to avoid cyclic calls
544 * @return the height of the heads up notification when pinned
545 */
Selim Cinekd127d792016-11-01 19:11:41 -0700546 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800547 if (mIsSummaryWithChildren) {
548 return mChildrenContainer.getIntrinsicHeight();
549 }
Selim Cinek31aada42015-12-18 17:51:15 -0800550 if(mExpandedWhenPinned) {
551 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
552 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700553 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800554 } else {
555 return mHeadsUpHeight;
556 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700557 }
558
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700559 /**
560 * Mark whether this notification was just clicked, i.e. the user has just clicked this
561 * notification in this frame.
562 */
563 public void setJustClicked(boolean justClicked) {
564 mJustClicked = justClicked;
565 }
566
567 /**
568 * @return true if this notification has been clicked in this frame, false otherwise
569 */
570 public boolean wasJustClicked() {
571 return mJustClicked;
572 }
573
Selim Cinek98713a42015-09-21 15:47:20 +0200574 public void setChronometerRunning(boolean running) {
575 mLastChronometerRunning = running;
576 setChronometerRunning(running, mPrivateLayout);
577 setChronometerRunning(running, mPublicLayout);
578 if (mChildrenContainer != null) {
579 List<ExpandableNotificationRow> notificationChildren =
580 mChildrenContainer.getNotificationChildren();
581 for (int i = 0; i < notificationChildren.size(); i++) {
582 ExpandableNotificationRow child = notificationChildren.get(i);
583 child.setChronometerRunning(running);
584 }
585 }
586 }
587
588 private void setChronometerRunning(boolean running, NotificationContentView layout) {
589 if (layout != null) {
590 running = running || isPinned();
591 View contractedChild = layout.getContractedChild();
592 View expandedChild = layout.getExpandedChild();
593 View headsUpChild = layout.getHeadsUpChild();
594 setChronometerRunningForChild(running, contractedChild);
595 setChronometerRunningForChild(running, expandedChild);
596 setChronometerRunningForChild(running, headsUpChild);
597 }
598 }
599
600 private void setChronometerRunningForChild(boolean running, View child) {
601 if (child != null) {
602 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
603 if (chronometer instanceof Chronometer) {
604 ((Chronometer) chronometer).setStarted(running);
605 }
606 }
607 }
608
Selim Cinekea4bef72015-12-02 15:51:10 -0800609 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700610 if (mIsSummaryWithChildren) {
611 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700612 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800613 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700614 }
615
Selim Cinek34eda5e2016-02-18 17:10:43 -0800616 private NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700617 if (mIsSummaryWithChildren && !mShowingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700618 return mChildrenContainer.getHeaderView();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800619 }
620 return getShowingLayout().getVisibleNotificationHeader();
621 }
622
Selim Cinek570981d2015-12-01 11:37:01 -0800623 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
624 mOnExpandClickListener = onExpandClickListener;
625 }
626
Selim Cinekddf1b392016-05-27 16:33:10 -0700627 @Override
628 public void setOnClickListener(@Nullable OnClickListener l) {
629 super.setOnClickListener(l);
630 mOnClickListener = l;
631 updateClickAndFocus();
632 }
633
634 private void updateClickAndFocus() {
635 boolean normalChild = !isChildInGroup() || isGroupExpanded();
636 boolean clickable = mOnClickListener != null && normalChild;
637 if (isFocusable() != normalChild) {
638 setFocusable(normalChild);
639 }
640 if (isClickable() != clickable) {
641 setClickable(clickable);
642 }
643 }
644
Selim Cinek31aada42015-12-18 17:51:15 -0800645 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
646 mHeadsUpManager = headsUpManager;
647 }
648
Selim Cinek01af3342016-02-09 19:25:31 -0800649 public void reInflateViews() {
650 initDimens();
651 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800652 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700653 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800654 }
655 }
656 if (mGuts != null) {
657 View oldGuts = mGuts;
658 int index = indexOfChild(oldGuts);
659 removeView(oldGuts);
660 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
661 R.layout.notification_guts, this, false);
662 mGuts.setVisibility(oldGuts.getVisibility());
663 addView(mGuts, index);
664 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800665 if (mSettingsIconRow != null) {
666 View oldSettings = mSettingsIconRow;
667 int settingsIndex = indexOfChild(oldSettings);
668 removeView(oldSettings);
669 mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
670 R.layout.notification_settings_icon_row, this, false);
671 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700672 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800673 mSettingsIconRow.setVisibility(oldSettings.getVisibility());
674 addView(mSettingsIconRow, settingsIndex);
675
676 }
Selim Cinekde33a4a2016-02-11 16:43:41 -0800677 mPrivateLayout.reInflateViews();
678 mPublicLayout.reInflateViews();
Selim Cinek01af3342016-02-09 19:25:31 -0800679 }
680
Selim Cinekc3179332016-03-04 14:44:56 -0800681 public void setContentBackground(int customBackgroundColor, boolean animate,
682 NotificationContentView notificationContentView) {
683 if (getShowingLayout() == notificationContentView) {
684 setTintColor(customBackgroundColor, animate);
685 }
686 }
687
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700688 public void closeRemoteInput() {
689 mPrivateLayout.closeRemoteInput();
690 mPublicLayout.closeRemoteInput();
691 }
692
Selim Cinekc897bd32016-03-18 17:32:31 -0700693 /**
694 * Set by how much the single line view should be indented.
695 */
696 public void setSingleLineWidthIndention(int indention) {
697 mPrivateLayout.setSingleLineWidthIndention(indention);
698 }
699
700 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700701 return mNotificationColor;
702 }
703
704 private void updateNotificationColor() {
705 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
706 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700707 }
708
709 public HybridNotificationView getSingleLineView() {
710 return mPrivateLayout.getSingleLineView();
711 }
712
Selim Cinekf07d0622016-03-21 19:52:52 -0700713 public boolean isOnKeyguard() {
714 return mOnKeyguard;
715 }
716
Selim Cinekc1e389d2016-04-07 11:02:57 -0700717 public void removeAllChildren() {
718 List<ExpandableNotificationRow> notificationChildren
719 = mChildrenContainer.getNotificationChildren();
720 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
721 for (int i = 0; i < clonedList.size(); i++) {
722 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700723 if (row.keepInParent()) {
724 continue;
725 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700726 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700727 row.setIsChildInGroup(false, null);
728 }
729 onChildrenCountChanged();
730 }
731
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700732 public void setForceUnlocked(boolean forceUnlocked) {
733 mForceUnlocked = forceUnlocked;
734 if (mIsSummaryWithChildren) {
735 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
736 for (ExpandableNotificationRow child : notificationChildren) {
737 child.setForceUnlocked(forceUnlocked);
738 }
739 }
740 }
741
Selim Cineke9bad242016-06-15 11:46:37 -0700742 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700743 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700744 mGroupParentWhenDismissed = mNotificationParent;
745 mRefocusOnDismiss = fromAccessibility;
746 mChildAfterViewWhenDismissed = null;
747 if (isChildInGroup()) {
748 List<ExpandableNotificationRow> notificationChildren =
749 mNotificationParent.getNotificationChildren();
750 int i = notificationChildren.indexOf(this);
751 if (i != -1 && i < notificationChildren.size() - 1) {
752 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
753 }
754 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700755 }
756
757 public boolean isDismissed() {
758 return mDismissed;
759 }
760
761 public boolean keepInParent() {
762 return mKeepInParent;
763 }
764
765 public void setKeepInParent(boolean keepInParent) {
766 mKeepInParent = keepInParent;
767 }
768
769 public boolean isRemoved() {
770 return mRemoved;
771 }
772
Adrian Roosd009ab12016-05-20 17:58:53 -0700773 public void setRemoved() {
774 mRemoved = true;
775
776 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700777 }
778
Selim Cinekd1395642016-04-28 12:22:42 -0700779 public NotificationChildrenContainer getChildrenContainer() {
780 return mChildrenContainer;
781 }
782
Selim Cinekcafa87f2016-10-26 17:00:17 -0700783 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
784 mHeadsupDisappearRunning = headsUpAnimatingAway;
785 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
786 }
787
788 /**
789 * @return if the view was just heads upped and is now animating away. During such a time the
790 * layout needs to be kept consistent
791 */
792 public boolean isHeadsUpAnimatingAway() {
793 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700794 }
795
Selim Cineke9bad242016-06-15 11:46:37 -0700796 public View getChildAfterViewWhenDismissed() {
797 return mChildAfterViewWhenDismissed;
798 }
799
800 public View getGroupParentWhenDismissed() {
801 return mGroupParentWhenDismissed;
802 }
803
Selim Cinek9e624e72016-07-20 13:46:49 -0700804 public void performDismiss() {
805 mVetoButton.performClick();
806 }
807
808 public void setOnDismissListener(OnClickListener listener) {
809 mVetoButton.setOnClickListener(listener);
810 }
811
Selim Cinek281c2022016-10-13 19:14:43 -0700812 public View getNotificationIcon() {
813 NotificationHeaderView notificationHeader = getNotificationHeader();
814 if (notificationHeader != null) {
815 return notificationHeader.getIcon();
816 }
817 return null;
818 }
819
820 /**
821 * @return whether the notification is currently showing a view with an icon.
822 */
823 public boolean isShowingIcon() {
824 if (mIsSummaryWithChildren) {
825 return true;
826 }
827 NotificationContentView showingLayout = getShowingLayout();
828 NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
829 return notificationHeader != null;
830 }
831
Selim Cinek0242fbb2016-10-19 13:38:32 -0700832 /**
833 * Set how much this notification is transformed into an icon.
834 *
835 * @param iconTransformationAmount A value from 0 to 1 indicating how much we are transformed
836 * to an icon
837 */
838 public void setIconTransformationAmount(float iconTransformationAmount) {
839 if (mIconTransformationAmount != iconTransformationAmount) {
840 mIconTransformationAmount = iconTransformationAmount;
841 updateContentFadeOut();
842 boolean iconsVisible = mIconTransformationAmount == 0.0f;
843 if (iconsVisible != mIconsVisible) {
844 mIconsVisible = iconsVisible;
845 updateIconVisibilities();
846 }
847 }
848 }
849
850 private void updateContentFadeOut() {
851 if (!isChildInGroup()) {
852 float contentAlpha = 1.0f - mIconTransformationAmount;
853 contentAlpha = Math.max((contentAlpha - 0.5f) / 0.5f, 0.0f);
854 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
855 mPublicLayout.setAlpha(contentAlpha);
856 float translationY = - mIconTransformationAmount * mIconTransformContentShift;
857 mPublicLayout.setTranslationY(translationY);
858 mPrivateLayout.setAlpha(contentAlpha);
859 mPrivateLayout.setTranslationY(translationY);
860 if (mChildrenContainer != null) {
861 mChildrenContainer.setAlpha(contentAlpha);
862 mChildrenContainer.setTranslationY(translationY);
863 // TODO: handle children fade out better
864 }
865 }
866 }
867
868 private void updateIconVisibilities() {
869 if (!isChildInGroup()) {
870 mPublicLayout.setIconsVisible(mIconsVisible);
871 mPrivateLayout.setIconsVisible(mIconsVisible);
872 if (mChildrenContainer != null) {
873 mChildrenContainer.setIconsVisible(mIconsVisible);
874 }
875 }
876 }
877
Chris Wren78403d72014-07-28 10:23:24 +0100878 public interface ExpansionLogger {
879 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
880 }
Selim Cinek1685e632014-04-08 02:27:49 +0200881
Chris Wren51c75102013-07-16 20:49:17 -0400882 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
883 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700884 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -0800885 initDimens();
886 }
887
888 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800889 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
890 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
891 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
892 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -0800893 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800894 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Mady Mellorb0a82462016-04-30 17:31:02 -0700895 mIncreasedPaddingBetweenElements = getResources()
896 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700897 mIconTransformContentShift = getResources().getDimensionPixelSize(
898 R.dimen.notification_icon_transform_content_shift);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800899 }
900
901 /**
902 * @param dimenId the dimen to look up
903 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
904 */
905 private int getFontScaledHeight(int dimenId) {
906 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
907 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
908 getResources().getDisplayMetrics().density);
909 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -0400910 }
911
Christoph Studera7fe6312014-06-27 19:32:44 +0200912 /**
913 * Resets this view so it can be re-used for an updated notification.
914 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200915 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200916 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200917 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +0100918 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +0200919 mExpandable = false;
920 mHasUserChangedExpansion = false;
921 mUserLocked = false;
922 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200923 mSensitive = false;
924 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200925 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700926 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -0800927 mPublicLayout.reset();
928 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +0200929 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -0800930 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +0200931 logExpansionEvent(false, wasExpanded);
932 }
933
934 public void resetHeight() {
Selim Cinek31094df2014-08-14 19:28:15 +0200935 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200936 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200937 }
938
Jorim Jaggi251957d2014-04-09 04:24:09 +0200939 @Override
940 protected void onFinishInflate() {
941 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200942 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800943 mPublicLayout.setContainingNotification(this);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200944 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800945 mPrivateLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800946 mPrivateLayout.setContainingNotification(this);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800947 mPublicLayout.setExpandClickListener(mExpandClickListener);
Mady Mellor4b80b102016-01-22 08:03:58 -0800948 mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
949 mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
950 @Override
951 public void onInflate(ViewStub stub, View inflated) {
952 mSettingsIconRow = (NotificationSettingsIconRow) inflated;
953 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700954 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800955 }
956 });
Selim Cinekab29aeb2015-02-20 18:18:32 +0100957 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
958 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200959 @Override
960 public void onInflate(ViewStub stub, View inflated) {
961 mGuts = (NotificationGuts) inflated;
962 mGuts.setClipTopAmount(getClipTopAmount());
963 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100964 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200965 }
966 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100967 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
968 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
969
970 @Override
971 public void onInflate(ViewStub stub, View inflated) {
972 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -0700973 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -0700974 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -0800975 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +0100976 }
977 });
Selim Cinek863834b2014-05-20 04:20:25 +0200978 mVetoButton = findViewById(R.id.veto);
Selim Cinek9e624e72016-07-20 13:46:49 -0700979 mVetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
980 mVetoButton.setContentDescription(mContext.getString(
981 R.string.accessibility_remove_notification));
Mady Mellor4b80b102016-01-22 08:03:58 -0800982
983 // Add the views that we translate to reveal the gear
984 mTranslateableViews = new ArrayList<View>();
985 for (int i = 0; i < getChildCount(); i++) {
986 mTranslateableViews.add(getChildAt(i));
987 }
988 // Remove views that don't translate
989 mTranslateableViews.remove(mVetoButton);
990 mTranslateableViews.remove(mSettingsIconRowStub);
991 mTranslateableViews.remove(mChildrenContainerStub);
992 mTranslateableViews.remove(mGutsStub);
993 }
994
Selim Cinek9e624e72016-07-20 13:46:49 -0700995 public View getVetoButton() {
996 return mVetoButton;
997 }
998
Mady Mellor4b80b102016-01-22 08:03:58 -0800999 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001000 if (mTranslateAnim != null) {
1001 mTranslateAnim.cancel();
1002 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001003 if (mTranslateableViews != null) {
1004 for (int i = 0; i < mTranslateableViews.size(); i++) {
1005 mTranslateableViews.get(i).setTranslationX(0);
1006 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001007 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001008 invalidateOutline();
Mady Mellor4b80b102016-01-22 08:03:58 -08001009 if (mSettingsIconRow != null) {
1010 mSettingsIconRow.resetState();
1011 }
1012 }
1013
1014 public void animateTranslateNotification(final float leftTarget) {
1015 if (mTranslateAnim != null) {
1016 mTranslateAnim.cancel();
1017 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001018 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001019 if (mTranslateAnim != null) {
1020 mTranslateAnim.start();
1021 }
1022 }
1023
1024 @Override
1025 public void setTranslation(float translationX) {
1026 if (areGutsExposed()) {
1027 // Don't translate if guts are showing.
1028 return;
1029 }
1030 // Translate the group of views
1031 for (int i = 0; i < mTranslateableViews.size(); i++) {
1032 if (mTranslateableViews.get(i) != null) {
1033 mTranslateableViews.get(i).setTranslationX(translationX);
1034 }
1035 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001036 invalidateOutline();
Mady Mellor34958fa2016-02-23 09:52:17 -08001037 if (mSettingsIconRow != null) {
1038 mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
1039 }
1040 }
1041
1042 @Override
1043 public float getTranslation() {
1044 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1045 // All of the views in the list should have same translation, just use first one.
1046 return mTranslateableViews.get(0).getTranslationX();
1047 }
1048 return 0;
1049 }
1050
1051 public Animator getTranslateViewAnimator(final float leftTarget,
1052 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001053 if (mTranslateAnim != null) {
1054 mTranslateAnim.cancel();
1055 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001056 if (areGutsExposed()) {
1057 // No translation if guts are exposed.
1058 return null;
1059 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001060 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1061 leftTarget);
1062 if (listener != null) {
1063 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001064 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001065 translateAnim.addListener(new AnimatorListenerAdapter() {
1066 boolean cancelled = false;
1067
1068 @Override
1069 public void onAnimationCancel(Animator anim) {
1070 cancelled = true;
1071 }
1072
1073 @Override
1074 public void onAnimationEnd(Animator anim) {
1075 if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
1076 mSettingsIconRow.resetState();
1077 mTranslateAnim = null;
1078 }
1079 }
1080 });
1081 mTranslateAnim = translateAnim;
1082 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001083 }
1084
1085 public float getSpaceForGear() {
1086 if (mSettingsIconRow != null) {
1087 return mSettingsIconRow.getSpaceForGear();
1088 }
1089 return 0;
1090 }
1091
1092 public NotificationSettingsIconRow getSettingsRow() {
1093 if (mSettingsIconRow == null) {
1094 mSettingsIconRowStub.inflate();
1095 }
1096 return mSettingsIconRow;
1097 }
1098
Selim Cinekab29aeb2015-02-20 18:18:32 +01001099 public void inflateGuts() {
1100 if (mGuts == null) {
1101 mGutsStub.inflate();
1102 }
1103 }
1104
Selim Cinekda42d652015-12-04 15:51:16 -08001105 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001106 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1107 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001108 if (mChildrenContainer != null) {
1109 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1110 : INVISIBLE);
Mady Mellorb0a82462016-04-30 17:31:02 -07001111 mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
1112 ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001113 : INVISIBLE);
1114 }
Selim Cinekda42d652015-12-04 15:51:16 -08001115 // The limits might have changed if the view suddenly became a group or vice versa
1116 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001117 }
1118
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001119 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001120 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1121 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001122 // Add a record for the entire layout since its content is somehow small.
1123 // The event comes from a leaf view that is interacted with.
1124 AccessibilityEvent record = AccessibilityEvent.obtain();
1125 onInitializeAccessibilityEvent(record);
1126 dispatchPopulateAccessibilityEvent(record);
1127 event.appendRecord(record);
1128 return true;
1129 }
1130 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001131 }
Chris Wren51c75102013-07-16 20:49:17 -04001132
John Spurlocke15452b2014-08-21 09:44:39 -04001133 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001134 public void setDark(boolean dark, boolean fade, long delay) {
1135 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001136 final NotificationContentView showing = getShowingLayout();
1137 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001138 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001139 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001140 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001141 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001142 }
John Spurlocke15452b2014-08-21 09:44:39 -04001143 }
1144
Chris Wren51c75102013-07-16 20:49:17 -04001145 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001146 if (mIsSummaryWithChildren && !mShowingPublic) {
1147 return !mChildrenExpanded;
1148 }
Chris Wren51c75102013-07-16 20:49:17 -04001149 return mExpandable;
1150 }
1151
1152 public void setExpandable(boolean expandable) {
1153 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001154 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001155 }
1156
Selim Cinek4ffd6362015-12-29 15:12:23 +01001157 @Override
1158 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001159 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1160 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001161 }
1162
Selim Cinek1685e632014-04-08 02:27:49 +02001163 /**
1164 * @return whether the user has changed the expansion state
1165 */
1166 public boolean hasUserChangedExpansion() {
1167 return mHasUserChangedExpansion;
1168 }
1169
Chris Wren51c75102013-07-16 20:49:17 -04001170 public boolean isUserExpanded() {
1171 return mUserExpanded;
1172 }
1173
Selim Cinek1685e632014-04-08 02:27:49 +02001174 /**
1175 * Set this notification to be expanded by the user
1176 *
1177 * @param userExpanded whether the user wants this notification to be expanded
1178 */
Chris Wren51c75102013-07-16 20:49:17 -04001179 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001180 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1181 }
1182
1183 /**
1184 * Set this notification to be expanded by the user
1185 *
1186 * @param userExpanded whether the user wants this notification to be expanded
1187 * @param allowChildExpansion whether a call to this method allows expanding children
1188 */
1189 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001190 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -07001191 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
Chris Wren698b1702016-05-23 11:16:32 -04001192 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001193 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Chris Wren698b1702016-05-23 11:16:32 -04001194 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001195 return;
1196 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001197 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001198 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001199 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001200 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001201 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001202 }
1203
Selim Cinekccd14fb2014-08-12 18:53:24 +02001204 public void resetUserExpansion() {
1205 mHasUserChangedExpansion = false;
1206 mUserExpanded = false;
1207 }
1208
Chris Wren51c75102013-07-16 20:49:17 -04001209 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001210 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001211 }
1212
1213 public void setUserLocked(boolean userLocked) {
1214 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001215 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001216 if (mIsSummaryWithChildren) {
1217 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek7baaa9e2016-07-21 17:21:09 -07001218 if (userLocked || !isGroupExpanded()) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001219 updateBackgroundForGroupState();
1220 }
Selim Cinek42357e02016-02-24 18:48:01 -08001221 }
Chris Wren51c75102013-07-16 20:49:17 -04001222 }
1223
Selim Cinek1685e632014-04-08 02:27:49 +02001224 /**
1225 * @return has the system set this notification to be expanded
1226 */
1227 public boolean isSystemExpanded() {
1228 return mIsSystemExpanded;
1229 }
1230
1231 /**
1232 * Set this notification to be expanded by the system.
1233 *
1234 * @param expand whether the system wants this notification to be expanded.
1235 */
1236 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001237 if (expand != mIsSystemExpanded) {
1238 final boolean wasExpanded = isExpanded();
1239 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001240 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001241 logExpansionEvent(false, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001242 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001243 mChildrenContainer.updateGroupOverflow();
1244 }
Selim Cinek31094df2014-08-14 19:28:15 +02001245 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001246 }
1247
1248 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001249 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001250 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001251 public void setOnKeyguard(boolean onKeyguard) {
1252 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001253 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001254 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001255 logExpansionEvent(false, wasExpanded);
1256 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001257 if (mIsSummaryWithChildren) {
1258 mChildrenContainer.updateGroupOverflow();
1259 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001260 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001261 }
1262 }
Selim Cinek1685e632014-04-08 02:27:49 +02001263 }
1264
1265 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001266 * @return Can the underlying notification be cleared? This can be different from whether the
1267 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1268 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001269 */
1270 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001271 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1272 return false;
1273 }
1274 if (mIsSummaryWithChildren) {
1275 List<ExpandableNotificationRow> notificationChildren =
1276 mChildrenContainer.getNotificationChildren();
1277 for (int i = 0; i < notificationChildren.size(); i++) {
1278 ExpandableNotificationRow child = notificationChildren.get(i);
1279 if (!child.isClearable()) {
1280 return false;
1281 }
1282 }
1283 }
1284 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001285 }
1286
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001287 @Override
1288 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001289 if (isUserLocked()) {
1290 return getActualHeight();
1291 }
Selim Cinekd84a5932015-12-15 11:45:36 -08001292 if (mGuts != null && mGuts.areGutsExposed()) {
1293 return mGuts.getHeight();
1294 } else if ((isChildInGroup() && !isGroupExpanded())) {
1295 return mPrivateLayout.getMinHeight();
1296 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1297 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001298 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001299 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek73cf02a2016-06-17 13:08:00 -07001300 } else if (mIsHeadsUp || mHeadsupDisappearRunning) {
1301 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001302 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1303 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001304 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001305 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001306 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001307 }
Selim Cinek31aada42015-12-18 17:51:15 -08001308 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001309 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001310 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001311 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001312 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001313 }
Selim Cinek1685e632014-04-08 02:27:49 +02001314
Mady Mellorb0a82462016-04-30 17:31:02 -07001315 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001316 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001317 }
1318
Selim Cinek263398f2015-10-21 17:40:23 -07001319 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001320 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001321 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1322 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
1323 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
1324 mEntry.notification);
Selim Cinek263398f2015-10-21 17:40:23 -07001325 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001326 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001327 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001328 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001329 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001330 }
1331
Mady Mellorb0a82462016-04-30 17:31:02 -07001332 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001333 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001334 mChildrenContainer.updateChildrenHeaderAppearance();
1335 }
1336 }
1337
Selim Cinek1685e632014-04-08 02:27:49 +02001338 /**
1339 * Check whether the view state is currently expanded. This is given by the system in {@link
1340 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1341 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1342 * view can differ from this state, if layout params are modified from outside.
1343 *
1344 * @return whether the view state is currently expanded.
1345 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001346 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001347 return isExpanded(false /* allowOnKeyguard */);
1348 }
1349
1350 public boolean isExpanded(boolean allowOnKeyguard) {
1351 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001352 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1353 || isUserExpanded());
1354 }
1355
1356 private boolean isSystemChildExpanded() {
1357 return mIsSystemChildExpanded;
1358 }
1359
1360 public void setSystemChildExpanded(boolean expanded) {
1361 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001362 }
1363
1364 @Override
1365 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1366 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001367 updateMaxHeights();
Mady Mellora6edc872016-04-26 11:01:03 -07001368 if (mSettingsIconRow != null) {
1369 mSettingsIconRow.updateVerticalLocation();
1370 }
Selim Cinek1685e632014-04-08 02:27:49 +02001371 }
1372
Selim Cinek8d490d42015-04-10 00:05:50 -07001373 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001374 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001375 View expandedChild = mPrivateLayout.getExpandedChild();
1376 if (expandedChild == null) {
1377 expandedChild = mPrivateLayout.getContractedChild();
1378 }
1379 mMaxExpandHeight = expandedChild.getHeight();
1380 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001381 if (headsUpChild == null) {
1382 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001383 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001384 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001385 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001386 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001387 }
1388 }
1389
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001390 @Override
1391 public void notifyHeightChanged(boolean needsAnimation) {
1392 super.notifyHeightChanged(needsAnimation);
1393 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1394 }
1395
Selim Cinek3c76d502016-02-19 15:16:33 -08001396 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001397 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001398 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001399 }
1400
1401 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001402 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001403 if (mIsSummaryWithChildren) {
1404 List<ExpandableNotificationRow> notificationChildren =
1405 mChildrenContainer.getNotificationChildren();
1406 for (int i = 0; i < notificationChildren.size(); i++) {
1407 ExpandableNotificationRow child = notificationChildren.get(i);
1408 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1409 }
1410 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001411 }
1412
1413 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1414 long duration) {
1415 boolean oldShowingPublic = mShowingPublic;
1416 mShowingPublic = mSensitive && hideSensitive;
1417 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1418 return;
1419 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001420
1421 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001422 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001423
Jorim Jaggiae441282014-08-01 02:45:18 +02001424 if (!animated) {
1425 mPublicLayout.animate().cancel();
1426 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001427 if (mChildrenContainer != null) {
1428 mChildrenContainer.animate().cancel();
1429 mChildrenContainer.setAlpha(1f);
1430 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001431 mPublicLayout.setAlpha(1f);
1432 mPrivateLayout.setAlpha(1f);
1433 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001434 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001435 } else {
1436 animateShowingPublic(delay, duration);
1437 }
Selim Cinekc3179332016-03-04 14:44:56 -08001438 NotificationContentView showingLayout = getShowingLayout();
1439 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001440 mPrivateLayout.updateExpandButtons(isExpandable());
Jorim Jaggiae441282014-08-01 02:45:18 +02001441 mShowingPublicInitialized = true;
1442 }
1443
1444 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001445 View[] privateViews = mIsSummaryWithChildren
1446 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001447 : new View[] {mPrivateLayout};
1448 View[] publicViews = new View[] {mPublicLayout};
1449 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1450 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1451 for (final View hiddenView : hiddenChildren) {
1452 hiddenView.setVisibility(View.VISIBLE);
1453 hiddenView.animate().cancel();
1454 hiddenView.animate()
1455 .alpha(0f)
1456 .setStartDelay(delay)
1457 .setDuration(duration)
1458 .withEndAction(new Runnable() {
1459 @Override
1460 public void run() {
1461 hiddenView.setVisibility(View.INVISIBLE);
1462 }
1463 });
1464 }
1465 for (View showView : shownChildren) {
1466 showView.setVisibility(View.VISIBLE);
1467 showView.setAlpha(0f);
1468 showView.animate().cancel();
1469 showView.animate()
1470 .alpha(1f)
1471 .setStartDelay(delay)
1472 .setDuration(duration);
1473 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001474 }
1475
Selim Cinek3776fe02016-02-04 13:32:43 -08001476 public boolean mustStayOnScreen() {
1477 return mIsHeadsUp;
1478 }
1479
Selim Cinek9e624e72016-07-20 13:46:49 -07001480 /**
1481 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1482 * otherwise some state might not be updated. To request about the general clearability
1483 * see {@link #isClearable()}.
1484 */
1485 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001486 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001487 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001488
Ricky Waicd35def2016-05-03 11:07:07 +01001489 public void makeActionsVisibile() {
1490 setUserExpanded(true, true);
1491 if (isChildInGroup()) {
1492 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1493 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001494 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001495 }
1496
Selim Cinekb5605e52015-02-20 18:21:41 +01001497 public void setChildrenExpanded(boolean expanded, boolean animate) {
1498 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001499 if (mChildrenContainer != null) {
1500 mChildrenContainer.setChildrenExpanded(expanded);
1501 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001502 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001503 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001504 }
1505
Selim Cinekb5605e52015-02-20 18:21:41 +01001506 public static void applyTint(View v, int color) {
1507 int alpha;
1508 if (color != 0) {
1509 alpha = COLORED_DIVIDER_ALPHA;
1510 } else {
1511 color = 0xff000000;
1512 alpha = DEFAULT_DIVIDER_ALPHA;
1513 }
1514 if (v.getBackground() instanceof ColorDrawable) {
1515 ColorDrawable background = (ColorDrawable) v.getBackground();
1516 background.mutate();
1517 background.setColor(color);
1518 background.setAlpha(alpha);
1519 }
1520 }
1521
Selim Cinek1685e632014-04-08 02:27:49 +02001522 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001523 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001524 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001525
Mady Mellor34958fa2016-02-23 09:52:17 -08001526 public boolean areGutsExposed() {
1527 return (mGuts != null && mGuts.areGutsExposed());
1528 }
1529
Jorim Jaggibe565df2014-04-28 17:51:23 +02001530 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001531 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001532 NotificationContentView showingLayout = getShowingLayout();
1533 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001534 }
1535
1536 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001537 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001538 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001539 return mChildrenContainer;
1540 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001541 return getShowingLayout();
1542 }
1543
1544 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001545 protected void onAppearAnimationFinished(boolean wasAppearing) {
1546 super.onAppearAnimationFinished(wasAppearing);
1547 if (wasAppearing) {
1548 // During the animation the visible view might have changed, so let's make sure all
1549 // alphas are reset
1550 if (mChildrenContainer != null) {
1551 mChildrenContainer.setAlpha(1.0f);
1552 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1553 }
1554 mPrivateLayout.setAlpha(1.0f);
1555 mPrivateLayout.setLayerType(LAYER_TYPE_NONE, null);
1556 mPublicLayout.setAlpha(1.0f);
1557 mPublicLayout.setLayerType(LAYER_TYPE_NONE, null);
1558 }
1559 }
1560
1561 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001562 public int getExtraBottomPadding() {
1563 if (mIsSummaryWithChildren && isGroupExpanded()) {
1564 return mIncreasedPaddingBetweenElements;
1565 }
1566 return 0;
1567 }
1568
1569 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001570 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001571 super.setActualHeight(height, notifyListeners);
Mady Mellorb53bc272016-02-11 18:28:23 -08001572 if (mGuts != null && mGuts.areGutsExposed()) {
1573 mGuts.setActualHeight(height);
1574 return;
1575 }
Selim Cinekeef84282015-10-30 16:28:00 -07001576 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +01001577 mPrivateLayout.setContentHeight(contentHeight);
1578 mPublicLayout.setContentHeight(contentHeight);
Selim Cinek42357e02016-02-24 18:48:01 -08001579 if (mIsSummaryWithChildren) {
1580 mChildrenContainer.setActualHeight(height);
1581 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001582 if (mGuts != null) {
1583 mGuts.setActualHeight(height);
1584 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001585 }
1586
1587 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001588 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001589 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001590 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001591 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001592 NotificationContentView showingLayout = getShowingLayout();
1593 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001594 }
1595
1596 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001597 public int getMinHeight() {
Selim Cinek31aada42015-12-18 17:51:15 -08001598 if (mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
1599 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1600 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001601 return mChildrenContainer.getMinHeight();
Selim Cinek31aada42015-12-18 17:51:15 -08001602 } else if (mIsHeadsUp) {
1603 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001604 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001605 NotificationContentView showingLayout = getShowingLayout();
1606 return showingLayout.getMinHeight();
1607 }
1608
1609 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001610 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001611 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001612 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001613 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001614 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001615 }
1616
1617 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001618 public void setClipTopAmount(int clipTopAmount) {
1619 super.setClipTopAmount(clipTopAmount);
1620 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001621 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001622 if (mGuts != null) {
1623 mGuts.setClipTopAmount(clipTopAmount);
1624 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001625 }
1626
Selim Cineka686b2c2016-10-26 13:58:27 -07001627 @Override
1628 public void setClipBottomAmount(int clipBottomAmount) {
1629 super.setClipBottomAmount(clipBottomAmount);
1630 mPrivateLayout.setClipBottomAmount(clipBottomAmount);
1631 mPublicLayout.setClipBottomAmount(clipBottomAmount);
1632 if (mGuts != null) {
1633 mGuts.setClipBottomAmount(clipBottomAmount);
1634 }
1635 }
1636
Selim Cinek31094df2014-08-14 19:28:15 +02001637 public boolean isMaxExpandHeightInitialized() {
1638 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001639 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001640
Selim Cinek42357e02016-02-24 18:48:01 -08001641 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001642 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1643 }
Chris Wren78403d72014-07-28 10:23:24 +01001644
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001645 @Override
1646 public void setShowingLegacyBackground(boolean showing) {
1647 super.setShowingLegacyBackground(showing);
1648 mPrivateLayout.setShowingLegacyBackground(showing);
1649 mPublicLayout.setShowingLegacyBackground(showing);
1650 }
1651
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001652 @Override
1653 protected void updateBackgroundTint() {
1654 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001655 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001656 if (mIsSummaryWithChildren) {
1657 List<ExpandableNotificationRow> notificationChildren =
1658 mChildrenContainer.getNotificationChildren();
1659 for (int i = 0; i < notificationChildren.size(); i++) {
1660 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001661 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001662 }
1663 }
1664 }
1665
Mady Mellorb0a82462016-04-30 17:31:02 -07001666 /**
1667 * Called when a group has finished animating from collapsed or expanded state.
1668 */
1669 public void onFinishedExpansionChange() {
1670 mGroupExpansionChanging = false;
1671 updateBackgroundForGroupState();
1672 }
1673
1674 /**
1675 * Updates the parent and children backgrounds in a group based on the expansion state.
1676 */
1677 public void updateBackgroundForGroupState() {
1678 if (mIsSummaryWithChildren) {
1679 // Only when the group has finished expanding do we hide its background.
1680 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1681 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1682 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1683 for (int i = 0; i < children.size(); i++) {
1684 children.get(i).updateBackgroundForGroupState();
1685 }
1686 } else if (isChildInGroup()) {
1687 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
1688 // Only show a background if the group is expanded OR if it is expanding / collapsing
1689 // and has a custom background color
1690 final boolean showBackground = isGroupExpanded()
1691 || ((mNotificationParent.isGroupExpansionChanging()
1692 || mNotificationParent.isUserLocked()) && childColor != 0);
1693 mShowNoBackground = !showBackground;
1694 } else {
1695 // Only children or parents ever need no background.
1696 mShowNoBackground = false;
1697 }
1698 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001699 updateBackground();
1700 }
1701
Adrian Roos4a579672016-05-24 16:54:37 -07001702 public int getPositionOfChild(ExpandableNotificationRow childRow) {
1703 if (mIsSummaryWithChildren) {
1704 return mChildrenContainer.getPositionInLinearLayout(childRow);
1705 }
1706 return 0;
1707 }
1708
Chris Wren78403d72014-07-28 10:23:24 +01001709 public void setExpansionLogger(ExpansionLogger logger, String key) {
1710 mLogger = logger;
1711 mLoggingKey = key;
1712 }
1713
Chris Wren6abeeb92016-05-26 14:44:38 -04001714 public void onExpandedByGesture(boolean userExpanded) {
1715 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
1716 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
1717 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
1718 }
1719 MetricsLogger.action(mContext, event, userExpanded);
1720 }
1721
Selim Cinek6183d122016-01-14 18:48:41 -08001722 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001723 public float getIncreasedPaddingAmount() {
1724 if (mIsSummaryWithChildren) {
1725 if (isGroupExpanded()) {
1726 return 1.0f;
1727 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001728 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001729 }
1730 }
1731 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001732 }
1733
1734 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001735 protected boolean disallowSingleClick(MotionEvent event) {
1736 float x = event.getX();
1737 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001738 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001739 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001740 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001741 }
1742 return super.disallowSingleClick(event);
1743 }
1744
Chris Wren78403d72014-07-28 10:23:24 +01001745 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04001746 boolean nowExpanded = isExpanded();
1747 if (mIsSummaryWithChildren) {
1748 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
1749 }
Chris Wren78403d72014-07-28 10:23:24 +01001750 if (wasExpanded != nowExpanded && mLogger != null) {
1751 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1752 }
1753 }
Selim Cinek570981d2015-12-01 11:37:01 -08001754
Selim Cineke9bad242016-06-15 11:46:37 -07001755 @Override
1756 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1757 super.onInitializeAccessibilityNodeInfoInternal(info);
1758 if (canViewBeDismissed()) {
1759 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
1760 }
1761 }
1762
1763 @Override
1764 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
1765 if (super.performAccessibilityActionInternal(action, arguments)) {
1766 return true;
1767 }
1768 switch (action) {
1769 case AccessibilityNodeInfo.ACTION_DISMISS:
1770 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
1771 true /* fromAccessibility */);
1772 return true;
1773 }
1774 return false;
1775 }
1776
1777 public boolean shouldRefocusOnDismiss() {
1778 return mRefocusOnDismiss || isAccessibilityFocused();
1779 }
1780
Selim Cinek570981d2015-12-01 11:37:01 -08001781 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001782 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001783 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001784
1785 @Override
1786 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
1787 return new NotificationViewState(stackScrollState);
1788 }
1789
Selim Cinekd127d792016-11-01 19:11:41 -07001790 @Override
1791 public boolean isAboveShelf() {
1792 return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
1793 }
1794
1795 public void setAboveShelf(boolean aboveShelf) {
1796 mAboveShelf = aboveShelf;
1797 }
1798
Selim Cinek0cfbef42016-11-09 19:06:36 -08001799 public class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08001800
1801 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07001802
Selim Cinekbbcebde2016-11-09 18:28:20 -08001803
1804 private NotificationViewState(StackScrollState stackScrollState) {
1805 mOverallState = stackScrollState;
1806 }
1807
1808 @Override
1809 public void applyToView(View view) {
1810 super.applyToView(view);
1811 if (view instanceof ExpandableNotificationRow) {
1812 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
1813 if (this.isBottomClipped) {
1814 row.setClipToActualHeight(true);
1815 }
1816 row.applyChildrenState(mOverallState);
1817 }
1818 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08001819
1820 @Override
1821 protected void onYTranslationAnimationFinished() {
1822 super.onYTranslationAnimationFinished();
1823 if (mHeadsupDisappearRunning) {
Selim Cinekcafa87f2016-10-26 17:00:17 -07001824 setHeadsUpAnimatingAway(false);
Selim Cinek0cfbef42016-11-09 19:06:36 -08001825 }
1826 }
1827
1828 @Override
1829 public void animateTo(View child, AnimationProperties properties) {
1830 super.animateTo(child, properties);
1831 if (child instanceof ExpandableNotificationRow) {
1832 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
1833 row.startChildAnimation(mOverallState, properties);
1834 }
1835 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001836 }
Chris Wren51c75102013-07-16 20:49:17 -04001837}