blob: e89fe55e0712305a1378300e01def0ef6a1e1b44 [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;
Selim Cinek875a3a12016-11-18 17:52:16 -080039import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020040import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020041import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070042import android.view.accessibility.AccessibilityNodeInfo;
Selim Cinek98713a42015-09-21 15:47:20 +020043import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020044import android.widget.ImageView;
Selim Cinekb5605e52015-02-20 18:21:41 +010045
Chris Wren698b1702016-05-23 11:16:32 -040046import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010047import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070048import com.android.internal.util.NotificationColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080049import com.android.internal.widget.CachingIconView;
Selim Cinek0242fbb2016-10-19 13:38:32 -070050import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050051import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070052import com.android.systemui.classifier.FalsingManager;
Selim Cinekc897bd32016-03-18 17:32:31 -070053import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinekb5605e52015-02-20 18:21:41 +010054import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinek31aada42015-12-18 17:51:15 -080055import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek0cfbef42016-11-09 19:06:36 -080056import com.android.systemui.statusbar.stack.AnimationProperties;
57import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010058import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070059import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010060import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010061
Mady Mellor4b80b102016-01-22 08:03:58 -080062import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010063import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050064
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020065public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010066
67 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
68 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Selim Cinek0242fbb2016-10-19 13:38:32 -070069 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -080070 private int mIconTransformContentShiftNoIcon;
Selim Cinek01af3342016-02-09 19:25:31 -080071 private int mNotificationMinHeightLegacy;
72 private int mMaxHeadsUpHeightLegacy;
73 private int mMaxHeadsUpHeight;
74 private int mNotificationMinHeight;
75 private int mNotificationMaxHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -070076 private int mIncreasedPaddingBetweenElements;
Chris Wren51c75102013-07-16 20:49:17 -040077
Selim Cinek1685e632014-04-08 02:27:49 +020078 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040079 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020080 /** Has the user actively changed the expansion state of this row */
81 private boolean mHasUserChangedExpansion;
82 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040083 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -080084
85 /**
86 * Has this notification been expanded while it was pinned
87 */
88 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +020089 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040090 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020091 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050092 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020093 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -080094 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +020095 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -070096 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -040097
Selim Cinek1685e632014-04-08 02:27:49 +020098 /**
99 * Is this notification expanded by the system. The expansion state can be overridden by the
100 * user expansion.
101 */
102 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200103
104 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700105 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200106 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700107 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200108
Mady Mellorb0a82462016-04-30 17:31:02 -0700109 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800110 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200111 private NotificationContentView mPublicLayout;
112 private NotificationContentView mPrivateLayout;
Selim Cinek1685e632014-04-08 02:27:49 +0200113 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700114 private int mHeadsUpHeight;
Selim Cinek863834b2014-05-20 04:20:25 +0200115 private View mVetoButton;
Selim Cinek4bb59342016-04-08 19:29:35 -0700116 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100117 private ExpansionLogger mLogger;
118 private String mLoggingKey;
Mady Mellor4b80b102016-01-22 08:03:58 -0800119 private NotificationSettingsIconRow mSettingsIconRow;
Selim Cinek8d490d42015-04-10 00:05:50 -0700120 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800121 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200122 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700123 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100124 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200125 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100126 private ViewStub mChildrenContainerStub;
127 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100128 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700129 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100130 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor4b80b102016-01-22 08:03:58 -0800131 private ViewStub mSettingsIconRowStub;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100132 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100133 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700134 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700135 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800136 private HeadsUpManager mHeadsUpManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200137
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700138 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800139 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700140 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700141 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800142 private OnExpandClickListener mOnExpandClickListener;
Mady Mellorb0a82462016-04-30 17:31:02 -0700143 private boolean mGroupExpansionChanging;
144
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800145 private OnClickListener mExpandClickListener = new OnClickListener() {
146 @Override
147 public void onClick(View v) {
Selim Cinek624c02db2015-12-14 21:00:02 -0800148 if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700149 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400150 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
151 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
152 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400153 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
154 nowExpanded);
155 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800156 } else {
Selim Cineke9bad242016-06-15 11:46:37 -0700157 if (v.isAccessibilityFocused()) {
158 mPrivateLayout.setFocusOnVisibilityChange();
159 }
Selim Cinek31aada42015-12-18 17:51:15 -0800160 boolean nowExpanded;
161 if (isPinned()) {
162 nowExpanded = !mExpandedWhenPinned;
163 mExpandedWhenPinned = nowExpanded;
164 } else {
165 nowExpanded = !isExpanded();
166 setUserExpanded(nowExpanded);
167 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800168 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800169 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400170 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
171 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800172 }
173 }
174 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700175 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700176 private boolean mDismissed;
177 private boolean mKeepInParent;
178 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700179 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
180 new FloatProperty<ExpandableNotificationRow>("translate") {
181 @Override
182 public void setValue(ExpandableNotificationRow object, float value) {
183 object.setTranslation(value);
184 }
185
186 @Override
187 public Float get(ExpandableNotificationRow object) {
188 return object.getTranslation();
189 }
190 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700191 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700192 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700193 private View mChildAfterViewWhenDismissed;
194 private View mGroupParentWhenDismissed;
195 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800196 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700197 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700198 private boolean mAboveShelf;
Selim Cinek875a3a12016-11-18 17:52:16 -0800199 private boolean mIsLastChild;
Mady Mellorb0a82462016-04-30 17:31:02 -0700200
201 public boolean isGroupExpansionChanging() {
202 if (isChildInGroup()) {
203 return mNotificationParent.isGroupExpansionChanging();
204 }
205 return mGroupExpansionChanging;
206 }
207
208 public void setGroupExpansionChanging(boolean changing) {
209 mGroupExpansionChanging = changing;
210 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700211
Adrian Roos599be342016-06-13 14:54:39 -0700212 @Override
213 public void setActualHeightAnimating(boolean animating) {
214 if (mPrivateLayout != null) {
215 mPrivateLayout.setContentHeightAnimating(animating);
216 }
217 }
218
Selim Cinek8d490d42015-04-10 00:05:50 -0700219 public NotificationContentView getPrivateLayout() {
220 return mPrivateLayout;
221 }
222
223 public NotificationContentView getPublicLayout() {
224 return mPublicLayout;
225 }
226
Selim Cinekcab4a602014-09-03 14:47:57 +0200227 public void setIconAnimationRunning(boolean running) {
228 setIconAnimationRunning(running, mPublicLayout);
229 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800230 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700231 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800232 List<ExpandableNotificationRow> notificationChildren =
233 mChildrenContainer.getNotificationChildren();
234 for (int i = 0; i < notificationChildren.size(); i++) {
235 ExpandableNotificationRow child = notificationChildren.get(i);
236 child.setIconAnimationRunning(running);
237 }
238 }
239 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200240 }
241
242 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
243 if (layout != null) {
244 View contractedChild = layout.getContractedChild();
245 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700246 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200247 setIconAnimationRunningForChild(running, contractedChild);
248 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700249 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200250 }
251 }
252
253 private void setIconAnimationRunningForChild(boolean running, View child) {
254 if (child != null) {
255 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
256 setIconRunning(icon, running);
257 ImageView rightIcon = (ImageView) child.findViewById(
258 com.android.internal.R.id.right_icon);
259 setIconRunning(rightIcon, running);
260 }
261 }
262
263 private void setIconRunning(ImageView imageView, boolean running) {
264 if (imageView != null) {
265 Drawable drawable = imageView.getDrawable();
266 if (drawable instanceof AnimationDrawable) {
267 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
268 if (running) {
269 animationDrawable.start();
270 } else {
271 animationDrawable.stop();
272 }
273 } else if (drawable instanceof AnimatedVectorDrawable) {
274 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
275 if (running) {
276 animationDrawable.start();
277 } else {
278 animationDrawable.stop();
279 }
280 }
281 }
282 }
283
Selim Cinekda42d652015-12-04 15:51:16 -0800284 public void onNotificationUpdated(NotificationData.Entry entry) {
285 mEntry = entry;
286 mStatusBarNotification = entry.notification;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800287 mPrivateLayout.onNotificationUpdated(entry);
288 mPublicLayout.onNotificationUpdated(entry);
Selim Cinek757d8792016-01-28 16:21:08 -0800289 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700290 updateNotificationColor();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800291 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700292 mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
Selim Cinekc897bd32016-03-18 17:32:31 -0700293 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800294 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800295 if (mIconAnimationRunning) {
296 setIconAnimationRunning(true);
297 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800298 if (mNotificationParent != null) {
299 mNotificationParent.updateChildrenHeaderAppearance();
300 }
Selim Cinek263398f2015-10-21 17:40:23 -0700301 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800302 // The public layouts expand button is always visible
303 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800304 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700305 updateIconVisibilities();
Selim Cinekda42d652015-12-04 15:51:16 -0800306 }
307
308 private void updateLimits() {
Selim Cineka1744872016-03-11 15:36:06 -0800309 updateLimitsForView(mPrivateLayout);
310 updateLimitsForView(mPublicLayout);
311 }
312
313 private void updateLimitsForView(NotificationContentView layout) {
314 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800315 != com.android.internal.R.id.status_bar_latest_event_content;
316 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
317 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
318 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800319 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
320 layout.getHeadsUpChild().getId()
321 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek77019c72015-12-09 10:18:02 -0800322 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
323 : mMaxHeadsUpHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800324 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200325 }
326
327 public StatusBarNotification getStatusBarNotification() {
328 return mStatusBarNotification;
329 }
330
Selim Cinek281c2022016-10-13 19:14:43 -0700331 public NotificationData.Entry getEntry() {
332 return mEntry;
333 }
334
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700335 public boolean isHeadsUp() {
336 return mIsHeadsUp;
337 }
338
Selim Cinek1a521f32014-11-03 17:39:29 +0100339 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700340 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100341 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700342 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700343 if (mIsSummaryWithChildren) {
344 // The overflow might change since we allow more lines as HUN.
345 mChildrenContainer.updateGroupOverflow();
346 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700347 if (intrinsicBefore != getIntrinsicHeight()) {
348 notifyHeightChanged(false /* needsAnimation */);
349 }
Selim Cinekd127d792016-11-01 19:11:41 -0700350 if (isHeadsUp) {
351 setAboveShelf(true);
352 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100353 }
354
Selim Cinekb5605e52015-02-20 18:21:41 +0100355 public void setGroupManager(NotificationGroupManager groupManager) {
356 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700357 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100358 }
359
Adrian Roosb88b1a12015-12-09 18:51:05 -0800360 public void setRemoteInputController(RemoteInputController r) {
361 mPrivateLayout.setRemoteInputController(r);
362 }
363
Mady Mellor3fd273e2016-03-15 21:08:14 -0700364 public void setAppName(String appName) {
365 mAppName = appName;
366 if (mSettingsIconRow != null) {
367 mSettingsIconRow.setAppName(mAppName);
368 }
369 }
370
Selim Cinekb5605e52015-02-20 18:21:41 +0100371 public void addChildNotification(ExpandableNotificationRow row) {
372 addChildNotification(row, -1);
373 }
374
375 /**
376 * Add a child notification to this view.
377 *
378 * @param row the row to add
379 * @param childIndex the index to add it at, if -1 it will be added at the end
380 */
381 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
382 if (mChildrenContainer == null) {
383 mChildrenContainerStub.inflate();
384 }
385 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700386 onChildrenCountChanged();
387 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100388 }
389
390 public void removeChildNotification(ExpandableNotificationRow row) {
391 if (mChildrenContainer != null) {
392 mChildrenContainer.removeNotification(row);
393 }
Selim Cinek263398f2015-10-21 17:40:23 -0700394 onChildrenCountChanged();
395 row.setIsChildInGroup(false, null);
396 }
397
398 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700399 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700400 }
401
Selim Cinek388df6d2015-10-22 13:25:11 -0700402 public ExpandableNotificationRow getNotificationParent() {
403 return mNotificationParent;
404 }
405
Selim Cinek263398f2015-10-21 17:40:23 -0700406 /**
407 * @param isChildInGroup Is this notification now in a group
408 * @param parent the new parent notification
409 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700410 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
411 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
412 mNotificationParent = childInGroup ? parent : null;
413 mPrivateLayout.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400414 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700415 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700416 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700417 if (mNotificationParent != null) {
418 mNotificationParent.updateBackgroundForGroupState();
419 }
Selim Cinekdb167372016-11-17 15:41:17 -0800420 updateIconVisibilities();
Selim Cinek34d93b02015-10-22 12:30:38 -0700421 }
422
423 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800424 public boolean onTouchEvent(MotionEvent event) {
425 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
426 || !isChildInGroup() || isGroupExpanded()) {
427 return super.onTouchEvent(event);
428 } else {
429 return false;
430 }
431 }
432
433 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800434 protected boolean handleSlideBack() {
435 if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
436 animateTranslateNotification(0 /* targetLeft */);
437 return true;
438 }
439 return false;
440 }
441
442 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700443 protected boolean shouldHideBackground() {
444 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700445 }
446
447 @Override
448 public boolean isSummaryWithChildren() {
449 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100450 }
451
452 @Override
453 public boolean areChildrenExpanded() {
454 return mChildrenExpanded;
455 }
456
457 public List<ExpandableNotificationRow> getNotificationChildren() {
458 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
459 }
460
Selim Cinekeef84282015-10-30 16:28:00 -0700461 public int getNumberOfNotificationChildren() {
462 if (mChildrenContainer == null) {
463 return 0;
464 }
465 return mChildrenContainer.getNotificationChildren().size();
466 }
467
Selim Cinekb5605e52015-02-20 18:21:41 +0100468 /**
469 * Apply the order given in the list to the children.
470 *
471 * @param childOrder the new list order
472 * @return whether the list order has changed
473 */
474 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
475 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
476 }
477
478 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700479 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800480 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100481 mChildrenContainer.getState(resultState, parentState);
482 }
483 }
484
485 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700486 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100487 mChildrenContainer.applyState(state);
488 }
489 }
490
491 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700492 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100493 mChildrenContainer.prepareExpansionChanged(state);
494 }
495 }
496
Selim Cinek0cfbef42016-11-09 19:06:36 -0800497 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700498 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800499 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100500 }
501 }
502
503 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800504 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100505 return this;
506 } else {
507 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
508 return view == null ? this : view;
509 }
510 }
511
Selim Cinekab29aeb2015-02-20 18:18:32 +0100512 public NotificationGuts getGuts() {
513 return mGuts;
514 }
515
Selim Cinek684a4422015-04-15 16:18:39 -0700516 /**
517 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
518 * the notification will be rendered on top of the screen.
519 *
520 * @param pinned whether it is pinned
521 */
522 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700523 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700524 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700525 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700526 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700527 }
Selim Cinek31aada42015-12-18 17:51:15 -0800528 if (pinned) {
529 setIconAnimationRunning(true);
530 mExpandedWhenPinned = false;
531 } else if (mExpandedWhenPinned) {
532 setUserExpanded(true);
533 }
Selim Cinek98713a42015-09-21 15:47:20 +0200534 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700535 }
536
Selim Cinek684a4422015-04-15 16:18:39 -0700537 public boolean isPinned() {
538 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700539 }
540
Selim Cinekd127d792016-11-01 19:11:41 -0700541 @Override
542 public int getPinnedHeadsUpHeight() {
543 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
544 }
545
Selim Cinek31aada42015-12-18 17:51:15 -0800546 /**
547 * @param atLeastMinHeight should the value returned be at least the minimum height.
548 * Used to avoid cyclic calls
549 * @return the height of the heads up notification when pinned
550 */
Selim Cinekd127d792016-11-01 19:11:41 -0700551 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800552 if (mIsSummaryWithChildren) {
553 return mChildrenContainer.getIntrinsicHeight();
554 }
Selim Cinek31aada42015-12-18 17:51:15 -0800555 if(mExpandedWhenPinned) {
556 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
557 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700558 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800559 } else {
560 return mHeadsUpHeight;
561 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700562 }
563
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700564 /**
565 * Mark whether this notification was just clicked, i.e. the user has just clicked this
566 * notification in this frame.
567 */
568 public void setJustClicked(boolean justClicked) {
569 mJustClicked = justClicked;
570 }
571
572 /**
573 * @return true if this notification has been clicked in this frame, false otherwise
574 */
575 public boolean wasJustClicked() {
576 return mJustClicked;
577 }
578
Selim Cinek98713a42015-09-21 15:47:20 +0200579 public void setChronometerRunning(boolean running) {
580 mLastChronometerRunning = running;
581 setChronometerRunning(running, mPrivateLayout);
582 setChronometerRunning(running, mPublicLayout);
583 if (mChildrenContainer != null) {
584 List<ExpandableNotificationRow> notificationChildren =
585 mChildrenContainer.getNotificationChildren();
586 for (int i = 0; i < notificationChildren.size(); i++) {
587 ExpandableNotificationRow child = notificationChildren.get(i);
588 child.setChronometerRunning(running);
589 }
590 }
591 }
592
593 private void setChronometerRunning(boolean running, NotificationContentView layout) {
594 if (layout != null) {
595 running = running || isPinned();
596 View contractedChild = layout.getContractedChild();
597 View expandedChild = layout.getExpandedChild();
598 View headsUpChild = layout.getHeadsUpChild();
599 setChronometerRunningForChild(running, contractedChild);
600 setChronometerRunningForChild(running, expandedChild);
601 setChronometerRunningForChild(running, headsUpChild);
602 }
603 }
604
605 private void setChronometerRunningForChild(boolean running, View child) {
606 if (child != null) {
607 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
608 if (chronometer instanceof Chronometer) {
609 ((Chronometer) chronometer).setStarted(running);
610 }
611 }
612 }
613
Selim Cinekea4bef72015-12-02 15:51:10 -0800614 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700615 if (mIsSummaryWithChildren) {
616 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700617 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800618 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700619 }
620
Selim Cinek34eda5e2016-02-18 17:10:43 -0800621 private NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700622 if (mIsSummaryWithChildren && !mShowingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700623 return mChildrenContainer.getHeaderView();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800624 }
625 return getShowingLayout().getVisibleNotificationHeader();
626 }
627
Selim Cinek570981d2015-12-01 11:37:01 -0800628 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
629 mOnExpandClickListener = onExpandClickListener;
630 }
631
Selim Cinekddf1b392016-05-27 16:33:10 -0700632 @Override
633 public void setOnClickListener(@Nullable OnClickListener l) {
634 super.setOnClickListener(l);
635 mOnClickListener = l;
636 updateClickAndFocus();
637 }
638
639 private void updateClickAndFocus() {
640 boolean normalChild = !isChildInGroup() || isGroupExpanded();
641 boolean clickable = mOnClickListener != null && normalChild;
642 if (isFocusable() != normalChild) {
643 setFocusable(normalChild);
644 }
645 if (isClickable() != clickable) {
646 setClickable(clickable);
647 }
648 }
649
Selim Cinek31aada42015-12-18 17:51:15 -0800650 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
651 mHeadsUpManager = headsUpManager;
652 }
653
Selim Cinek01af3342016-02-09 19:25:31 -0800654 public void reInflateViews() {
655 initDimens();
656 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800657 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700658 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800659 }
660 }
661 if (mGuts != null) {
662 View oldGuts = mGuts;
663 int index = indexOfChild(oldGuts);
664 removeView(oldGuts);
665 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
666 R.layout.notification_guts, this, false);
667 mGuts.setVisibility(oldGuts.getVisibility());
668 addView(mGuts, index);
669 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800670 if (mSettingsIconRow != null) {
671 View oldSettings = mSettingsIconRow;
672 int settingsIndex = indexOfChild(oldSettings);
673 removeView(oldSettings);
674 mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
675 R.layout.notification_settings_icon_row, this, false);
676 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700677 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800678 mSettingsIconRow.setVisibility(oldSettings.getVisibility());
679 addView(mSettingsIconRow, settingsIndex);
680
681 }
Selim Cinekde33a4a2016-02-11 16:43:41 -0800682 mPrivateLayout.reInflateViews();
683 mPublicLayout.reInflateViews();
Selim Cinek01af3342016-02-09 19:25:31 -0800684 }
685
Selim Cinekc3179332016-03-04 14:44:56 -0800686 public void setContentBackground(int customBackgroundColor, boolean animate,
687 NotificationContentView notificationContentView) {
688 if (getShowingLayout() == notificationContentView) {
689 setTintColor(customBackgroundColor, animate);
690 }
691 }
692
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700693 public void closeRemoteInput() {
694 mPrivateLayout.closeRemoteInput();
695 mPublicLayout.closeRemoteInput();
696 }
697
Selim Cinekc897bd32016-03-18 17:32:31 -0700698 /**
699 * Set by how much the single line view should be indented.
700 */
701 public void setSingleLineWidthIndention(int indention) {
702 mPrivateLayout.setSingleLineWidthIndention(indention);
703 }
704
705 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700706 return mNotificationColor;
707 }
708
709 private void updateNotificationColor() {
710 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
711 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700712 }
713
714 public HybridNotificationView getSingleLineView() {
715 return mPrivateLayout.getSingleLineView();
716 }
717
Selim Cinekf07d0622016-03-21 19:52:52 -0700718 public boolean isOnKeyguard() {
719 return mOnKeyguard;
720 }
721
Selim Cinekc1e389d2016-04-07 11:02:57 -0700722 public void removeAllChildren() {
723 List<ExpandableNotificationRow> notificationChildren
724 = mChildrenContainer.getNotificationChildren();
725 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
726 for (int i = 0; i < clonedList.size(); i++) {
727 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700728 if (row.keepInParent()) {
729 continue;
730 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700731 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700732 row.setIsChildInGroup(false, null);
733 }
734 onChildrenCountChanged();
735 }
736
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700737 public void setForceUnlocked(boolean forceUnlocked) {
738 mForceUnlocked = forceUnlocked;
739 if (mIsSummaryWithChildren) {
740 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
741 for (ExpandableNotificationRow child : notificationChildren) {
742 child.setForceUnlocked(forceUnlocked);
743 }
744 }
745 }
746
Selim Cineke9bad242016-06-15 11:46:37 -0700747 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700748 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700749 mGroupParentWhenDismissed = mNotificationParent;
750 mRefocusOnDismiss = fromAccessibility;
751 mChildAfterViewWhenDismissed = null;
752 if (isChildInGroup()) {
753 List<ExpandableNotificationRow> notificationChildren =
754 mNotificationParent.getNotificationChildren();
755 int i = notificationChildren.indexOf(this);
756 if (i != -1 && i < notificationChildren.size() - 1) {
757 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
758 }
759 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700760 }
761
762 public boolean isDismissed() {
763 return mDismissed;
764 }
765
766 public boolean keepInParent() {
767 return mKeepInParent;
768 }
769
770 public void setKeepInParent(boolean keepInParent) {
771 mKeepInParent = keepInParent;
772 }
773
774 public boolean isRemoved() {
775 return mRemoved;
776 }
777
Adrian Roosd009ab12016-05-20 17:58:53 -0700778 public void setRemoved() {
779 mRemoved = true;
780
781 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700782 }
783
Selim Cinekd1395642016-04-28 12:22:42 -0700784 public NotificationChildrenContainer getChildrenContainer() {
785 return mChildrenContainer;
786 }
787
Selim Cinekcafa87f2016-10-26 17:00:17 -0700788 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
789 mHeadsupDisappearRunning = headsUpAnimatingAway;
790 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
791 }
792
793 /**
794 * @return if the view was just heads upped and is now animating away. During such a time the
795 * layout needs to be kept consistent
796 */
797 public boolean isHeadsUpAnimatingAway() {
798 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700799 }
800
Selim Cineke9bad242016-06-15 11:46:37 -0700801 public View getChildAfterViewWhenDismissed() {
802 return mChildAfterViewWhenDismissed;
803 }
804
805 public View getGroupParentWhenDismissed() {
806 return mGroupParentWhenDismissed;
807 }
808
Selim Cinek9e624e72016-07-20 13:46:49 -0700809 public void performDismiss() {
810 mVetoButton.performClick();
811 }
812
813 public void setOnDismissListener(OnClickListener listener) {
814 mVetoButton.setOnClickListener(listener);
815 }
816
Selim Cinek281c2022016-10-13 19:14:43 -0700817 public View getNotificationIcon() {
818 NotificationHeaderView notificationHeader = getNotificationHeader();
819 if (notificationHeader != null) {
820 return notificationHeader.getIcon();
821 }
822 return null;
823 }
824
825 /**
826 * @return whether the notification is currently showing a view with an icon.
827 */
828 public boolean isShowingIcon() {
829 if (mIsSummaryWithChildren) {
830 return true;
831 }
832 NotificationContentView showingLayout = getShowingLayout();
833 NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
834 return notificationHeader != null;
835 }
836
Selim Cinek0242fbb2016-10-19 13:38:32 -0700837 /**
838 * Set how much this notification is transformed into an icon.
839 *
Selim Cinek2b549f42016-11-22 16:38:51 -0800840 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
841 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -0800842 * @param isLastChild is this the last child in the list. If true, then the transformation is
843 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -0700844 */
Selim Cinek2b549f42016-11-22 16:38:51 -0800845 public void setContentTransformationAmount(float contentTransformationAmount,
846 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -0800847 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800848 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800849 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800850 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800851 if (changeTransformation) {
852 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -0800853 }
854 }
855
856 /**
857 * Set the icons to be visible of this notification.
858 */
859 public void setIconsVisible(boolean iconsVisible) {
860 if (iconsVisible != mIconsVisible) {
861 mIconsVisible = iconsVisible;
862 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700863 }
864 }
865
Selim Cinekdb167372016-11-17 15:41:17 -0800866 @Override
867 protected void onBelowSpeedBumpChanged() {
868 updateIconVisibilities();
869 }
870
Selim Cinek875a3a12016-11-18 17:52:16 -0800871 private void updateContentTransformation() {
872 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -0800873 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800874 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -0800875 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800876 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700877 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -0800878 translationY *= 0.4f;
879 } else {
880 contentAlpha = 1.0f;
881 }
882 mPublicLayout.setAlpha(contentAlpha);
883 mPrivateLayout.setAlpha(contentAlpha);
884 mPublicLayout.setTranslationY(translationY);
885 mPrivateLayout.setTranslationY(translationY);
886 if (mChildrenContainer != null) {
887 mChildrenContainer.setAlpha(contentAlpha);
888 mChildrenContainer.setTranslationY(translationY);
889 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -0700890 }
891 }
892
893 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -0800894 boolean visible = isChildInGroup()
895 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
896 || mIconsVisible;
Selim Cinekdb167372016-11-17 15:41:17 -0800897 mPublicLayout.setIconsVisible(visible);
898 mPrivateLayout.setIconsVisible(visible);
899 if (mChildrenContainer != null) {
900 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700901 }
902 }
903
Selim Cinek875a3a12016-11-18 17:52:16 -0800904 /**
905 * Get the relative top padding of a view relative to this view. This recursively walks up the
906 * hierarchy and does the corresponding measuring.
907 *
908 * @param view the view to the the padding for. The requested view has to be a child of this
909 * notification.
910 * @return the toppadding
911 */
912 public int getRelativeTopPadding(View view) {
913 int topPadding = 0;
914 while (view.getParent() instanceof ViewGroup) {
915 topPadding += view.getTop();
916 view = (View) view.getParent();
917 if (view instanceof ExpandableNotificationRow) {
918 return topPadding;
919 }
920 }
921 return topPadding;
922 }
923
Chris Wren78403d72014-07-28 10:23:24 +0100924 public interface ExpansionLogger {
925 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
926 }
Selim Cinek1685e632014-04-08 02:27:49 +0200927
Chris Wren51c75102013-07-16 20:49:17 -0400928 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
929 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700930 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -0800931 initDimens();
932 }
933
934 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800935 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
936 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
937 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
938 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -0800939 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800940 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Mady Mellorb0a82462016-04-30 17:31:02 -0700941 mIncreasedPaddingBetweenElements = getResources()
942 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinek875a3a12016-11-18 17:52:16 -0800943 mIconTransformContentShiftNoIcon = getResources().getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -0700944 R.dimen.notification_icon_transform_content_shift);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800945 }
946
947 /**
948 * @param dimenId the dimen to look up
949 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
950 */
951 private int getFontScaledHeight(int dimenId) {
952 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
953 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
954 getResources().getDisplayMetrics().density);
955 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -0400956 }
957
Christoph Studera7fe6312014-06-27 19:32:44 +0200958 /**
959 * Resets this view so it can be re-used for an updated notification.
960 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200961 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200962 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200963 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +0100964 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +0200965 mExpandable = false;
966 mHasUserChangedExpansion = false;
967 mUserLocked = false;
968 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200969 mSensitive = false;
970 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200971 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700972 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -0800973 mPublicLayout.reset();
974 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +0200975 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -0800976 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +0200977 logExpansionEvent(false, wasExpanded);
978 }
979
980 public void resetHeight() {
Selim Cinek31094df2014-08-14 19:28:15 +0200981 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200982 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200983 }
984
Jorim Jaggi251957d2014-04-09 04:24:09 +0200985 @Override
986 protected void onFinishInflate() {
987 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200988 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800989 mPublicLayout.setContainingNotification(this);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200990 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800991 mPrivateLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800992 mPrivateLayout.setContainingNotification(this);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800993 mPublicLayout.setExpandClickListener(mExpandClickListener);
Mady Mellor4b80b102016-01-22 08:03:58 -0800994 mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
995 mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
996 @Override
997 public void onInflate(ViewStub stub, View inflated) {
998 mSettingsIconRow = (NotificationSettingsIconRow) inflated;
999 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -07001000 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -08001001 }
1002 });
Selim Cinekab29aeb2015-02-20 18:18:32 +01001003 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1004 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001005 @Override
1006 public void onInflate(ViewStub stub, View inflated) {
1007 mGuts = (NotificationGuts) inflated;
1008 mGuts.setClipTopAmount(getClipTopAmount());
1009 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001010 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001011 }
1012 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001013 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1014 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1015
1016 @Override
1017 public void onInflate(ViewStub stub, View inflated) {
1018 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -07001019 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001020 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -08001021 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +01001022 }
1023 });
Selim Cinek863834b2014-05-20 04:20:25 +02001024 mVetoButton = findViewById(R.id.veto);
Selim Cinek9e624e72016-07-20 13:46:49 -07001025 mVetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
1026 mVetoButton.setContentDescription(mContext.getString(
1027 R.string.accessibility_remove_notification));
Mady Mellor4b80b102016-01-22 08:03:58 -08001028
1029 // Add the views that we translate to reveal the gear
1030 mTranslateableViews = new ArrayList<View>();
1031 for (int i = 0; i < getChildCount(); i++) {
1032 mTranslateableViews.add(getChildAt(i));
1033 }
1034 // Remove views that don't translate
1035 mTranslateableViews.remove(mVetoButton);
1036 mTranslateableViews.remove(mSettingsIconRowStub);
1037 mTranslateableViews.remove(mChildrenContainerStub);
1038 mTranslateableViews.remove(mGutsStub);
1039 }
1040
Selim Cinek9e624e72016-07-20 13:46:49 -07001041 public View getVetoButton() {
1042 return mVetoButton;
1043 }
1044
Mady Mellor4b80b102016-01-22 08:03:58 -08001045 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001046 if (mTranslateAnim != null) {
1047 mTranslateAnim.cancel();
1048 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001049 if (mTranslateableViews != null) {
1050 for (int i = 0; i < mTranslateableViews.size(); i++) {
1051 mTranslateableViews.get(i).setTranslationX(0);
1052 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001053 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001054 invalidateOutline();
Mady Mellor4b80b102016-01-22 08:03:58 -08001055 if (mSettingsIconRow != null) {
1056 mSettingsIconRow.resetState();
1057 }
1058 }
1059
1060 public void animateTranslateNotification(final float leftTarget) {
1061 if (mTranslateAnim != null) {
1062 mTranslateAnim.cancel();
1063 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001064 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001065 if (mTranslateAnim != null) {
1066 mTranslateAnim.start();
1067 }
1068 }
1069
1070 @Override
1071 public void setTranslation(float translationX) {
1072 if (areGutsExposed()) {
1073 // Don't translate if guts are showing.
1074 return;
1075 }
1076 // Translate the group of views
1077 for (int i = 0; i < mTranslateableViews.size(); i++) {
1078 if (mTranslateableViews.get(i) != null) {
1079 mTranslateableViews.get(i).setTranslationX(translationX);
1080 }
1081 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001082 invalidateOutline();
Mady Mellor34958fa2016-02-23 09:52:17 -08001083 if (mSettingsIconRow != null) {
1084 mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
1085 }
1086 }
1087
1088 @Override
1089 public float getTranslation() {
1090 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1091 // All of the views in the list should have same translation, just use first one.
1092 return mTranslateableViews.get(0).getTranslationX();
1093 }
1094 return 0;
1095 }
1096
1097 public Animator getTranslateViewAnimator(final float leftTarget,
1098 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001099 if (mTranslateAnim != null) {
1100 mTranslateAnim.cancel();
1101 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001102 if (areGutsExposed()) {
1103 // No translation if guts are exposed.
1104 return null;
1105 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001106 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1107 leftTarget);
1108 if (listener != null) {
1109 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001110 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001111 translateAnim.addListener(new AnimatorListenerAdapter() {
1112 boolean cancelled = false;
1113
1114 @Override
1115 public void onAnimationCancel(Animator anim) {
1116 cancelled = true;
1117 }
1118
1119 @Override
1120 public void onAnimationEnd(Animator anim) {
1121 if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
1122 mSettingsIconRow.resetState();
1123 mTranslateAnim = null;
1124 }
1125 }
1126 });
1127 mTranslateAnim = translateAnim;
1128 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001129 }
1130
1131 public float getSpaceForGear() {
1132 if (mSettingsIconRow != null) {
1133 return mSettingsIconRow.getSpaceForGear();
1134 }
1135 return 0;
1136 }
1137
1138 public NotificationSettingsIconRow getSettingsRow() {
1139 if (mSettingsIconRow == null) {
1140 mSettingsIconRowStub.inflate();
1141 }
1142 return mSettingsIconRow;
1143 }
1144
Selim Cinekab29aeb2015-02-20 18:18:32 +01001145 public void inflateGuts() {
1146 if (mGuts == null) {
1147 mGutsStub.inflate();
1148 }
1149 }
1150
Selim Cinekda42d652015-12-04 15:51:16 -08001151 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001152 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1153 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001154 if (mChildrenContainer != null) {
1155 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1156 : INVISIBLE);
Mady Mellorb0a82462016-04-30 17:31:02 -07001157 mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
1158 ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001159 : INVISIBLE);
1160 }
Selim Cinekda42d652015-12-04 15:51:16 -08001161 // The limits might have changed if the view suddenly became a group or vice versa
1162 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001163 }
1164
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001165 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001166 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1167 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001168 // Add a record for the entire layout since its content is somehow small.
1169 // The event comes from a leaf view that is interacted with.
1170 AccessibilityEvent record = AccessibilityEvent.obtain();
1171 onInitializeAccessibilityEvent(record);
1172 dispatchPopulateAccessibilityEvent(record);
1173 event.appendRecord(record);
1174 return true;
1175 }
1176 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001177 }
Chris Wren51c75102013-07-16 20:49:17 -04001178
John Spurlocke15452b2014-08-21 09:44:39 -04001179 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001180 public void setDark(boolean dark, boolean fade, long delay) {
1181 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001182 final NotificationContentView showing = getShowingLayout();
1183 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001184 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001185 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001186 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001187 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001188 }
John Spurlocke15452b2014-08-21 09:44:39 -04001189 }
1190
Chris Wren51c75102013-07-16 20:49:17 -04001191 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001192 if (mIsSummaryWithChildren && !mShowingPublic) {
1193 return !mChildrenExpanded;
1194 }
Chris Wren51c75102013-07-16 20:49:17 -04001195 return mExpandable;
1196 }
1197
1198 public void setExpandable(boolean expandable) {
1199 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001200 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001201 }
1202
Selim Cinek4ffd6362015-12-29 15:12:23 +01001203 @Override
1204 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001205 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1206 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001207 }
1208
Selim Cinek1685e632014-04-08 02:27:49 +02001209 /**
1210 * @return whether the user has changed the expansion state
1211 */
1212 public boolean hasUserChangedExpansion() {
1213 return mHasUserChangedExpansion;
1214 }
1215
Chris Wren51c75102013-07-16 20:49:17 -04001216 public boolean isUserExpanded() {
1217 return mUserExpanded;
1218 }
1219
Selim Cinek1685e632014-04-08 02:27:49 +02001220 /**
1221 * Set this notification to be expanded by the user
1222 *
1223 * @param userExpanded whether the user wants this notification to be expanded
1224 */
Chris Wren51c75102013-07-16 20:49:17 -04001225 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001226 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1227 }
1228
1229 /**
1230 * Set this notification to be expanded by the user
1231 *
1232 * @param userExpanded whether the user wants this notification to be expanded
1233 * @param allowChildExpansion whether a call to this method allows expanding children
1234 */
1235 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001236 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -07001237 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
Chris Wren698b1702016-05-23 11:16:32 -04001238 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001239 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Chris Wren698b1702016-05-23 11:16:32 -04001240 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001241 return;
1242 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001243 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001244 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001245 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001246 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001247 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001248 }
1249
Selim Cinekccd14fb2014-08-12 18:53:24 +02001250 public void resetUserExpansion() {
1251 mHasUserChangedExpansion = false;
1252 mUserExpanded = false;
1253 }
1254
Chris Wren51c75102013-07-16 20:49:17 -04001255 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001256 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001257 }
1258
1259 public void setUserLocked(boolean userLocked) {
1260 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001261 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001262 if (mIsSummaryWithChildren) {
1263 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek7baaa9e2016-07-21 17:21:09 -07001264 if (userLocked || !isGroupExpanded()) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001265 updateBackgroundForGroupState();
1266 }
Selim Cinek42357e02016-02-24 18:48:01 -08001267 }
Chris Wren51c75102013-07-16 20:49:17 -04001268 }
1269
Selim Cinek1685e632014-04-08 02:27:49 +02001270 /**
1271 * @return has the system set this notification to be expanded
1272 */
1273 public boolean isSystemExpanded() {
1274 return mIsSystemExpanded;
1275 }
1276
1277 /**
1278 * Set this notification to be expanded by the system.
1279 *
1280 * @param expand whether the system wants this notification to be expanded.
1281 */
1282 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001283 if (expand != mIsSystemExpanded) {
1284 final boolean wasExpanded = isExpanded();
1285 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001286 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001287 logExpansionEvent(false, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001288 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001289 mChildrenContainer.updateGroupOverflow();
1290 }
Selim Cinek31094df2014-08-14 19:28:15 +02001291 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001292 }
1293
1294 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001295 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001296 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001297 public void setOnKeyguard(boolean onKeyguard) {
1298 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001299 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001300 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001301 logExpansionEvent(false, wasExpanded);
1302 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001303 if (mIsSummaryWithChildren) {
1304 mChildrenContainer.updateGroupOverflow();
1305 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001306 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001307 }
1308 }
Selim Cinek1685e632014-04-08 02:27:49 +02001309 }
1310
1311 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001312 * @return Can the underlying notification be cleared? This can be different from whether the
1313 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1314 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001315 */
1316 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001317 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1318 return false;
1319 }
1320 if (mIsSummaryWithChildren) {
1321 List<ExpandableNotificationRow> notificationChildren =
1322 mChildrenContainer.getNotificationChildren();
1323 for (int i = 0; i < notificationChildren.size(); i++) {
1324 ExpandableNotificationRow child = notificationChildren.get(i);
1325 if (!child.isClearable()) {
1326 return false;
1327 }
1328 }
1329 }
1330 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001331 }
1332
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001333 @Override
1334 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001335 if (isUserLocked()) {
1336 return getActualHeight();
1337 }
Selim Cinekd84a5932015-12-15 11:45:36 -08001338 if (mGuts != null && mGuts.areGutsExposed()) {
1339 return mGuts.getHeight();
1340 } else if ((isChildInGroup() && !isGroupExpanded())) {
1341 return mPrivateLayout.getMinHeight();
1342 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1343 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001344 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001345 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek73cf02a2016-06-17 13:08:00 -07001346 } else if (mIsHeadsUp || mHeadsupDisappearRunning) {
1347 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001348 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1349 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001350 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001351 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001352 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001353 }
Selim Cinek31aada42015-12-18 17:51:15 -08001354 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001355 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001356 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001357 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001358 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001359 }
Selim Cinek1685e632014-04-08 02:27:49 +02001360
Mady Mellorb0a82462016-04-30 17:31:02 -07001361 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001362 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001363 }
1364
Selim Cinek263398f2015-10-21 17:40:23 -07001365 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001366 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001367 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1368 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
1369 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
1370 mEntry.notification);
Selim Cinek263398f2015-10-21 17:40:23 -07001371 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001372 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001373 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001374 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001375 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001376 }
1377
Mady Mellorb0a82462016-04-30 17:31:02 -07001378 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001379 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001380 mChildrenContainer.updateChildrenHeaderAppearance();
1381 }
1382 }
1383
Selim Cinek1685e632014-04-08 02:27:49 +02001384 /**
1385 * Check whether the view state is currently expanded. This is given by the system in {@link
1386 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1387 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1388 * view can differ from this state, if layout params are modified from outside.
1389 *
1390 * @return whether the view state is currently expanded.
1391 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001392 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001393 return isExpanded(false /* allowOnKeyguard */);
1394 }
1395
1396 public boolean isExpanded(boolean allowOnKeyguard) {
1397 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001398 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1399 || isUserExpanded());
1400 }
1401
1402 private boolean isSystemChildExpanded() {
1403 return mIsSystemChildExpanded;
1404 }
1405
1406 public void setSystemChildExpanded(boolean expanded) {
1407 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001408 }
1409
1410 @Override
1411 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1412 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001413 updateMaxHeights();
Mady Mellora6edc872016-04-26 11:01:03 -07001414 if (mSettingsIconRow != null) {
1415 mSettingsIconRow.updateVerticalLocation();
1416 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001417 updateContentShiftHeight();
1418 }
1419
1420 /**
1421 * Updates the content shift height such that the header is completely hidden when coming from
1422 * the top.
1423 */
1424 private void updateContentShiftHeight() {
1425 NotificationHeaderView notificationHeader = getNotificationHeader();
1426 if (notificationHeader != null) {
1427 CachingIconView icon = notificationHeader.getIcon();
1428 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1429 } else {
1430 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1431 }
Selim Cinek1685e632014-04-08 02:27:49 +02001432 }
1433
Selim Cinek8d490d42015-04-10 00:05:50 -07001434 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001435 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001436 View expandedChild = mPrivateLayout.getExpandedChild();
1437 if (expandedChild == null) {
1438 expandedChild = mPrivateLayout.getContractedChild();
1439 }
1440 mMaxExpandHeight = expandedChild.getHeight();
1441 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001442 if (headsUpChild == null) {
1443 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001444 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001445 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001446 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001447 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001448 }
1449 }
1450
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001451 @Override
1452 public void notifyHeightChanged(boolean needsAnimation) {
1453 super.notifyHeightChanged(needsAnimation);
1454 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1455 }
1456
Selim Cinek3c76d502016-02-19 15:16:33 -08001457 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001458 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001459 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001460 }
1461
1462 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001463 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001464 if (mIsSummaryWithChildren) {
1465 List<ExpandableNotificationRow> notificationChildren =
1466 mChildrenContainer.getNotificationChildren();
1467 for (int i = 0; i < notificationChildren.size(); i++) {
1468 ExpandableNotificationRow child = notificationChildren.get(i);
1469 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1470 }
1471 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001472 }
1473
1474 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1475 long duration) {
1476 boolean oldShowingPublic = mShowingPublic;
1477 mShowingPublic = mSensitive && hideSensitive;
1478 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1479 return;
1480 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001481
1482 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001483 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001484
Jorim Jaggiae441282014-08-01 02:45:18 +02001485 if (!animated) {
1486 mPublicLayout.animate().cancel();
1487 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001488 if (mChildrenContainer != null) {
1489 mChildrenContainer.animate().cancel();
1490 mChildrenContainer.setAlpha(1f);
1491 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001492 mPublicLayout.setAlpha(1f);
1493 mPrivateLayout.setAlpha(1f);
1494 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001495 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001496 } else {
1497 animateShowingPublic(delay, duration);
1498 }
Selim Cinekc3179332016-03-04 14:44:56 -08001499 NotificationContentView showingLayout = getShowingLayout();
1500 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001501 mPrivateLayout.updateExpandButtons(isExpandable());
Jorim Jaggiae441282014-08-01 02:45:18 +02001502 mShowingPublicInitialized = true;
1503 }
1504
1505 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001506 View[] privateViews = mIsSummaryWithChildren
1507 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001508 : new View[] {mPrivateLayout};
1509 View[] publicViews = new View[] {mPublicLayout};
1510 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1511 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1512 for (final View hiddenView : hiddenChildren) {
1513 hiddenView.setVisibility(View.VISIBLE);
1514 hiddenView.animate().cancel();
1515 hiddenView.animate()
1516 .alpha(0f)
1517 .setStartDelay(delay)
1518 .setDuration(duration)
1519 .withEndAction(new Runnable() {
1520 @Override
1521 public void run() {
1522 hiddenView.setVisibility(View.INVISIBLE);
1523 }
1524 });
1525 }
1526 for (View showView : shownChildren) {
1527 showView.setVisibility(View.VISIBLE);
1528 showView.setAlpha(0f);
1529 showView.animate().cancel();
1530 showView.animate()
1531 .alpha(1f)
1532 .setStartDelay(delay)
1533 .setDuration(duration);
1534 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001535 }
1536
Selim Cinek3776fe02016-02-04 13:32:43 -08001537 public boolean mustStayOnScreen() {
1538 return mIsHeadsUp;
1539 }
1540
Selim Cinek9e624e72016-07-20 13:46:49 -07001541 /**
1542 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1543 * otherwise some state might not be updated. To request about the general clearability
1544 * see {@link #isClearable()}.
1545 */
1546 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001547 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001548 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001549
Ricky Waicd35def2016-05-03 11:07:07 +01001550 public void makeActionsVisibile() {
1551 setUserExpanded(true, true);
1552 if (isChildInGroup()) {
1553 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1554 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001555 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001556 }
1557
Selim Cinekb5605e52015-02-20 18:21:41 +01001558 public void setChildrenExpanded(boolean expanded, boolean animate) {
1559 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001560 if (mChildrenContainer != null) {
1561 mChildrenContainer.setChildrenExpanded(expanded);
1562 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001563 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001564 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001565 }
1566
Selim Cinekb5605e52015-02-20 18:21:41 +01001567 public static void applyTint(View v, int color) {
1568 int alpha;
1569 if (color != 0) {
1570 alpha = COLORED_DIVIDER_ALPHA;
1571 } else {
1572 color = 0xff000000;
1573 alpha = DEFAULT_DIVIDER_ALPHA;
1574 }
1575 if (v.getBackground() instanceof ColorDrawable) {
1576 ColorDrawable background = (ColorDrawable) v.getBackground();
1577 background.mutate();
1578 background.setColor(color);
1579 background.setAlpha(alpha);
1580 }
1581 }
1582
Selim Cinek1685e632014-04-08 02:27:49 +02001583 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001584 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001585 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001586
Mady Mellor34958fa2016-02-23 09:52:17 -08001587 public boolean areGutsExposed() {
1588 return (mGuts != null && mGuts.areGutsExposed());
1589 }
1590
Jorim Jaggibe565df2014-04-28 17:51:23 +02001591 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001592 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001593 NotificationContentView showingLayout = getShowingLayout();
1594 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001595 }
1596
1597 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001598 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001599 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001600 return mChildrenContainer;
1601 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001602 return getShowingLayout();
1603 }
1604
1605 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001606 protected void onAppearAnimationFinished(boolean wasAppearing) {
1607 super.onAppearAnimationFinished(wasAppearing);
1608 if (wasAppearing) {
1609 // During the animation the visible view might have changed, so let's make sure all
1610 // alphas are reset
1611 if (mChildrenContainer != null) {
1612 mChildrenContainer.setAlpha(1.0f);
1613 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1614 }
1615 mPrivateLayout.setAlpha(1.0f);
1616 mPrivateLayout.setLayerType(LAYER_TYPE_NONE, null);
1617 mPublicLayout.setAlpha(1.0f);
1618 mPublicLayout.setLayerType(LAYER_TYPE_NONE, null);
1619 }
1620 }
1621
1622 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001623 public int getExtraBottomPadding() {
1624 if (mIsSummaryWithChildren && isGroupExpanded()) {
1625 return mIncreasedPaddingBetweenElements;
1626 }
1627 return 0;
1628 }
1629
1630 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001631 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001632 super.setActualHeight(height, notifyListeners);
Mady Mellorb53bc272016-02-11 18:28:23 -08001633 if (mGuts != null && mGuts.areGutsExposed()) {
1634 mGuts.setActualHeight(height);
1635 return;
1636 }
Selim Cinekeef84282015-10-30 16:28:00 -07001637 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +01001638 mPrivateLayout.setContentHeight(contentHeight);
1639 mPublicLayout.setContentHeight(contentHeight);
Selim Cinek42357e02016-02-24 18:48:01 -08001640 if (mIsSummaryWithChildren) {
1641 mChildrenContainer.setActualHeight(height);
1642 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001643 if (mGuts != null) {
1644 mGuts.setActualHeight(height);
1645 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001646 }
1647
1648 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001649 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001650 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001651 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001652 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001653 NotificationContentView showingLayout = getShowingLayout();
1654 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001655 }
1656
1657 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001658 public int getMinHeight() {
Selim Cinek31aada42015-12-18 17:51:15 -08001659 if (mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
1660 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1661 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001662 return mChildrenContainer.getMinHeight();
Selim Cinek31aada42015-12-18 17:51:15 -08001663 } else if (mIsHeadsUp) {
1664 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001665 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001666 NotificationContentView showingLayout = getShowingLayout();
1667 return showingLayout.getMinHeight();
1668 }
1669
1670 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001671 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001672 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001673 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001674 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001675 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001676 }
1677
1678 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001679 public void setClipTopAmount(int clipTopAmount) {
1680 super.setClipTopAmount(clipTopAmount);
1681 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001682 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001683 if (mGuts != null) {
1684 mGuts.setClipTopAmount(clipTopAmount);
1685 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001686 }
1687
Selim Cineka686b2c2016-10-26 13:58:27 -07001688 @Override
1689 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001690 if (clipBottomAmount != mClipBottomAmount) {
1691 super.setClipBottomAmount(clipBottomAmount);
1692 mPrivateLayout.setClipBottomAmount(clipBottomAmount);
1693 mPublicLayout.setClipBottomAmount(clipBottomAmount);
1694 if (mGuts != null) {
1695 mGuts.setClipBottomAmount(clipBottomAmount);
1696 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001697 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001698 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001699 // We have to update this even if it hasn't changed, since the children locations can
1700 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001701 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
1702 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001703 }
1704
Selim Cinek31094df2014-08-14 19:28:15 +02001705 public boolean isMaxExpandHeightInitialized() {
1706 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001707 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001708
Selim Cinek42357e02016-02-24 18:48:01 -08001709 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001710 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1711 }
Chris Wren78403d72014-07-28 10:23:24 +01001712
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001713 @Override
1714 public void setShowingLegacyBackground(boolean showing) {
1715 super.setShowingLegacyBackground(showing);
1716 mPrivateLayout.setShowingLegacyBackground(showing);
1717 mPublicLayout.setShowingLegacyBackground(showing);
1718 }
1719
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001720 @Override
1721 protected void updateBackgroundTint() {
1722 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001723 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001724 if (mIsSummaryWithChildren) {
1725 List<ExpandableNotificationRow> notificationChildren =
1726 mChildrenContainer.getNotificationChildren();
1727 for (int i = 0; i < notificationChildren.size(); i++) {
1728 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001729 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001730 }
1731 }
1732 }
1733
Mady Mellorb0a82462016-04-30 17:31:02 -07001734 /**
1735 * Called when a group has finished animating from collapsed or expanded state.
1736 */
1737 public void onFinishedExpansionChange() {
1738 mGroupExpansionChanging = false;
1739 updateBackgroundForGroupState();
1740 }
1741
1742 /**
1743 * Updates the parent and children backgrounds in a group based on the expansion state.
1744 */
1745 public void updateBackgroundForGroupState() {
1746 if (mIsSummaryWithChildren) {
1747 // Only when the group has finished expanding do we hide its background.
1748 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1749 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1750 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1751 for (int i = 0; i < children.size(); i++) {
1752 children.get(i).updateBackgroundForGroupState();
1753 }
1754 } else if (isChildInGroup()) {
1755 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
1756 // Only show a background if the group is expanded OR if it is expanding / collapsing
1757 // and has a custom background color
1758 final boolean showBackground = isGroupExpanded()
1759 || ((mNotificationParent.isGroupExpansionChanging()
1760 || mNotificationParent.isUserLocked()) && childColor != 0);
1761 mShowNoBackground = !showBackground;
1762 } else {
1763 // Only children or parents ever need no background.
1764 mShowNoBackground = false;
1765 }
1766 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001767 updateBackground();
1768 }
1769
Adrian Roos4a579672016-05-24 16:54:37 -07001770 public int getPositionOfChild(ExpandableNotificationRow childRow) {
1771 if (mIsSummaryWithChildren) {
1772 return mChildrenContainer.getPositionInLinearLayout(childRow);
1773 }
1774 return 0;
1775 }
1776
Chris Wren78403d72014-07-28 10:23:24 +01001777 public void setExpansionLogger(ExpansionLogger logger, String key) {
1778 mLogger = logger;
1779 mLoggingKey = key;
1780 }
1781
Chris Wren6abeeb92016-05-26 14:44:38 -04001782 public void onExpandedByGesture(boolean userExpanded) {
1783 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
1784 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
1785 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
1786 }
1787 MetricsLogger.action(mContext, event, userExpanded);
1788 }
1789
Selim Cinek6183d122016-01-14 18:48:41 -08001790 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001791 public float getIncreasedPaddingAmount() {
1792 if (mIsSummaryWithChildren) {
1793 if (isGroupExpanded()) {
1794 return 1.0f;
1795 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001796 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001797 }
1798 }
1799 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001800 }
1801
1802 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001803 protected boolean disallowSingleClick(MotionEvent event) {
1804 float x = event.getX();
1805 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001806 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001807 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001808 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001809 }
1810 return super.disallowSingleClick(event);
1811 }
1812
Chris Wren78403d72014-07-28 10:23:24 +01001813 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04001814 boolean nowExpanded = isExpanded();
1815 if (mIsSummaryWithChildren) {
1816 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
1817 }
Chris Wren78403d72014-07-28 10:23:24 +01001818 if (wasExpanded != nowExpanded && mLogger != null) {
1819 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1820 }
1821 }
Selim Cinek570981d2015-12-01 11:37:01 -08001822
Selim Cineke9bad242016-06-15 11:46:37 -07001823 @Override
1824 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1825 super.onInitializeAccessibilityNodeInfoInternal(info);
1826 if (canViewBeDismissed()) {
1827 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
1828 }
1829 }
1830
1831 @Override
1832 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
1833 if (super.performAccessibilityActionInternal(action, arguments)) {
1834 return true;
1835 }
1836 switch (action) {
1837 case AccessibilityNodeInfo.ACTION_DISMISS:
1838 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
1839 true /* fromAccessibility */);
1840 return true;
1841 }
1842 return false;
1843 }
1844
1845 public boolean shouldRefocusOnDismiss() {
1846 return mRefocusOnDismiss || isAccessibilityFocused();
1847 }
1848
Selim Cinek570981d2015-12-01 11:37:01 -08001849 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001850 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001851 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001852
1853 @Override
1854 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
1855 return new NotificationViewState(stackScrollState);
1856 }
1857
Selim Cinekd127d792016-11-01 19:11:41 -07001858 @Override
1859 public boolean isAboveShelf() {
1860 return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
1861 }
1862
1863 public void setAboveShelf(boolean aboveShelf) {
1864 mAboveShelf = aboveShelf;
1865 }
1866
Selim Cinek0cfbef42016-11-09 19:06:36 -08001867 public class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08001868
1869 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07001870
Selim Cinekbbcebde2016-11-09 18:28:20 -08001871
1872 private NotificationViewState(StackScrollState stackScrollState) {
1873 mOverallState = stackScrollState;
1874 }
1875
1876 @Override
1877 public void applyToView(View view) {
1878 super.applyToView(view);
1879 if (view instanceof ExpandableNotificationRow) {
1880 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinekbbcebde2016-11-09 18:28:20 -08001881 row.applyChildrenState(mOverallState);
1882 }
1883 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08001884
1885 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08001886 protected void onYTranslationAnimationFinished(View view) {
1887 super.onYTranslationAnimationFinished(view);
Selim Cinek0cfbef42016-11-09 19:06:36 -08001888 if (mHeadsupDisappearRunning) {
Selim Cinekcafa87f2016-10-26 17:00:17 -07001889 setHeadsUpAnimatingAway(false);
Selim Cinek0cfbef42016-11-09 19:06:36 -08001890 }
1891 }
1892
1893 @Override
1894 public void animateTo(View child, AnimationProperties properties) {
1895 super.animateTo(child, properties);
1896 if (child instanceof ExpandableNotificationRow) {
1897 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
1898 row.startChildAnimation(mOverallState, properties);
1899 }
1900 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001901 }
Chris Wren51c75102013-07-16 20:49:17 -04001902}