blob: 3c00c4e3eae917217b4804e5992b16a1927c3a69 [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;
Mady Mellorb0a82462016-04-30 17:31:02 -0700195
196 public boolean isGroupExpansionChanging() {
197 if (isChildInGroup()) {
198 return mNotificationParent.isGroupExpansionChanging();
199 }
200 return mGroupExpansionChanging;
201 }
202
203 public void setGroupExpansionChanging(boolean changing) {
204 mGroupExpansionChanging = changing;
205 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700206
Adrian Roos599be342016-06-13 14:54:39 -0700207 @Override
208 public void setActualHeightAnimating(boolean animating) {
209 if (mPrivateLayout != null) {
210 mPrivateLayout.setContentHeightAnimating(animating);
211 }
212 }
213
Selim Cinek8d490d42015-04-10 00:05:50 -0700214 public NotificationContentView getPrivateLayout() {
215 return mPrivateLayout;
216 }
217
218 public NotificationContentView getPublicLayout() {
219 return mPublicLayout;
220 }
221
Selim Cinekcab4a602014-09-03 14:47:57 +0200222 public void setIconAnimationRunning(boolean running) {
223 setIconAnimationRunning(running, mPublicLayout);
224 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800225 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700226 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800227 List<ExpandableNotificationRow> notificationChildren =
228 mChildrenContainer.getNotificationChildren();
229 for (int i = 0; i < notificationChildren.size(); i++) {
230 ExpandableNotificationRow child = notificationChildren.get(i);
231 child.setIconAnimationRunning(running);
232 }
233 }
234 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200235 }
236
237 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
238 if (layout != null) {
239 View contractedChild = layout.getContractedChild();
240 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700241 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200242 setIconAnimationRunningForChild(running, contractedChild);
243 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700244 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200245 }
246 }
247
248 private void setIconAnimationRunningForChild(boolean running, View child) {
249 if (child != null) {
250 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
251 setIconRunning(icon, running);
252 ImageView rightIcon = (ImageView) child.findViewById(
253 com.android.internal.R.id.right_icon);
254 setIconRunning(rightIcon, running);
255 }
256 }
257
258 private void setIconRunning(ImageView imageView, boolean running) {
259 if (imageView != null) {
260 Drawable drawable = imageView.getDrawable();
261 if (drawable instanceof AnimationDrawable) {
262 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
263 if (running) {
264 animationDrawable.start();
265 } else {
266 animationDrawable.stop();
267 }
268 } else if (drawable instanceof AnimatedVectorDrawable) {
269 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
270 if (running) {
271 animationDrawable.start();
272 } else {
273 animationDrawable.stop();
274 }
275 }
276 }
277 }
278
Selim Cinekda42d652015-12-04 15:51:16 -0800279 public void onNotificationUpdated(NotificationData.Entry entry) {
280 mEntry = entry;
281 mStatusBarNotification = entry.notification;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800282 mPrivateLayout.onNotificationUpdated(entry);
283 mPublicLayout.onNotificationUpdated(entry);
Selim Cinek757d8792016-01-28 16:21:08 -0800284 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700285 updateNotificationColor();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800286 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700287 mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
Selim Cinekc897bd32016-03-18 17:32:31 -0700288 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800289 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800290 if (mIconAnimationRunning) {
291 setIconAnimationRunning(true);
292 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800293 if (mNotificationParent != null) {
294 mNotificationParent.updateChildrenHeaderAppearance();
295 }
Selim Cinek263398f2015-10-21 17:40:23 -0700296 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800297 // The public layouts expand button is always visible
298 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800299 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700300 updateIconVisibilities();
Selim Cinekda42d652015-12-04 15:51:16 -0800301 }
302
303 private void updateLimits() {
Selim Cineka1744872016-03-11 15:36:06 -0800304 updateLimitsForView(mPrivateLayout);
305 updateLimitsForView(mPublicLayout);
306 }
307
308 private void updateLimitsForView(NotificationContentView layout) {
309 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800310 != com.android.internal.R.id.status_bar_latest_event_content;
311 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
312 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
313 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800314 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
315 layout.getHeadsUpChild().getId()
316 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek77019c72015-12-09 10:18:02 -0800317 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
318 : mMaxHeadsUpHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800319 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200320 }
321
322 public StatusBarNotification getStatusBarNotification() {
323 return mStatusBarNotification;
324 }
325
Selim Cinek281c2022016-10-13 19:14:43 -0700326 public NotificationData.Entry getEntry() {
327 return mEntry;
328 }
329
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700330 public boolean isHeadsUp() {
331 return mIsHeadsUp;
332 }
333
Selim Cinek1a521f32014-11-03 17:39:29 +0100334 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700335 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100336 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700337 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700338 if (mIsSummaryWithChildren) {
339 // The overflow might change since we allow more lines as HUN.
340 mChildrenContainer.updateGroupOverflow();
341 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700342 if (intrinsicBefore != getIntrinsicHeight()) {
343 notifyHeightChanged(false /* needsAnimation */);
344 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100345 }
346
Selim Cinekb5605e52015-02-20 18:21:41 +0100347 public void setGroupManager(NotificationGroupManager groupManager) {
348 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700349 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100350 }
351
Adrian Roosb88b1a12015-12-09 18:51:05 -0800352 public void setRemoteInputController(RemoteInputController r) {
353 mPrivateLayout.setRemoteInputController(r);
354 }
355
Mady Mellor3fd273e2016-03-15 21:08:14 -0700356 public void setAppName(String appName) {
357 mAppName = appName;
358 if (mSettingsIconRow != null) {
359 mSettingsIconRow.setAppName(mAppName);
360 }
361 }
362
Selim Cinekb5605e52015-02-20 18:21:41 +0100363 public void addChildNotification(ExpandableNotificationRow row) {
364 addChildNotification(row, -1);
365 }
366
367 /**
368 * Add a child notification to this view.
369 *
370 * @param row the row to add
371 * @param childIndex the index to add it at, if -1 it will be added at the end
372 */
373 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
374 if (mChildrenContainer == null) {
375 mChildrenContainerStub.inflate();
376 }
377 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700378 onChildrenCountChanged();
379 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100380 }
381
382 public void removeChildNotification(ExpandableNotificationRow row) {
383 if (mChildrenContainer != null) {
384 mChildrenContainer.removeNotification(row);
385 }
Selim Cinek263398f2015-10-21 17:40:23 -0700386 onChildrenCountChanged();
387 row.setIsChildInGroup(false, null);
388 }
389
390 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700391 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700392 }
393
Selim Cinek388df6d2015-10-22 13:25:11 -0700394 public ExpandableNotificationRow getNotificationParent() {
395 return mNotificationParent;
396 }
397
Selim Cinek263398f2015-10-21 17:40:23 -0700398 /**
399 * @param isChildInGroup Is this notification now in a group
400 * @param parent the new parent notification
401 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700402 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
403 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
404 mNotificationParent = childInGroup ? parent : null;
405 mPrivateLayout.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400406 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700407 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700408 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700409 if (mNotificationParent != null) {
410 mNotificationParent.updateBackgroundForGroupState();
411 }
Selim Cinek34d93b02015-10-22 12:30:38 -0700412 }
413
414 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800415 public boolean onTouchEvent(MotionEvent event) {
416 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
417 || !isChildInGroup() || isGroupExpanded()) {
418 return super.onTouchEvent(event);
419 } else {
420 return false;
421 }
422 }
423
424 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800425 protected boolean handleSlideBack() {
426 if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
427 animateTranslateNotification(0 /* targetLeft */);
428 return true;
429 }
430 return false;
431 }
432
433 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700434 protected boolean shouldHideBackground() {
435 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700436 }
437
438 @Override
439 public boolean isSummaryWithChildren() {
440 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100441 }
442
443 @Override
444 public boolean areChildrenExpanded() {
445 return mChildrenExpanded;
446 }
447
448 public List<ExpandableNotificationRow> getNotificationChildren() {
449 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
450 }
451
Selim Cinekeef84282015-10-30 16:28:00 -0700452 public int getNumberOfNotificationChildren() {
453 if (mChildrenContainer == null) {
454 return 0;
455 }
456 return mChildrenContainer.getNotificationChildren().size();
457 }
458
Selim Cinekb5605e52015-02-20 18:21:41 +0100459 /**
460 * Apply the order given in the list to the children.
461 *
462 * @param childOrder the new list order
463 * @return whether the list order has changed
464 */
465 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
466 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
467 }
468
469 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700470 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800471 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100472 mChildrenContainer.getState(resultState, parentState);
473 }
474 }
475
476 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700477 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100478 mChildrenContainer.applyState(state);
479 }
480 }
481
482 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700483 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100484 mChildrenContainer.prepareExpansionChanged(state);
485 }
486 }
487
Selim Cinek0cfbef42016-11-09 19:06:36 -0800488 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700489 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800490 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100491 }
492 }
493
494 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800495 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100496 return this;
497 } else {
498 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
499 return view == null ? this : view;
500 }
501 }
502
Selim Cinekab29aeb2015-02-20 18:18:32 +0100503 public NotificationGuts getGuts() {
504 return mGuts;
505 }
506
Selim Cinek684a4422015-04-15 16:18:39 -0700507 /**
508 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
509 * the notification will be rendered on top of the screen.
510 *
511 * @param pinned whether it is pinned
512 */
513 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700514 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700515 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700516 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700517 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700518 }
Selim Cinek31aada42015-12-18 17:51:15 -0800519 if (pinned) {
520 setIconAnimationRunning(true);
521 mExpandedWhenPinned = false;
522 } else if (mExpandedWhenPinned) {
523 setUserExpanded(true);
524 }
Selim Cinek98713a42015-09-21 15:47:20 +0200525 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700526 }
527
Selim Cinek684a4422015-04-15 16:18:39 -0700528 public boolean isPinned() {
529 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700530 }
531
Selim Cinek31aada42015-12-18 17:51:15 -0800532 /**
533 * @param atLeastMinHeight should the value returned be at least the minimum height.
534 * Used to avoid cyclic calls
535 * @return the height of the heads up notification when pinned
536 */
537 public int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800538 if (mIsSummaryWithChildren) {
539 return mChildrenContainer.getIntrinsicHeight();
540 }
Selim Cinek31aada42015-12-18 17:51:15 -0800541 if(mExpandedWhenPinned) {
542 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
543 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700544 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800545 } else {
546 return mHeadsUpHeight;
547 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700548 }
549
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700550 /**
551 * Mark whether this notification was just clicked, i.e. the user has just clicked this
552 * notification in this frame.
553 */
554 public void setJustClicked(boolean justClicked) {
555 mJustClicked = justClicked;
556 }
557
558 /**
559 * @return true if this notification has been clicked in this frame, false otherwise
560 */
561 public boolean wasJustClicked() {
562 return mJustClicked;
563 }
564
Selim Cinek98713a42015-09-21 15:47:20 +0200565 public void setChronometerRunning(boolean running) {
566 mLastChronometerRunning = running;
567 setChronometerRunning(running, mPrivateLayout);
568 setChronometerRunning(running, mPublicLayout);
569 if (mChildrenContainer != null) {
570 List<ExpandableNotificationRow> notificationChildren =
571 mChildrenContainer.getNotificationChildren();
572 for (int i = 0; i < notificationChildren.size(); i++) {
573 ExpandableNotificationRow child = notificationChildren.get(i);
574 child.setChronometerRunning(running);
575 }
576 }
577 }
578
579 private void setChronometerRunning(boolean running, NotificationContentView layout) {
580 if (layout != null) {
581 running = running || isPinned();
582 View contractedChild = layout.getContractedChild();
583 View expandedChild = layout.getExpandedChild();
584 View headsUpChild = layout.getHeadsUpChild();
585 setChronometerRunningForChild(running, contractedChild);
586 setChronometerRunningForChild(running, expandedChild);
587 setChronometerRunningForChild(running, headsUpChild);
588 }
589 }
590
591 private void setChronometerRunningForChild(boolean running, View child) {
592 if (child != null) {
593 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
594 if (chronometer instanceof Chronometer) {
595 ((Chronometer) chronometer).setStarted(running);
596 }
597 }
598 }
599
Selim Cinekea4bef72015-12-02 15:51:10 -0800600 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700601 if (mIsSummaryWithChildren) {
602 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700603 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800604 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700605 }
606
Selim Cinek34eda5e2016-02-18 17:10:43 -0800607 private NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700608 if (mIsSummaryWithChildren && !mShowingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700609 return mChildrenContainer.getHeaderView();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800610 }
611 return getShowingLayout().getVisibleNotificationHeader();
612 }
613
Selim Cinek570981d2015-12-01 11:37:01 -0800614 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
615 mOnExpandClickListener = onExpandClickListener;
616 }
617
Selim Cinekddf1b392016-05-27 16:33:10 -0700618 @Override
619 public void setOnClickListener(@Nullable OnClickListener l) {
620 super.setOnClickListener(l);
621 mOnClickListener = l;
622 updateClickAndFocus();
623 }
624
625 private void updateClickAndFocus() {
626 boolean normalChild = !isChildInGroup() || isGroupExpanded();
627 boolean clickable = mOnClickListener != null && normalChild;
628 if (isFocusable() != normalChild) {
629 setFocusable(normalChild);
630 }
631 if (isClickable() != clickable) {
632 setClickable(clickable);
633 }
634 }
635
Selim Cinek31aada42015-12-18 17:51:15 -0800636 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
637 mHeadsUpManager = headsUpManager;
638 }
639
Selim Cinek01af3342016-02-09 19:25:31 -0800640 public void reInflateViews() {
641 initDimens();
642 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800643 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700644 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800645 }
646 }
647 if (mGuts != null) {
648 View oldGuts = mGuts;
649 int index = indexOfChild(oldGuts);
650 removeView(oldGuts);
651 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
652 R.layout.notification_guts, this, false);
653 mGuts.setVisibility(oldGuts.getVisibility());
654 addView(mGuts, index);
655 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800656 if (mSettingsIconRow != null) {
657 View oldSettings = mSettingsIconRow;
658 int settingsIndex = indexOfChild(oldSettings);
659 removeView(oldSettings);
660 mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
661 R.layout.notification_settings_icon_row, this, false);
662 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700663 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800664 mSettingsIconRow.setVisibility(oldSettings.getVisibility());
665 addView(mSettingsIconRow, settingsIndex);
666
667 }
Selim Cinekde33a4a2016-02-11 16:43:41 -0800668 mPrivateLayout.reInflateViews();
669 mPublicLayout.reInflateViews();
Selim Cinek01af3342016-02-09 19:25:31 -0800670 }
671
Selim Cinekc3179332016-03-04 14:44:56 -0800672 public void setContentBackground(int customBackgroundColor, boolean animate,
673 NotificationContentView notificationContentView) {
674 if (getShowingLayout() == notificationContentView) {
675 setTintColor(customBackgroundColor, animate);
676 }
677 }
678
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700679 public void closeRemoteInput() {
680 mPrivateLayout.closeRemoteInput();
681 mPublicLayout.closeRemoteInput();
682 }
683
Selim Cinekc897bd32016-03-18 17:32:31 -0700684 /**
685 * Set by how much the single line view should be indented.
686 */
687 public void setSingleLineWidthIndention(int indention) {
688 mPrivateLayout.setSingleLineWidthIndention(indention);
689 }
690
691 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700692 return mNotificationColor;
693 }
694
695 private void updateNotificationColor() {
696 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
697 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700698 }
699
700 public HybridNotificationView getSingleLineView() {
701 return mPrivateLayout.getSingleLineView();
702 }
703
Selim Cinekf07d0622016-03-21 19:52:52 -0700704 public boolean isOnKeyguard() {
705 return mOnKeyguard;
706 }
707
Selim Cinekc1e389d2016-04-07 11:02:57 -0700708 public void removeAllChildren() {
709 List<ExpandableNotificationRow> notificationChildren
710 = mChildrenContainer.getNotificationChildren();
711 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
712 for (int i = 0; i < clonedList.size(); i++) {
713 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700714 if (row.keepInParent()) {
715 continue;
716 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700717 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700718 row.setIsChildInGroup(false, null);
719 }
720 onChildrenCountChanged();
721 }
722
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700723 public void setForceUnlocked(boolean forceUnlocked) {
724 mForceUnlocked = forceUnlocked;
725 if (mIsSummaryWithChildren) {
726 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
727 for (ExpandableNotificationRow child : notificationChildren) {
728 child.setForceUnlocked(forceUnlocked);
729 }
730 }
731 }
732
Selim Cineke9bad242016-06-15 11:46:37 -0700733 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700734 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700735 mGroupParentWhenDismissed = mNotificationParent;
736 mRefocusOnDismiss = fromAccessibility;
737 mChildAfterViewWhenDismissed = null;
738 if (isChildInGroup()) {
739 List<ExpandableNotificationRow> notificationChildren =
740 mNotificationParent.getNotificationChildren();
741 int i = notificationChildren.indexOf(this);
742 if (i != -1 && i < notificationChildren.size() - 1) {
743 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
744 }
745 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700746 }
747
748 public boolean isDismissed() {
749 return mDismissed;
750 }
751
752 public boolean keepInParent() {
753 return mKeepInParent;
754 }
755
756 public void setKeepInParent(boolean keepInParent) {
757 mKeepInParent = keepInParent;
758 }
759
760 public boolean isRemoved() {
761 return mRemoved;
762 }
763
Adrian Roosd009ab12016-05-20 17:58:53 -0700764 public void setRemoved() {
765 mRemoved = true;
766
767 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700768 }
769
Selim Cinekd1395642016-04-28 12:22:42 -0700770 public NotificationChildrenContainer getChildrenContainer() {
771 return mChildrenContainer;
772 }
773
Selim Cinekcafa87f2016-10-26 17:00:17 -0700774 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
775 mHeadsupDisappearRunning = headsUpAnimatingAway;
776 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
777 }
778
779 /**
780 * @return if the view was just heads upped and is now animating away. During such a time the
781 * layout needs to be kept consistent
782 */
783 public boolean isHeadsUpAnimatingAway() {
784 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700785 }
786
Selim Cineke9bad242016-06-15 11:46:37 -0700787 public View getChildAfterViewWhenDismissed() {
788 return mChildAfterViewWhenDismissed;
789 }
790
791 public View getGroupParentWhenDismissed() {
792 return mGroupParentWhenDismissed;
793 }
794
Selim Cinek9e624e72016-07-20 13:46:49 -0700795 public void performDismiss() {
796 mVetoButton.performClick();
797 }
798
799 public void setOnDismissListener(OnClickListener listener) {
800 mVetoButton.setOnClickListener(listener);
801 }
802
Selim Cinek281c2022016-10-13 19:14:43 -0700803 public View getNotificationIcon() {
804 NotificationHeaderView notificationHeader = getNotificationHeader();
805 if (notificationHeader != null) {
806 return notificationHeader.getIcon();
807 }
808 return null;
809 }
810
811 /**
812 * @return whether the notification is currently showing a view with an icon.
813 */
814 public boolean isShowingIcon() {
815 if (mIsSummaryWithChildren) {
816 return true;
817 }
818 NotificationContentView showingLayout = getShowingLayout();
819 NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
820 return notificationHeader != null;
821 }
822
Selim Cinek0242fbb2016-10-19 13:38:32 -0700823 /**
824 * Set how much this notification is transformed into an icon.
825 *
826 * @param iconTransformationAmount A value from 0 to 1 indicating how much we are transformed
827 * to an icon
828 */
829 public void setIconTransformationAmount(float iconTransformationAmount) {
830 if (mIconTransformationAmount != iconTransformationAmount) {
831 mIconTransformationAmount = iconTransformationAmount;
832 updateContentFadeOut();
833 boolean iconsVisible = mIconTransformationAmount == 0.0f;
834 if (iconsVisible != mIconsVisible) {
835 mIconsVisible = iconsVisible;
836 updateIconVisibilities();
837 }
838 }
839 }
840
841 private void updateContentFadeOut() {
842 if (!isChildInGroup()) {
843 float contentAlpha = 1.0f - mIconTransformationAmount;
844 contentAlpha = Math.max((contentAlpha - 0.5f) / 0.5f, 0.0f);
845 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
846 mPublicLayout.setAlpha(contentAlpha);
847 float translationY = - mIconTransformationAmount * mIconTransformContentShift;
848 mPublicLayout.setTranslationY(translationY);
849 mPrivateLayout.setAlpha(contentAlpha);
850 mPrivateLayout.setTranslationY(translationY);
851 if (mChildrenContainer != null) {
852 mChildrenContainer.setAlpha(contentAlpha);
853 mChildrenContainer.setTranslationY(translationY);
854 // TODO: handle children fade out better
855 }
856 }
857 }
858
859 private void updateIconVisibilities() {
860 if (!isChildInGroup()) {
861 mPublicLayout.setIconsVisible(mIconsVisible);
862 mPrivateLayout.setIconsVisible(mIconsVisible);
863 if (mChildrenContainer != null) {
864 mChildrenContainer.setIconsVisible(mIconsVisible);
865 }
866 }
867 }
868
Chris Wren78403d72014-07-28 10:23:24 +0100869 public interface ExpansionLogger {
870 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
871 }
Selim Cinek1685e632014-04-08 02:27:49 +0200872
Chris Wren51c75102013-07-16 20:49:17 -0400873 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
874 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700875 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -0800876 initDimens();
877 }
878
879 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800880 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
881 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
882 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
883 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -0800884 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800885 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Mady Mellorb0a82462016-04-30 17:31:02 -0700886 mIncreasedPaddingBetweenElements = getResources()
887 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700888 mIconTransformContentShift = getResources().getDimensionPixelSize(
889 R.dimen.notification_icon_transform_content_shift);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800890 }
891
892 /**
893 * @param dimenId the dimen to look up
894 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
895 */
896 private int getFontScaledHeight(int dimenId) {
897 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
898 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
899 getResources().getDisplayMetrics().density);
900 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -0400901 }
902
Christoph Studera7fe6312014-06-27 19:32:44 +0200903 /**
904 * Resets this view so it can be re-used for an updated notification.
905 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200906 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200907 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200908 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +0100909 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +0200910 mExpandable = false;
911 mHasUserChangedExpansion = false;
912 mUserLocked = false;
913 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200914 mSensitive = false;
915 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200916 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700917 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -0800918 mPublicLayout.reset();
919 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +0200920 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -0800921 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +0200922 logExpansionEvent(false, wasExpanded);
923 }
924
925 public void resetHeight() {
Selim Cinek31094df2014-08-14 19:28:15 +0200926 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200927 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200928 }
929
Jorim Jaggi251957d2014-04-09 04:24:09 +0200930 @Override
931 protected void onFinishInflate() {
932 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200933 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800934 mPublicLayout.setContainingNotification(this);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200935 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800936 mPrivateLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800937 mPrivateLayout.setContainingNotification(this);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800938 mPublicLayout.setExpandClickListener(mExpandClickListener);
Mady Mellor4b80b102016-01-22 08:03:58 -0800939 mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
940 mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
941 @Override
942 public void onInflate(ViewStub stub, View inflated) {
943 mSettingsIconRow = (NotificationSettingsIconRow) inflated;
944 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700945 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800946 }
947 });
Selim Cinekab29aeb2015-02-20 18:18:32 +0100948 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
949 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200950 @Override
951 public void onInflate(ViewStub stub, View inflated) {
952 mGuts = (NotificationGuts) inflated;
953 mGuts.setClipTopAmount(getClipTopAmount());
954 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100955 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200956 }
957 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100958 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
959 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
960
961 @Override
962 public void onInflate(ViewStub stub, View inflated) {
963 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -0700964 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -0700965 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -0800966 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +0100967 }
968 });
Selim Cinek863834b2014-05-20 04:20:25 +0200969 mVetoButton = findViewById(R.id.veto);
Selim Cinek9e624e72016-07-20 13:46:49 -0700970 mVetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
971 mVetoButton.setContentDescription(mContext.getString(
972 R.string.accessibility_remove_notification));
Mady Mellor4b80b102016-01-22 08:03:58 -0800973
974 // Add the views that we translate to reveal the gear
975 mTranslateableViews = new ArrayList<View>();
976 for (int i = 0; i < getChildCount(); i++) {
977 mTranslateableViews.add(getChildAt(i));
978 }
979 // Remove views that don't translate
980 mTranslateableViews.remove(mVetoButton);
981 mTranslateableViews.remove(mSettingsIconRowStub);
982 mTranslateableViews.remove(mChildrenContainerStub);
983 mTranslateableViews.remove(mGutsStub);
984 }
985
Selim Cinek9e624e72016-07-20 13:46:49 -0700986 public View getVetoButton() {
987 return mVetoButton;
988 }
989
Mady Mellor4b80b102016-01-22 08:03:58 -0800990 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -0700991 if (mTranslateAnim != null) {
992 mTranslateAnim.cancel();
993 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800994 if (mTranslateableViews != null) {
995 for (int i = 0; i < mTranslateableViews.size(); i++) {
996 mTranslateableViews.get(i).setTranslationX(0);
997 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800998 }
Mady Mellorb0a82462016-04-30 17:31:02 -0700999 invalidateOutline();
Mady Mellor4b80b102016-01-22 08:03:58 -08001000 if (mSettingsIconRow != null) {
1001 mSettingsIconRow.resetState();
1002 }
1003 }
1004
1005 public void animateTranslateNotification(final float leftTarget) {
1006 if (mTranslateAnim != null) {
1007 mTranslateAnim.cancel();
1008 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001009 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001010 if (mTranslateAnim != null) {
1011 mTranslateAnim.start();
1012 }
1013 }
1014
1015 @Override
1016 public void setTranslation(float translationX) {
1017 if (areGutsExposed()) {
1018 // Don't translate if guts are showing.
1019 return;
1020 }
1021 // Translate the group of views
1022 for (int i = 0; i < mTranslateableViews.size(); i++) {
1023 if (mTranslateableViews.get(i) != null) {
1024 mTranslateableViews.get(i).setTranslationX(translationX);
1025 }
1026 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001027 invalidateOutline();
Mady Mellor34958fa2016-02-23 09:52:17 -08001028 if (mSettingsIconRow != null) {
1029 mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
1030 }
1031 }
1032
1033 @Override
1034 public float getTranslation() {
1035 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1036 // All of the views in the list should have same translation, just use first one.
1037 return mTranslateableViews.get(0).getTranslationX();
1038 }
1039 return 0;
1040 }
1041
1042 public Animator getTranslateViewAnimator(final float leftTarget,
1043 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001044 if (mTranslateAnim != null) {
1045 mTranslateAnim.cancel();
1046 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001047 if (areGutsExposed()) {
1048 // No translation if guts are exposed.
1049 return null;
1050 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001051 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1052 leftTarget);
1053 if (listener != null) {
1054 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001055 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001056 translateAnim.addListener(new AnimatorListenerAdapter() {
1057 boolean cancelled = false;
1058
1059 @Override
1060 public void onAnimationCancel(Animator anim) {
1061 cancelled = true;
1062 }
1063
1064 @Override
1065 public void onAnimationEnd(Animator anim) {
1066 if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
1067 mSettingsIconRow.resetState();
1068 mTranslateAnim = null;
1069 }
1070 }
1071 });
1072 mTranslateAnim = translateAnim;
1073 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001074 }
1075
1076 public float getSpaceForGear() {
1077 if (mSettingsIconRow != null) {
1078 return mSettingsIconRow.getSpaceForGear();
1079 }
1080 return 0;
1081 }
1082
1083 public NotificationSettingsIconRow getSettingsRow() {
1084 if (mSettingsIconRow == null) {
1085 mSettingsIconRowStub.inflate();
1086 }
1087 return mSettingsIconRow;
1088 }
1089
Selim Cinekab29aeb2015-02-20 18:18:32 +01001090 public void inflateGuts() {
1091 if (mGuts == null) {
1092 mGutsStub.inflate();
1093 }
1094 }
1095
Selim Cinekda42d652015-12-04 15:51:16 -08001096 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001097 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1098 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001099 if (mChildrenContainer != null) {
1100 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1101 : INVISIBLE);
Mady Mellorb0a82462016-04-30 17:31:02 -07001102 mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
1103 ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001104 : INVISIBLE);
1105 }
Selim Cinekda42d652015-12-04 15:51:16 -08001106 // The limits might have changed if the view suddenly became a group or vice versa
1107 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001108 }
1109
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001110 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001111 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1112 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001113 // Add a record for the entire layout since its content is somehow small.
1114 // The event comes from a leaf view that is interacted with.
1115 AccessibilityEvent record = AccessibilityEvent.obtain();
1116 onInitializeAccessibilityEvent(record);
1117 dispatchPopulateAccessibilityEvent(record);
1118 event.appendRecord(record);
1119 return true;
1120 }
1121 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001122 }
Chris Wren51c75102013-07-16 20:49:17 -04001123
John Spurlocke15452b2014-08-21 09:44:39 -04001124 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001125 public void setDark(boolean dark, boolean fade, long delay) {
1126 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001127 final NotificationContentView showing = getShowingLayout();
1128 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001129 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001130 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001131 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001132 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001133 }
John Spurlocke15452b2014-08-21 09:44:39 -04001134 }
1135
Chris Wren51c75102013-07-16 20:49:17 -04001136 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001137 if (mIsSummaryWithChildren && !mShowingPublic) {
1138 return !mChildrenExpanded;
1139 }
Chris Wren51c75102013-07-16 20:49:17 -04001140 return mExpandable;
1141 }
1142
1143 public void setExpandable(boolean expandable) {
1144 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001145 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001146 }
1147
Selim Cinek4ffd6362015-12-29 15:12:23 +01001148 @Override
1149 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001150 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1151 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001152 }
1153
Selim Cinek1685e632014-04-08 02:27:49 +02001154 /**
1155 * @return whether the user has changed the expansion state
1156 */
1157 public boolean hasUserChangedExpansion() {
1158 return mHasUserChangedExpansion;
1159 }
1160
Chris Wren51c75102013-07-16 20:49:17 -04001161 public boolean isUserExpanded() {
1162 return mUserExpanded;
1163 }
1164
Selim Cinek1685e632014-04-08 02:27:49 +02001165 /**
1166 * Set this notification to be expanded by the user
1167 *
1168 * @param userExpanded whether the user wants this notification to be expanded
1169 */
Chris Wren51c75102013-07-16 20:49:17 -04001170 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001171 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1172 }
1173
1174 /**
1175 * Set this notification to be expanded by the user
1176 *
1177 * @param userExpanded whether the user wants this notification to be expanded
1178 * @param allowChildExpansion whether a call to this method allows expanding children
1179 */
1180 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001181 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -07001182 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
Chris Wren698b1702016-05-23 11:16:32 -04001183 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001184 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Chris Wren698b1702016-05-23 11:16:32 -04001185 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001186 return;
1187 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001188 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001189 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001190 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001191 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001192 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001193 }
1194
Selim Cinekccd14fb2014-08-12 18:53:24 +02001195 public void resetUserExpansion() {
1196 mHasUserChangedExpansion = false;
1197 mUserExpanded = false;
1198 }
1199
Chris Wren51c75102013-07-16 20:49:17 -04001200 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001201 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001202 }
1203
1204 public void setUserLocked(boolean userLocked) {
1205 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001206 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001207 if (mIsSummaryWithChildren) {
1208 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek7baaa9e2016-07-21 17:21:09 -07001209 if (userLocked || !isGroupExpanded()) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001210 updateBackgroundForGroupState();
1211 }
Selim Cinek42357e02016-02-24 18:48:01 -08001212 }
Chris Wren51c75102013-07-16 20:49:17 -04001213 }
1214
Selim Cinek1685e632014-04-08 02:27:49 +02001215 /**
1216 * @return has the system set this notification to be expanded
1217 */
1218 public boolean isSystemExpanded() {
1219 return mIsSystemExpanded;
1220 }
1221
1222 /**
1223 * Set this notification to be expanded by the system.
1224 *
1225 * @param expand whether the system wants this notification to be expanded.
1226 */
1227 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001228 if (expand != mIsSystemExpanded) {
1229 final boolean wasExpanded = isExpanded();
1230 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001231 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001232 logExpansionEvent(false, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001233 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001234 mChildrenContainer.updateGroupOverflow();
1235 }
Selim Cinek31094df2014-08-14 19:28:15 +02001236 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001237 }
1238
1239 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001240 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001241 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001242 public void setOnKeyguard(boolean onKeyguard) {
1243 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001244 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001245 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001246 logExpansionEvent(false, wasExpanded);
1247 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001248 if (mIsSummaryWithChildren) {
1249 mChildrenContainer.updateGroupOverflow();
1250 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001251 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001252 }
1253 }
Selim Cinek1685e632014-04-08 02:27:49 +02001254 }
1255
1256 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001257 * @return Can the underlying notification be cleared? This can be different from whether the
1258 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1259 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001260 */
1261 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001262 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1263 return false;
1264 }
1265 if (mIsSummaryWithChildren) {
1266 List<ExpandableNotificationRow> notificationChildren =
1267 mChildrenContainer.getNotificationChildren();
1268 for (int i = 0; i < notificationChildren.size(); i++) {
1269 ExpandableNotificationRow child = notificationChildren.get(i);
1270 if (!child.isClearable()) {
1271 return false;
1272 }
1273 }
1274 }
1275 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001276 }
1277
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001278 @Override
1279 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001280 if (isUserLocked()) {
1281 return getActualHeight();
1282 }
Selim Cinekd84a5932015-12-15 11:45:36 -08001283 if (mGuts != null && mGuts.areGutsExposed()) {
1284 return mGuts.getHeight();
1285 } else if ((isChildInGroup() && !isGroupExpanded())) {
1286 return mPrivateLayout.getMinHeight();
1287 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1288 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001289 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001290 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek73cf02a2016-06-17 13:08:00 -07001291 } else if (mIsHeadsUp || mHeadsupDisappearRunning) {
1292 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001293 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1294 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001295 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001296 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001297 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001298 }
Selim Cinek31aada42015-12-18 17:51:15 -08001299 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001300 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001301 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001302 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001303 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001304 }
Selim Cinek1685e632014-04-08 02:27:49 +02001305
Mady Mellorb0a82462016-04-30 17:31:02 -07001306 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001307 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001308 }
1309
Selim Cinek263398f2015-10-21 17:40:23 -07001310 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001311 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001312 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1313 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
1314 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
1315 mEntry.notification);
Selim Cinek263398f2015-10-21 17:40:23 -07001316 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001317 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001318 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001319 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001320 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001321 }
1322
Mady Mellorb0a82462016-04-30 17:31:02 -07001323 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001324 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001325 mChildrenContainer.updateChildrenHeaderAppearance();
1326 }
1327 }
1328
Selim Cinek1685e632014-04-08 02:27:49 +02001329 /**
1330 * Check whether the view state is currently expanded. This is given by the system in {@link
1331 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1332 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1333 * view can differ from this state, if layout params are modified from outside.
1334 *
1335 * @return whether the view state is currently expanded.
1336 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001337 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001338 return isExpanded(false /* allowOnKeyguard */);
1339 }
1340
1341 public boolean isExpanded(boolean allowOnKeyguard) {
1342 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001343 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1344 || isUserExpanded());
1345 }
1346
1347 private boolean isSystemChildExpanded() {
1348 return mIsSystemChildExpanded;
1349 }
1350
1351 public void setSystemChildExpanded(boolean expanded) {
1352 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001353 }
1354
1355 @Override
1356 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1357 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001358 updateMaxHeights();
Mady Mellora6edc872016-04-26 11:01:03 -07001359 if (mSettingsIconRow != null) {
1360 mSettingsIconRow.updateVerticalLocation();
1361 }
Selim Cinek1685e632014-04-08 02:27:49 +02001362 }
1363
Selim Cinek8d490d42015-04-10 00:05:50 -07001364 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001365 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001366 View expandedChild = mPrivateLayout.getExpandedChild();
1367 if (expandedChild == null) {
1368 expandedChild = mPrivateLayout.getContractedChild();
1369 }
1370 mMaxExpandHeight = expandedChild.getHeight();
1371 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001372 if (headsUpChild == null) {
1373 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001374 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001375 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001376 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001377 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001378 }
1379 }
1380
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001381 @Override
1382 public void notifyHeightChanged(boolean needsAnimation) {
1383 super.notifyHeightChanged(needsAnimation);
1384 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1385 }
1386
Selim Cinek3c76d502016-02-19 15:16:33 -08001387 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001388 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001389 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001390 }
1391
1392 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001393 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001394 if (mIsSummaryWithChildren) {
1395 List<ExpandableNotificationRow> notificationChildren =
1396 mChildrenContainer.getNotificationChildren();
1397 for (int i = 0; i < notificationChildren.size(); i++) {
1398 ExpandableNotificationRow child = notificationChildren.get(i);
1399 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1400 }
1401 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001402 }
1403
1404 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1405 long duration) {
1406 boolean oldShowingPublic = mShowingPublic;
1407 mShowingPublic = mSensitive && hideSensitive;
1408 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1409 return;
1410 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001411
1412 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001413 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001414
Jorim Jaggiae441282014-08-01 02:45:18 +02001415 if (!animated) {
1416 mPublicLayout.animate().cancel();
1417 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001418 if (mChildrenContainer != null) {
1419 mChildrenContainer.animate().cancel();
1420 mChildrenContainer.setAlpha(1f);
1421 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001422 mPublicLayout.setAlpha(1f);
1423 mPrivateLayout.setAlpha(1f);
1424 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001425 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001426 } else {
1427 animateShowingPublic(delay, duration);
1428 }
Selim Cinekc3179332016-03-04 14:44:56 -08001429 NotificationContentView showingLayout = getShowingLayout();
1430 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001431 mPrivateLayout.updateExpandButtons(isExpandable());
Jorim Jaggiae441282014-08-01 02:45:18 +02001432 mShowingPublicInitialized = true;
1433 }
1434
1435 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001436 View[] privateViews = mIsSummaryWithChildren
1437 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001438 : new View[] {mPrivateLayout};
1439 View[] publicViews = new View[] {mPublicLayout};
1440 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1441 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1442 for (final View hiddenView : hiddenChildren) {
1443 hiddenView.setVisibility(View.VISIBLE);
1444 hiddenView.animate().cancel();
1445 hiddenView.animate()
1446 .alpha(0f)
1447 .setStartDelay(delay)
1448 .setDuration(duration)
1449 .withEndAction(new Runnable() {
1450 @Override
1451 public void run() {
1452 hiddenView.setVisibility(View.INVISIBLE);
1453 }
1454 });
1455 }
1456 for (View showView : shownChildren) {
1457 showView.setVisibility(View.VISIBLE);
1458 showView.setAlpha(0f);
1459 showView.animate().cancel();
1460 showView.animate()
1461 .alpha(1f)
1462 .setStartDelay(delay)
1463 .setDuration(duration);
1464 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001465 }
1466
Selim Cinek3776fe02016-02-04 13:32:43 -08001467 public boolean mustStayOnScreen() {
1468 return mIsHeadsUp;
1469 }
1470
Selim Cinek9e624e72016-07-20 13:46:49 -07001471 /**
1472 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1473 * otherwise some state might not be updated. To request about the general clearability
1474 * see {@link #isClearable()}.
1475 */
1476 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001477 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001478 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001479
Ricky Waicd35def2016-05-03 11:07:07 +01001480 public void makeActionsVisibile() {
1481 setUserExpanded(true, true);
1482 if (isChildInGroup()) {
1483 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1484 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001485 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001486 }
1487
Selim Cinekb5605e52015-02-20 18:21:41 +01001488 public void setChildrenExpanded(boolean expanded, boolean animate) {
1489 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001490 if (mChildrenContainer != null) {
1491 mChildrenContainer.setChildrenExpanded(expanded);
1492 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001493 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001494 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001495 }
1496
Selim Cinekb5605e52015-02-20 18:21:41 +01001497 public static void applyTint(View v, int color) {
1498 int alpha;
1499 if (color != 0) {
1500 alpha = COLORED_DIVIDER_ALPHA;
1501 } else {
1502 color = 0xff000000;
1503 alpha = DEFAULT_DIVIDER_ALPHA;
1504 }
1505 if (v.getBackground() instanceof ColorDrawable) {
1506 ColorDrawable background = (ColorDrawable) v.getBackground();
1507 background.mutate();
1508 background.setColor(color);
1509 background.setAlpha(alpha);
1510 }
1511 }
1512
Selim Cinek1685e632014-04-08 02:27:49 +02001513 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001514 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001515 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001516
Mady Mellor34958fa2016-02-23 09:52:17 -08001517 public boolean areGutsExposed() {
1518 return (mGuts != null && mGuts.areGutsExposed());
1519 }
1520
Jorim Jaggibe565df2014-04-28 17:51:23 +02001521 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001522 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001523 NotificationContentView showingLayout = getShowingLayout();
1524 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001525 }
1526
1527 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001528 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001529 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001530 return mChildrenContainer;
1531 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001532 return getShowingLayout();
1533 }
1534
1535 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001536 protected void onAppearAnimationFinished(boolean wasAppearing) {
1537 super.onAppearAnimationFinished(wasAppearing);
1538 if (wasAppearing) {
1539 // During the animation the visible view might have changed, so let's make sure all
1540 // alphas are reset
1541 if (mChildrenContainer != null) {
1542 mChildrenContainer.setAlpha(1.0f);
1543 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1544 }
1545 mPrivateLayout.setAlpha(1.0f);
1546 mPrivateLayout.setLayerType(LAYER_TYPE_NONE, null);
1547 mPublicLayout.setAlpha(1.0f);
1548 mPublicLayout.setLayerType(LAYER_TYPE_NONE, null);
1549 }
1550 }
1551
1552 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001553 public int getExtraBottomPadding() {
1554 if (mIsSummaryWithChildren && isGroupExpanded()) {
1555 return mIncreasedPaddingBetweenElements;
1556 }
1557 return 0;
1558 }
1559
1560 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001561 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001562 super.setActualHeight(height, notifyListeners);
Mady Mellorb53bc272016-02-11 18:28:23 -08001563 if (mGuts != null && mGuts.areGutsExposed()) {
1564 mGuts.setActualHeight(height);
1565 return;
1566 }
Selim Cinekeef84282015-10-30 16:28:00 -07001567 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +01001568 mPrivateLayout.setContentHeight(contentHeight);
1569 mPublicLayout.setContentHeight(contentHeight);
Selim Cinek42357e02016-02-24 18:48:01 -08001570 if (mIsSummaryWithChildren) {
1571 mChildrenContainer.setActualHeight(height);
1572 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001573 if (mGuts != null) {
1574 mGuts.setActualHeight(height);
1575 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001576 }
1577
1578 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001579 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001580 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001581 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001582 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001583 NotificationContentView showingLayout = getShowingLayout();
1584 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001585 }
1586
1587 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001588 public int getMinHeight() {
Selim Cinek31aada42015-12-18 17:51:15 -08001589 if (mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
1590 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1591 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001592 return mChildrenContainer.getMinHeight();
Selim Cinek31aada42015-12-18 17:51:15 -08001593 } else if (mIsHeadsUp) {
1594 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001595 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001596 NotificationContentView showingLayout = getShowingLayout();
1597 return showingLayout.getMinHeight();
1598 }
1599
1600 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001601 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001602 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001603 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001604 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001605 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001606 }
1607
1608 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001609 public void setClipTopAmount(int clipTopAmount) {
1610 super.setClipTopAmount(clipTopAmount);
1611 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001612 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001613 if (mGuts != null) {
1614 mGuts.setClipTopAmount(clipTopAmount);
1615 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001616 }
1617
Selim Cineka686b2c2016-10-26 13:58:27 -07001618 @Override
1619 public void setClipBottomAmount(int clipBottomAmount) {
1620 super.setClipBottomAmount(clipBottomAmount);
1621 mPrivateLayout.setClipBottomAmount(clipBottomAmount);
1622 mPublicLayout.setClipBottomAmount(clipBottomAmount);
1623 if (mGuts != null) {
1624 mGuts.setClipBottomAmount(clipBottomAmount);
1625 }
1626 }
1627
Selim Cinek31094df2014-08-14 19:28:15 +02001628 public boolean isMaxExpandHeightInitialized() {
1629 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001630 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001631
Selim Cinek42357e02016-02-24 18:48:01 -08001632 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001633 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1634 }
Chris Wren78403d72014-07-28 10:23:24 +01001635
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001636 @Override
1637 public void setShowingLegacyBackground(boolean showing) {
1638 super.setShowingLegacyBackground(showing);
1639 mPrivateLayout.setShowingLegacyBackground(showing);
1640 mPublicLayout.setShowingLegacyBackground(showing);
1641 }
1642
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001643 @Override
1644 protected void updateBackgroundTint() {
1645 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001646 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001647 if (mIsSummaryWithChildren) {
1648 List<ExpandableNotificationRow> notificationChildren =
1649 mChildrenContainer.getNotificationChildren();
1650 for (int i = 0; i < notificationChildren.size(); i++) {
1651 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001652 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001653 }
1654 }
1655 }
1656
Mady Mellorb0a82462016-04-30 17:31:02 -07001657 /**
1658 * Called when a group has finished animating from collapsed or expanded state.
1659 */
1660 public void onFinishedExpansionChange() {
1661 mGroupExpansionChanging = false;
1662 updateBackgroundForGroupState();
1663 }
1664
1665 /**
1666 * Updates the parent and children backgrounds in a group based on the expansion state.
1667 */
1668 public void updateBackgroundForGroupState() {
1669 if (mIsSummaryWithChildren) {
1670 // Only when the group has finished expanding do we hide its background.
1671 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1672 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1673 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1674 for (int i = 0; i < children.size(); i++) {
1675 children.get(i).updateBackgroundForGroupState();
1676 }
1677 } else if (isChildInGroup()) {
1678 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
1679 // Only show a background if the group is expanded OR if it is expanding / collapsing
1680 // and has a custom background color
1681 final boolean showBackground = isGroupExpanded()
1682 || ((mNotificationParent.isGroupExpansionChanging()
1683 || mNotificationParent.isUserLocked()) && childColor != 0);
1684 mShowNoBackground = !showBackground;
1685 } else {
1686 // Only children or parents ever need no background.
1687 mShowNoBackground = false;
1688 }
1689 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001690 updateBackground();
1691 }
1692
Adrian Roos4a579672016-05-24 16:54:37 -07001693 public int getPositionOfChild(ExpandableNotificationRow childRow) {
1694 if (mIsSummaryWithChildren) {
1695 return mChildrenContainer.getPositionInLinearLayout(childRow);
1696 }
1697 return 0;
1698 }
1699
Chris Wren78403d72014-07-28 10:23:24 +01001700 public void setExpansionLogger(ExpansionLogger logger, String key) {
1701 mLogger = logger;
1702 mLoggingKey = key;
1703 }
1704
Chris Wren6abeeb92016-05-26 14:44:38 -04001705 public void onExpandedByGesture(boolean userExpanded) {
1706 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
1707 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
1708 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
1709 }
1710 MetricsLogger.action(mContext, event, userExpanded);
1711 }
1712
Selim Cinek6183d122016-01-14 18:48:41 -08001713 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001714 public float getIncreasedPaddingAmount() {
1715 if (mIsSummaryWithChildren) {
1716 if (isGroupExpanded()) {
1717 return 1.0f;
1718 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001719 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001720 }
1721 }
1722 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001723 }
1724
1725 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001726 protected boolean disallowSingleClick(MotionEvent event) {
1727 float x = event.getX();
1728 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001729 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001730 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001731 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001732 }
1733 return super.disallowSingleClick(event);
1734 }
1735
Chris Wren78403d72014-07-28 10:23:24 +01001736 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04001737 boolean nowExpanded = isExpanded();
1738 if (mIsSummaryWithChildren) {
1739 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
1740 }
Chris Wren78403d72014-07-28 10:23:24 +01001741 if (wasExpanded != nowExpanded && mLogger != null) {
1742 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1743 }
1744 }
Selim Cinek570981d2015-12-01 11:37:01 -08001745
Selim Cineke9bad242016-06-15 11:46:37 -07001746 @Override
1747 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1748 super.onInitializeAccessibilityNodeInfoInternal(info);
1749 if (canViewBeDismissed()) {
1750 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
1751 }
1752 }
1753
1754 @Override
1755 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
1756 if (super.performAccessibilityActionInternal(action, arguments)) {
1757 return true;
1758 }
1759 switch (action) {
1760 case AccessibilityNodeInfo.ACTION_DISMISS:
1761 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
1762 true /* fromAccessibility */);
1763 return true;
1764 }
1765 return false;
1766 }
1767
1768 public boolean shouldRefocusOnDismiss() {
1769 return mRefocusOnDismiss || isAccessibilityFocused();
1770 }
1771
Selim Cinek570981d2015-12-01 11:37:01 -08001772 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001773 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001774 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001775
1776 @Override
1777 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
1778 return new NotificationViewState(stackScrollState);
1779 }
1780
Selim Cinek0cfbef42016-11-09 19:06:36 -08001781 public class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08001782
1783 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07001784
Selim Cinekbbcebde2016-11-09 18:28:20 -08001785
1786 private NotificationViewState(StackScrollState stackScrollState) {
1787 mOverallState = stackScrollState;
1788 }
1789
1790 @Override
1791 public void applyToView(View view) {
1792 super.applyToView(view);
1793 if (view instanceof ExpandableNotificationRow) {
1794 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
1795 if (this.isBottomClipped) {
1796 row.setClipToActualHeight(true);
1797 }
1798 row.applyChildrenState(mOverallState);
1799 }
1800 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08001801
1802 @Override
1803 protected void onYTranslationAnimationFinished() {
1804 super.onYTranslationAnimationFinished();
1805 if (mHeadsupDisappearRunning) {
Selim Cinekcafa87f2016-10-26 17:00:17 -07001806 setHeadsUpAnimatingAway(false);
Selim Cinek0cfbef42016-11-09 19:06:36 -08001807 }
1808 }
1809
1810 @Override
1811 public void animateTo(View child, AnimationProperties properties) {
1812 super.animateTo(child, properties);
1813 if (child instanceof ExpandableNotificationRow) {
1814 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
1815 row.startChildAnimation(mOverallState, properties);
1816 }
1817 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001818 }
Chris Wren51c75102013-07-16 20:49:17 -04001819}