blob: 6e690f8747b4879a4bd7fb9a8d8d0e7f33c06bc0 [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;
Dan Sandlera5e0f412014-01-23 15:11:54 -050048import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070049import com.android.systemui.classifier.FalsingManager;
Selim Cinekc897bd32016-03-18 17:32:31 -070050import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinekb5605e52015-02-20 18:21:41 +010051import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinek31aada42015-12-18 17:51:15 -080052import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010053import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070054import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010055import com.android.systemui.statusbar.stack.StackScrollState;
56import com.android.systemui.statusbar.stack.StackStateAnimator;
Selim Cinekbbcebde2016-11-09 18:28:20 -080057import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010058
Mady Mellor4b80b102016-01-22 08:03:58 -080059import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010060import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050061
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020062public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010063
64 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
65 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Selim Cinek01af3342016-02-09 19:25:31 -080066 private int mNotificationMinHeightLegacy;
67 private int mMaxHeadsUpHeightLegacy;
68 private int mMaxHeadsUpHeight;
69 private int mNotificationMinHeight;
70 private int mNotificationMaxHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -070071 private int mIncreasedPaddingBetweenElements;
Chris Wren51c75102013-07-16 20:49:17 -040072
Selim Cinek1685e632014-04-08 02:27:49 +020073 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040074 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020075 /** Has the user actively changed the expansion state of this row */
76 private boolean mHasUserChangedExpansion;
77 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040078 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -080079
80 /**
81 * Has this notification been expanded while it was pinned
82 */
83 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +020084 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040085 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020086 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050087 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020088 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -080089 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +020090 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -070091 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -040092
Selim Cinek1685e632014-04-08 02:27:49 +020093 /**
94 * Is this notification expanded by the system. The expansion state can be overridden by the
95 * user expansion.
96 */
97 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020098
99 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700100 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200101 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700102 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200103
Mady Mellorb0a82462016-04-30 17:31:02 -0700104 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800105 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200106 private NotificationContentView mPublicLayout;
107 private NotificationContentView mPrivateLayout;
Selim Cinek1685e632014-04-08 02:27:49 +0200108 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700109 private int mHeadsUpHeight;
Selim Cinek863834b2014-05-20 04:20:25 +0200110 private View mVetoButton;
Selim Cinek4bb59342016-04-08 19:29:35 -0700111 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100112 private ExpansionLogger mLogger;
113 private String mLoggingKey;
Mady Mellor4b80b102016-01-22 08:03:58 -0800114 private NotificationSettingsIconRow mSettingsIconRow;
Selim Cinek8d490d42015-04-10 00:05:50 -0700115 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800116 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200117 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700118 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100119 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200120 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100121 private ViewStub mChildrenContainerStub;
122 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100123 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700124 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100125 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor4b80b102016-01-22 08:03:58 -0800126 private ViewStub mSettingsIconRowStub;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100127 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100128 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700129 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700130 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800131 private HeadsUpManager mHeadsUpManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200132
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700133 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800134 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700135 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700136 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800137 private OnExpandClickListener mOnExpandClickListener;
Mady Mellorb0a82462016-04-30 17:31:02 -0700138 private boolean mGroupExpansionChanging;
139
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800140 private OnClickListener mExpandClickListener = new OnClickListener() {
141 @Override
142 public void onClick(View v) {
Selim Cinek624c02db2015-12-14 21:00:02 -0800143 if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700144 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400145 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
146 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
147 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400148 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
149 nowExpanded);
150 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800151 } else {
Selim Cineke9bad242016-06-15 11:46:37 -0700152 if (v.isAccessibilityFocused()) {
153 mPrivateLayout.setFocusOnVisibilityChange();
154 }
Selim Cinek31aada42015-12-18 17:51:15 -0800155 boolean nowExpanded;
156 if (isPinned()) {
157 nowExpanded = !mExpandedWhenPinned;
158 mExpandedWhenPinned = nowExpanded;
159 } else {
160 nowExpanded = !isExpanded();
161 setUserExpanded(nowExpanded);
162 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800163 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800164 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400165 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
166 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800167 }
168 }
169 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700170 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700171 private boolean mDismissed;
172 private boolean mKeepInParent;
173 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700174 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
175 new FloatProperty<ExpandableNotificationRow>("translate") {
176 @Override
177 public void setValue(ExpandableNotificationRow object, float value) {
178 object.setTranslation(value);
179 }
180
181 @Override
182 public Float get(ExpandableNotificationRow object) {
183 return object.getTranslation();
184 }
185 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700186 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700187 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700188 private View mChildAfterViewWhenDismissed;
189 private View mGroupParentWhenDismissed;
190 private boolean mRefocusOnDismiss;
Mady Mellorb0a82462016-04-30 17:31:02 -0700191
192 public boolean isGroupExpansionChanging() {
193 if (isChildInGroup()) {
194 return mNotificationParent.isGroupExpansionChanging();
195 }
196 return mGroupExpansionChanging;
197 }
198
199 public void setGroupExpansionChanging(boolean changing) {
200 mGroupExpansionChanging = changing;
201 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700202
Adrian Roos599be342016-06-13 14:54:39 -0700203 @Override
204 public void setActualHeightAnimating(boolean animating) {
205 if (mPrivateLayout != null) {
206 mPrivateLayout.setContentHeightAnimating(animating);
207 }
208 }
209
Selim Cinek8d490d42015-04-10 00:05:50 -0700210 public NotificationContentView getPrivateLayout() {
211 return mPrivateLayout;
212 }
213
214 public NotificationContentView getPublicLayout() {
215 return mPublicLayout;
216 }
217
Selim Cinekcab4a602014-09-03 14:47:57 +0200218 public void setIconAnimationRunning(boolean running) {
219 setIconAnimationRunning(running, mPublicLayout);
220 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800221 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700222 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800223 List<ExpandableNotificationRow> notificationChildren =
224 mChildrenContainer.getNotificationChildren();
225 for (int i = 0; i < notificationChildren.size(); i++) {
226 ExpandableNotificationRow child = notificationChildren.get(i);
227 child.setIconAnimationRunning(running);
228 }
229 }
230 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200231 }
232
233 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
234 if (layout != null) {
235 View contractedChild = layout.getContractedChild();
236 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700237 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200238 setIconAnimationRunningForChild(running, contractedChild);
239 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700240 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200241 }
242 }
243
244 private void setIconAnimationRunningForChild(boolean running, View child) {
245 if (child != null) {
246 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
247 setIconRunning(icon, running);
248 ImageView rightIcon = (ImageView) child.findViewById(
249 com.android.internal.R.id.right_icon);
250 setIconRunning(rightIcon, running);
251 }
252 }
253
254 private void setIconRunning(ImageView imageView, boolean running) {
255 if (imageView != null) {
256 Drawable drawable = imageView.getDrawable();
257 if (drawable instanceof AnimationDrawable) {
258 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
259 if (running) {
260 animationDrawable.start();
261 } else {
262 animationDrawable.stop();
263 }
264 } else if (drawable instanceof AnimatedVectorDrawable) {
265 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
266 if (running) {
267 animationDrawable.start();
268 } else {
269 animationDrawable.stop();
270 }
271 }
272 }
273 }
274
Selim Cinekda42d652015-12-04 15:51:16 -0800275 public void onNotificationUpdated(NotificationData.Entry entry) {
276 mEntry = entry;
277 mStatusBarNotification = entry.notification;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800278 mPrivateLayout.onNotificationUpdated(entry);
279 mPublicLayout.onNotificationUpdated(entry);
Selim Cinek757d8792016-01-28 16:21:08 -0800280 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700281 updateNotificationColor();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800282 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700283 mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
Selim Cinekc897bd32016-03-18 17:32:31 -0700284 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800285 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800286 if (mIconAnimationRunning) {
287 setIconAnimationRunning(true);
288 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800289 if (mNotificationParent != null) {
290 mNotificationParent.updateChildrenHeaderAppearance();
291 }
Selim Cinek263398f2015-10-21 17:40:23 -0700292 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800293 // The public layouts expand button is always visible
294 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800295 updateLimits();
296 }
297
298 private void updateLimits() {
Selim Cineka1744872016-03-11 15:36:06 -0800299 updateLimitsForView(mPrivateLayout);
300 updateLimitsForView(mPublicLayout);
301 }
302
303 private void updateLimitsForView(NotificationContentView layout) {
304 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800305 != com.android.internal.R.id.status_bar_latest_event_content;
306 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
307 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
308 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800309 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
310 layout.getHeadsUpChild().getId()
311 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek77019c72015-12-09 10:18:02 -0800312 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
313 : mMaxHeadsUpHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800314 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200315 }
316
317 public StatusBarNotification getStatusBarNotification() {
318 return mStatusBarNotification;
319 }
320
Selim Cinek281c2022016-10-13 19:14:43 -0700321 public NotificationData.Entry getEntry() {
322 return mEntry;
323 }
324
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700325 public boolean isHeadsUp() {
326 return mIsHeadsUp;
327 }
328
Selim Cinek1a521f32014-11-03 17:39:29 +0100329 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700330 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100331 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700332 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700333 if (mIsSummaryWithChildren) {
334 // The overflow might change since we allow more lines as HUN.
335 mChildrenContainer.updateGroupOverflow();
336 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700337 if (intrinsicBefore != getIntrinsicHeight()) {
338 notifyHeightChanged(false /* needsAnimation */);
339 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100340 }
341
Selim Cinekb5605e52015-02-20 18:21:41 +0100342 public void setGroupManager(NotificationGroupManager groupManager) {
343 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700344 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100345 }
346
Adrian Roosb88b1a12015-12-09 18:51:05 -0800347 public void setRemoteInputController(RemoteInputController r) {
348 mPrivateLayout.setRemoteInputController(r);
349 }
350
Mady Mellor3fd273e2016-03-15 21:08:14 -0700351 public void setAppName(String appName) {
352 mAppName = appName;
353 if (mSettingsIconRow != null) {
354 mSettingsIconRow.setAppName(mAppName);
355 }
356 }
357
Selim Cinekb5605e52015-02-20 18:21:41 +0100358 public void addChildNotification(ExpandableNotificationRow row) {
359 addChildNotification(row, -1);
360 }
361
362 /**
363 * Add a child notification to this view.
364 *
365 * @param row the row to add
366 * @param childIndex the index to add it at, if -1 it will be added at the end
367 */
368 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
369 if (mChildrenContainer == null) {
370 mChildrenContainerStub.inflate();
371 }
372 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700373 onChildrenCountChanged();
374 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100375 }
376
377 public void removeChildNotification(ExpandableNotificationRow row) {
378 if (mChildrenContainer != null) {
379 mChildrenContainer.removeNotification(row);
380 }
Selim Cinek263398f2015-10-21 17:40:23 -0700381 onChildrenCountChanged();
382 row.setIsChildInGroup(false, null);
383 }
384
385 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700386 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700387 }
388
Selim Cinek388df6d2015-10-22 13:25:11 -0700389 public ExpandableNotificationRow getNotificationParent() {
390 return mNotificationParent;
391 }
392
Selim Cinek263398f2015-10-21 17:40:23 -0700393 /**
394 * @param isChildInGroup Is this notification now in a group
395 * @param parent the new parent notification
396 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700397 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
398 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
399 mNotificationParent = childInGroup ? parent : null;
400 mPrivateLayout.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400401 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700402 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700403 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700404 if (mNotificationParent != null) {
405 mNotificationParent.updateBackgroundForGroupState();
406 }
Selim Cinek34d93b02015-10-22 12:30:38 -0700407 }
408
409 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800410 public boolean onTouchEvent(MotionEvent event) {
411 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
412 || !isChildInGroup() || isGroupExpanded()) {
413 return super.onTouchEvent(event);
414 } else {
415 return false;
416 }
417 }
418
419 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800420 protected boolean handleSlideBack() {
421 if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
422 animateTranslateNotification(0 /* targetLeft */);
423 return true;
424 }
425 return false;
426 }
427
428 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700429 protected boolean shouldHideBackground() {
430 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700431 }
432
433 @Override
434 public boolean isSummaryWithChildren() {
435 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100436 }
437
438 @Override
439 public boolean areChildrenExpanded() {
440 return mChildrenExpanded;
441 }
442
443 public List<ExpandableNotificationRow> getNotificationChildren() {
444 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
445 }
446
Selim Cinekeef84282015-10-30 16:28:00 -0700447 public int getNumberOfNotificationChildren() {
448 if (mChildrenContainer == null) {
449 return 0;
450 }
451 return mChildrenContainer.getNotificationChildren().size();
452 }
453
Selim Cinekb5605e52015-02-20 18:21:41 +0100454 /**
455 * Apply the order given in the list to the children.
456 *
457 * @param childOrder the new list order
458 * @return whether the list order has changed
459 */
460 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
461 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
462 }
463
464 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700465 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800466 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100467 mChildrenContainer.getState(resultState, parentState);
468 }
469 }
470
471 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700472 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100473 mChildrenContainer.applyState(state);
474 }
475 }
476
477 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700478 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100479 mChildrenContainer.prepareExpansionChanged(state);
480 }
481 }
482
483 public void startChildAnimation(StackScrollState finalState,
Selim Cinek99695592016-01-12 17:51:35 -0800484 StackStateAnimator stateAnimator, long delay, long duration) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700485 if (mIsSummaryWithChildren) {
Selim Cinek99695592016-01-12 17:51:35 -0800486 mChildrenContainer.startAnimationToState(finalState, stateAnimator, delay,
Selim Cinekb5605e52015-02-20 18:21:41 +0100487 duration);
488 }
489 }
490
491 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800492 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100493 return this;
494 } else {
495 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
496 return view == null ? this : view;
497 }
498 }
499
Selim Cinekab29aeb2015-02-20 18:18:32 +0100500 public NotificationGuts getGuts() {
501 return mGuts;
502 }
503
Selim Cinek684a4422015-04-15 16:18:39 -0700504 /**
505 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
506 * the notification will be rendered on top of the screen.
507 *
508 * @param pinned whether it is pinned
509 */
510 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700511 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700512 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700513 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700514 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700515 }
Selim Cinek31aada42015-12-18 17:51:15 -0800516 if (pinned) {
517 setIconAnimationRunning(true);
518 mExpandedWhenPinned = false;
519 } else if (mExpandedWhenPinned) {
520 setUserExpanded(true);
521 }
Selim Cinek98713a42015-09-21 15:47:20 +0200522 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700523 }
524
Selim Cinek684a4422015-04-15 16:18:39 -0700525 public boolean isPinned() {
526 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700527 }
528
Selim Cinek31aada42015-12-18 17:51:15 -0800529 /**
530 * @param atLeastMinHeight should the value returned be at least the minimum height.
531 * Used to avoid cyclic calls
532 * @return the height of the heads up notification when pinned
533 */
534 public int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800535 if (mIsSummaryWithChildren) {
536 return mChildrenContainer.getIntrinsicHeight();
537 }
Selim Cinek31aada42015-12-18 17:51:15 -0800538 if(mExpandedWhenPinned) {
539 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
540 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700541 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800542 } else {
543 return mHeadsUpHeight;
544 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700545 }
546
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700547 /**
548 * Mark whether this notification was just clicked, i.e. the user has just clicked this
549 * notification in this frame.
550 */
551 public void setJustClicked(boolean justClicked) {
552 mJustClicked = justClicked;
553 }
554
555 /**
556 * @return true if this notification has been clicked in this frame, false otherwise
557 */
558 public boolean wasJustClicked() {
559 return mJustClicked;
560 }
561
Selim Cinek98713a42015-09-21 15:47:20 +0200562 public void setChronometerRunning(boolean running) {
563 mLastChronometerRunning = running;
564 setChronometerRunning(running, mPrivateLayout);
565 setChronometerRunning(running, mPublicLayout);
566 if (mChildrenContainer != null) {
567 List<ExpandableNotificationRow> notificationChildren =
568 mChildrenContainer.getNotificationChildren();
569 for (int i = 0; i < notificationChildren.size(); i++) {
570 ExpandableNotificationRow child = notificationChildren.get(i);
571 child.setChronometerRunning(running);
572 }
573 }
574 }
575
576 private void setChronometerRunning(boolean running, NotificationContentView layout) {
577 if (layout != null) {
578 running = running || isPinned();
579 View contractedChild = layout.getContractedChild();
580 View expandedChild = layout.getExpandedChild();
581 View headsUpChild = layout.getHeadsUpChild();
582 setChronometerRunningForChild(running, contractedChild);
583 setChronometerRunningForChild(running, expandedChild);
584 setChronometerRunningForChild(running, headsUpChild);
585 }
586 }
587
588 private void setChronometerRunningForChild(boolean running, View child) {
589 if (child != null) {
590 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
591 if (chronometer instanceof Chronometer) {
592 ((Chronometer) chronometer).setStarted(running);
593 }
594 }
595 }
596
Selim Cinekea4bef72015-12-02 15:51:10 -0800597 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700598 if (mIsSummaryWithChildren) {
599 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700600 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800601 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700602 }
603
Selim Cinek34eda5e2016-02-18 17:10:43 -0800604 private NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700605 if (mIsSummaryWithChildren && !mShowingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700606 return mChildrenContainer.getHeaderView();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800607 }
608 return getShowingLayout().getVisibleNotificationHeader();
609 }
610
Selim Cinek570981d2015-12-01 11:37:01 -0800611 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
612 mOnExpandClickListener = onExpandClickListener;
613 }
614
Selim Cinekddf1b392016-05-27 16:33:10 -0700615 @Override
616 public void setOnClickListener(@Nullable OnClickListener l) {
617 super.setOnClickListener(l);
618 mOnClickListener = l;
619 updateClickAndFocus();
620 }
621
622 private void updateClickAndFocus() {
623 boolean normalChild = !isChildInGroup() || isGroupExpanded();
624 boolean clickable = mOnClickListener != null && normalChild;
625 if (isFocusable() != normalChild) {
626 setFocusable(normalChild);
627 }
628 if (isClickable() != clickable) {
629 setClickable(clickable);
630 }
631 }
632
Selim Cinek31aada42015-12-18 17:51:15 -0800633 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
634 mHeadsUpManager = headsUpManager;
635 }
636
Selim Cinek01af3342016-02-09 19:25:31 -0800637 public void reInflateViews() {
638 initDimens();
639 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800640 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700641 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800642 }
643 }
644 if (mGuts != null) {
645 View oldGuts = mGuts;
646 int index = indexOfChild(oldGuts);
647 removeView(oldGuts);
648 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
649 R.layout.notification_guts, this, false);
650 mGuts.setVisibility(oldGuts.getVisibility());
651 addView(mGuts, index);
652 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800653 if (mSettingsIconRow != null) {
654 View oldSettings = mSettingsIconRow;
655 int settingsIndex = indexOfChild(oldSettings);
656 removeView(oldSettings);
657 mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
658 R.layout.notification_settings_icon_row, this, false);
659 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700660 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800661 mSettingsIconRow.setVisibility(oldSettings.getVisibility());
662 addView(mSettingsIconRow, settingsIndex);
663
664 }
Selim Cinekde33a4a2016-02-11 16:43:41 -0800665 mPrivateLayout.reInflateViews();
666 mPublicLayout.reInflateViews();
Selim Cinek01af3342016-02-09 19:25:31 -0800667 }
668
Selim Cinekc3179332016-03-04 14:44:56 -0800669 public void setContentBackground(int customBackgroundColor, boolean animate,
670 NotificationContentView notificationContentView) {
671 if (getShowingLayout() == notificationContentView) {
672 setTintColor(customBackgroundColor, animate);
673 }
674 }
675
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700676 public void closeRemoteInput() {
677 mPrivateLayout.closeRemoteInput();
678 mPublicLayout.closeRemoteInput();
679 }
680
Selim Cinekc897bd32016-03-18 17:32:31 -0700681 /**
682 * Set by how much the single line view should be indented.
683 */
684 public void setSingleLineWidthIndention(int indention) {
685 mPrivateLayout.setSingleLineWidthIndention(indention);
686 }
687
688 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700689 return mNotificationColor;
690 }
691
692 private void updateNotificationColor() {
693 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
694 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700695 }
696
697 public HybridNotificationView getSingleLineView() {
698 return mPrivateLayout.getSingleLineView();
699 }
700
Selim Cinekf07d0622016-03-21 19:52:52 -0700701 public boolean isOnKeyguard() {
702 return mOnKeyguard;
703 }
704
Selim Cinekc1e389d2016-04-07 11:02:57 -0700705 public void removeAllChildren() {
706 List<ExpandableNotificationRow> notificationChildren
707 = mChildrenContainer.getNotificationChildren();
708 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
709 for (int i = 0; i < clonedList.size(); i++) {
710 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700711 if (row.keepInParent()) {
712 continue;
713 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700714 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700715 row.setIsChildInGroup(false, null);
716 }
717 onChildrenCountChanged();
718 }
719
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700720 public void setForceUnlocked(boolean forceUnlocked) {
721 mForceUnlocked = forceUnlocked;
722 if (mIsSummaryWithChildren) {
723 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
724 for (ExpandableNotificationRow child : notificationChildren) {
725 child.setForceUnlocked(forceUnlocked);
726 }
727 }
728 }
729
Selim Cineke9bad242016-06-15 11:46:37 -0700730 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700731 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700732 mGroupParentWhenDismissed = mNotificationParent;
733 mRefocusOnDismiss = fromAccessibility;
734 mChildAfterViewWhenDismissed = null;
735 if (isChildInGroup()) {
736 List<ExpandableNotificationRow> notificationChildren =
737 mNotificationParent.getNotificationChildren();
738 int i = notificationChildren.indexOf(this);
739 if (i != -1 && i < notificationChildren.size() - 1) {
740 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
741 }
742 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700743 }
744
745 public boolean isDismissed() {
746 return mDismissed;
747 }
748
749 public boolean keepInParent() {
750 return mKeepInParent;
751 }
752
753 public void setKeepInParent(boolean keepInParent) {
754 mKeepInParent = keepInParent;
755 }
756
757 public boolean isRemoved() {
758 return mRemoved;
759 }
760
Adrian Roosd009ab12016-05-20 17:58:53 -0700761 public void setRemoved() {
762 mRemoved = true;
763
764 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700765 }
766
Selim Cinekd1395642016-04-28 12:22:42 -0700767 public NotificationChildrenContainer getChildrenContainer() {
768 return mChildrenContainer;
769 }
770
Selim Cinek73cf02a2016-06-17 13:08:00 -0700771 public void setHeadsupDisappearRunning(boolean running) {
772 mHeadsupDisappearRunning = running;
773 mPrivateLayout.setHeadsupDisappearRunning(running);
774 }
775
Selim Cineke9bad242016-06-15 11:46:37 -0700776 public View getChildAfterViewWhenDismissed() {
777 return mChildAfterViewWhenDismissed;
778 }
779
780 public View getGroupParentWhenDismissed() {
781 return mGroupParentWhenDismissed;
782 }
783
Selim Cinek9e624e72016-07-20 13:46:49 -0700784 public void performDismiss() {
785 mVetoButton.performClick();
786 }
787
788 public void setOnDismissListener(OnClickListener listener) {
789 mVetoButton.setOnClickListener(listener);
790 }
791
Selim Cinek281c2022016-10-13 19:14:43 -0700792 public View getNotificationIcon() {
793 NotificationHeaderView notificationHeader = getNotificationHeader();
794 if (notificationHeader != null) {
795 return notificationHeader.getIcon();
796 }
797 return null;
798 }
799
800 /**
801 * @return whether the notification is currently showing a view with an icon.
802 */
803 public boolean isShowingIcon() {
804 if (mIsSummaryWithChildren) {
805 return true;
806 }
807 NotificationContentView showingLayout = getShowingLayout();
808 NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
809 return notificationHeader != null;
810 }
811
Chris Wren78403d72014-07-28 10:23:24 +0100812 public interface ExpansionLogger {
813 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
814 }
Selim Cinek1685e632014-04-08 02:27:49 +0200815
Chris Wren51c75102013-07-16 20:49:17 -0400816 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
817 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700818 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -0800819 initDimens();
820 }
821
822 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800823 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
824 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
825 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
826 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -0800827 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800828 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Mady Mellorb0a82462016-04-30 17:31:02 -0700829 mIncreasedPaddingBetweenElements = getResources()
830 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800831 }
832
833 /**
834 * @param dimenId the dimen to look up
835 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
836 */
837 private int getFontScaledHeight(int dimenId) {
838 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
839 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
840 getResources().getDisplayMetrics().density);
841 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -0400842 }
843
Christoph Studera7fe6312014-06-27 19:32:44 +0200844 /**
845 * Resets this view so it can be re-used for an updated notification.
846 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200847 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200848 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200849 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +0100850 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +0200851 mExpandable = false;
852 mHasUserChangedExpansion = false;
853 mUserLocked = false;
854 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200855 mSensitive = false;
856 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200857 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700858 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -0800859 mPublicLayout.reset();
860 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +0200861 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -0800862 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +0200863 logExpansionEvent(false, wasExpanded);
864 }
865
866 public void resetHeight() {
Selim Cinek31094df2014-08-14 19:28:15 +0200867 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200868 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200869 }
870
Jorim Jaggi251957d2014-04-09 04:24:09 +0200871 @Override
872 protected void onFinishInflate() {
873 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200874 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800875 mPublicLayout.setContainingNotification(this);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200876 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800877 mPrivateLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800878 mPrivateLayout.setContainingNotification(this);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800879 mPublicLayout.setExpandClickListener(mExpandClickListener);
Mady Mellor4b80b102016-01-22 08:03:58 -0800880 mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
881 mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
882 @Override
883 public void onInflate(ViewStub stub, View inflated) {
884 mSettingsIconRow = (NotificationSettingsIconRow) inflated;
885 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700886 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800887 }
888 });
Selim Cinekab29aeb2015-02-20 18:18:32 +0100889 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
890 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200891 @Override
892 public void onInflate(ViewStub stub, View inflated) {
893 mGuts = (NotificationGuts) inflated;
894 mGuts.setClipTopAmount(getClipTopAmount());
895 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100896 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200897 }
898 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100899 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
900 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
901
902 @Override
903 public void onInflate(ViewStub stub, View inflated) {
904 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -0700905 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -0700906 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -0800907 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +0100908 }
909 });
Selim Cinek863834b2014-05-20 04:20:25 +0200910 mVetoButton = findViewById(R.id.veto);
Selim Cinek9e624e72016-07-20 13:46:49 -0700911 mVetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
912 mVetoButton.setContentDescription(mContext.getString(
913 R.string.accessibility_remove_notification));
Mady Mellor4b80b102016-01-22 08:03:58 -0800914
915 // Add the views that we translate to reveal the gear
916 mTranslateableViews = new ArrayList<View>();
917 for (int i = 0; i < getChildCount(); i++) {
918 mTranslateableViews.add(getChildAt(i));
919 }
920 // Remove views that don't translate
921 mTranslateableViews.remove(mVetoButton);
922 mTranslateableViews.remove(mSettingsIconRowStub);
923 mTranslateableViews.remove(mChildrenContainerStub);
924 mTranslateableViews.remove(mGutsStub);
925 }
926
Selim Cinek9e624e72016-07-20 13:46:49 -0700927 public View getVetoButton() {
928 return mVetoButton;
929 }
930
Mady Mellor4b80b102016-01-22 08:03:58 -0800931 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -0700932 if (mTranslateAnim != null) {
933 mTranslateAnim.cancel();
934 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800935 if (mTranslateableViews != null) {
936 for (int i = 0; i < mTranslateableViews.size(); i++) {
937 mTranslateableViews.get(i).setTranslationX(0);
938 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800939 }
Mady Mellorb0a82462016-04-30 17:31:02 -0700940 invalidateOutline();
Mady Mellor4b80b102016-01-22 08:03:58 -0800941 if (mSettingsIconRow != null) {
942 mSettingsIconRow.resetState();
943 }
944 }
945
946 public void animateTranslateNotification(final float leftTarget) {
947 if (mTranslateAnim != null) {
948 mTranslateAnim.cancel();
949 }
Mady Mellorb0a82462016-04-30 17:31:02 -0700950 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -0800951 if (mTranslateAnim != null) {
952 mTranslateAnim.start();
953 }
954 }
955
956 @Override
957 public void setTranslation(float translationX) {
958 if (areGutsExposed()) {
959 // Don't translate if guts are showing.
960 return;
961 }
962 // Translate the group of views
963 for (int i = 0; i < mTranslateableViews.size(); i++) {
964 if (mTranslateableViews.get(i) != null) {
965 mTranslateableViews.get(i).setTranslationX(translationX);
966 }
967 }
Mady Mellorb0a82462016-04-30 17:31:02 -0700968 invalidateOutline();
Mady Mellor34958fa2016-02-23 09:52:17 -0800969 if (mSettingsIconRow != null) {
970 mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
971 }
972 }
973
974 @Override
975 public float getTranslation() {
976 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
977 // All of the views in the list should have same translation, just use first one.
978 return mTranslateableViews.get(0).getTranslationX();
979 }
980 return 0;
981 }
982
983 public Animator getTranslateViewAnimator(final float leftTarget,
984 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -0700985 if (mTranslateAnim != null) {
986 mTranslateAnim.cancel();
987 }
Mady Mellor34958fa2016-02-23 09:52:17 -0800988 if (areGutsExposed()) {
989 // No translation if guts are exposed.
990 return null;
991 }
Mady Mellorb0a82462016-04-30 17:31:02 -0700992 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
993 leftTarget);
994 if (listener != null) {
995 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -0800996 }
Mady Mellorb0a82462016-04-30 17:31:02 -0700997 translateAnim.addListener(new AnimatorListenerAdapter() {
998 boolean cancelled = false;
999
1000 @Override
1001 public void onAnimationCancel(Animator anim) {
1002 cancelled = true;
1003 }
1004
1005 @Override
1006 public void onAnimationEnd(Animator anim) {
1007 if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
1008 mSettingsIconRow.resetState();
1009 mTranslateAnim = null;
1010 }
1011 }
1012 });
1013 mTranslateAnim = translateAnim;
1014 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001015 }
1016
1017 public float getSpaceForGear() {
1018 if (mSettingsIconRow != null) {
1019 return mSettingsIconRow.getSpaceForGear();
1020 }
1021 return 0;
1022 }
1023
1024 public NotificationSettingsIconRow getSettingsRow() {
1025 if (mSettingsIconRow == null) {
1026 mSettingsIconRowStub.inflate();
1027 }
1028 return mSettingsIconRow;
1029 }
1030
Selim Cinekab29aeb2015-02-20 18:18:32 +01001031 public void inflateGuts() {
1032 if (mGuts == null) {
1033 mGutsStub.inflate();
1034 }
1035 }
1036
Selim Cinekda42d652015-12-04 15:51:16 -08001037 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001038 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1039 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001040 if (mChildrenContainer != null) {
1041 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1042 : INVISIBLE);
Mady Mellorb0a82462016-04-30 17:31:02 -07001043 mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
1044 ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001045 : INVISIBLE);
1046 }
Selim Cinekda42d652015-12-04 15:51:16 -08001047 // The limits might have changed if the view suddenly became a group or vice versa
1048 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001049 }
1050
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001051 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001052 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1053 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001054 // Add a record for the entire layout since its content is somehow small.
1055 // The event comes from a leaf view that is interacted with.
1056 AccessibilityEvent record = AccessibilityEvent.obtain();
1057 onInitializeAccessibilityEvent(record);
1058 dispatchPopulateAccessibilityEvent(record);
1059 event.appendRecord(record);
1060 return true;
1061 }
1062 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001063 }
Chris Wren51c75102013-07-16 20:49:17 -04001064
John Spurlocke15452b2014-08-21 09:44:39 -04001065 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001066 public void setDark(boolean dark, boolean fade, long delay) {
1067 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001068 final NotificationContentView showing = getShowingLayout();
1069 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001070 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001071 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001072 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001073 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001074 }
John Spurlocke15452b2014-08-21 09:44:39 -04001075 }
1076
Chris Wren51c75102013-07-16 20:49:17 -04001077 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001078 if (mIsSummaryWithChildren && !mShowingPublic) {
1079 return !mChildrenExpanded;
1080 }
Chris Wren51c75102013-07-16 20:49:17 -04001081 return mExpandable;
1082 }
1083
1084 public void setExpandable(boolean expandable) {
1085 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001086 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001087 }
1088
Selim Cinek4ffd6362015-12-29 15:12:23 +01001089 @Override
1090 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001091 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1092 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001093 }
1094
Selim Cinek1685e632014-04-08 02:27:49 +02001095 /**
1096 * @return whether the user has changed the expansion state
1097 */
1098 public boolean hasUserChangedExpansion() {
1099 return mHasUserChangedExpansion;
1100 }
1101
Chris Wren51c75102013-07-16 20:49:17 -04001102 public boolean isUserExpanded() {
1103 return mUserExpanded;
1104 }
1105
Selim Cinek1685e632014-04-08 02:27:49 +02001106 /**
1107 * Set this notification to be expanded by the user
1108 *
1109 * @param userExpanded whether the user wants this notification to be expanded
1110 */
Chris Wren51c75102013-07-16 20:49:17 -04001111 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001112 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1113 }
1114
1115 /**
1116 * Set this notification to be expanded by the user
1117 *
1118 * @param userExpanded whether the user wants this notification to be expanded
1119 * @param allowChildExpansion whether a call to this method allows expanding children
1120 */
1121 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001122 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -07001123 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
Chris Wren698b1702016-05-23 11:16:32 -04001124 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001125 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Chris Wren698b1702016-05-23 11:16:32 -04001126 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001127 return;
1128 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001129 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001130 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001131 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001132 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001133 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001134 }
1135
Selim Cinekccd14fb2014-08-12 18:53:24 +02001136 public void resetUserExpansion() {
1137 mHasUserChangedExpansion = false;
1138 mUserExpanded = false;
1139 }
1140
Chris Wren51c75102013-07-16 20:49:17 -04001141 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001142 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001143 }
1144
1145 public void setUserLocked(boolean userLocked) {
1146 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001147 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001148 if (mIsSummaryWithChildren) {
1149 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek7baaa9e2016-07-21 17:21:09 -07001150 if (userLocked || !isGroupExpanded()) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001151 updateBackgroundForGroupState();
1152 }
Selim Cinek42357e02016-02-24 18:48:01 -08001153 }
Chris Wren51c75102013-07-16 20:49:17 -04001154 }
1155
Selim Cinek1685e632014-04-08 02:27:49 +02001156 /**
1157 * @return has the system set this notification to be expanded
1158 */
1159 public boolean isSystemExpanded() {
1160 return mIsSystemExpanded;
1161 }
1162
1163 /**
1164 * Set this notification to be expanded by the system.
1165 *
1166 * @param expand whether the system wants this notification to be expanded.
1167 */
1168 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001169 if (expand != mIsSystemExpanded) {
1170 final boolean wasExpanded = isExpanded();
1171 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001172 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001173 logExpansionEvent(false, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001174 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001175 mChildrenContainer.updateGroupOverflow();
1176 }
Selim Cinek31094df2014-08-14 19:28:15 +02001177 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001178 }
1179
1180 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001181 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001182 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001183 public void setOnKeyguard(boolean onKeyguard) {
1184 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001185 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001186 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001187 logExpansionEvent(false, wasExpanded);
1188 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001189 if (mIsSummaryWithChildren) {
1190 mChildrenContainer.updateGroupOverflow();
1191 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001192 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001193 }
1194 }
Selim Cinek1685e632014-04-08 02:27:49 +02001195 }
1196
1197 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001198 * @return Can the underlying notification be cleared? This can be different from whether the
1199 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1200 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001201 */
1202 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001203 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1204 return false;
1205 }
1206 if (mIsSummaryWithChildren) {
1207 List<ExpandableNotificationRow> notificationChildren =
1208 mChildrenContainer.getNotificationChildren();
1209 for (int i = 0; i < notificationChildren.size(); i++) {
1210 ExpandableNotificationRow child = notificationChildren.get(i);
1211 if (!child.isClearable()) {
1212 return false;
1213 }
1214 }
1215 }
1216 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001217 }
1218
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001219 @Override
1220 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001221 if (isUserLocked()) {
1222 return getActualHeight();
1223 }
Selim Cinekd84a5932015-12-15 11:45:36 -08001224 if (mGuts != null && mGuts.areGutsExposed()) {
1225 return mGuts.getHeight();
1226 } else if ((isChildInGroup() && !isGroupExpanded())) {
1227 return mPrivateLayout.getMinHeight();
1228 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1229 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001230 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001231 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek73cf02a2016-06-17 13:08:00 -07001232 } else if (mIsHeadsUp || mHeadsupDisappearRunning) {
1233 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001234 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1235 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001236 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001237 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001238 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001239 }
Selim Cinek31aada42015-12-18 17:51:15 -08001240 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001241 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001242 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001243 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001244 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001245 }
Selim Cinek1685e632014-04-08 02:27:49 +02001246
Mady Mellorb0a82462016-04-30 17:31:02 -07001247 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001248 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001249 }
1250
Selim Cinek263398f2015-10-21 17:40:23 -07001251 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001252 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001253 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1254 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
1255 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
1256 mEntry.notification);
Selim Cinek263398f2015-10-21 17:40:23 -07001257 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001258 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001259 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001260 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001261 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001262 }
1263
Mady Mellorb0a82462016-04-30 17:31:02 -07001264 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001265 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001266 mChildrenContainer.updateChildrenHeaderAppearance();
1267 }
1268 }
1269
Selim Cinek1685e632014-04-08 02:27:49 +02001270 /**
1271 * Check whether the view state is currently expanded. This is given by the system in {@link
1272 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1273 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1274 * view can differ from this state, if layout params are modified from outside.
1275 *
1276 * @return whether the view state is currently expanded.
1277 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001278 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001279 return isExpanded(false /* allowOnKeyguard */);
1280 }
1281
1282 public boolean isExpanded(boolean allowOnKeyguard) {
1283 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001284 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1285 || isUserExpanded());
1286 }
1287
1288 private boolean isSystemChildExpanded() {
1289 return mIsSystemChildExpanded;
1290 }
1291
1292 public void setSystemChildExpanded(boolean expanded) {
1293 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001294 }
1295
1296 @Override
1297 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1298 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001299 updateMaxHeights();
Mady Mellora6edc872016-04-26 11:01:03 -07001300 if (mSettingsIconRow != null) {
1301 mSettingsIconRow.updateVerticalLocation();
1302 }
Selim Cinek1685e632014-04-08 02:27:49 +02001303 }
1304
Selim Cinek8d490d42015-04-10 00:05:50 -07001305 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001306 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001307 View expandedChild = mPrivateLayout.getExpandedChild();
1308 if (expandedChild == null) {
1309 expandedChild = mPrivateLayout.getContractedChild();
1310 }
1311 mMaxExpandHeight = expandedChild.getHeight();
1312 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001313 if (headsUpChild == null) {
1314 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001315 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001316 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001317 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001318 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001319 }
1320 }
1321
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001322 @Override
1323 public void notifyHeightChanged(boolean needsAnimation) {
1324 super.notifyHeightChanged(needsAnimation);
1325 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1326 }
1327
Selim Cinek3c76d502016-02-19 15:16:33 -08001328 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001329 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001330 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001331 }
1332
1333 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001334 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001335 if (mIsSummaryWithChildren) {
1336 List<ExpandableNotificationRow> notificationChildren =
1337 mChildrenContainer.getNotificationChildren();
1338 for (int i = 0; i < notificationChildren.size(); i++) {
1339 ExpandableNotificationRow child = notificationChildren.get(i);
1340 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1341 }
1342 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001343 }
1344
1345 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1346 long duration) {
1347 boolean oldShowingPublic = mShowingPublic;
1348 mShowingPublic = mSensitive && hideSensitive;
1349 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1350 return;
1351 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001352
1353 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001354 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001355
Jorim Jaggiae441282014-08-01 02:45:18 +02001356 if (!animated) {
1357 mPublicLayout.animate().cancel();
1358 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001359 if (mChildrenContainer != null) {
1360 mChildrenContainer.animate().cancel();
1361 mChildrenContainer.setAlpha(1f);
1362 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001363 mPublicLayout.setAlpha(1f);
1364 mPrivateLayout.setAlpha(1f);
1365 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001366 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001367 } else {
1368 animateShowingPublic(delay, duration);
1369 }
Selim Cinekc3179332016-03-04 14:44:56 -08001370 NotificationContentView showingLayout = getShowingLayout();
1371 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001372 mPrivateLayout.updateExpandButtons(isExpandable());
Jorim Jaggiae441282014-08-01 02:45:18 +02001373 mShowingPublicInitialized = true;
1374 }
1375
1376 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001377 View[] privateViews = mIsSummaryWithChildren
1378 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001379 : new View[] {mPrivateLayout};
1380 View[] publicViews = new View[] {mPublicLayout};
1381 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1382 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1383 for (final View hiddenView : hiddenChildren) {
1384 hiddenView.setVisibility(View.VISIBLE);
1385 hiddenView.animate().cancel();
1386 hiddenView.animate()
1387 .alpha(0f)
1388 .setStartDelay(delay)
1389 .setDuration(duration)
1390 .withEndAction(new Runnable() {
1391 @Override
1392 public void run() {
1393 hiddenView.setVisibility(View.INVISIBLE);
1394 }
1395 });
1396 }
1397 for (View showView : shownChildren) {
1398 showView.setVisibility(View.VISIBLE);
1399 showView.setAlpha(0f);
1400 showView.animate().cancel();
1401 showView.animate()
1402 .alpha(1f)
1403 .setStartDelay(delay)
1404 .setDuration(duration);
1405 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001406 }
1407
Selim Cinek3776fe02016-02-04 13:32:43 -08001408 public boolean mustStayOnScreen() {
1409 return mIsHeadsUp;
1410 }
1411
Selim Cinek9e624e72016-07-20 13:46:49 -07001412 /**
1413 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1414 * otherwise some state might not be updated. To request about the general clearability
1415 * see {@link #isClearable()}.
1416 */
1417 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001418 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001419 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001420
Ricky Waicd35def2016-05-03 11:07:07 +01001421 public void makeActionsVisibile() {
1422 setUserExpanded(true, true);
1423 if (isChildInGroup()) {
1424 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1425 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001426 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001427 }
1428
Selim Cinekb5605e52015-02-20 18:21:41 +01001429 public void setChildrenExpanded(boolean expanded, boolean animate) {
1430 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001431 if (mChildrenContainer != null) {
1432 mChildrenContainer.setChildrenExpanded(expanded);
1433 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001434 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001435 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001436 }
1437
Selim Cinekb5605e52015-02-20 18:21:41 +01001438 public static void applyTint(View v, int color) {
1439 int alpha;
1440 if (color != 0) {
1441 alpha = COLORED_DIVIDER_ALPHA;
1442 } else {
1443 color = 0xff000000;
1444 alpha = DEFAULT_DIVIDER_ALPHA;
1445 }
1446 if (v.getBackground() instanceof ColorDrawable) {
1447 ColorDrawable background = (ColorDrawable) v.getBackground();
1448 background.mutate();
1449 background.setColor(color);
1450 background.setAlpha(alpha);
1451 }
1452 }
1453
Selim Cinek1685e632014-04-08 02:27:49 +02001454 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001455 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001456 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001457
Mady Mellor34958fa2016-02-23 09:52:17 -08001458 public boolean areGutsExposed() {
1459 return (mGuts != null && mGuts.areGutsExposed());
1460 }
1461
Jorim Jaggibe565df2014-04-28 17:51:23 +02001462 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001463 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001464 NotificationContentView showingLayout = getShowingLayout();
1465 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001466 }
1467
1468 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001469 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001470 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001471 return mChildrenContainer;
1472 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001473 return getShowingLayout();
1474 }
1475
1476 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001477 protected void onAppearAnimationFinished(boolean wasAppearing) {
1478 super.onAppearAnimationFinished(wasAppearing);
1479 if (wasAppearing) {
1480 // During the animation the visible view might have changed, so let's make sure all
1481 // alphas are reset
1482 if (mChildrenContainer != null) {
1483 mChildrenContainer.setAlpha(1.0f);
1484 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1485 }
1486 mPrivateLayout.setAlpha(1.0f);
1487 mPrivateLayout.setLayerType(LAYER_TYPE_NONE, null);
1488 mPublicLayout.setAlpha(1.0f);
1489 mPublicLayout.setLayerType(LAYER_TYPE_NONE, null);
1490 }
1491 }
1492
1493 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001494 public int getExtraBottomPadding() {
1495 if (mIsSummaryWithChildren && isGroupExpanded()) {
1496 return mIncreasedPaddingBetweenElements;
1497 }
1498 return 0;
1499 }
1500
1501 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001502 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001503 super.setActualHeight(height, notifyListeners);
Mady Mellorb53bc272016-02-11 18:28:23 -08001504 if (mGuts != null && mGuts.areGutsExposed()) {
1505 mGuts.setActualHeight(height);
1506 return;
1507 }
Selim Cinekeef84282015-10-30 16:28:00 -07001508 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +01001509 mPrivateLayout.setContentHeight(contentHeight);
1510 mPublicLayout.setContentHeight(contentHeight);
Selim Cinek42357e02016-02-24 18:48:01 -08001511 if (mIsSummaryWithChildren) {
1512 mChildrenContainer.setActualHeight(height);
1513 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001514 if (mGuts != null) {
1515 mGuts.setActualHeight(height);
1516 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001517 }
1518
1519 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001520 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001521 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001522 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001523 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001524 NotificationContentView showingLayout = getShowingLayout();
1525 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001526 }
1527
1528 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001529 public int getMinHeight() {
Selim Cinek31aada42015-12-18 17:51:15 -08001530 if (mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
1531 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1532 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001533 return mChildrenContainer.getMinHeight();
Selim Cinek31aada42015-12-18 17:51:15 -08001534 } else if (mIsHeadsUp) {
1535 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001536 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001537 NotificationContentView showingLayout = getShowingLayout();
1538 return showingLayout.getMinHeight();
1539 }
1540
1541 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001542 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001543 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001544 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001545 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001546 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001547 }
1548
1549 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001550 public void setClipTopAmount(int clipTopAmount) {
1551 super.setClipTopAmount(clipTopAmount);
1552 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001553 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001554 if (mGuts != null) {
1555 mGuts.setClipTopAmount(clipTopAmount);
1556 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001557 }
1558
Selim Cinek31094df2014-08-14 19:28:15 +02001559 public boolean isMaxExpandHeightInitialized() {
1560 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001561 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001562
Selim Cinek42357e02016-02-24 18:48:01 -08001563 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001564 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1565 }
Chris Wren78403d72014-07-28 10:23:24 +01001566
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001567 @Override
1568 public void setShowingLegacyBackground(boolean showing) {
1569 super.setShowingLegacyBackground(showing);
1570 mPrivateLayout.setShowingLegacyBackground(showing);
1571 mPublicLayout.setShowingLegacyBackground(showing);
1572 }
1573
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001574 @Override
1575 protected void updateBackgroundTint() {
1576 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001577 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001578 if (mIsSummaryWithChildren) {
1579 List<ExpandableNotificationRow> notificationChildren =
1580 mChildrenContainer.getNotificationChildren();
1581 for (int i = 0; i < notificationChildren.size(); i++) {
1582 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001583 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001584 }
1585 }
1586 }
1587
Mady Mellorb0a82462016-04-30 17:31:02 -07001588 /**
1589 * Called when a group has finished animating from collapsed or expanded state.
1590 */
1591 public void onFinishedExpansionChange() {
1592 mGroupExpansionChanging = false;
1593 updateBackgroundForGroupState();
1594 }
1595
1596 /**
1597 * Updates the parent and children backgrounds in a group based on the expansion state.
1598 */
1599 public void updateBackgroundForGroupState() {
1600 if (mIsSummaryWithChildren) {
1601 // Only when the group has finished expanding do we hide its background.
1602 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1603 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1604 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1605 for (int i = 0; i < children.size(); i++) {
1606 children.get(i).updateBackgroundForGroupState();
1607 }
1608 } else if (isChildInGroup()) {
1609 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
1610 // Only show a background if the group is expanded OR if it is expanding / collapsing
1611 // and has a custom background color
1612 final boolean showBackground = isGroupExpanded()
1613 || ((mNotificationParent.isGroupExpansionChanging()
1614 || mNotificationParent.isUserLocked()) && childColor != 0);
1615 mShowNoBackground = !showBackground;
1616 } else {
1617 // Only children or parents ever need no background.
1618 mShowNoBackground = false;
1619 }
1620 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001621 updateBackground();
1622 }
1623
Adrian Roos4a579672016-05-24 16:54:37 -07001624 public int getPositionOfChild(ExpandableNotificationRow childRow) {
1625 if (mIsSummaryWithChildren) {
1626 return mChildrenContainer.getPositionInLinearLayout(childRow);
1627 }
1628 return 0;
1629 }
1630
Chris Wren78403d72014-07-28 10:23:24 +01001631 public void setExpansionLogger(ExpansionLogger logger, String key) {
1632 mLogger = logger;
1633 mLoggingKey = key;
1634 }
1635
Chris Wren6abeeb92016-05-26 14:44:38 -04001636 public void onExpandedByGesture(boolean userExpanded) {
1637 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
1638 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
1639 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
1640 }
1641 MetricsLogger.action(mContext, event, userExpanded);
1642 }
1643
Selim Cinek6183d122016-01-14 18:48:41 -08001644 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001645 public float getIncreasedPaddingAmount() {
1646 if (mIsSummaryWithChildren) {
1647 if (isGroupExpanded()) {
1648 return 1.0f;
1649 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001650 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001651 }
1652 }
1653 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001654 }
1655
1656 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001657 protected boolean disallowSingleClick(MotionEvent event) {
1658 float x = event.getX();
1659 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001660 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001661 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001662 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001663 }
1664 return super.disallowSingleClick(event);
1665 }
1666
Chris Wren78403d72014-07-28 10:23:24 +01001667 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04001668 boolean nowExpanded = isExpanded();
1669 if (mIsSummaryWithChildren) {
1670 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
1671 }
Chris Wren78403d72014-07-28 10:23:24 +01001672 if (wasExpanded != nowExpanded && mLogger != null) {
1673 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1674 }
1675 }
Selim Cinek570981d2015-12-01 11:37:01 -08001676
Selim Cineke9bad242016-06-15 11:46:37 -07001677 @Override
1678 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1679 super.onInitializeAccessibilityNodeInfoInternal(info);
1680 if (canViewBeDismissed()) {
1681 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
1682 }
1683 }
1684
1685 @Override
1686 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
1687 if (super.performAccessibilityActionInternal(action, arguments)) {
1688 return true;
1689 }
1690 switch (action) {
1691 case AccessibilityNodeInfo.ACTION_DISMISS:
1692 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
1693 true /* fromAccessibility */);
1694 return true;
1695 }
1696 return false;
1697 }
1698
1699 public boolean shouldRefocusOnDismiss() {
1700 return mRefocusOnDismiss || isAccessibilityFocused();
1701 }
1702
Selim Cinek570981d2015-12-01 11:37:01 -08001703 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001704 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001705 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001706
1707 @Override
1708 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
1709 return new NotificationViewState(stackScrollState);
1710 }
1711
1712 public static class NotificationViewState extends ExpandableViewState {
1713
1714 private final StackScrollState mOverallState;
1715
1716 private NotificationViewState(StackScrollState stackScrollState) {
1717 mOverallState = stackScrollState;
1718 }
1719
1720 @Override
1721 public void applyToView(View view) {
1722 super.applyToView(view);
1723 if (view instanceof ExpandableNotificationRow) {
1724 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
1725 if (this.isBottomClipped) {
1726 row.setClipToActualHeight(true);
1727 }
1728 row.applyChildrenState(mOverallState);
1729 }
1730 }
1731 }
Chris Wren51c75102013-07-16 20:49:17 -04001732}