blob: 8ae84cf3515b28abb6cbee027b930f086b738a71 [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 Cineka7d4f822016-12-06 14:34:47 -080054import com.android.systemui.statusbar.notification.VisualStabilityManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010055import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinek31aada42015-12-18 17:51:15 -080056import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek0cfbef42016-11-09 19:06:36 -080057import com.android.systemui.statusbar.stack.AnimationProperties;
58import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010059import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070060import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010061import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010062
Mady Mellor4b80b102016-01-22 08:03:58 -080063import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010064import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050065
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020066public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010067
68 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
69 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Selim Cinek0242fbb2016-10-19 13:38:32 -070070 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -080071 private int mIconTransformContentShiftNoIcon;
Selim Cinek01af3342016-02-09 19:25:31 -080072 private int mNotificationMinHeightLegacy;
73 private int mMaxHeadsUpHeightLegacy;
74 private int mMaxHeadsUpHeight;
75 private int mNotificationMinHeight;
76 private int mNotificationMaxHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -070077 private int mIncreasedPaddingBetweenElements;
Chris Wren51c75102013-07-16 20:49:17 -040078
Selim Cinek1685e632014-04-08 02:27:49 +020079 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040080 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020081 /** Has the user actively changed the expansion state of this row */
82 private boolean mHasUserChangedExpansion;
83 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040084 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -080085
86 /**
87 * Has this notification been expanded while it was pinned
88 */
89 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +020090 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040091 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020092 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050093 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020094 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -080095 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +020096 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -070097 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -040098
Selim Cinek1685e632014-04-08 02:27:49 +020099 /**
100 * Is this notification expanded by the system. The expansion state can be overridden by the
101 * user expansion.
102 */
103 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200104
105 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700106 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200107 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700108 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200109
Mady Mellorb0a82462016-04-30 17:31:02 -0700110 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800111 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200112 private NotificationContentView mPublicLayout;
113 private NotificationContentView mPrivateLayout;
Selim Cinek1685e632014-04-08 02:27:49 +0200114 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700115 private int mHeadsUpHeight;
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;
Selim Cineke9079112016-12-14 14:41:01 -0800200 private Runnable mOnDismissRunnable;
Mady Mellorb0a82462016-04-30 17:31:02 -0700201
202 public boolean isGroupExpansionChanging() {
203 if (isChildInGroup()) {
204 return mNotificationParent.isGroupExpansionChanging();
205 }
206 return mGroupExpansionChanging;
207 }
208
209 public void setGroupExpansionChanging(boolean changing) {
210 mGroupExpansionChanging = changing;
211 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700212
Adrian Roos599be342016-06-13 14:54:39 -0700213 @Override
214 public void setActualHeightAnimating(boolean animating) {
215 if (mPrivateLayout != null) {
216 mPrivateLayout.setContentHeightAnimating(animating);
217 }
218 }
219
Selim Cinek8d490d42015-04-10 00:05:50 -0700220 public NotificationContentView getPrivateLayout() {
221 return mPrivateLayout;
222 }
223
224 public NotificationContentView getPublicLayout() {
225 return mPublicLayout;
226 }
227
Selim Cinekcab4a602014-09-03 14:47:57 +0200228 public void setIconAnimationRunning(boolean running) {
229 setIconAnimationRunning(running, mPublicLayout);
230 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800231 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700232 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800233 List<ExpandableNotificationRow> notificationChildren =
234 mChildrenContainer.getNotificationChildren();
235 for (int i = 0; i < notificationChildren.size(); i++) {
236 ExpandableNotificationRow child = notificationChildren.get(i);
237 child.setIconAnimationRunning(running);
238 }
239 }
240 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200241 }
242
243 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
244 if (layout != null) {
245 View contractedChild = layout.getContractedChild();
246 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700247 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200248 setIconAnimationRunningForChild(running, contractedChild);
249 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700250 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200251 }
252 }
253
254 private void setIconAnimationRunningForChild(boolean running, View child) {
255 if (child != null) {
256 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
257 setIconRunning(icon, running);
258 ImageView rightIcon = (ImageView) child.findViewById(
259 com.android.internal.R.id.right_icon);
260 setIconRunning(rightIcon, running);
261 }
262 }
263
264 private void setIconRunning(ImageView imageView, boolean running) {
265 if (imageView != null) {
266 Drawable drawable = imageView.getDrawable();
267 if (drawable instanceof AnimationDrawable) {
268 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
269 if (running) {
270 animationDrawable.start();
271 } else {
272 animationDrawable.stop();
273 }
274 } else if (drawable instanceof AnimatedVectorDrawable) {
275 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
276 if (running) {
277 animationDrawable.start();
278 } else {
279 animationDrawable.stop();
280 }
281 }
282 }
283 }
284
Selim Cinekda42d652015-12-04 15:51:16 -0800285 public void onNotificationUpdated(NotificationData.Entry entry) {
286 mEntry = entry;
287 mStatusBarNotification = entry.notification;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800288 mPrivateLayout.onNotificationUpdated(entry);
289 mPublicLayout.onNotificationUpdated(entry);
Selim Cinek757d8792016-01-28 16:21:08 -0800290 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700291 updateNotificationColor();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800292 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700293 mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
Selim Cinekc897bd32016-03-18 17:32:31 -0700294 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800295 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800296 if (mIconAnimationRunning) {
297 setIconAnimationRunning(true);
298 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800299 if (mNotificationParent != null) {
300 mNotificationParent.updateChildrenHeaderAppearance();
301 }
Selim Cinek263398f2015-10-21 17:40:23 -0700302 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800303 // The public layouts expand button is always visible
304 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800305 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700306 updateIconVisibilities();
Selim Cinekda42d652015-12-04 15:51:16 -0800307 }
308
309 private void updateLimits() {
Selim Cineka1744872016-03-11 15:36:06 -0800310 updateLimitsForView(mPrivateLayout);
311 updateLimitsForView(mPublicLayout);
312 }
313
314 private void updateLimitsForView(NotificationContentView layout) {
315 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800316 != com.android.internal.R.id.status_bar_latest_event_content;
317 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
318 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
319 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800320 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
321 layout.getHeadsUpChild().getId()
322 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek77019c72015-12-09 10:18:02 -0800323 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
324 : mMaxHeadsUpHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800325 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200326 }
327
328 public StatusBarNotification getStatusBarNotification() {
329 return mStatusBarNotification;
330 }
331
Selim Cinek281c2022016-10-13 19:14:43 -0700332 public NotificationData.Entry getEntry() {
333 return mEntry;
334 }
335
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700336 public boolean isHeadsUp() {
337 return mIsHeadsUp;
338 }
339
Selim Cinek1a521f32014-11-03 17:39:29 +0100340 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700341 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100342 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700343 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700344 if (mIsSummaryWithChildren) {
345 // The overflow might change since we allow more lines as HUN.
346 mChildrenContainer.updateGroupOverflow();
347 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700348 if (intrinsicBefore != getIntrinsicHeight()) {
349 notifyHeightChanged(false /* needsAnimation */);
350 }
Selim Cinekd127d792016-11-01 19:11:41 -0700351 if (isHeadsUp) {
352 setAboveShelf(true);
353 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100354 }
355
Selim Cinekb5605e52015-02-20 18:21:41 +0100356 public void setGroupManager(NotificationGroupManager groupManager) {
357 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700358 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100359 }
360
Adrian Roosb88b1a12015-12-09 18:51:05 -0800361 public void setRemoteInputController(RemoteInputController r) {
362 mPrivateLayout.setRemoteInputController(r);
363 }
364
Mady Mellor3fd273e2016-03-15 21:08:14 -0700365 public void setAppName(String appName) {
366 mAppName = appName;
367 if (mSettingsIconRow != null) {
368 mSettingsIconRow.setAppName(mAppName);
369 }
370 }
371
Selim Cinekb5605e52015-02-20 18:21:41 +0100372 public void addChildNotification(ExpandableNotificationRow row) {
373 addChildNotification(row, -1);
374 }
375
376 /**
377 * Add a child notification to this view.
378 *
379 * @param row the row to add
380 * @param childIndex the index to add it at, if -1 it will be added at the end
381 */
382 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
383 if (mChildrenContainer == null) {
384 mChildrenContainerStub.inflate();
385 }
386 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700387 onChildrenCountChanged();
388 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100389 }
390
391 public void removeChildNotification(ExpandableNotificationRow row) {
392 if (mChildrenContainer != null) {
393 mChildrenContainer.removeNotification(row);
394 }
Selim Cinek263398f2015-10-21 17:40:23 -0700395 onChildrenCountChanged();
396 row.setIsChildInGroup(false, null);
397 }
398
399 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700400 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700401 }
402
Selim Cinek388df6d2015-10-22 13:25:11 -0700403 public ExpandableNotificationRow getNotificationParent() {
404 return mNotificationParent;
405 }
406
Selim Cinek263398f2015-10-21 17:40:23 -0700407 /**
408 * @param isChildInGroup Is this notification now in a group
409 * @param parent the new parent notification
410 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700411 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
412 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
413 mNotificationParent = childInGroup ? parent : null;
414 mPrivateLayout.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400415 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700416 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700417 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700418 if (mNotificationParent != null) {
419 mNotificationParent.updateBackgroundForGroupState();
420 }
Selim Cinekdb167372016-11-17 15:41:17 -0800421 updateIconVisibilities();
Selim Cinek34d93b02015-10-22 12:30:38 -0700422 }
423
424 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800425 public boolean onTouchEvent(MotionEvent event) {
426 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
427 || !isChildInGroup() || isGroupExpanded()) {
428 return super.onTouchEvent(event);
429 } else {
430 return false;
431 }
432 }
433
434 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800435 protected boolean handleSlideBack() {
436 if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
437 animateTranslateNotification(0 /* targetLeft */);
438 return true;
439 }
440 return false;
441 }
442
443 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700444 protected boolean shouldHideBackground() {
445 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700446 }
447
448 @Override
449 public boolean isSummaryWithChildren() {
450 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100451 }
452
453 @Override
454 public boolean areChildrenExpanded() {
455 return mChildrenExpanded;
456 }
457
458 public List<ExpandableNotificationRow> getNotificationChildren() {
459 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
460 }
461
Selim Cinekeef84282015-10-30 16:28:00 -0700462 public int getNumberOfNotificationChildren() {
463 if (mChildrenContainer == null) {
464 return 0;
465 }
466 return mChildrenContainer.getNotificationChildren().size();
467 }
468
Selim Cinekb5605e52015-02-20 18:21:41 +0100469 /**
470 * Apply the order given in the list to the children.
471 *
472 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800473 * @param visualStabilityManager
474 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100475 * @return whether the list order has changed
476 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800477 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
478 VisualStabilityManager visualStabilityManager,
479 VisualStabilityManager.Callback callback) {
480 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
481 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100482 }
483
484 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700485 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800486 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100487 mChildrenContainer.getState(resultState, parentState);
488 }
489 }
490
491 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700492 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100493 mChildrenContainer.applyState(state);
494 }
495 }
496
497 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700498 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100499 mChildrenContainer.prepareExpansionChanged(state);
500 }
501 }
502
Selim Cinek0cfbef42016-11-09 19:06:36 -0800503 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700504 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800505 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100506 }
507 }
508
509 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800510 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100511 return this;
512 } else {
513 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
514 return view == null ? this : view;
515 }
516 }
517
Selim Cinekab29aeb2015-02-20 18:18:32 +0100518 public NotificationGuts getGuts() {
519 return mGuts;
520 }
521
Selim Cinek684a4422015-04-15 16:18:39 -0700522 /**
523 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
524 * the notification will be rendered on top of the screen.
525 *
526 * @param pinned whether it is pinned
527 */
528 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700529 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700530 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700531 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700532 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700533 }
Selim Cinek31aada42015-12-18 17:51:15 -0800534 if (pinned) {
535 setIconAnimationRunning(true);
536 mExpandedWhenPinned = false;
537 } else if (mExpandedWhenPinned) {
538 setUserExpanded(true);
539 }
Selim Cinek98713a42015-09-21 15:47:20 +0200540 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700541 }
542
Selim Cinek684a4422015-04-15 16:18:39 -0700543 public boolean isPinned() {
544 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700545 }
546
Selim Cinekd127d792016-11-01 19:11:41 -0700547 @Override
548 public int getPinnedHeadsUpHeight() {
549 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
550 }
551
Selim Cinek31aada42015-12-18 17:51:15 -0800552 /**
553 * @param atLeastMinHeight should the value returned be at least the minimum height.
554 * Used to avoid cyclic calls
555 * @return the height of the heads up notification when pinned
556 */
Selim Cinekd127d792016-11-01 19:11:41 -0700557 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800558 if (mIsSummaryWithChildren) {
559 return mChildrenContainer.getIntrinsicHeight();
560 }
Selim Cinek31aada42015-12-18 17:51:15 -0800561 if(mExpandedWhenPinned) {
562 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
563 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700564 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800565 } else {
566 return mHeadsUpHeight;
567 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700568 }
569
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700570 /**
571 * Mark whether this notification was just clicked, i.e. the user has just clicked this
572 * notification in this frame.
573 */
574 public void setJustClicked(boolean justClicked) {
575 mJustClicked = justClicked;
576 }
577
578 /**
579 * @return true if this notification has been clicked in this frame, false otherwise
580 */
581 public boolean wasJustClicked() {
582 return mJustClicked;
583 }
584
Selim Cinek98713a42015-09-21 15:47:20 +0200585 public void setChronometerRunning(boolean running) {
586 mLastChronometerRunning = running;
587 setChronometerRunning(running, mPrivateLayout);
588 setChronometerRunning(running, mPublicLayout);
589 if (mChildrenContainer != null) {
590 List<ExpandableNotificationRow> notificationChildren =
591 mChildrenContainer.getNotificationChildren();
592 for (int i = 0; i < notificationChildren.size(); i++) {
593 ExpandableNotificationRow child = notificationChildren.get(i);
594 child.setChronometerRunning(running);
595 }
596 }
597 }
598
599 private void setChronometerRunning(boolean running, NotificationContentView layout) {
600 if (layout != null) {
601 running = running || isPinned();
602 View contractedChild = layout.getContractedChild();
603 View expandedChild = layout.getExpandedChild();
604 View headsUpChild = layout.getHeadsUpChild();
605 setChronometerRunningForChild(running, contractedChild);
606 setChronometerRunningForChild(running, expandedChild);
607 setChronometerRunningForChild(running, headsUpChild);
608 }
609 }
610
611 private void setChronometerRunningForChild(boolean running, View child) {
612 if (child != null) {
613 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
614 if (chronometer instanceof Chronometer) {
615 ((Chronometer) chronometer).setStarted(running);
616 }
617 }
618 }
619
Selim Cinekea4bef72015-12-02 15:51:10 -0800620 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700621 if (mIsSummaryWithChildren) {
622 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700623 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800624 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700625 }
626
Selim Cinek34eda5e2016-02-18 17:10:43 -0800627 private NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700628 if (mIsSummaryWithChildren && !mShowingPublic) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700629 return mChildrenContainer.getHeaderView();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800630 }
631 return getShowingLayout().getVisibleNotificationHeader();
632 }
633
Selim Cinek570981d2015-12-01 11:37:01 -0800634 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
635 mOnExpandClickListener = onExpandClickListener;
636 }
637
Selim Cinekddf1b392016-05-27 16:33:10 -0700638 @Override
639 public void setOnClickListener(@Nullable OnClickListener l) {
640 super.setOnClickListener(l);
641 mOnClickListener = l;
642 updateClickAndFocus();
643 }
644
645 private void updateClickAndFocus() {
646 boolean normalChild = !isChildInGroup() || isGroupExpanded();
647 boolean clickable = mOnClickListener != null && normalChild;
648 if (isFocusable() != normalChild) {
649 setFocusable(normalChild);
650 }
651 if (isClickable() != clickable) {
652 setClickable(clickable);
653 }
654 }
655
Selim Cinek31aada42015-12-18 17:51:15 -0800656 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
657 mHeadsUpManager = headsUpManager;
658 }
659
Selim Cinek01af3342016-02-09 19:25:31 -0800660 public void reInflateViews() {
661 initDimens();
662 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800663 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700664 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800665 }
666 }
667 if (mGuts != null) {
668 View oldGuts = mGuts;
669 int index = indexOfChild(oldGuts);
670 removeView(oldGuts);
671 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
672 R.layout.notification_guts, this, false);
673 mGuts.setVisibility(oldGuts.getVisibility());
674 addView(mGuts, index);
675 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800676 if (mSettingsIconRow != null) {
677 View oldSettings = mSettingsIconRow;
678 int settingsIndex = indexOfChild(oldSettings);
679 removeView(oldSettings);
680 mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
681 R.layout.notification_settings_icon_row, this, false);
682 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700683 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800684 mSettingsIconRow.setVisibility(oldSettings.getVisibility());
685 addView(mSettingsIconRow, settingsIndex);
686
687 }
Selim Cinekde33a4a2016-02-11 16:43:41 -0800688 mPrivateLayout.reInflateViews();
689 mPublicLayout.reInflateViews();
Selim Cinek01af3342016-02-09 19:25:31 -0800690 }
691
Selim Cinekc3179332016-03-04 14:44:56 -0800692 public void setContentBackground(int customBackgroundColor, boolean animate,
693 NotificationContentView notificationContentView) {
694 if (getShowingLayout() == notificationContentView) {
695 setTintColor(customBackgroundColor, animate);
696 }
697 }
698
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700699 public void closeRemoteInput() {
700 mPrivateLayout.closeRemoteInput();
701 mPublicLayout.closeRemoteInput();
702 }
703
Selim Cinekc897bd32016-03-18 17:32:31 -0700704 /**
705 * Set by how much the single line view should be indented.
706 */
707 public void setSingleLineWidthIndention(int indention) {
708 mPrivateLayout.setSingleLineWidthIndention(indention);
709 }
710
711 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700712 return mNotificationColor;
713 }
714
715 private void updateNotificationColor() {
716 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
717 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700718 }
719
720 public HybridNotificationView getSingleLineView() {
721 return mPrivateLayout.getSingleLineView();
722 }
723
Selim Cinekf07d0622016-03-21 19:52:52 -0700724 public boolean isOnKeyguard() {
725 return mOnKeyguard;
726 }
727
Selim Cinekc1e389d2016-04-07 11:02:57 -0700728 public void removeAllChildren() {
729 List<ExpandableNotificationRow> notificationChildren
730 = mChildrenContainer.getNotificationChildren();
731 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
732 for (int i = 0; i < clonedList.size(); i++) {
733 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700734 if (row.keepInParent()) {
735 continue;
736 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700737 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700738 row.setIsChildInGroup(false, null);
739 }
740 onChildrenCountChanged();
741 }
742
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700743 public void setForceUnlocked(boolean forceUnlocked) {
744 mForceUnlocked = forceUnlocked;
745 if (mIsSummaryWithChildren) {
746 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
747 for (ExpandableNotificationRow child : notificationChildren) {
748 child.setForceUnlocked(forceUnlocked);
749 }
750 }
751 }
752
Selim Cineke9bad242016-06-15 11:46:37 -0700753 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700754 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700755 mGroupParentWhenDismissed = mNotificationParent;
756 mRefocusOnDismiss = fromAccessibility;
757 mChildAfterViewWhenDismissed = null;
758 if (isChildInGroup()) {
759 List<ExpandableNotificationRow> notificationChildren =
760 mNotificationParent.getNotificationChildren();
761 int i = notificationChildren.indexOf(this);
762 if (i != -1 && i < notificationChildren.size() - 1) {
763 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
764 }
765 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700766 }
767
768 public boolean isDismissed() {
769 return mDismissed;
770 }
771
772 public boolean keepInParent() {
773 return mKeepInParent;
774 }
775
776 public void setKeepInParent(boolean keepInParent) {
777 mKeepInParent = keepInParent;
778 }
779
780 public boolean isRemoved() {
781 return mRemoved;
782 }
783
Adrian Roosd009ab12016-05-20 17:58:53 -0700784 public void setRemoved() {
785 mRemoved = true;
786
787 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700788 }
789
Selim Cinekd1395642016-04-28 12:22:42 -0700790 public NotificationChildrenContainer getChildrenContainer() {
791 return mChildrenContainer;
792 }
793
Selim Cinekcafa87f2016-10-26 17:00:17 -0700794 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
795 mHeadsupDisappearRunning = headsUpAnimatingAway;
796 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
797 }
798
799 /**
800 * @return if the view was just heads upped and is now animating away. During such a time the
801 * layout needs to be kept consistent
802 */
803 public boolean isHeadsUpAnimatingAway() {
804 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700805 }
806
Selim Cineke9bad242016-06-15 11:46:37 -0700807 public View getChildAfterViewWhenDismissed() {
808 return mChildAfterViewWhenDismissed;
809 }
810
811 public View getGroupParentWhenDismissed() {
812 return mGroupParentWhenDismissed;
813 }
814
Selim Cinek9e624e72016-07-20 13:46:49 -0700815 public void performDismiss() {
Selim Cineke9079112016-12-14 14:41:01 -0800816 if (mOnDismissRunnable != null) {
817 mOnDismissRunnable.run();
818 }
Selim Cinek9e624e72016-07-20 13:46:49 -0700819 }
820
Selim Cineke9079112016-12-14 14:41:01 -0800821 public void setOnDismissRunnable(Runnable onDismissRunnable) {
822 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -0700823 }
824
Selim Cinek281c2022016-10-13 19:14:43 -0700825 public View getNotificationIcon() {
826 NotificationHeaderView notificationHeader = getNotificationHeader();
827 if (notificationHeader != null) {
828 return notificationHeader.getIcon();
829 }
830 return null;
831 }
832
833 /**
834 * @return whether the notification is currently showing a view with an icon.
835 */
836 public boolean isShowingIcon() {
837 if (mIsSummaryWithChildren) {
838 return true;
839 }
840 NotificationContentView showingLayout = getShowingLayout();
841 NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
842 return notificationHeader != null;
843 }
844
Selim Cinek0242fbb2016-10-19 13:38:32 -0700845 /**
846 * Set how much this notification is transformed into an icon.
847 *
Selim Cinek2b549f42016-11-22 16:38:51 -0800848 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
849 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -0800850 * @param isLastChild is this the last child in the list. If true, then the transformation is
851 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -0700852 */
Selim Cinek2b549f42016-11-22 16:38:51 -0800853 public void setContentTransformationAmount(float contentTransformationAmount,
854 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -0800855 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800856 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800857 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -0800858 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800859 if (changeTransformation) {
860 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -0800861 }
862 }
863
864 /**
865 * Set the icons to be visible of this notification.
866 */
867 public void setIconsVisible(boolean iconsVisible) {
868 if (iconsVisible != mIconsVisible) {
869 mIconsVisible = iconsVisible;
870 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700871 }
872 }
873
Selim Cinekdb167372016-11-17 15:41:17 -0800874 @Override
875 protected void onBelowSpeedBumpChanged() {
876 updateIconVisibilities();
877 }
878
Selim Cinek875a3a12016-11-18 17:52:16 -0800879 private void updateContentTransformation() {
880 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -0800881 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -0800882 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -0800883 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -0800884 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700885 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -0800886 translationY *= 0.4f;
887 } else {
888 contentAlpha = 1.0f;
889 }
890 mPublicLayout.setAlpha(contentAlpha);
891 mPrivateLayout.setAlpha(contentAlpha);
892 mPublicLayout.setTranslationY(translationY);
893 mPrivateLayout.setTranslationY(translationY);
894 if (mChildrenContainer != null) {
895 mChildrenContainer.setAlpha(contentAlpha);
896 mChildrenContainer.setTranslationY(translationY);
897 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -0700898 }
899 }
900
901 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -0800902 boolean visible = isChildInGroup()
903 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
904 || mIconsVisible;
Selim Cinekdb167372016-11-17 15:41:17 -0800905 mPublicLayout.setIconsVisible(visible);
906 mPrivateLayout.setIconsVisible(visible);
907 if (mChildrenContainer != null) {
908 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -0700909 }
910 }
911
Selim Cinek875a3a12016-11-18 17:52:16 -0800912 /**
913 * Get the relative top padding of a view relative to this view. This recursively walks up the
914 * hierarchy and does the corresponding measuring.
915 *
916 * @param view the view to the the padding for. The requested view has to be a child of this
917 * notification.
918 * @return the toppadding
919 */
920 public int getRelativeTopPadding(View view) {
921 int topPadding = 0;
922 while (view.getParent() instanceof ViewGroup) {
923 topPadding += view.getTop();
924 view = (View) view.getParent();
925 if (view instanceof ExpandableNotificationRow) {
926 return topPadding;
927 }
928 }
929 return topPadding;
930 }
931
Selim Cineka1d97902016-12-14 16:31:40 -0800932 public float getContentTranslation() {
933 return mPrivateLayout.getTranslationY();
934 }
935
Chris Wren78403d72014-07-28 10:23:24 +0100936 public interface ExpansionLogger {
937 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
938 }
Selim Cinek1685e632014-04-08 02:27:49 +0200939
Chris Wren51c75102013-07-16 20:49:17 -0400940 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
941 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700942 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -0800943 initDimens();
944 }
945
946 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800947 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
948 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
949 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
950 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -0800951 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800952 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Mady Mellorb0a82462016-04-30 17:31:02 -0700953 mIncreasedPaddingBetweenElements = getResources()
954 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinek875a3a12016-11-18 17:52:16 -0800955 mIconTransformContentShiftNoIcon = getResources().getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -0700956 R.dimen.notification_icon_transform_content_shift);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800957 }
958
959 /**
960 * @param dimenId the dimen to look up
961 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
962 */
963 private int getFontScaledHeight(int dimenId) {
964 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
965 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
966 getResources().getDisplayMetrics().density);
967 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -0400968 }
969
Christoph Studera7fe6312014-06-27 19:32:44 +0200970 /**
971 * Resets this view so it can be re-used for an updated notification.
972 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200973 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200974 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200975 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +0100976 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +0200977 mExpandable = false;
978 mHasUserChangedExpansion = false;
979 mUserLocked = false;
980 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200981 mSensitive = false;
982 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200983 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700984 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -0800985 mPublicLayout.reset();
986 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +0200987 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -0800988 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +0200989 logExpansionEvent(false, wasExpanded);
990 }
991
992 public void resetHeight() {
Selim Cinek31094df2014-08-14 19:28:15 +0200993 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200994 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200995 }
996
Jorim Jaggi251957d2014-04-09 04:24:09 +0200997 @Override
998 protected void onFinishInflate() {
999 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001000 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001001 mPublicLayout.setContainingNotification(this);
Jorim Jaggibe565df2014-04-28 17:51:23 +02001002 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001003 mPrivateLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001004 mPrivateLayout.setContainingNotification(this);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001005 mPublicLayout.setExpandClickListener(mExpandClickListener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001006 mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
1007 mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1008 @Override
1009 public void onInflate(ViewStub stub, View inflated) {
1010 mSettingsIconRow = (NotificationSettingsIconRow) inflated;
1011 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -07001012 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -08001013 }
1014 });
Selim Cinekab29aeb2015-02-20 18:18:32 +01001015 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1016 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001017 @Override
1018 public void onInflate(ViewStub stub, View inflated) {
1019 mGuts = (NotificationGuts) inflated;
1020 mGuts.setClipTopAmount(getClipTopAmount());
1021 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001022 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001023 }
1024 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001025 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1026 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1027
1028 @Override
1029 public void onInflate(ViewStub stub, View inflated) {
1030 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -07001031 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001032 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -08001033 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +01001034 }
1035 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001036
1037 // Add the views that we translate to reveal the gear
1038 mTranslateableViews = new ArrayList<View>();
1039 for (int i = 0; i < getChildCount(); i++) {
1040 mTranslateableViews.add(getChildAt(i));
1041 }
1042 // Remove views that don't translate
Mady Mellor4b80b102016-01-22 08:03:58 -08001043 mTranslateableViews.remove(mSettingsIconRowStub);
1044 mTranslateableViews.remove(mChildrenContainerStub);
1045 mTranslateableViews.remove(mGutsStub);
1046 }
1047
Mady Mellor4b80b102016-01-22 08:03:58 -08001048 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001049 if (mTranslateAnim != null) {
1050 mTranslateAnim.cancel();
1051 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001052 if (mTranslateableViews != null) {
1053 for (int i = 0; i < mTranslateableViews.size(); i++) {
1054 mTranslateableViews.get(i).setTranslationX(0);
1055 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001056 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001057 invalidateOutline();
Mady Mellor4b80b102016-01-22 08:03:58 -08001058 if (mSettingsIconRow != null) {
1059 mSettingsIconRow.resetState();
1060 }
1061 }
1062
1063 public void animateTranslateNotification(final float leftTarget) {
1064 if (mTranslateAnim != null) {
1065 mTranslateAnim.cancel();
1066 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001067 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001068 if (mTranslateAnim != null) {
1069 mTranslateAnim.start();
1070 }
1071 }
1072
1073 @Override
1074 public void setTranslation(float translationX) {
1075 if (areGutsExposed()) {
1076 // Don't translate if guts are showing.
1077 return;
1078 }
1079 // Translate the group of views
1080 for (int i = 0; i < mTranslateableViews.size(); i++) {
1081 if (mTranslateableViews.get(i) != null) {
1082 mTranslateableViews.get(i).setTranslationX(translationX);
1083 }
1084 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001085 invalidateOutline();
Mady Mellor34958fa2016-02-23 09:52:17 -08001086 if (mSettingsIconRow != null) {
1087 mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
1088 }
1089 }
1090
1091 @Override
1092 public float getTranslation() {
1093 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1094 // All of the views in the list should have same translation, just use first one.
1095 return mTranslateableViews.get(0).getTranslationX();
1096 }
1097 return 0;
1098 }
1099
1100 public Animator getTranslateViewAnimator(final float leftTarget,
1101 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001102 if (mTranslateAnim != null) {
1103 mTranslateAnim.cancel();
1104 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001105 if (areGutsExposed()) {
1106 // No translation if guts are exposed.
1107 return null;
1108 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001109 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1110 leftTarget);
1111 if (listener != null) {
1112 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001113 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001114 translateAnim.addListener(new AnimatorListenerAdapter() {
1115 boolean cancelled = false;
1116
1117 @Override
1118 public void onAnimationCancel(Animator anim) {
1119 cancelled = true;
1120 }
1121
1122 @Override
1123 public void onAnimationEnd(Animator anim) {
1124 if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
1125 mSettingsIconRow.resetState();
1126 mTranslateAnim = null;
1127 }
1128 }
1129 });
1130 mTranslateAnim = translateAnim;
1131 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001132 }
1133
1134 public float getSpaceForGear() {
1135 if (mSettingsIconRow != null) {
1136 return mSettingsIconRow.getSpaceForGear();
1137 }
1138 return 0;
1139 }
1140
1141 public NotificationSettingsIconRow getSettingsRow() {
1142 if (mSettingsIconRow == null) {
1143 mSettingsIconRowStub.inflate();
1144 }
1145 return mSettingsIconRow;
1146 }
1147
Selim Cinekab29aeb2015-02-20 18:18:32 +01001148 public void inflateGuts() {
1149 if (mGuts == null) {
1150 mGutsStub.inflate();
1151 }
1152 }
1153
Selim Cinekda42d652015-12-04 15:51:16 -08001154 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001155 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1156 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001157 if (mChildrenContainer != null) {
1158 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1159 : INVISIBLE);
Mady Mellorb0a82462016-04-30 17:31:02 -07001160 mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
1161 ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -08001162 : INVISIBLE);
1163 }
Selim Cinekda42d652015-12-04 15:51:16 -08001164 // The limits might have changed if the view suddenly became a group or vice versa
1165 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001166 }
1167
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001168 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001169 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1170 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001171 // Add a record for the entire layout since its content is somehow small.
1172 // The event comes from a leaf view that is interacted with.
1173 AccessibilityEvent record = AccessibilityEvent.obtain();
1174 onInitializeAccessibilityEvent(record);
1175 dispatchPopulateAccessibilityEvent(record);
1176 event.appendRecord(record);
1177 return true;
1178 }
1179 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001180 }
Chris Wren51c75102013-07-16 20:49:17 -04001181
John Spurlocke15452b2014-08-21 09:44:39 -04001182 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001183 public void setDark(boolean dark, boolean fade, long delay) {
1184 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001185 final NotificationContentView showing = getShowingLayout();
1186 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001187 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001188 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001189 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001190 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001191 }
John Spurlocke15452b2014-08-21 09:44:39 -04001192 }
1193
Chris Wren51c75102013-07-16 20:49:17 -04001194 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001195 if (mIsSummaryWithChildren && !mShowingPublic) {
1196 return !mChildrenExpanded;
1197 }
Chris Wren51c75102013-07-16 20:49:17 -04001198 return mExpandable;
1199 }
1200
1201 public void setExpandable(boolean expandable) {
1202 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001203 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001204 }
1205
Selim Cinek4ffd6362015-12-29 15:12:23 +01001206 @Override
1207 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001208 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1209 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001210 }
1211
Selim Cinek1685e632014-04-08 02:27:49 +02001212 /**
1213 * @return whether the user has changed the expansion state
1214 */
1215 public boolean hasUserChangedExpansion() {
1216 return mHasUserChangedExpansion;
1217 }
1218
Chris Wren51c75102013-07-16 20:49:17 -04001219 public boolean isUserExpanded() {
1220 return mUserExpanded;
1221 }
1222
Selim Cinek1685e632014-04-08 02:27:49 +02001223 /**
1224 * Set this notification to be expanded by the user
1225 *
1226 * @param userExpanded whether the user wants this notification to be expanded
1227 */
Chris Wren51c75102013-07-16 20:49:17 -04001228 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001229 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1230 }
1231
1232 /**
1233 * Set this notification to be expanded by the user
1234 *
1235 * @param userExpanded whether the user wants this notification to be expanded
1236 * @param allowChildExpansion whether a call to this method allows expanding children
1237 */
1238 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001239 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -07001240 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
Chris Wren698b1702016-05-23 11:16:32 -04001241 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001242 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Chris Wren698b1702016-05-23 11:16:32 -04001243 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001244 return;
1245 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001246 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001247 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001248 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001249 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001250 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001251 }
1252
Selim Cinekccd14fb2014-08-12 18:53:24 +02001253 public void resetUserExpansion() {
1254 mHasUserChangedExpansion = false;
1255 mUserExpanded = false;
1256 }
1257
Chris Wren51c75102013-07-16 20:49:17 -04001258 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001259 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001260 }
1261
1262 public void setUserLocked(boolean userLocked) {
1263 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001264 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001265 if (mIsSummaryWithChildren) {
1266 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek7baaa9e2016-07-21 17:21:09 -07001267 if (userLocked || !isGroupExpanded()) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001268 updateBackgroundForGroupState();
1269 }
Selim Cinek42357e02016-02-24 18:48:01 -08001270 }
Chris Wren51c75102013-07-16 20:49:17 -04001271 }
1272
Selim Cinek1685e632014-04-08 02:27:49 +02001273 /**
1274 * @return has the system set this notification to be expanded
1275 */
1276 public boolean isSystemExpanded() {
1277 return mIsSystemExpanded;
1278 }
1279
1280 /**
1281 * Set this notification to be expanded by the system.
1282 *
1283 * @param expand whether the system wants this notification to be expanded.
1284 */
1285 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001286 if (expand != mIsSystemExpanded) {
1287 final boolean wasExpanded = isExpanded();
1288 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001289 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001290 logExpansionEvent(false, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001291 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001292 mChildrenContainer.updateGroupOverflow();
1293 }
Selim Cinek31094df2014-08-14 19:28:15 +02001294 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001295 }
1296
1297 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001298 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001299 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001300 public void setOnKeyguard(boolean onKeyguard) {
1301 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001302 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001303 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001304 logExpansionEvent(false, wasExpanded);
1305 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001306 if (mIsSummaryWithChildren) {
1307 mChildrenContainer.updateGroupOverflow();
1308 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001309 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001310 }
1311 }
Selim Cinek1685e632014-04-08 02:27:49 +02001312 }
1313
1314 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001315 * @return Can the underlying notification be cleared? This can be different from whether the
1316 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1317 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001318 */
1319 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001320 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1321 return false;
1322 }
1323 if (mIsSummaryWithChildren) {
1324 List<ExpandableNotificationRow> notificationChildren =
1325 mChildrenContainer.getNotificationChildren();
1326 for (int i = 0; i < notificationChildren.size(); i++) {
1327 ExpandableNotificationRow child = notificationChildren.get(i);
1328 if (!child.isClearable()) {
1329 return false;
1330 }
1331 }
1332 }
1333 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001334 }
1335
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001336 @Override
1337 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001338 if (isUserLocked()) {
1339 return getActualHeight();
1340 }
Selim Cinekd84a5932015-12-15 11:45:36 -08001341 if (mGuts != null && mGuts.areGutsExposed()) {
1342 return mGuts.getHeight();
1343 } else if ((isChildInGroup() && !isGroupExpanded())) {
1344 return mPrivateLayout.getMinHeight();
1345 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1346 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001347 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001348 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek73cf02a2016-06-17 13:08:00 -07001349 } else if (mIsHeadsUp || mHeadsupDisappearRunning) {
1350 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001351 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1352 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001353 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001354 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001355 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001356 }
Selim Cinek31aada42015-12-18 17:51:15 -08001357 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001358 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001359 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001360 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001361 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001362 }
Selim Cinek1685e632014-04-08 02:27:49 +02001363
Mady Mellorb0a82462016-04-30 17:31:02 -07001364 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001365 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001366 }
1367
Selim Cinek263398f2015-10-21 17:40:23 -07001368 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001369 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001370 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1371 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
1372 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
1373 mEntry.notification);
Selim Cinek263398f2015-10-21 17:40:23 -07001374 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001375 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001376 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001377 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001378 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001379 }
1380
Mady Mellorb0a82462016-04-30 17:31:02 -07001381 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001382 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001383 mChildrenContainer.updateChildrenHeaderAppearance();
1384 }
1385 }
1386
Selim Cinek1685e632014-04-08 02:27:49 +02001387 /**
1388 * Check whether the view state is currently expanded. This is given by the system in {@link
1389 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1390 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1391 * view can differ from this state, if layout params are modified from outside.
1392 *
1393 * @return whether the view state is currently expanded.
1394 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001395 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001396 return isExpanded(false /* allowOnKeyguard */);
1397 }
1398
1399 public boolean isExpanded(boolean allowOnKeyguard) {
1400 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001401 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1402 || isUserExpanded());
1403 }
1404
1405 private boolean isSystemChildExpanded() {
1406 return mIsSystemChildExpanded;
1407 }
1408
1409 public void setSystemChildExpanded(boolean expanded) {
1410 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001411 }
1412
1413 @Override
1414 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1415 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001416 updateMaxHeights();
Mady Mellora6edc872016-04-26 11:01:03 -07001417 if (mSettingsIconRow != null) {
1418 mSettingsIconRow.updateVerticalLocation();
1419 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001420 updateContentShiftHeight();
1421 }
1422
1423 /**
1424 * Updates the content shift height such that the header is completely hidden when coming from
1425 * the top.
1426 */
1427 private void updateContentShiftHeight() {
1428 NotificationHeaderView notificationHeader = getNotificationHeader();
1429 if (notificationHeader != null) {
1430 CachingIconView icon = notificationHeader.getIcon();
1431 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1432 } else {
1433 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1434 }
Selim Cinek1685e632014-04-08 02:27:49 +02001435 }
1436
Selim Cinek8d490d42015-04-10 00:05:50 -07001437 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001438 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001439 View expandedChild = mPrivateLayout.getExpandedChild();
1440 if (expandedChild == null) {
1441 expandedChild = mPrivateLayout.getContractedChild();
1442 }
1443 mMaxExpandHeight = expandedChild.getHeight();
1444 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001445 if (headsUpChild == null) {
1446 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001447 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001448 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001449 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001450 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001451 }
1452 }
1453
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001454 @Override
1455 public void notifyHeightChanged(boolean needsAnimation) {
1456 super.notifyHeightChanged(needsAnimation);
1457 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1458 }
1459
Selim Cinek3c76d502016-02-19 15:16:33 -08001460 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001461 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001462 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001463 }
1464
1465 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001466 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001467 if (mIsSummaryWithChildren) {
1468 List<ExpandableNotificationRow> notificationChildren =
1469 mChildrenContainer.getNotificationChildren();
1470 for (int i = 0; i < notificationChildren.size(); i++) {
1471 ExpandableNotificationRow child = notificationChildren.get(i);
1472 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1473 }
1474 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001475 }
1476
1477 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1478 long duration) {
1479 boolean oldShowingPublic = mShowingPublic;
1480 mShowingPublic = mSensitive && hideSensitive;
1481 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1482 return;
1483 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001484
1485 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001486 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001487
Jorim Jaggiae441282014-08-01 02:45:18 +02001488 if (!animated) {
1489 mPublicLayout.animate().cancel();
1490 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001491 if (mChildrenContainer != null) {
1492 mChildrenContainer.animate().cancel();
1493 mChildrenContainer.setAlpha(1f);
1494 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001495 mPublicLayout.setAlpha(1f);
1496 mPrivateLayout.setAlpha(1f);
1497 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001498 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001499 } else {
1500 animateShowingPublic(delay, duration);
1501 }
Selim Cinekc3179332016-03-04 14:44:56 -08001502 NotificationContentView showingLayout = getShowingLayout();
1503 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001504 mPrivateLayout.updateExpandButtons(isExpandable());
Jorim Jaggiae441282014-08-01 02:45:18 +02001505 mShowingPublicInitialized = true;
1506 }
1507
1508 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001509 View[] privateViews = mIsSummaryWithChildren
1510 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001511 : new View[] {mPrivateLayout};
1512 View[] publicViews = new View[] {mPublicLayout};
1513 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1514 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1515 for (final View hiddenView : hiddenChildren) {
1516 hiddenView.setVisibility(View.VISIBLE);
1517 hiddenView.animate().cancel();
1518 hiddenView.animate()
1519 .alpha(0f)
1520 .setStartDelay(delay)
1521 .setDuration(duration)
1522 .withEndAction(new Runnable() {
1523 @Override
1524 public void run() {
1525 hiddenView.setVisibility(View.INVISIBLE);
1526 }
1527 });
1528 }
1529 for (View showView : shownChildren) {
1530 showView.setVisibility(View.VISIBLE);
1531 showView.setAlpha(0f);
1532 showView.animate().cancel();
1533 showView.animate()
1534 .alpha(1f)
1535 .setStartDelay(delay)
1536 .setDuration(duration);
1537 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001538 }
1539
Selim Cinek3776fe02016-02-04 13:32:43 -08001540 public boolean mustStayOnScreen() {
1541 return mIsHeadsUp;
1542 }
1543
Selim Cinek9e624e72016-07-20 13:46:49 -07001544 /**
1545 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1546 * otherwise some state might not be updated. To request about the general clearability
1547 * see {@link #isClearable()}.
1548 */
1549 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001550 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001551 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001552
Ricky Waicd35def2016-05-03 11:07:07 +01001553 public void makeActionsVisibile() {
1554 setUserExpanded(true, true);
1555 if (isChildInGroup()) {
1556 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1557 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001558 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001559 }
1560
Selim Cinekb5605e52015-02-20 18:21:41 +01001561 public void setChildrenExpanded(boolean expanded, boolean animate) {
1562 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001563 if (mChildrenContainer != null) {
1564 mChildrenContainer.setChildrenExpanded(expanded);
1565 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001566 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001567 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001568 }
1569
Selim Cinekb5605e52015-02-20 18:21:41 +01001570 public static void applyTint(View v, int color) {
1571 int alpha;
1572 if (color != 0) {
1573 alpha = COLORED_DIVIDER_ALPHA;
1574 } else {
1575 color = 0xff000000;
1576 alpha = DEFAULT_DIVIDER_ALPHA;
1577 }
1578 if (v.getBackground() instanceof ColorDrawable) {
1579 ColorDrawable background = (ColorDrawable) v.getBackground();
1580 background.mutate();
1581 background.setColor(color);
1582 background.setAlpha(alpha);
1583 }
1584 }
1585
Selim Cinek1685e632014-04-08 02:27:49 +02001586 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001587 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001588 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001589
Mady Mellor34958fa2016-02-23 09:52:17 -08001590 public boolean areGutsExposed() {
1591 return (mGuts != null && mGuts.areGutsExposed());
1592 }
1593
Jorim Jaggibe565df2014-04-28 17:51:23 +02001594 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001595 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001596 NotificationContentView showingLayout = getShowingLayout();
1597 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001598 }
1599
1600 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001601 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001602 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001603 return mChildrenContainer;
1604 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001605 return getShowingLayout();
1606 }
1607
1608 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001609 protected void onAppearAnimationFinished(boolean wasAppearing) {
1610 super.onAppearAnimationFinished(wasAppearing);
1611 if (wasAppearing) {
1612 // During the animation the visible view might have changed, so let's make sure all
1613 // alphas are reset
1614 if (mChildrenContainer != null) {
1615 mChildrenContainer.setAlpha(1.0f);
1616 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1617 }
1618 mPrivateLayout.setAlpha(1.0f);
1619 mPrivateLayout.setLayerType(LAYER_TYPE_NONE, null);
1620 mPublicLayout.setAlpha(1.0f);
1621 mPublicLayout.setLayerType(LAYER_TYPE_NONE, null);
1622 }
1623 }
1624
1625 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001626 public int getExtraBottomPadding() {
1627 if (mIsSummaryWithChildren && isGroupExpanded()) {
1628 return mIncreasedPaddingBetweenElements;
1629 }
1630 return 0;
1631 }
1632
1633 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001634 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001635 super.setActualHeight(height, notifyListeners);
Mady Mellorb53bc272016-02-11 18:28:23 -08001636 if (mGuts != null && mGuts.areGutsExposed()) {
1637 mGuts.setActualHeight(height);
1638 return;
1639 }
Selim Cinekeef84282015-10-30 16:28:00 -07001640 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +01001641 mPrivateLayout.setContentHeight(contentHeight);
1642 mPublicLayout.setContentHeight(contentHeight);
Selim Cinek42357e02016-02-24 18:48:01 -08001643 if (mIsSummaryWithChildren) {
1644 mChildrenContainer.setActualHeight(height);
1645 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001646 if (mGuts != null) {
1647 mGuts.setActualHeight(height);
1648 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001649 }
1650
1651 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001652 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001653 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001654 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001655 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001656 NotificationContentView showingLayout = getShowingLayout();
1657 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001658 }
1659
1660 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001661 public int getMinHeight() {
Selim Cinek31aada42015-12-18 17:51:15 -08001662 if (mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
1663 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1664 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001665 return mChildrenContainer.getMinHeight();
Selim Cinek31aada42015-12-18 17:51:15 -08001666 } else if (mIsHeadsUp) {
1667 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001668 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001669 NotificationContentView showingLayout = getShowingLayout();
1670 return showingLayout.getMinHeight();
1671 }
1672
1673 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001674 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001675 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001676 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001677 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001678 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001679 }
1680
1681 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001682 public void setClipTopAmount(int clipTopAmount) {
1683 super.setClipTopAmount(clipTopAmount);
1684 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001685 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001686 if (mGuts != null) {
1687 mGuts.setClipTopAmount(clipTopAmount);
1688 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001689 }
1690
Selim Cineka686b2c2016-10-26 13:58:27 -07001691 @Override
1692 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001693 if (clipBottomAmount != mClipBottomAmount) {
1694 super.setClipBottomAmount(clipBottomAmount);
1695 mPrivateLayout.setClipBottomAmount(clipBottomAmount);
1696 mPublicLayout.setClipBottomAmount(clipBottomAmount);
1697 if (mGuts != null) {
1698 mGuts.setClipBottomAmount(clipBottomAmount);
1699 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001700 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001701 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001702 // We have to update this even if it hasn't changed, since the children locations can
1703 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001704 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
1705 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001706 }
1707
Selim Cinek31094df2014-08-14 19:28:15 +02001708 public boolean isMaxExpandHeightInitialized() {
1709 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001710 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001711
Selim Cinek42357e02016-02-24 18:48:01 -08001712 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001713 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1714 }
Chris Wren78403d72014-07-28 10:23:24 +01001715
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001716 @Override
1717 public void setShowingLegacyBackground(boolean showing) {
1718 super.setShowingLegacyBackground(showing);
1719 mPrivateLayout.setShowingLegacyBackground(showing);
1720 mPublicLayout.setShowingLegacyBackground(showing);
1721 }
1722
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001723 @Override
1724 protected void updateBackgroundTint() {
1725 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001726 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001727 if (mIsSummaryWithChildren) {
1728 List<ExpandableNotificationRow> notificationChildren =
1729 mChildrenContainer.getNotificationChildren();
1730 for (int i = 0; i < notificationChildren.size(); i++) {
1731 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001732 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001733 }
1734 }
1735 }
1736
Mady Mellorb0a82462016-04-30 17:31:02 -07001737 /**
1738 * Called when a group has finished animating from collapsed or expanded state.
1739 */
1740 public void onFinishedExpansionChange() {
1741 mGroupExpansionChanging = false;
1742 updateBackgroundForGroupState();
1743 }
1744
1745 /**
1746 * Updates the parent and children backgrounds in a group based on the expansion state.
1747 */
1748 public void updateBackgroundForGroupState() {
1749 if (mIsSummaryWithChildren) {
1750 // Only when the group has finished expanding do we hide its background.
1751 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1752 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1753 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1754 for (int i = 0; i < children.size(); i++) {
1755 children.get(i).updateBackgroundForGroupState();
1756 }
1757 } else if (isChildInGroup()) {
1758 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
1759 // Only show a background if the group is expanded OR if it is expanding / collapsing
1760 // and has a custom background color
1761 final boolean showBackground = isGroupExpanded()
1762 || ((mNotificationParent.isGroupExpansionChanging()
1763 || mNotificationParent.isUserLocked()) && childColor != 0);
1764 mShowNoBackground = !showBackground;
1765 } else {
1766 // Only children or parents ever need no background.
1767 mShowNoBackground = false;
1768 }
1769 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001770 updateBackground();
1771 }
1772
Adrian Roos4a579672016-05-24 16:54:37 -07001773 public int getPositionOfChild(ExpandableNotificationRow childRow) {
1774 if (mIsSummaryWithChildren) {
1775 return mChildrenContainer.getPositionInLinearLayout(childRow);
1776 }
1777 return 0;
1778 }
1779
Chris Wren78403d72014-07-28 10:23:24 +01001780 public void setExpansionLogger(ExpansionLogger logger, String key) {
1781 mLogger = logger;
1782 mLoggingKey = key;
1783 }
1784
Chris Wren6abeeb92016-05-26 14:44:38 -04001785 public void onExpandedByGesture(boolean userExpanded) {
1786 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
1787 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
1788 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
1789 }
1790 MetricsLogger.action(mContext, event, userExpanded);
1791 }
1792
Selim Cinek6183d122016-01-14 18:48:41 -08001793 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001794 public float getIncreasedPaddingAmount() {
1795 if (mIsSummaryWithChildren) {
1796 if (isGroupExpanded()) {
1797 return 1.0f;
1798 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001799 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001800 }
1801 }
1802 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001803 }
1804
1805 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001806 protected boolean disallowSingleClick(MotionEvent event) {
1807 float x = event.getX();
1808 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001809 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001810 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001811 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001812 }
1813 return super.disallowSingleClick(event);
1814 }
1815
Chris Wren78403d72014-07-28 10:23:24 +01001816 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04001817 boolean nowExpanded = isExpanded();
1818 if (mIsSummaryWithChildren) {
1819 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
1820 }
Chris Wren78403d72014-07-28 10:23:24 +01001821 if (wasExpanded != nowExpanded && mLogger != null) {
1822 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1823 }
1824 }
Selim Cinek570981d2015-12-01 11:37:01 -08001825
Selim Cineke9bad242016-06-15 11:46:37 -07001826 @Override
1827 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
1828 super.onInitializeAccessibilityNodeInfoInternal(info);
1829 if (canViewBeDismissed()) {
1830 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
1831 }
1832 }
1833
1834 @Override
1835 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
1836 if (super.performAccessibilityActionInternal(action, arguments)) {
1837 return true;
1838 }
1839 switch (action) {
1840 case AccessibilityNodeInfo.ACTION_DISMISS:
1841 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
1842 true /* fromAccessibility */);
1843 return true;
1844 }
1845 return false;
1846 }
1847
1848 public boolean shouldRefocusOnDismiss() {
1849 return mRefocusOnDismiss || isAccessibilityFocused();
1850 }
1851
Selim Cinek570981d2015-12-01 11:37:01 -08001852 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001853 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001854 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001855
1856 @Override
1857 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
1858 return new NotificationViewState(stackScrollState);
1859 }
1860
Selim Cinekd127d792016-11-01 19:11:41 -07001861 @Override
1862 public boolean isAboveShelf() {
1863 return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
1864 }
1865
1866 public void setAboveShelf(boolean aboveShelf) {
1867 mAboveShelf = aboveShelf;
1868 }
1869
Selim Cinek0cfbef42016-11-09 19:06:36 -08001870 public class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08001871
1872 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07001873
Selim Cinekbbcebde2016-11-09 18:28:20 -08001874
1875 private NotificationViewState(StackScrollState stackScrollState) {
1876 mOverallState = stackScrollState;
1877 }
1878
1879 @Override
1880 public void applyToView(View view) {
1881 super.applyToView(view);
1882 if (view instanceof ExpandableNotificationRow) {
1883 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinekbbcebde2016-11-09 18:28:20 -08001884 row.applyChildrenState(mOverallState);
1885 }
1886 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08001887
1888 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08001889 protected void onYTranslationAnimationFinished(View view) {
1890 super.onYTranslationAnimationFinished(view);
Selim Cinek0cfbef42016-11-09 19:06:36 -08001891 if (mHeadsupDisappearRunning) {
Selim Cinekcafa87f2016-10-26 17:00:17 -07001892 setHeadsUpAnimatingAway(false);
Selim Cinek0cfbef42016-11-09 19:06:36 -08001893 }
1894 }
1895
1896 @Override
1897 public void animateTo(View child, AnimationProperties properties) {
1898 super.animateTo(child, properties);
1899 if (child instanceof ExpandableNotificationRow) {
1900 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
1901 row.startChildAnimation(mOverallState, properties);
1902 }
1903 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08001904 }
Chris Wren51c75102013-07-16 20:49:17 -04001905}