blob: 8887beae5afe207faf89659c4581dde4ff0b864f [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
Selim Cinek5ba22542017-04-20 15:16:10 -070019import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;
Selim Cinekc478f902017-02-22 20:55:44 -080020
Mady Mellor4b80b102016-01-22 08:03:58 -080021import android.animation.Animator;
22import android.animation.AnimatorListenerAdapter;
Mady Mellor4b80b102016-01-22 08:03:58 -080023import android.animation.ObjectAnimator;
Mady Mellor4b80b102016-01-22 08:03:58 -080024import android.animation.ValueAnimator.AnimatorUpdateListener;
Selim Cinekddf1b392016-05-27 16:33:10 -070025import android.annotation.Nullable;
Chris Wren51c75102013-07-16 20:49:17 -040026import android.content.Context;
Anthony Chen7acbb772017-04-07 16:45:25 -070027import android.content.res.Resources;
Mady Mellor9d03a522017-04-04 18:45:30 -070028import android.content.res.Configuration;
Selim Cinekcab4a602014-09-03 14:47:57 +020029import android.graphics.drawable.AnimatedVectorDrawable;
30import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010031import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020032import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080033import android.os.Build;
Selim Cineke9bad242016-06-15 11:46:37 -070034import android.os.Bundle;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020035import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040036import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070037import android.util.FloatProperty;
38import android.util.Property;
Selim Cinek01af3342016-02-09 19:25:31 -080039import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080040import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080041import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050042import android.view.View;
Selim Cinek875a3a12016-11-18 17:52:16 -080043import android.view.ViewGroup;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020044import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020045import android.view.accessibility.AccessibilityEvent;
Selim Cineke9bad242016-06-15 11:46:37 -070046import android.view.accessibility.AccessibilityNodeInfo;
Selim Cinek98713a42015-09-21 15:47:20 +020047import android.widget.Chronometer;
Mady Mellor95d743c2017-01-10 12:05:27 -080048import android.widget.FrameLayout;
Selim Cinekcab4a602014-09-03 14:47:57 +020049import android.widget.ImageView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080050import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010051
Selim Cinek5ba22542017-04-20 15:16:10 -070052import com.android.internal.annotations.VisibleForTesting;
Chris Wren698b1702016-05-23 11:16:32 -040053import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010054import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070055import com.android.internal.util.NotificationColorUtil;
Selim Cinek875a3a12016-11-18 17:52:16 -080056import com.android.internal.widget.CachingIconView;
Mady Mellor95d743c2017-01-10 12:05:27 -080057import com.android.systemui.Dependency;
Selim Cinek0242fbb2016-10-19 13:38:32 -070058import com.android.systemui.Interpolators;
Dan Sandlera5e0f412014-01-23 15:11:54 -050059import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070060import com.android.systemui.classifier.FalsingManager;
Mady Mellor95d743c2017-01-10 12:05:27 -080061import com.android.systemui.plugins.PluginListener;
62import com.android.systemui.plugins.PluginManager;
63import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
64import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
65import com.android.systemui.statusbar.NotificationGuts.GutsContent;
Selim Cinekc897bd32016-03-18 17:32:31 -070066import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinek1a48bab2017-02-17 19:38:40 -080067import com.android.systemui.statusbar.notification.NotificationInflater;
Selim Cinek6743c0b2017-01-18 18:24:01 -080068import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cineka7d4f822016-12-06 14:34:47 -080069import com.android.systemui.statusbar.notification.VisualStabilityManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010070import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050071import com.android.systemui.statusbar.phone.StatusBar;
Selim Cinek31aada42015-12-18 17:51:15 -080072import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek0cfbef42016-11-09 19:06:36 -080073import com.android.systemui.statusbar.stack.AnimationProperties;
74import com.android.systemui.statusbar.stack.ExpandableViewState;
Selim Cinekb5605e52015-02-20 18:21:41 +010075import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
Selim Cineke9bad242016-06-15 11:46:37 -070076import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekb5605e52015-02-20 18:21:41 +010077import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinekb5605e52015-02-20 18:21:41 +010078
Mady Mellor4b80b102016-01-22 08:03:58 -080079import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010080import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050081
Mady Mellor95d743c2017-01-10 12:05:27 -080082public class ExpandableNotificationRow extends ActivatableNotificationView
83 implements PluginListener<NotificationMenuRowPlugin> {
Selim Cinekb5605e52015-02-20 18:21:41 +010084
85 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
86 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Mady Mellor95d743c2017-01-10 12:05:27 -080087 private static final int MENU_VIEW_INDEX = 0;
88
Mady Mellor035badd2017-04-04 18:45:30 -070089 public interface LayoutListener {
90 public void onLayout();
91 }
92
93 private LayoutListener mLayoutListener;
Selim Cinek1a48bab2017-02-17 19:38:40 -080094 private final NotificationInflater mNotificationInflater;
Selim Cinek0242fbb2016-10-19 13:38:32 -070095 private int mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -080096 private int mIconTransformContentShiftNoIcon;
Selim Cinek01af3342016-02-09 19:25:31 -080097 private int mNotificationMinHeightLegacy;
98 private int mMaxHeadsUpHeightLegacy;
99 private int mMaxHeadsUpHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800100 private int mMaxHeadsUpHeightIncreased;
Selim Cinek01af3342016-02-09 19:25:31 -0800101 private int mNotificationMinHeight;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800102 private int mNotificationMinHeightLarge;
Selim Cinek01af3342016-02-09 19:25:31 -0800103 private int mNotificationMaxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800104 private int mNotificationAmbientHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -0700105 private int mIncreasedPaddingBetweenElements;
Chris Wren51c75102013-07-16 20:49:17 -0400106
Selim Cinek1685e632014-04-08 02:27:49 +0200107 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -0400108 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +0200109 /** Has the user actively changed the expansion state of this row */
110 private boolean mHasUserChangedExpansion;
111 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -0400112 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -0800113
114 /**
115 * Has this notification been expanded while it was pinned
116 */
117 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +0200118 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -0400119 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +0200120 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -0500121 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +0200122 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -0800123 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +0200124 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -0700125 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400126
Selim Cinek1685e632014-04-08 02:27:49 +0200127 /**
128 * Is this notification expanded by the system. The expansion state can be overridden by the
129 * user expansion.
130 */
131 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200132
133 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700134 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200135 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700136 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200137
Mady Mellorb0a82462016-04-30 17:31:02 -0700138 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800139 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200140 private NotificationContentView mPublicLayout;
141 private NotificationContentView mPrivateLayout;
Adrian Rooseb434ff2017-01-11 11:18:48 -0800142 private NotificationContentView[] mLayouts;
Selim Cinek1685e632014-04-08 02:27:49 +0200143 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700144 private int mHeadsUpHeight;
Selim Cinek4bb59342016-04-08 19:29:35 -0700145 private int mNotificationColor;
Chris Wren78403d72014-07-28 10:23:24 +0100146 private ExpansionLogger mLogger;
147 private String mLoggingKey;
Selim Cinek8d490d42015-04-10 00:05:50 -0700148 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800149 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200150 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700151 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100152 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200153 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100154 private ViewStub mChildrenContainerStub;
155 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100156 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700157 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100158 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor95d743c2017-01-10 12:05:27 -0800159 private NotificationMenuRowPlugin mMenuRow;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100160 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100161 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700162 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700163 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800164 private HeadsUpManager mHeadsUpManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200165
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700166 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800167 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700168 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700169 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800170 private OnExpandClickListener mOnExpandClickListener;
Mady Mellorb0a82462016-04-30 17:31:02 -0700171 private boolean mGroupExpansionChanging;
172
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800173 private OnClickListener mExpandClickListener = new OnClickListener() {
174 @Override
175 public void onClick(View v) {
Selim Cinek414ad332017-02-24 19:06:12 -0800176 if (!mShowingPublic && (!mIsLowPriority || isExpanded())
177 && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Mady Mellor1a5d8ea2016-06-09 10:42:42 -0700178 mGroupExpansionChanging = true;
Chris Wren698b1702016-05-23 11:16:32 -0400179 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
180 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
181 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400182 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
183 nowExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -0800184 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800185 } else {
Selim Cineke9bad242016-06-15 11:46:37 -0700186 if (v.isAccessibilityFocused()) {
187 mPrivateLayout.setFocusOnVisibilityChange();
188 }
Selim Cinek31aada42015-12-18 17:51:15 -0800189 boolean nowExpanded;
190 if (isPinned()) {
191 nowExpanded = !mExpandedWhenPinned;
192 mExpandedWhenPinned = nowExpanded;
193 } else {
194 nowExpanded = !isExpanded();
195 setUserExpanded(nowExpanded);
196 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800197 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800198 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400199 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
200 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800201 }
202 }
203 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700204 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700205 private boolean mDismissed;
206 private boolean mKeepInParent;
207 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700208 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
209 new FloatProperty<ExpandableNotificationRow>("translate") {
210 @Override
211 public void setValue(ExpandableNotificationRow object, float value) {
212 object.setTranslation(value);
213 }
214
215 @Override
216 public Float get(ExpandableNotificationRow object) {
217 return object.getTranslation();
218 }
219 };
Selim Cinekddf1b392016-05-27 16:33:10 -0700220 private OnClickListener mOnClickListener;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700221 private boolean mHeadsupDisappearRunning;
Selim Cineke9bad242016-06-15 11:46:37 -0700222 private View mChildAfterViewWhenDismissed;
223 private View mGroupParentWhenDismissed;
224 private boolean mRefocusOnDismiss;
Selim Cinek2b549f42016-11-22 16:38:51 -0800225 private float mContentTransformationAmount;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700226 private boolean mIconsVisible = true;
Selim Cinekd127d792016-11-01 19:11:41 -0700227 private boolean mAboveShelf;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800228 private boolean mShowAmbient;
Selim Cinek875a3a12016-11-18 17:52:16 -0800229 private boolean mIsLastChild;
Selim Cineke9079112016-12-14 14:41:01 -0800230 private Runnable mOnDismissRunnable;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800231 private boolean mIsLowPriority;
Selim Cineka7ed2c12017-01-23 20:47:24 -0800232 private boolean mIsColorized;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800233 private boolean mUseIncreasedCollapsedHeight;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800234 private boolean mUseIncreasedHeadsUpHeight;
Selim Cinekef8c2252017-02-10 14:52:18 -0800235 private float mTranslationWhenRemoved;
236 private boolean mWasChildInGroupWhenRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700237
Mady Mellor43c2cd12016-12-12 21:05:13 -0800238 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -0700239 public boolean isGroupExpansionChanging() {
240 if (isChildInGroup()) {
241 return mNotificationParent.isGroupExpansionChanging();
242 }
243 return mGroupExpansionChanging;
244 }
245
246 public void setGroupExpansionChanging(boolean changing) {
247 mGroupExpansionChanging = changing;
248 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700249
Adrian Roos599be342016-06-13 14:54:39 -0700250 @Override
251 public void setActualHeightAnimating(boolean animating) {
252 if (mPrivateLayout != null) {
253 mPrivateLayout.setContentHeightAnimating(animating);
254 }
255 }
256
Selim Cinek8d490d42015-04-10 00:05:50 -0700257 public NotificationContentView getPrivateLayout() {
258 return mPrivateLayout;
259 }
260
261 public NotificationContentView getPublicLayout() {
262 return mPublicLayout;
263 }
264
Selim Cinekcab4a602014-09-03 14:47:57 +0200265 public void setIconAnimationRunning(boolean running) {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800266 for (NotificationContentView l : mLayouts) {
267 setIconAnimationRunning(running, l);
268 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800269 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700270 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek414ad332017-02-24 19:06:12 -0800271 setIconAnimationRunningForChild(running, mChildrenContainer.getLowPriorityHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800272 List<ExpandableNotificationRow> notificationChildren =
273 mChildrenContainer.getNotificationChildren();
274 for (int i = 0; i < notificationChildren.size(); i++) {
275 ExpandableNotificationRow child = notificationChildren.get(i);
276 child.setIconAnimationRunning(running);
277 }
278 }
279 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200280 }
281
282 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
283 if (layout != null) {
284 View contractedChild = layout.getContractedChild();
285 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700286 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200287 setIconAnimationRunningForChild(running, contractedChild);
288 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700289 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200290 }
291 }
292
293 private void setIconAnimationRunningForChild(boolean running, View child) {
294 if (child != null) {
295 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
296 setIconRunning(icon, running);
297 ImageView rightIcon = (ImageView) child.findViewById(
298 com.android.internal.R.id.right_icon);
299 setIconRunning(rightIcon, running);
300 }
301 }
302
303 private void setIconRunning(ImageView imageView, boolean running) {
304 if (imageView != null) {
305 Drawable drawable = imageView.getDrawable();
306 if (drawable instanceof AnimationDrawable) {
307 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
308 if (running) {
309 animationDrawable.start();
310 } else {
311 animationDrawable.stop();
312 }
313 } else if (drawable instanceof AnimatedVectorDrawable) {
314 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
315 if (running) {
316 animationDrawable.start();
317 } else {
318 animationDrawable.stop();
319 }
320 }
321 }
322 }
323
Selim Cinek5ba22542017-04-20 15:16:10 -0700324 public void updateNotification(NotificationData.Entry entry) {
Selim Cinekda42d652015-12-04 15:51:16 -0800325 mEntry = entry;
326 mStatusBarNotification = entry.notification;
Selim Cinek1a48bab2017-02-17 19:38:40 -0800327 mNotificationInflater.inflateNotificationViews();
Selim Cinekc478f902017-02-22 20:55:44 -0800328 }
329
Selim Cinek5ba22542017-04-20 15:16:10 -0700330 public void onNotificationUpdated() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800331 for (NotificationContentView l : mLayouts) {
Selim Cinekc478f902017-02-22 20:55:44 -0800332 l.onNotificationUpdated(mEntry);
Adrian Rooseb434ff2017-01-11 11:18:48 -0800333 }
Selim Cineka7ed2c12017-01-23 20:47:24 -0800334 mIsColorized = mStatusBarNotification.getNotification().isColorized();
Selim Cinek757d8792016-01-28 16:21:08 -0800335 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700336 updateNotificationColor();
Mady Mellor4c197602017-04-10 17:57:52 -0700337 if (mMenuRow != null) {
338 mMenuRow.onNotificationUpdated();
339 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800340 if (mIsSummaryWithChildren) {
Selim Cinek414ad332017-02-24 19:06:12 -0800341 mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
Selim Cinekc897bd32016-03-18 17:32:31 -0700342 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800343 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800344 if (mIconAnimationRunning) {
345 setIconAnimationRunning(true);
346 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800347 if (mNotificationParent != null) {
348 mNotificationParent.updateChildrenHeaderAppearance();
349 }
Selim Cinek263398f2015-10-21 17:40:23 -0700350 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800351 // The public layouts expand button is always visible
352 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800353 updateLimits();
Selim Cinek0242fbb2016-10-19 13:38:32 -0700354 updateIconVisibilities();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800355 updateShelfIconColor();
356 }
357
358 private void updateShelfIconColor() {
359 StatusBarIconView expandedIcon = mEntry.expandedIcon;
360 boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
361 boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
362 NotificationColorUtil.getInstance(mContext));
Selim Cinek875ba9b2017-02-13 16:20:17 -0800363 int color = StatusBarIconView.NO_COLOR;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800364 if (colorize) {
Selim Cinek875ba9b2017-02-13 16:20:17 -0800365 color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded());
Selim Cinek6743c0b2017-01-18 18:24:01 -0800366 }
Selim Cinek875ba9b2017-02-13 16:20:17 -0800367 expandedIcon.setStaticDrawableColor(color);
Selim Cinekda42d652015-12-04 15:51:16 -0800368 }
369
Selim Cinek4705f292017-04-24 22:18:48 -0700370 @Override
371 public boolean isDimmable() {
372 if (!getShowingLayout().isDimmable()) {
373 return false;
374 }
375 return super.isDimmable();
376 }
377
Selim Cinekda42d652015-12-04 15:51:16 -0800378 private void updateLimits() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800379 for (NotificationContentView l : mLayouts) {
380 updateLimitsForView(l);
381 }
Selim Cineka1744872016-03-11 15:36:06 -0800382 }
383
384 private void updateLimitsForView(NotificationContentView layout) {
385 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800386 != com.android.internal.R.id.status_bar_latest_event_content;
387 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek7d1009b2017-01-25 15:28:28 -0800388 int minHeight;
389 if (customView && beforeN && !mIsSummaryWithChildren) {
390 minHeight = mNotificationMinHeightLegacy;
391 } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
392 minHeight = mNotificationMinHeightLarge;
393 } else {
394 minHeight = mNotificationMinHeight;
395 }
Selim Cineka1744872016-03-11 15:36:06 -0800396 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
397 layout.getHeadsUpChild().getId()
398 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek87ed69b2017-02-09 15:59:43 -0800399 int headsUpheight;
400 if (headsUpCustom && beforeN) {
401 headsUpheight = mMaxHeadsUpHeightLegacy;
402 } else if (mUseIncreasedHeadsUpHeight && layout == mPrivateLayout) {
403 headsUpheight = mMaxHeadsUpHeightIncreased;
404 } else {
405 headsUpheight = mMaxHeadsUpHeight;
406 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800407 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
408 mNotificationAmbientHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200409 }
410
411 public StatusBarNotification getStatusBarNotification() {
412 return mStatusBarNotification;
413 }
414
Selim Cinek281c2022016-10-13 19:14:43 -0700415 public NotificationData.Entry getEntry() {
416 return mEntry;
417 }
418
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700419 public boolean isHeadsUp() {
420 return mIsHeadsUp;
421 }
422
Selim Cinek1a521f32014-11-03 17:39:29 +0100423 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700424 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100425 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700426 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700427 if (mIsSummaryWithChildren) {
428 // The overflow might change since we allow more lines as HUN.
429 mChildrenContainer.updateGroupOverflow();
430 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700431 if (intrinsicBefore != getIntrinsicHeight()) {
432 notifyHeightChanged(false /* needsAnimation */);
433 }
Selim Cinekd127d792016-11-01 19:11:41 -0700434 if (isHeadsUp) {
435 setAboveShelf(true);
436 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100437 }
438
Selim Cinekb5605e52015-02-20 18:21:41 +0100439 public void setGroupManager(NotificationGroupManager groupManager) {
440 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700441 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100442 }
443
Adrian Roosb88b1a12015-12-09 18:51:05 -0800444 public void setRemoteInputController(RemoteInputController r) {
445 mPrivateLayout.setRemoteInputController(r);
446 }
447
Mady Mellor3fd273e2016-03-15 21:08:14 -0700448 public void setAppName(String appName) {
449 mAppName = appName;
Mady Mellor95d743c2017-01-10 12:05:27 -0800450 if (mMenuRow != null && mMenuRow.getMenuView() != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800451 mMenuRow.setAppName(mAppName);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700452 }
453 }
454
Selim Cinekb5605e52015-02-20 18:21:41 +0100455 public void addChildNotification(ExpandableNotificationRow row) {
456 addChildNotification(row, -1);
457 }
458
459 /**
460 * Add a child notification to this view.
461 *
462 * @param row the row to add
463 * @param childIndex the index to add it at, if -1 it will be added at the end
464 */
465 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
466 if (mChildrenContainer == null) {
467 mChildrenContainerStub.inflate();
468 }
469 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700470 onChildrenCountChanged();
471 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100472 }
473
474 public void removeChildNotification(ExpandableNotificationRow row) {
475 if (mChildrenContainer != null) {
476 mChildrenContainer.removeNotification(row);
477 }
Selim Cinek263398f2015-10-21 17:40:23 -0700478 onChildrenCountChanged();
479 row.setIsChildInGroup(false, null);
480 }
481
Mady Mellor43c2cd12016-12-12 21:05:13 -0800482 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700483 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700484 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700485 }
486
Selim Cinek388df6d2015-10-22 13:25:11 -0700487 public ExpandableNotificationRow getNotificationParent() {
488 return mNotificationParent;
489 }
490
Selim Cinek263398f2015-10-21 17:40:23 -0700491 /**
492 * @param isChildInGroup Is this notification now in a group
493 * @param parent the new parent notification
494 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700495 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500496 boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700497 mNotificationParent = childInGroup ? parent : null;
498 mPrivateLayout.setIsChildInGroup(childInGroup);
Selim Cinek5ba22542017-04-20 15:16:10 -0700499 mNotificationInflater.setIsChildInGroup(childInGroup);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400500 resetBackgroundAlpha();
Mady Mellorb0a82462016-04-30 17:31:02 -0700501 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -0700502 updateClickAndFocus();
Mady Mellorb0a82462016-04-30 17:31:02 -0700503 if (mNotificationParent != null) {
Selim Cinek9ce32852017-02-15 16:21:10 -0800504 setOverrideTintColor(NO_COLOR, 0.0f);
Mady Mellorb0a82462016-04-30 17:31:02 -0700505 mNotificationParent.updateBackgroundForGroupState();
506 }
Selim Cinekdb167372016-11-17 15:41:17 -0800507 updateIconVisibilities();
Selim Cinek34d93b02015-10-22 12:30:38 -0700508 }
509
510 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800511 public boolean onTouchEvent(MotionEvent event) {
512 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
513 || !isChildInGroup() || isGroupExpanded()) {
514 return super.onTouchEvent(event);
515 } else {
516 return false;
517 }
518 }
519
520 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800521 protected boolean handleSlideBack() {
Mady Mellor95d743c2017-01-10 12:05:27 -0800522 if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Mady Mellorf0625802016-02-11 18:03:48 -0800523 animateTranslateNotification(0 /* targetLeft */);
524 return true;
525 }
526 return false;
527 }
528
529 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700530 protected boolean shouldHideBackground() {
531 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700532 }
533
534 @Override
535 public boolean isSummaryWithChildren() {
536 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100537 }
538
539 @Override
540 public boolean areChildrenExpanded() {
541 return mChildrenExpanded;
542 }
543
544 public List<ExpandableNotificationRow> getNotificationChildren() {
545 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
546 }
547
Selim Cinekeef84282015-10-30 16:28:00 -0700548 public int getNumberOfNotificationChildren() {
549 if (mChildrenContainer == null) {
550 return 0;
551 }
552 return mChildrenContainer.getNotificationChildren().size();
553 }
554
Selim Cinekb5605e52015-02-20 18:21:41 +0100555 /**
556 * Apply the order given in the list to the children.
557 *
558 * @param childOrder the new list order
Selim Cineka7d4f822016-12-06 14:34:47 -0800559 * @param visualStabilityManager
560 * @param callback the callback to invoked in case it is not allowed
Selim Cinekb5605e52015-02-20 18:21:41 +0100561 * @return whether the list order has changed
562 */
Selim Cineka7d4f822016-12-06 14:34:47 -0800563 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
564 VisualStabilityManager visualStabilityManager,
565 VisualStabilityManager.Callback callback) {
566 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
567 visualStabilityManager, callback);
Selim Cinekb5605e52015-02-20 18:21:41 +0100568 }
569
570 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700571 if (mIsSummaryWithChildren) {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800572 ExpandableViewState parentState = resultState.getViewStateForView(this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100573 mChildrenContainer.getState(resultState, parentState);
574 }
575 }
576
577 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700578 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100579 mChildrenContainer.applyState(state);
580 }
581 }
582
583 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700584 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100585 mChildrenContainer.prepareExpansionChanged(state);
586 }
587 }
588
Selim Cinek0cfbef42016-11-09 19:06:36 -0800589 public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700590 if (mIsSummaryWithChildren) {
Selim Cinek0cfbef42016-11-09 19:06:36 -0800591 mChildrenContainer.startAnimationToState(finalState, properties);
Selim Cinekb5605e52015-02-20 18:21:41 +0100592 }
593 }
594
595 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800596 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100597 return this;
598 } else {
599 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
600 return view == null ? this : view;
601 }
602 }
603
Selim Cinekab29aeb2015-02-20 18:18:32 +0100604 public NotificationGuts getGuts() {
605 return mGuts;
606 }
607
Selim Cinek684a4422015-04-15 16:18:39 -0700608 /**
609 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
610 * the notification will be rendered on top of the screen.
611 *
612 * @param pinned whether it is pinned
613 */
614 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700615 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700616 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700617 if (intrinsicHeight != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -0700618 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekdef35a82016-05-03 15:52:51 -0700619 }
Selim Cinek31aada42015-12-18 17:51:15 -0800620 if (pinned) {
621 setIconAnimationRunning(true);
622 mExpandedWhenPinned = false;
623 } else if (mExpandedWhenPinned) {
624 setUserExpanded(true);
625 }
Selim Cinek98713a42015-09-21 15:47:20 +0200626 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700627 }
628
Selim Cinek684a4422015-04-15 16:18:39 -0700629 public boolean isPinned() {
630 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700631 }
632
Selim Cinekd127d792016-11-01 19:11:41 -0700633 @Override
634 public int getPinnedHeadsUpHeight() {
635 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
636 }
637
Selim Cinek31aada42015-12-18 17:51:15 -0800638 /**
639 * @param atLeastMinHeight should the value returned be at least the minimum height.
640 * Used to avoid cyclic calls
641 * @return the height of the heads up notification when pinned
642 */
Selim Cinekd127d792016-11-01 19:11:41 -0700643 private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800644 if (mIsSummaryWithChildren) {
645 return mChildrenContainer.getIntrinsicHeight();
646 }
Selim Cinek31aada42015-12-18 17:51:15 -0800647 if(mExpandedWhenPinned) {
648 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
649 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700650 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800651 } else {
652 return mHeadsUpHeight;
653 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700654 }
655
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700656 /**
657 * Mark whether this notification was just clicked, i.e. the user has just clicked this
658 * notification in this frame.
659 */
660 public void setJustClicked(boolean justClicked) {
661 mJustClicked = justClicked;
662 }
663
664 /**
665 * @return true if this notification has been clicked in this frame, false otherwise
666 */
667 public boolean wasJustClicked() {
668 return mJustClicked;
669 }
670
Selim Cinek98713a42015-09-21 15:47:20 +0200671 public void setChronometerRunning(boolean running) {
672 mLastChronometerRunning = running;
673 setChronometerRunning(running, mPrivateLayout);
674 setChronometerRunning(running, mPublicLayout);
675 if (mChildrenContainer != null) {
676 List<ExpandableNotificationRow> notificationChildren =
677 mChildrenContainer.getNotificationChildren();
678 for (int i = 0; i < notificationChildren.size(); i++) {
679 ExpandableNotificationRow child = notificationChildren.get(i);
680 child.setChronometerRunning(running);
681 }
682 }
683 }
684
685 private void setChronometerRunning(boolean running, NotificationContentView layout) {
686 if (layout != null) {
687 running = running || isPinned();
688 View contractedChild = layout.getContractedChild();
689 View expandedChild = layout.getExpandedChild();
690 View headsUpChild = layout.getHeadsUpChild();
691 setChronometerRunningForChild(running, contractedChild);
692 setChronometerRunningForChild(running, expandedChild);
693 setChronometerRunningForChild(running, headsUpChild);
694 }
695 }
696
697 private void setChronometerRunningForChild(boolean running, View child) {
698 if (child != null) {
699 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
700 if (chronometer instanceof Chronometer) {
701 ((Chronometer) chronometer).setStarted(running);
702 }
703 }
704 }
705
Selim Cinekea4bef72015-12-02 15:51:10 -0800706 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700707 if (mIsSummaryWithChildren) {
708 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700709 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800710 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700711 }
712
Selim Cinek414ad332017-02-24 19:06:12 -0800713 /**
714 * @return the currently visible notification header. This can be different from
715 * {@link #getNotificationHeader()} in case it is a low-priority group.
716 */
717 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekaa3901a2016-08-05 11:04:37 -0700718 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek414ad332017-02-24 19:06:12 -0800719 return mChildrenContainer.getVisibleHeader();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800720 }
721 return getShowingLayout().getVisibleNotificationHeader();
722 }
723
Selim Cinek570981d2015-12-01 11:37:01 -0800724 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
725 mOnExpandClickListener = onExpandClickListener;
726 }
727
Selim Cinekddf1b392016-05-27 16:33:10 -0700728 @Override
729 public void setOnClickListener(@Nullable OnClickListener l) {
730 super.setOnClickListener(l);
731 mOnClickListener = l;
732 updateClickAndFocus();
733 }
734
735 private void updateClickAndFocus() {
736 boolean normalChild = !isChildInGroup() || isGroupExpanded();
737 boolean clickable = mOnClickListener != null && normalChild;
738 if (isFocusable() != normalChild) {
739 setFocusable(normalChild);
740 }
741 if (isClickable() != clickable) {
742 setClickable(clickable);
743 }
744 }
745
Selim Cinek31aada42015-12-18 17:51:15 -0800746 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
747 mHeadsUpManager = headsUpManager;
748 }
749
Mady Mellor87d79452017-01-10 11:52:52 -0800750 public void setGutsView(MenuItem item) {
Mady Mellor95d743c2017-01-10 12:05:27 -0800751 if (mGuts != null && item.getGutsView() instanceof GutsContent) {
752 ((GutsContent) item.getGutsView()).setGutsParent(mGuts);
753 mGuts.setGutsContent((GutsContent) item.getGutsView());
Mady Mellor87d79452017-01-10 11:52:52 -0800754 }
755 }
756
Mady Mellor95d743c2017-01-10 12:05:27 -0800757 @Override
758 protected void onAttachedToWindow() {
759 super.onAttachedToWindow();
760 Dependency.get(PluginManager.class).addPluginListener(this,
761 NotificationMenuRowPlugin.class, false /* Allow multiple */);
762 }
763
764 @Override
765 protected void onDetachedFromWindow() {
766 super.onDetachedFromWindow();
767 Dependency.get(PluginManager.class).removePluginListener(this);
768 }
769
770 @Override
771 public void onPluginConnected(NotificationMenuRowPlugin plugin, Context pluginContext) {
772 boolean existed = mMenuRow.getMenuView() != null;
773 if (existed) {
774 removeView(mMenuRow.getMenuView());
775 }
776 mMenuRow = plugin;
777 if (mMenuRow.useDefaultMenuItems()) {
Mady Mellor4c197602017-04-10 17:57:52 -0700778 ArrayList<MenuItem> items = new ArrayList<>();
779 items.add(NotificationMenuRow.createInfoItem(mContext));
780 items.add(NotificationMenuRow.createSnoozeItem(mContext));
781 mMenuRow.setMenuItems(items);
Mady Mellor95d743c2017-01-10 12:05:27 -0800782 }
783 if (existed) {
784 createMenu();
785 }
786 }
787
788 @Override
789 public void onPluginDisconnected(NotificationMenuRowPlugin plugin) {
790 boolean existed = mMenuRow.getMenuView() != null;
791 mMenuRow = new NotificationMenuRow(mContext); // Back to default
792 if (existed) {
793 createMenu();
794 }
795 }
796
797 public NotificationMenuRowPlugin createMenu() {
798 if (mMenuRow.getMenuView() == null) {
799 mMenuRow.createMenu(this);
800 mMenuRow.setAppName(mAppName);
801 FrameLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
802 LayoutParams.MATCH_PARENT);
803 addView(mMenuRow.getMenuView(), MENU_VIEW_INDEX, lp);
804 }
805 return mMenuRow;
806 }
807
Mady Mellor95d743c2017-01-10 12:05:27 -0800808 public NotificationMenuRowPlugin getProvider() {
809 return mMenuRow;
810 }
811
Anthony Chen9fe1ee72017-04-07 13:53:37 -0700812 @Override
Selim Cinek1a48bab2017-02-17 19:38:40 -0800813 public void onDensityOrFontScaleChanged() {
Anthony Chen9fe1ee72017-04-07 13:53:37 -0700814 super.onDensityOrFontScaleChanged();
Selim Cinek01af3342016-02-09 19:25:31 -0800815 initDimens();
816 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800817 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700818 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800819 }
820 }
821 if (mGuts != null) {
822 View oldGuts = mGuts;
823 int index = indexOfChild(oldGuts);
824 removeView(oldGuts);
825 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
826 R.layout.notification_guts, this, false);
827 mGuts.setVisibility(oldGuts.getVisibility());
828 addView(mGuts, index);
829 }
Mady Mellor95d743c2017-01-10 12:05:27 -0800830 View oldMenu = mMenuRow.getMenuView();
831 if (oldMenu != null) {
Mady Mellor761cde12017-01-10 11:36:39 -0800832 int menuIndex = indexOfChild(oldMenu);
833 removeView(oldMenu);
Mady Mellor95d743c2017-01-10 12:05:27 -0800834 mMenuRow.createMenu(ExpandableNotificationRow.this);
Mady Mellor761cde12017-01-10 11:36:39 -0800835 mMenuRow.setAppName(mAppName);
Mady Mellor95d743c2017-01-10 12:05:27 -0800836 addView(mMenuRow.getMenuView(), menuIndex);
Mady Mellor4b80b102016-01-22 08:03:58 -0800837 }
Adrian Rooseb434ff2017-01-11 11:18:48 -0800838 for (NotificationContentView l : mLayouts) {
839 l.reInflateViews();
840 }
Selim Cinek1a48bab2017-02-17 19:38:40 -0800841 mNotificationInflater.onDensityOrFontScaleChanged();
842 onNotificationUpdated();
Selim Cinek01af3342016-02-09 19:25:31 -0800843 }
844
Mady Mellor9d03a522017-04-04 18:45:30 -0700845 @Override
846 public void onConfigurationChanged(Configuration newConfig) {
847 if (mMenuRow.getMenuView() != null) {
848 mMenuRow.onConfigurationChanged();
849 }
850 }
851
Selim Cinekc3179332016-03-04 14:44:56 -0800852 public void setContentBackground(int customBackgroundColor, boolean animate,
853 NotificationContentView notificationContentView) {
854 if (getShowingLayout() == notificationContentView) {
855 setTintColor(customBackgroundColor, animate);
856 }
857 }
858
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700859 public void closeRemoteInput() {
Adrian Rooseb434ff2017-01-11 11:18:48 -0800860 for (NotificationContentView l : mLayouts) {
861 l.closeRemoteInput();
862 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700863 }
864
Selim Cinekc897bd32016-03-18 17:32:31 -0700865 /**
866 * Set by how much the single line view should be indented.
867 */
868 public void setSingleLineWidthIndention(int indention) {
869 mPrivateLayout.setSingleLineWidthIndention(indention);
870 }
871
872 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700873 return mNotificationColor;
874 }
875
876 private void updateNotificationColor() {
877 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
878 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700879 }
880
881 public HybridNotificationView getSingleLineView() {
882 return mPrivateLayout.getSingleLineView();
883 }
884
Selim Cinekf07d0622016-03-21 19:52:52 -0700885 public boolean isOnKeyguard() {
886 return mOnKeyguard;
887 }
888
Selim Cinekc1e389d2016-04-07 11:02:57 -0700889 public void removeAllChildren() {
890 List<ExpandableNotificationRow> notificationChildren
891 = mChildrenContainer.getNotificationChildren();
892 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
893 for (int i = 0; i < clonedList.size(); i++) {
894 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700895 if (row.keepInParent()) {
896 continue;
897 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700898 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700899 row.setIsChildInGroup(false, null);
900 }
901 onChildrenCountChanged();
902 }
903
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700904 public void setForceUnlocked(boolean forceUnlocked) {
905 mForceUnlocked = forceUnlocked;
906 if (mIsSummaryWithChildren) {
907 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
908 for (ExpandableNotificationRow child : notificationChildren) {
909 child.setForceUnlocked(forceUnlocked);
910 }
911 }
912 }
913
Selim Cineke9bad242016-06-15 11:46:37 -0700914 public void setDismissed(boolean dismissed, boolean fromAccessibility) {
Selim Cinek3f19f602016-05-02 18:01:56 -0700915 mDismissed = dismissed;
Selim Cineke9bad242016-06-15 11:46:37 -0700916 mGroupParentWhenDismissed = mNotificationParent;
917 mRefocusOnDismiss = fromAccessibility;
918 mChildAfterViewWhenDismissed = null;
919 if (isChildInGroup()) {
920 List<ExpandableNotificationRow> notificationChildren =
921 mNotificationParent.getNotificationChildren();
922 int i = notificationChildren.indexOf(this);
923 if (i != -1 && i < notificationChildren.size() - 1) {
924 mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
925 }
926 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700927 }
928
929 public boolean isDismissed() {
930 return mDismissed;
931 }
932
933 public boolean keepInParent() {
934 return mKeepInParent;
935 }
936
937 public void setKeepInParent(boolean keepInParent) {
938 mKeepInParent = keepInParent;
939 }
940
941 public boolean isRemoved() {
942 return mRemoved;
943 }
944
Adrian Roosd009ab12016-05-20 17:58:53 -0700945 public void setRemoved() {
946 mRemoved = true;
Selim Cinekef8c2252017-02-10 14:52:18 -0800947 mTranslationWhenRemoved = getTranslationY();
948 mWasChildInGroupWhenRemoved = isChildInGroup();
949 if (isChildInGroup()) {
950 mTranslationWhenRemoved += getNotificationParent().getTranslationY();
951 }
Adrian Roosd009ab12016-05-20 17:58:53 -0700952 mPrivateLayout.setRemoved();
Selim Cinek3f19f602016-05-02 18:01:56 -0700953 }
954
Selim Cinekef8c2252017-02-10 14:52:18 -0800955 public boolean wasChildInGroupWhenRemoved() {
956 return mWasChildInGroupWhenRemoved;
957 }
958
959 public float getTranslationWhenRemoved() {
960 return mTranslationWhenRemoved;
961 }
962
Selim Cinekd1395642016-04-28 12:22:42 -0700963 public NotificationChildrenContainer getChildrenContainer() {
964 return mChildrenContainer;
965 }
966
Selim Cinekcafa87f2016-10-26 17:00:17 -0700967 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
968 mHeadsupDisappearRunning = headsUpAnimatingAway;
969 mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
970 }
971
972 /**
973 * @return if the view was just heads upped and is now animating away. During such a time the
974 * layout needs to be kept consistent
975 */
976 public boolean isHeadsUpAnimatingAway() {
977 return mHeadsupDisappearRunning;
Selim Cinek73cf02a2016-06-17 13:08:00 -0700978 }
979
Selim Cineke9bad242016-06-15 11:46:37 -0700980 public View getChildAfterViewWhenDismissed() {
981 return mChildAfterViewWhenDismissed;
982 }
983
984 public View getGroupParentWhenDismissed() {
985 return mGroupParentWhenDismissed;
986 }
987
Selim Cinek9e624e72016-07-20 13:46:49 -0700988 public void performDismiss() {
Selim Cineke9079112016-12-14 14:41:01 -0800989 if (mOnDismissRunnable != null) {
990 mOnDismissRunnable.run();
991 }
Selim Cinek9e624e72016-07-20 13:46:49 -0700992 }
993
Selim Cineke9079112016-12-14 14:41:01 -0800994 public void setOnDismissRunnable(Runnable onDismissRunnable) {
995 mOnDismissRunnable = onDismissRunnable;
Selim Cinek9e624e72016-07-20 13:46:49 -0700996 }
997
Selim Cinek281c2022016-10-13 19:14:43 -0700998 public View getNotificationIcon() {
Selim Cinek414ad332017-02-24 19:06:12 -0800999 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek281c2022016-10-13 19:14:43 -07001000 if (notificationHeader != null) {
1001 return notificationHeader.getIcon();
1002 }
1003 return null;
1004 }
1005
1006 /**
1007 * @return whether the notification is currently showing a view with an icon.
1008 */
1009 public boolean isShowingIcon() {
Mady Mellor434180c2017-02-13 11:29:42 -08001010 if (areGutsExposed()) {
1011 return false;
1012 }
Selim Cinek2ffa02f2017-03-06 15:56:37 -08001013 return getVisibleNotificationHeader() != null;
Selim Cinek281c2022016-10-13 19:14:43 -07001014 }
1015
Selim Cinek0242fbb2016-10-19 13:38:32 -07001016 /**
1017 * Set how much this notification is transformed into an icon.
1018 *
Selim Cinek2b549f42016-11-22 16:38:51 -08001019 * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
1020 * to the content away
Selim Cinek875a3a12016-11-18 17:52:16 -08001021 * @param isLastChild is this the last child in the list. If true, then the transformation is
1022 * different since it's content fades out.
Selim Cinek0242fbb2016-10-19 13:38:32 -07001023 */
Selim Cinek2b549f42016-11-22 16:38:51 -08001024 public void setContentTransformationAmount(float contentTransformationAmount,
1025 boolean isLastChild) {
Selim Cinek875a3a12016-11-18 17:52:16 -08001026 boolean changeTransformation = isLastChild != mIsLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001027 changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001028 mIsLastChild = isLastChild;
Selim Cinek2b549f42016-11-22 16:38:51 -08001029 mContentTransformationAmount = contentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001030 if (changeTransformation) {
1031 updateContentTransformation();
Selim Cinek2b549f42016-11-22 16:38:51 -08001032 }
1033 }
1034
1035 /**
1036 * Set the icons to be visible of this notification.
1037 */
1038 public void setIconsVisible(boolean iconsVisible) {
1039 if (iconsVisible != mIconsVisible) {
1040 mIconsVisible = iconsVisible;
1041 updateIconVisibilities();
Selim Cinek0242fbb2016-10-19 13:38:32 -07001042 }
1043 }
1044
Selim Cinekdb167372016-11-17 15:41:17 -08001045 @Override
1046 protected void onBelowSpeedBumpChanged() {
1047 updateIconVisibilities();
1048 }
1049
Selim Cinek875a3a12016-11-18 17:52:16 -08001050 private void updateContentTransformation() {
1051 float contentAlpha;
Selim Cinek2b549f42016-11-22 16:38:51 -08001052 float translationY = -mContentTransformationAmount * mIconTransformContentShift;
Selim Cinek875a3a12016-11-18 17:52:16 -08001053 if (mIsLastChild) {
Selim Cinek2b549f42016-11-22 16:38:51 -08001054 contentAlpha = 1.0f - mContentTransformationAmount;
Selim Cinek875a3a12016-11-18 17:52:16 -08001055 contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001056 contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
Selim Cinek875a3a12016-11-18 17:52:16 -08001057 translationY *= 0.4f;
1058 } else {
1059 contentAlpha = 1.0f;
1060 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001061 for (NotificationContentView l : mLayouts) {
1062 l.setAlpha(contentAlpha);
1063 l.setTranslationY(translationY);
1064 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001065 if (mChildrenContainer != null) {
1066 mChildrenContainer.setAlpha(contentAlpha);
1067 mChildrenContainer.setTranslationY(translationY);
1068 // TODO: handle children fade out better
Selim Cinek0242fbb2016-10-19 13:38:32 -07001069 }
1070 }
1071
1072 private void updateIconVisibilities() {
Selim Cinek17e1b692016-12-02 18:19:11 -08001073 boolean visible = isChildInGroup()
1074 || (isBelowSpeedBump() && !NotificationShelf.SHOW_AMBIENT_ICONS)
1075 || mIconsVisible;
Adrian Rooseb434ff2017-01-11 11:18:48 -08001076 for (NotificationContentView l : mLayouts) {
1077 l.setIconsVisible(visible);
1078 }
Selim Cinekdb167372016-11-17 15:41:17 -08001079 if (mChildrenContainer != null) {
1080 mChildrenContainer.setIconsVisible(visible);
Selim Cinek0242fbb2016-10-19 13:38:32 -07001081 }
1082 }
1083
Selim Cinek875a3a12016-11-18 17:52:16 -08001084 /**
1085 * Get the relative top padding of a view relative to this view. This recursively walks up the
1086 * hierarchy and does the corresponding measuring.
1087 *
1088 * @param view the view to the the padding for. The requested view has to be a child of this
1089 * notification.
1090 * @return the toppadding
1091 */
1092 public int getRelativeTopPadding(View view) {
1093 int topPadding = 0;
1094 while (view.getParent() instanceof ViewGroup) {
1095 topPadding += view.getTop();
1096 view = (View) view.getParent();
1097 if (view instanceof ExpandableNotificationRow) {
1098 return topPadding;
1099 }
1100 }
1101 return topPadding;
1102 }
1103
Selim Cineka1d97902016-12-14 16:31:40 -08001104 public float getContentTranslation() {
1105 return mPrivateLayout.getTranslationY();
1106 }
1107
Selim Cinek6743c0b2017-01-18 18:24:01 -08001108 public void setIsLowPriority(boolean isLowPriority) {
1109 mIsLowPriority = isLowPriority;
1110 mPrivateLayout.setIsLowPriority(isLowPriority);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001111 mNotificationInflater.setIsLowPriority(mIsLowPriority);
Selim Cinek6743c0b2017-01-18 18:24:01 -08001112 if (mChildrenContainer != null) {
1113 mChildrenContainer.setIsLowPriority(isLowPriority);
1114 }
1115 }
1116
Selim Cinek414ad332017-02-24 19:06:12 -08001117 public boolean isLowPriority() {
1118 return mIsLowPriority;
1119 }
1120
Selim Cinek7d1009b2017-01-25 15:28:28 -08001121 public void setUseIncreasedCollapsedHeight(boolean use) {
1122 mUseIncreasedCollapsedHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001123 mNotificationInflater.setUsesIncreasedHeight(use);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001124 }
1125
Selim Cinek87ed69b2017-02-09 15:59:43 -08001126 public void setUseIncreasedHeadsUpHeight(boolean use) {
1127 mUseIncreasedHeadsUpHeight = use;
Selim Cinek1a48bab2017-02-17 19:38:40 -08001128 mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
1129 }
1130
1131 public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
1132 mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001133 }
1134
Selim Cinek5ba22542017-04-20 15:16:10 -07001135 public void setInflationCallback(InflationCallback callback) {
1136 mNotificationInflater.setInflationCallback(callback);
Selim Cinekc478f902017-02-22 20:55:44 -08001137 }
1138
Adrian Roos1a1ecfc2017-04-17 11:17:59 -07001139 public void setNeedsRedaction(boolean needsRedaction) {
1140 mNotificationInflater.setRedactAmbient(needsRedaction);
1141 }
1142
Selim Cinek5ba22542017-04-20 15:16:10 -07001143 @VisibleForTesting
1144 public NotificationInflater getNotificationInflater() {
1145 return mNotificationInflater;
1146 }
1147
Chris Wren78403d72014-07-28 10:23:24 +01001148 public interface ExpansionLogger {
1149 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
1150 }
Selim Cinek1685e632014-04-08 02:27:49 +02001151
Chris Wren51c75102013-07-16 20:49:17 -04001152 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
1153 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001154 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001155 mNotificationInflater = new NotificationInflater(this);
Mady Mellor95d743c2017-01-10 12:05:27 -08001156 mMenuRow = new NotificationMenuRow(mContext);
Selim Cinek01af3342016-02-09 19:25:31 -08001157 initDimens();
1158 }
1159
1160 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -08001161 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
1162 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
Selim Cinek7d1009b2017-01-25 15:28:28 -08001163 mNotificationMinHeightLarge = getFontScaledHeight(
Selim Cinek87ed69b2017-02-09 15:59:43 -08001164 R.dimen.notification_min_height_increased);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001165 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
Adrian Roos0aac04f2016-12-08 15:59:29 -08001166 mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001167 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -08001168 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001169 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Selim Cinek87ed69b2017-02-09 15:59:43 -08001170 mMaxHeadsUpHeightIncreased = getFontScaledHeight(
1171 R.dimen.notification_max_heads_up_height_increased);
Anthony Chen7acbb772017-04-07 16:45:25 -07001172 Resources res = getResources();
1173 mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
1174 R.dimen.notification_divider_height_increased);
1175 mIconTransformContentShiftNoIcon = res.getDimensionPixelSize(
Selim Cinek0242fbb2016-10-19 13:38:32 -07001176 R.dimen.notification_icon_transform_content_shift);
Selim Cinekf619ffc2016-02-17 14:53:05 -08001177 }
1178
1179 /**
1180 * @param dimenId the dimen to look up
1181 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
1182 */
1183 private int getFontScaledHeight(int dimenId) {
1184 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
1185 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
1186 getResources().getDisplayMetrics().density);
1187 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -04001188 }
1189
Christoph Studera7fe6312014-06-27 19:32:44 +02001190 /**
1191 * Resets this view so it can be re-used for an updated notification.
1192 */
1193 public void reset() {
Jorim Jaggiae441282014-08-01 02:45:18 +02001194 mShowingPublicInitialized = false;
Selim Cinek31094df2014-08-14 19:28:15 +02001195 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +02001196 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +02001197 }
1198
Jorim Jaggi251957d2014-04-09 04:24:09 +02001199 @Override
1200 protected void onFinishInflate() {
1201 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001202 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
1203 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001204 mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
1205
1206 for (NotificationContentView l : mLayouts) {
1207 l.setExpandClickListener(mExpandClickListener);
1208 l.setContainingNotification(this);
1209 }
Selim Cinekab29aeb2015-02-20 18:18:32 +01001210 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
1211 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001212 @Override
1213 public void onInflate(ViewStub stub, View inflated) {
1214 mGuts = (NotificationGuts) inflated;
1215 mGuts.setClipTopAmount(getClipTopAmount());
1216 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +01001217 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001218 }
1219 });
Selim Cinekb5605e52015-02-20 18:21:41 +01001220 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
1221 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
1222
1223 @Override
1224 public void onInflate(ViewStub stub, View inflated) {
1225 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek6743c0b2017-01-18 18:24:01 -08001226 mChildrenContainer.setIsLowPriority(mIsLowPriority);
Selim Cinek414ad332017-02-24 19:06:12 -08001227 mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -07001228 mChildrenContainer.onNotificationUpdated();
Anthony Chen7acbb772017-04-07 16:45:25 -07001229
1230 if (mShouldTranslateContents) {
1231 mTranslateableViews.add(mChildrenContainer);
1232 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001233 }
1234 });
Mady Mellor4b80b102016-01-22 08:03:58 -08001235
Anthony Chen7acbb772017-04-07 16:45:25 -07001236 if (mShouldTranslateContents) {
1237 // Add the views that we translate to reveal the menu
1238 mTranslateableViews = new ArrayList<>();
1239 for (int i = 0; i < getChildCount(); i++) {
1240 mTranslateableViews.add(getChildAt(i));
1241 }
1242 // Remove views that don't translate
1243 mTranslateableViews.remove(mChildrenContainerStub);
1244 mTranslateableViews.remove(mGutsStub);
Mady Mellor4b80b102016-01-22 08:03:58 -08001245 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001246 }
1247
Mady Mellor4b80b102016-01-22 08:03:58 -08001248 public void resetTranslation() {
Mady Mellor32c638a2016-09-14 08:58:25 -07001249 if (mTranslateAnim != null) {
1250 mTranslateAnim.cancel();
1251 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001252
1253 if (!mShouldTranslateContents) {
1254 setTranslationX(0);
1255 } else if (mTranslateableViews != null) {
Mady Mellor4b80b102016-01-22 08:03:58 -08001256 for (int i = 0; i < mTranslateableViews.size(); i++) {
1257 mTranslateableViews.get(i).setTranslationX(0);
1258 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001259 invalidateOutline();
Mady Mellor4b80b102016-01-22 08:03:58 -08001260 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001261
Mady Mellor95d743c2017-01-10 12:05:27 -08001262 mMenuRow.resetMenu();
Mady Mellor4b80b102016-01-22 08:03:58 -08001263 }
1264
1265 public void animateTranslateNotification(final float leftTarget) {
1266 if (mTranslateAnim != null) {
1267 mTranslateAnim.cancel();
1268 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001269 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -08001270 if (mTranslateAnim != null) {
1271 mTranslateAnim.start();
1272 }
1273 }
1274
1275 @Override
1276 public void setTranslation(float translationX) {
1277 if (areGutsExposed()) {
1278 // Don't translate if guts are showing.
1279 return;
1280 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001281 if (!mShouldTranslateContents) {
1282 setTranslationX(translationX);
1283 } else if (mTranslateableViews != null) {
1284 // Translate the group of views
1285 for (int i = 0; i < mTranslateableViews.size(); i++) {
1286 if (mTranslateableViews.get(i) != null) {
1287 mTranslateableViews.get(i).setTranslationX(translationX);
1288 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001289 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001290 invalidateOutline();
Mady Mellor34958fa2016-02-23 09:52:17 -08001291 }
Mady Mellor95d743c2017-01-10 12:05:27 -08001292 if (mMenuRow.getMenuView() != null) {
1293 mMenuRow.onTranslationUpdate(translationX);
Mady Mellor34958fa2016-02-23 09:52:17 -08001294 }
1295 }
1296
1297 @Override
1298 public float getTranslation() {
Anthony Chene04afcb2017-04-21 13:51:32 -07001299 if (!mShouldTranslateContents) {
Anthony Chen7acbb772017-04-07 16:45:25 -07001300 return getTranslationX();
1301 }
1302
Mady Mellor34958fa2016-02-23 09:52:17 -08001303 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
1304 // All of the views in the list should have same translation, just use first one.
1305 return mTranslateableViews.get(0).getTranslationX();
1306 }
Anthony Chen7acbb772017-04-07 16:45:25 -07001307
Mady Mellor34958fa2016-02-23 09:52:17 -08001308 return 0;
1309 }
1310
1311 public Animator getTranslateViewAnimator(final float leftTarget,
1312 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -07001313 if (mTranslateAnim != null) {
1314 mTranslateAnim.cancel();
1315 }
Mady Mellor34958fa2016-02-23 09:52:17 -08001316 if (areGutsExposed()) {
1317 // No translation if guts are exposed.
1318 return null;
1319 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001320 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
1321 leftTarget);
1322 if (listener != null) {
1323 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -08001324 }
Mady Mellorb0a82462016-04-30 17:31:02 -07001325 translateAnim.addListener(new AnimatorListenerAdapter() {
1326 boolean cancelled = false;
1327
1328 @Override
1329 public void onAnimationCancel(Animator anim) {
1330 cancelled = true;
1331 }
1332
1333 @Override
1334 public void onAnimationEnd(Animator anim) {
Mady Mellor95d743c2017-01-10 12:05:27 -08001335 if (!cancelled && leftTarget == 0) {
1336 mMenuRow.resetMenu();
Mady Mellorb0a82462016-04-30 17:31:02 -07001337 mTranslateAnim = null;
1338 }
1339 }
1340 });
1341 mTranslateAnim = translateAnim;
1342 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -08001343 }
1344
Selim Cinekab29aeb2015-02-20 18:18:32 +01001345 public void inflateGuts() {
1346 if (mGuts == null) {
1347 mGutsStub.inflate();
1348 }
1349 }
1350
Selim Cinekda42d652015-12-04 15:51:16 -08001351 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -08001352 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
1353 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001354 if (mChildrenContainer != null) {
1355 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
1356 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -08001357 }
Selim Cinekda42d652015-12-04 15:51:16 -08001358 // The limits might have changed if the view suddenly became a group or vice versa
1359 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +01001360 }
1361
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001362 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08001363 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
1364 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +02001365 // Add a record for the entire layout since its content is somehow small.
1366 // The event comes from a leaf view that is interacted with.
1367 AccessibilityEvent record = AccessibilityEvent.obtain();
1368 onInitializeAccessibilityEvent(record);
1369 dispatchPopulateAccessibilityEvent(record);
1370 event.appendRecord(record);
1371 return true;
1372 }
1373 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +02001374 }
Chris Wren51c75102013-07-16 20:49:17 -04001375
John Spurlocke15452b2014-08-21 09:44:39 -04001376 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001377 public void setDark(boolean dark, boolean fade, long delay) {
1378 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001379 final NotificationContentView showing = getShowingLayout();
1380 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001381 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -04001382 }
Selim Cinek9c7712d2015-12-08 19:19:48 -08001383 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001384 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001385 }
John Spurlocke15452b2014-08-21 09:44:39 -04001386 }
1387
Chris Wren51c75102013-07-16 20:49:17 -04001388 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -07001389 if (mIsSummaryWithChildren && !mShowingPublic) {
1390 return !mChildrenExpanded;
1391 }
Chris Wren51c75102013-07-16 20:49:17 -04001392 return mExpandable;
1393 }
1394
1395 public void setExpandable(boolean expandable) {
1396 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001397 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -04001398 }
1399
Selim Cinek4ffd6362015-12-29 15:12:23 +01001400 @Override
1401 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -08001402 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
1403 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +01001404 }
1405
Selim Cinek1685e632014-04-08 02:27:49 +02001406 /**
1407 * @return whether the user has changed the expansion state
1408 */
1409 public boolean hasUserChangedExpansion() {
1410 return mHasUserChangedExpansion;
1411 }
1412
Chris Wren51c75102013-07-16 20:49:17 -04001413 public boolean isUserExpanded() {
1414 return mUserExpanded;
1415 }
1416
Selim Cinek1685e632014-04-08 02:27:49 +02001417 /**
1418 * Set this notification to be expanded by the user
1419 *
1420 * @param userExpanded whether the user wants this notification to be expanded
1421 */
Chris Wren51c75102013-07-16 20:49:17 -04001422 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001423 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1424 }
1425
1426 /**
1427 * Set this notification to be expanded by the user
1428 *
1429 * @param userExpanded whether the user wants this notification to be expanded
1430 * @param allowChildExpansion whether a call to this method allows expanding children
1431 */
1432 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001433 mFalsingManager.setNotificationExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08001434 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion
1435 && !mChildrenContainer.showingAsLowPriority()) {
Chris Wren698b1702016-05-23 11:16:32 -04001436 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001437 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Selim Cinek414ad332017-02-24 19:06:12 -08001438 onExpansionChanged(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001439 return;
1440 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001441 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001442 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001443 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001444 mUserExpanded = userExpanded;
Selim Cinek414ad332017-02-24 19:06:12 -08001445 onExpansionChanged(true /* userAction */, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001446 }
1447
Selim Cinekccd14fb2014-08-12 18:53:24 +02001448 public void resetUserExpansion() {
Selim Cinek414ad332017-02-24 19:06:12 -08001449 boolean changed = mUserExpanded;
Selim Cinekccd14fb2014-08-12 18:53:24 +02001450 mHasUserChangedExpansion = false;
1451 mUserExpanded = false;
Selim Cinek414ad332017-02-24 19:06:12 -08001452 if (changed && mIsSummaryWithChildren) {
1453 mChildrenContainer.onExpansionChanged();
1454 }
1455 updateShelfIconColor();
Selim Cinekccd14fb2014-08-12 18:53:24 +02001456 }
1457
Chris Wren51c75102013-07-16 20:49:17 -04001458 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001459 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001460 }
1461
1462 public void setUserLocked(boolean userLocked) {
1463 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001464 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001465 if (mIsSummaryWithChildren) {
1466 mChildrenContainer.setUserLocked(userLocked);
Selim Cinek7baaa9e2016-07-21 17:21:09 -07001467 if (userLocked || !isGroupExpanded()) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001468 updateBackgroundForGroupState();
1469 }
Selim Cinek42357e02016-02-24 18:48:01 -08001470 }
Chris Wren51c75102013-07-16 20:49:17 -04001471 }
1472
Selim Cinek1685e632014-04-08 02:27:49 +02001473 /**
1474 * @return has the system set this notification to be expanded
1475 */
1476 public boolean isSystemExpanded() {
1477 return mIsSystemExpanded;
1478 }
1479
1480 /**
1481 * Set this notification to be expanded by the system.
1482 *
1483 * @param expand whether the system wants this notification to be expanded.
1484 */
1485 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001486 if (expand != mIsSystemExpanded) {
1487 final boolean wasExpanded = isExpanded();
1488 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001489 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek414ad332017-02-24 19:06:12 -08001490 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cineked6913b2016-06-01 12:01:17 -07001491 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001492 mChildrenContainer.updateGroupOverflow();
1493 }
Selim Cinek31094df2014-08-14 19:28:15 +02001494 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001495 }
1496
1497 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001498 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001499 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001500 public void setOnKeyguard(boolean onKeyguard) {
1501 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001502 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001503 mOnKeyguard = onKeyguard;
Selim Cinek414ad332017-02-24 19:06:12 -08001504 onExpansionChanged(false /* userAction */, wasExpanded);
Selim Cinek31094df2014-08-14 19:28:15 +02001505 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001506 if (mIsSummaryWithChildren) {
1507 mChildrenContainer.updateGroupOverflow();
1508 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001509 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001510 }
1511 }
Selim Cinek1685e632014-04-08 02:27:49 +02001512 }
1513
1514 /**
Selim Cinek9e624e72016-07-20 13:46:49 -07001515 * @return Can the underlying notification be cleared? This can be different from whether the
1516 * notification can be dismissed in case notifications are sensitive on the lockscreen.
1517 * @see #canViewBeDismissed()
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001518 */
1519 public boolean isClearable() {
Selim Cinek506deb62016-07-20 15:43:59 -07001520 if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
1521 return false;
1522 }
1523 if (mIsSummaryWithChildren) {
1524 List<ExpandableNotificationRow> notificationChildren =
1525 mChildrenContainer.getNotificationChildren();
1526 for (int i = 0; i < notificationChildren.size(); i++) {
1527 ExpandableNotificationRow child = notificationChildren.get(i);
1528 if (!child.isClearable()) {
1529 return false;
1530 }
1531 }
1532 }
1533 return true;
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001534 }
1535
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001536 @Override
1537 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001538 if (isUserLocked()) {
1539 return getActualHeight();
1540 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001541 if (mGuts != null && mGuts.isExposed()) {
Mady Mellore09fb702017-03-30 13:23:29 -07001542 return mGuts.getIntrinsicHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001543 } else if ((isChildInGroup() && !isGroupExpanded())) {
1544 return mPrivateLayout.getMinHeight();
Adrian Roos0aac04f2016-12-08 15:59:29 -08001545 } else if (mShowAmbient) {
1546 return getAmbientHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001547 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1548 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001549 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001550 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001551 } else if (!mOnKeyguard && (mIsHeadsUp || mHeadsupDisappearRunning)) {
Selim Cinek73cf02a2016-06-17 13:08:00 -07001552 if (isPinned() || mHeadsupDisappearRunning) {
Selim Cinek31aada42015-12-18 17:51:15 -08001553 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1554 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001555 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001556 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001557 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001558 }
Selim Cinek31aada42015-12-18 17:51:15 -08001559 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001560 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001561 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001562 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001563 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001564 }
Selim Cinek1685e632014-04-08 02:27:49 +02001565
Mady Mellor43c2cd12016-12-12 21:05:13 -08001566 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001567 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001568 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001569 }
1570
Selim Cinek263398f2015-10-21 17:40:23 -07001571 private void onChildrenCountChanged() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -05001572 mIsSummaryWithChildren = StatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001573 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1574 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
Selim Cinek414ad332017-02-24 19:06:12 -08001575 mChildrenContainer.recreateNotificationHeader(mExpandClickListener
1576 );
Selim Cinek263398f2015-10-21 17:40:23 -07001577 }
Mady Mellor6baed9e2016-05-25 16:05:09 -07001578 getShowingLayout().updateBackgroundColor(false /* animate */);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001579 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001580 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001581 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001582 }
1583
Mady Mellorb0a82462016-04-30 17:31:02 -07001584 public void updateChildrenHeaderAppearance() {
Selim Cineked6913b2016-06-01 12:01:17 -07001585 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001586 mChildrenContainer.updateChildrenHeaderAppearance();
1587 }
1588 }
1589
Selim Cinek1685e632014-04-08 02:27:49 +02001590 /**
1591 * Check whether the view state is currently expanded. This is given by the system in {@link
1592 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1593 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1594 * view can differ from this state, if layout params are modified from outside.
1595 *
1596 * @return whether the view state is currently expanded.
1597 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001598 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001599 return isExpanded(false /* allowOnKeyguard */);
1600 }
1601
1602 public boolean isExpanded(boolean allowOnKeyguard) {
1603 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001604 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1605 || isUserExpanded());
1606 }
1607
1608 private boolean isSystemChildExpanded() {
1609 return mIsSystemChildExpanded;
1610 }
1611
1612 public void setSystemChildExpanded(boolean expanded) {
1613 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001614 }
1615
Mady Mellor035badd2017-04-04 18:45:30 -07001616 public void setLayoutListener(LayoutListener listener) {
1617 mLayoutListener = listener;
1618 }
1619
1620 public void removeListener() {
1621 mLayoutListener = null;
1622 }
1623
Selim Cinek1685e632014-04-08 02:27:49 +02001624 @Override
1625 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1626 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001627 updateMaxHeights();
Mady Mellor95d743c2017-01-10 12:05:27 -08001628 if (mMenuRow.getMenuView() != null) {
1629 mMenuRow.onHeightUpdate();
Mady Mellora6edc872016-04-26 11:01:03 -07001630 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001631 updateContentShiftHeight();
Mady Mellor035badd2017-04-04 18:45:30 -07001632 if (mLayoutListener != null) {
1633 mLayoutListener.onLayout();
1634 }
Selim Cinek875a3a12016-11-18 17:52:16 -08001635 }
1636
1637 /**
1638 * Updates the content shift height such that the header is completely hidden when coming from
1639 * the top.
1640 */
1641 private void updateContentShiftHeight() {
Selim Cinek414ad332017-02-24 19:06:12 -08001642 NotificationHeaderView notificationHeader = getVisibleNotificationHeader();
Selim Cinek875a3a12016-11-18 17:52:16 -08001643 if (notificationHeader != null) {
1644 CachingIconView icon = notificationHeader.getIcon();
1645 mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
1646 } else {
1647 mIconTransformContentShift = mIconTransformContentShiftNoIcon;
1648 }
Selim Cinek1685e632014-04-08 02:27:49 +02001649 }
1650
Selim Cinek8d490d42015-04-10 00:05:50 -07001651 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001652 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001653 View expandedChild = mPrivateLayout.getExpandedChild();
1654 if (expandedChild == null) {
1655 expandedChild = mPrivateLayout.getContractedChild();
1656 }
1657 mMaxExpandHeight = expandedChild.getHeight();
1658 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001659 if (headsUpChild == null) {
1660 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001661 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001662 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001663 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001664 notifyHeightChanged(true /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001665 }
1666 }
1667
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001668 @Override
1669 public void notifyHeightChanged(boolean needsAnimation) {
1670 super.notifyHeightChanged(needsAnimation);
1671 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1672 }
1673
Selim Cinek3c76d502016-02-19 15:16:33 -08001674 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001675 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001676 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001677 }
1678
Mady Mellor43c2cd12016-12-12 21:05:13 -08001679 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001680 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001681 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001682 if (mIsSummaryWithChildren) {
1683 List<ExpandableNotificationRow> notificationChildren =
1684 mChildrenContainer.getNotificationChildren();
1685 for (int i = 0; i < notificationChildren.size(); i++) {
1686 ExpandableNotificationRow child = notificationChildren.get(i);
1687 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1688 }
1689 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001690 }
1691
Mady Mellor43c2cd12016-12-12 21:05:13 -08001692 @Override
Jorim Jaggiae441282014-08-01 02:45:18 +02001693 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1694 long duration) {
1695 boolean oldShowingPublic = mShowingPublic;
1696 mShowingPublic = mSensitive && hideSensitive;
1697 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1698 return;
1699 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001700
1701 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001702 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001703
Jorim Jaggiae441282014-08-01 02:45:18 +02001704 if (!animated) {
1705 mPublicLayout.animate().cancel();
1706 mPrivateLayout.animate().cancel();
Selim Cineka554c702016-06-17 18:02:12 -07001707 if (mChildrenContainer != null) {
1708 mChildrenContainer.animate().cancel();
1709 mChildrenContainer.setAlpha(1f);
1710 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001711 mPublicLayout.setAlpha(1f);
1712 mPrivateLayout.setAlpha(1f);
1713 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001714 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001715 } else {
1716 animateShowingPublic(delay, duration);
1717 }
Selim Cinekc3179332016-03-04 14:44:56 -08001718 NotificationContentView showingLayout = getShowingLayout();
1719 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001720 mPrivateLayout.updateExpandButtons(isExpandable());
Adrian Roose5726a22016-12-19 14:26:51 -08001721 showingLayout.setDark(isDark(), false /* animate */, 0 /* delay */);
Jorim Jaggiae441282014-08-01 02:45:18 +02001722 mShowingPublicInitialized = true;
1723 }
1724
1725 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001726 View[] privateViews = mIsSummaryWithChildren
1727 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001728 : new View[] {mPrivateLayout};
1729 View[] publicViews = new View[] {mPublicLayout};
1730 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1731 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1732 for (final View hiddenView : hiddenChildren) {
1733 hiddenView.setVisibility(View.VISIBLE);
1734 hiddenView.animate().cancel();
1735 hiddenView.animate()
1736 .alpha(0f)
1737 .setStartDelay(delay)
1738 .setDuration(duration)
1739 .withEndAction(new Runnable() {
1740 @Override
1741 public void run() {
1742 hiddenView.setVisibility(View.INVISIBLE);
1743 }
1744 });
1745 }
1746 for (View showView : shownChildren) {
1747 showView.setVisibility(View.VISIBLE);
1748 showView.setAlpha(0f);
1749 showView.animate().cancel();
1750 showView.animate()
1751 .alpha(1f)
1752 .setStartDelay(delay)
1753 .setDuration(duration);
1754 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001755 }
1756
Mady Mellor43c2cd12016-12-12 21:05:13 -08001757 @Override
Selim Cinek3776fe02016-02-04 13:32:43 -08001758 public boolean mustStayOnScreen() {
1759 return mIsHeadsUp;
1760 }
1761
Selim Cinek9e624e72016-07-20 13:46:49 -07001762 /**
1763 * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
1764 * otherwise some state might not be updated. To request about the general clearability
1765 * see {@link #isClearable()}.
1766 */
1767 public boolean canViewBeDismissed() {
Selim Cineke9bad242016-06-15 11:46:37 -07001768 return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001769 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001770
Ricky Waicd35def2016-05-03 11:07:07 +01001771 public void makeActionsVisibile() {
1772 setUserExpanded(true, true);
1773 if (isChildInGroup()) {
1774 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1775 }
Selim Cinekbb42b7d2016-08-10 13:02:38 -07001776 notifyHeightChanged(false /* needsAnimation */);
Ricky Waicd35def2016-05-03 11:07:07 +01001777 }
1778
Selim Cinekb5605e52015-02-20 18:21:41 +01001779 public void setChildrenExpanded(boolean expanded, boolean animate) {
1780 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001781 if (mChildrenContainer != null) {
1782 mChildrenContainer.setChildrenExpanded(expanded);
1783 }
Mady Mellor1a5d8ea2016-06-09 10:42:42 -07001784 updateBackgroundForGroupState();
Selim Cinekddf1b392016-05-27 16:33:10 -07001785 updateClickAndFocus();
Selim Cinekb5605e52015-02-20 18:21:41 +01001786 }
1787
Selim Cinekb5605e52015-02-20 18:21:41 +01001788 public static void applyTint(View v, int color) {
1789 int alpha;
1790 if (color != 0) {
1791 alpha = COLORED_DIVIDER_ALPHA;
1792 } else {
1793 color = 0xff000000;
1794 alpha = DEFAULT_DIVIDER_ALPHA;
1795 }
1796 if (v.getBackground() instanceof ColorDrawable) {
1797 ColorDrawable background = (ColorDrawable) v.getBackground();
1798 background.mutate();
1799 background.setColor(color);
1800 background.setAlpha(alpha);
1801 }
1802 }
1803
Selim Cinek1685e632014-04-08 02:27:49 +02001804 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001805 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001806 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001807
Mady Mellor34958fa2016-02-23 09:52:17 -08001808 public boolean areGutsExposed() {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001809 return (mGuts != null && mGuts.isExposed());
Mady Mellor34958fa2016-02-23 09:52:17 -08001810 }
1811
Jorim Jaggibe565df2014-04-28 17:51:23 +02001812 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001813 public boolean isContentExpandable() {
Selim Cinekc0ac4af2017-03-03 15:13:48 -08001814 if (mIsSummaryWithChildren && !mShowingPublic) {
1815 return true;
1816 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001817 NotificationContentView showingLayout = getShowingLayout();
1818 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001819 }
1820
1821 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001822 protected View getContentView() {
Selim Cinekaa3901a2016-08-05 11:04:37 -07001823 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cineka5703182016-05-11 21:23:16 -04001824 return mChildrenContainer;
1825 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001826 return getShowingLayout();
1827 }
1828
1829 @Override
Selim Cinekaa3901a2016-08-05 11:04:37 -07001830 protected void onAppearAnimationFinished(boolean wasAppearing) {
1831 super.onAppearAnimationFinished(wasAppearing);
1832 if (wasAppearing) {
1833 // During the animation the visible view might have changed, so let's make sure all
1834 // alphas are reset
1835 if (mChildrenContainer != null) {
1836 mChildrenContainer.setAlpha(1.0f);
1837 mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
1838 }
Adrian Rooseb434ff2017-01-11 11:18:48 -08001839 for (NotificationContentView l : mLayouts) {
1840 l.setAlpha(1.0f);
1841 l.setLayerType(LAYER_TYPE_NONE, null);
1842 }
Selim Cinekaa3901a2016-08-05 11:04:37 -07001843 }
1844 }
1845
1846 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001847 public int getExtraBottomPadding() {
1848 if (mIsSummaryWithChildren && isGroupExpanded()) {
1849 return mIncreasedPaddingBetweenElements;
1850 }
1851 return 0;
1852 }
1853
1854 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001855 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinek4ca6c632017-02-23 18:03:37 -08001856 boolean changed = height != getActualHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +01001857 super.setActualHeight(height, notifyListeners);
Selim Cinek4ca6c632017-02-23 18:03:37 -08001858 if (changed && isRemoved()) {
1859 // TODO: remove this once we found the gfx bug for this.
1860 // This is a hack since a removed view sometimes would just stay blank. it occured
1861 // when sending yourself a message and then clicking on it.
1862 ViewGroup parent = (ViewGroup) getParent();
1863 if (parent != null) {
1864 parent.invalidate();
1865 }
1866 }
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001867 if (mGuts != null && mGuts.isExposed()) {
Mady Mellorb53bc272016-02-11 18:28:23 -08001868 mGuts.setActualHeight(height);
1869 return;
1870 }
Selim Cinekeef84282015-10-30 16:28:00 -07001871 int contentHeight = Math.max(getMinHeight(), height);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001872 for (NotificationContentView l : mLayouts) {
1873 l.setContentHeight(contentHeight);
1874 }
Selim Cinek42357e02016-02-24 18:48:01 -08001875 if (mIsSummaryWithChildren) {
1876 mChildrenContainer.setActualHeight(height);
1877 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001878 if (mGuts != null) {
1879 mGuts.setActualHeight(height);
1880 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001881 }
1882
1883 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001884 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001885 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001886 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001887 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001888 NotificationContentView showingLayout = getShowingLayout();
1889 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001890 }
1891
1892 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001893 public int getMinHeight() {
Mady Mellore09fb702017-03-30 13:23:29 -07001894 if (mGuts != null && mGuts.isExposed()) {
1895 return mGuts.getIntrinsicHeight();
1896 } else if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
Selim Cinek31aada42015-12-18 17:51:15 -08001897 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1898 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001899 return mChildrenContainer.getMinHeight();
Selim Cinek01ee2cd52016-12-21 18:23:11 +01001900 } else if (!mOnKeyguard && mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001901 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001902 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001903 NotificationContentView showingLayout = getShowingLayout();
1904 return showingLayout.getMinHeight();
1905 }
1906
Adrian Roos0aac04f2016-12-08 15:59:29 -08001907 private int getAmbientHeight() {
1908 NotificationContentView showingLayout = getShowingLayout();
1909 return showingLayout.getAmbientChild() != null
1910 ? showingLayout.getAmbientChild().getHeight()
1911 : getCollapsedHeight();
1912 }
1913
Selim Cinek816c8e42015-11-19 12:00:45 -08001914 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001915 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001916 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001917 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001918 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001919 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001920 }
1921
1922 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001923 public void setClipTopAmount(int clipTopAmount) {
1924 super.setClipTopAmount(clipTopAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001925 for (NotificationContentView l : mLayouts) {
1926 l.setClipTopAmount(clipTopAmount);
1927 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001928 if (mGuts != null) {
1929 mGuts.setClipTopAmount(clipTopAmount);
1930 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001931 }
1932
Selim Cineka686b2c2016-10-26 13:58:27 -07001933 @Override
1934 public void setClipBottomAmount(int clipBottomAmount) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001935 if (clipBottomAmount != mClipBottomAmount) {
1936 super.setClipBottomAmount(clipBottomAmount);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001937 for (NotificationContentView l : mLayouts) {
1938 l.setClipBottomAmount(clipBottomAmount);
1939 }
Selim Cinek65d418e2016-11-29 15:42:34 -08001940 if (mGuts != null) {
1941 mGuts.setClipBottomAmount(clipBottomAmount);
1942 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001943 }
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001944 if (mChildrenContainer != null) {
Selim Cinek65d418e2016-11-29 15:42:34 -08001945 // We have to update this even if it hasn't changed, since the children locations can
1946 // have changed
Selim Cinekb3dadcc2016-11-21 17:21:13 -08001947 mChildrenContainer.setClipBottomAmount(clipBottomAmount);
1948 }
Selim Cineka686b2c2016-10-26 13:58:27 -07001949 }
1950
Selim Cinek31094df2014-08-14 19:28:15 +02001951 public boolean isMaxExpandHeightInitialized() {
1952 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001953 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001954
Selim Cinek42357e02016-02-24 18:48:01 -08001955 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001956 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1957 }
Chris Wren78403d72014-07-28 10:23:24 +01001958
Selim Cinek1a48bab2017-02-17 19:38:40 -08001959 public void setLegacy(boolean legacy) {
Adrian Rooseb434ff2017-01-11 11:18:48 -08001960 for (NotificationContentView l : mLayouts) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08001961 l.setLegacy(legacy);
Adrian Rooseb434ff2017-01-11 11:18:48 -08001962 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001963 }
1964
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001965 @Override
1966 protected void updateBackgroundTint() {
1967 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001968 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001969 if (mIsSummaryWithChildren) {
1970 List<ExpandableNotificationRow> notificationChildren =
1971 mChildrenContainer.getNotificationChildren();
1972 for (int i = 0; i < notificationChildren.size(); i++) {
1973 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001974 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001975 }
1976 }
1977 }
1978
Mady Mellorb0a82462016-04-30 17:31:02 -07001979 /**
1980 * Called when a group has finished animating from collapsed or expanded state.
1981 */
1982 public void onFinishedExpansionChange() {
1983 mGroupExpansionChanging = false;
1984 updateBackgroundForGroupState();
1985 }
1986
1987 /**
1988 * Updates the parent and children backgrounds in a group based on the expansion state.
1989 */
1990 public void updateBackgroundForGroupState() {
1991 if (mIsSummaryWithChildren) {
1992 // Only when the group has finished expanding do we hide its background.
1993 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1994 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1995 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1996 for (int i = 0; i < children.size(); i++) {
1997 children.get(i).updateBackgroundForGroupState();
1998 }
1999 } else if (isChildInGroup()) {
2000 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
2001 // Only show a background if the group is expanded OR if it is expanding / collapsing
2002 // and has a custom background color
2003 final boolean showBackground = isGroupExpanded()
2004 || ((mNotificationParent.isGroupExpansionChanging()
2005 || mNotificationParent.isUserLocked()) && childColor != 0);
2006 mShowNoBackground = !showBackground;
2007 } else {
2008 // Only children or parents ever need no background.
2009 mShowNoBackground = false;
2010 }
2011 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07002012 updateBackground();
2013 }
2014
Adrian Roos4a579672016-05-24 16:54:37 -07002015 public int getPositionOfChild(ExpandableNotificationRow childRow) {
2016 if (mIsSummaryWithChildren) {
2017 return mChildrenContainer.getPositionInLinearLayout(childRow);
2018 }
2019 return 0;
2020 }
2021
Chris Wren78403d72014-07-28 10:23:24 +01002022 public void setExpansionLogger(ExpansionLogger logger, String key) {
2023 mLogger = logger;
2024 mLoggingKey = key;
2025 }
2026
Chris Wren6abeeb92016-05-26 14:44:38 -04002027 public void onExpandedByGesture(boolean userExpanded) {
2028 int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
2029 if (mGroupManager.isSummaryOfGroup(getStatusBarNotification())) {
2030 event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
2031 }
2032 MetricsLogger.action(mContext, event, userExpanded);
2033 }
2034
Selim Cinek6183d122016-01-14 18:48:41 -08002035 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08002036 public float getIncreasedPaddingAmount() {
2037 if (mIsSummaryWithChildren) {
2038 if (isGroupExpanded()) {
2039 return 1.0f;
2040 } else if (isUserLocked()) {
Selim Cinek414ad332017-02-24 19:06:12 -08002041 return mChildrenContainer.getIncreasedPaddingAmount();
Selim Cinek42357e02016-02-24 18:48:01 -08002042 }
Selim Cinek99104832017-01-25 14:47:33 -08002043 } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
Selim Cineka7ed2c12017-01-23 20:47:24 -08002044 return -1.0f;
Selim Cinek42357e02016-02-24 18:48:01 -08002045 }
2046 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08002047 }
2048
Selim Cineka7ed2c12017-01-23 20:47:24 -08002049 private boolean isColorized() {
Selim Cinek99104832017-01-25 14:47:33 -08002050 return mIsColorized && mBgTint != NO_COLOR;
Selim Cineka7ed2c12017-01-23 20:47:24 -08002051 }
2052
Selim Cinek61633a82016-01-25 15:54:10 -08002053 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08002054 protected boolean disallowSingleClick(MotionEvent event) {
2055 float x = event.getX();
2056 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08002057 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08002058 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08002059 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08002060 }
2061 return super.disallowSingleClick(event);
2062 }
2063
Selim Cinek414ad332017-02-24 19:06:12 -08002064 private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04002065 boolean nowExpanded = isExpanded();
Selim Cinek414ad332017-02-24 19:06:12 -08002066 if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
Chris Wren698b1702016-05-23 11:16:32 -04002067 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
2068 }
Selim Cinek414ad332017-02-24 19:06:12 -08002069 if (nowExpanded != wasExpanded) {
2070 updateShelfIconColor();
2071 if (mLogger != null) {
2072 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded);
2073 }
2074 if (mIsSummaryWithChildren) {
2075 mChildrenContainer.onExpansionChanged();
2076 }
Chris Wren78403d72014-07-28 10:23:24 +01002077 }
2078 }
Selim Cinek570981d2015-12-01 11:37:01 -08002079
Selim Cineke9bad242016-06-15 11:46:37 -07002080 @Override
2081 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2082 super.onInitializeAccessibilityNodeInfoInternal(info);
2083 if (canViewBeDismissed()) {
2084 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
2085 }
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002086 boolean expandable = mShowingPublic;
2087 boolean isExpanded = false;
2088 if (!expandable) {
2089 if (mIsSummaryWithChildren) {
2090 expandable = true;
2091 if (!mIsLowPriority || isExpanded()) {
2092 isExpanded = isGroupExpanded();
2093 }
2094 } else {
2095 expandable = mPrivateLayout.isContentExpandable();
2096 isExpanded = isExpanded();
2097 }
2098 }
2099 if (expandable) {
2100 if (isExpanded) {
2101 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
2102 } else {
2103 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
2104 }
2105 }
Selim Cineke9bad242016-06-15 11:46:37 -07002106 }
2107
2108 @Override
2109 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
2110 if (super.performAccessibilityActionInternal(action, arguments)) {
2111 return true;
2112 }
2113 switch (action) {
2114 case AccessibilityNodeInfo.ACTION_DISMISS:
2115 NotificationStackScrollLayout.performDismiss(this, mGroupManager,
2116 true /* fromAccessibility */);
2117 return true;
Selim Cinekc0ac4af2017-03-03 15:13:48 -08002118 case AccessibilityNodeInfo.ACTION_COLLAPSE:
2119 case AccessibilityNodeInfo.ACTION_EXPAND:
2120 mExpandClickListener.onClick(this);
2121 return true;
Selim Cineke9bad242016-06-15 11:46:37 -07002122 }
2123 return false;
2124 }
2125
2126 public boolean shouldRefocusOnDismiss() {
2127 return mRefocusOnDismiss || isAccessibilityFocused();
2128 }
2129
Selim Cinek570981d2015-12-01 11:37:01 -08002130 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08002131 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08002132 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002133
2134 @Override
2135 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
2136 return new NotificationViewState(stackScrollState);
2137 }
2138
Selim Cinekd127d792016-11-01 19:11:41 -07002139 @Override
2140 public boolean isAboveShelf() {
Selim Cinekc8007c52017-02-28 16:09:56 -08002141 return !isOnKeyguard()
2142 && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf));
Selim Cinekd127d792016-11-01 19:11:41 -07002143 }
2144
Adrian Roos0aac04f2016-12-08 15:59:29 -08002145 public void setShowAmbient(boolean showAmbient) {
2146 if (showAmbient != mShowAmbient) {
2147 mShowAmbient = showAmbient;
2148 notifyHeightChanged(false /* needsAnimation */);
2149 }
2150 }
2151
Selim Cinekd127d792016-11-01 19:11:41 -07002152 public void setAboveShelf(boolean aboveShelf) {
2153 mAboveShelf = aboveShelf;
2154 }
2155
Selim Cinekd4776a52017-02-14 18:50:16 -08002156 public static class NotificationViewState extends ExpandableViewState {
Selim Cinekbbcebde2016-11-09 18:28:20 -08002157
2158 private final StackScrollState mOverallState;
Selim Cinek0242fbb2016-10-19 13:38:32 -07002159
Selim Cinekbbcebde2016-11-09 18:28:20 -08002160
2161 private NotificationViewState(StackScrollState stackScrollState) {
2162 mOverallState = stackScrollState;
2163 }
2164
2165 @Override
2166 public void applyToView(View view) {
2167 super.applyToView(view);
2168 if (view instanceof ExpandableNotificationRow) {
2169 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
Selim Cinekbbcebde2016-11-09 18:28:20 -08002170 row.applyChildrenState(mOverallState);
2171 }
2172 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002173
2174 @Override
Selim Cinek2b549f42016-11-22 16:38:51 -08002175 protected void onYTranslationAnimationFinished(View view) {
2176 super.onYTranslationAnimationFinished(view);
Selim Cinekd4776a52017-02-14 18:50:16 -08002177 if (view instanceof ExpandableNotificationRow) {
2178 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
2179 if (row.isHeadsUpAnimatingAway()) {
2180 row.setHeadsUpAnimatingAway(false);
2181 }
Selim Cinek0cfbef42016-11-09 19:06:36 -08002182 }
2183 }
2184
2185 @Override
2186 public void animateTo(View child, AnimationProperties properties) {
2187 super.animateTo(child, properties);
2188 if (child instanceof ExpandableNotificationRow) {
2189 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
2190 row.startChildAnimation(mOverallState, properties);
2191 }
2192 }
Selim Cinekbbcebde2016-11-09 18:28:20 -08002193 }
Chris Wren51c75102013-07-16 20:49:17 -04002194}