blob: 6f6b02def0407c28be03ab47da4a0184ebc192c9 [file] [log] [blame]
Chris Wren51c75102013-07-16 20:49:17 -04001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar;
18
Mady Mellor4b80b102016-01-22 08:03:58 -080019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.AnimatorSet;
22import android.animation.ObjectAnimator;
23import android.animation.ValueAnimator;
24import android.animation.ValueAnimator.AnimatorUpdateListener;
Chris Wren51c75102013-07-16 20:49:17 -040025import android.content.Context;
Selim Cinekcab4a602014-09-03 14:47:57 +020026import android.graphics.drawable.AnimatedVectorDrawable;
27import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010028import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020029import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080030import android.os.Build;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020031import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040032import android.util.AttributeSet;
Mady Mellorb0a82462016-04-30 17:31:02 -070033import android.util.FloatProperty;
34import android.util.Property;
Selim Cinek01af3342016-02-09 19:25:31 -080035import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080036import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080037import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050038import android.view.View;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020039import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020040import android.view.accessibility.AccessibilityEvent;
Selim Cinek98713a42015-09-21 15:47:20 +020041import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020042import android.widget.ImageView;
Selim Cinekb5605e52015-02-20 18:21:41 +010043
Chris Wren698b1702016-05-23 11:16:32 -040044import com.android.internal.logging.MetricsLogger;
45import com.android.internal.logging.MetricsProto;
46import com.android.internal.logging.MetricsProto.MetricsEvent;
Selim Cinek4bb59342016-04-08 19:29:35 -070047import com.android.internal.util.NotificationColorUtil;
Dan Sandlera5e0f412014-01-23 15:11:54 -050048import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070049import com.android.systemui.classifier.FalsingManager;
Selim Cinekc897bd32016-03-18 17:32:31 -070050import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinekb5605e52015-02-20 18:21:41 +010051import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinek31aada42015-12-18 17:51:15 -080052import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010053import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
54import com.android.systemui.statusbar.stack.StackScrollState;
55import com.android.systemui.statusbar.stack.StackStateAnimator;
56import com.android.systemui.statusbar.stack.StackViewState;
57
Mady Mellor4b80b102016-01-22 08:03:58 -080058import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010059import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050060
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020061public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010062
63 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
64 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Selim Cinek01af3342016-02-09 19:25:31 -080065 private int mNotificationMinHeightLegacy;
66 private int mMaxHeadsUpHeightLegacy;
67 private int mMaxHeadsUpHeight;
68 private int mNotificationMinHeight;
69 private int mNotificationMaxHeight;
Mady Mellorb0a82462016-04-30 17:31:02 -070070 private int mIncreasedPaddingBetweenElements;
Chris Wren51c75102013-07-16 20:49:17 -040071
Selim Cinek1685e632014-04-08 02:27:49 +020072 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040073 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020074 /** Has the user actively changed the expansion state of this row */
75 private boolean mHasUserChangedExpansion;
76 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040077 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -080078
79 /**
80 * Has this notification been expanded while it was pinned
81 */
82 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +020083 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040084 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020085 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050086 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020087 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -080088 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +020089 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -070090 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -040091
Selim Cinek1685e632014-04-08 02:27:49 +020092 /**
93 * Is this notification expanded by the system. The expansion state can be overridden by the
94 * user expansion.
95 */
96 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020097
98 /**
Selim Cinek83bc7832015-10-22 13:26:54 -070099 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200100 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700101 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200102
Mady Mellorb0a82462016-04-30 17:31:02 -0700103 private Animator mTranslateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800104 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200105 private NotificationContentView mPublicLayout;
106 private NotificationContentView mPrivateLayout;
Selim Cinek1685e632014-04-08 02:27:49 +0200107 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700108 private int mHeadsUpHeight;
Selim Cinek863834b2014-05-20 04:20:25 +0200109 private View mVetoButton;
Selim Cinek4bb59342016-04-08 19:29:35 -0700110 private int mNotificationColor;
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400111 private boolean mClearable;
Chris Wren78403d72014-07-28 10:23:24 +0100112 private ExpansionLogger mLogger;
113 private String mLoggingKey;
Mady Mellor4b80b102016-01-22 08:03:58 -0800114 private NotificationSettingsIconRow mSettingsIconRow;
Selim Cinek8d490d42015-04-10 00:05:50 -0700115 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800116 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200117 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700118 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100119 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200120 private boolean mLastChronometerRunning = true;
Selim Cinekb5605e52015-02-20 18:21:41 +0100121 private ViewStub mChildrenContainerStub;
122 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100123 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700124 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100125 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor4b80b102016-01-22 08:03:58 -0800126 private ViewStub mSettingsIconRowStub;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100127 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100128 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700129 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700130 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800131 private HeadsUpManager mHeadsUpManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200132
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700133 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800134 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700135 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700136 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800137 private OnExpandClickListener mOnExpandClickListener;
Mady Mellorb0a82462016-04-30 17:31:02 -0700138 private boolean mGroupExpansionChanging;
139
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800140 private OnClickListener mExpandClickListener = new OnClickListener() {
141 @Override
142 public void onClick(View v) {
Selim Cinek624c02db2015-12-14 21:00:02 -0800143 if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Chris Wren698b1702016-05-23 11:16:32 -0400144 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
145 boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
146 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Mady Mellorb0a82462016-04-30 17:31:02 -0700147 mGroupExpansionChanging = true;
148 updateBackgroundForGroupState();
Chris Wren698b1702016-05-23 11:16:32 -0400149 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
150 nowExpanded);
151 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800152 } else {
Selim Cinek31aada42015-12-18 17:51:15 -0800153 boolean nowExpanded;
154 if (isPinned()) {
155 nowExpanded = !mExpandedWhenPinned;
156 mExpandedWhenPinned = nowExpanded;
157 } else {
158 nowExpanded = !isExpanded();
159 setUserExpanded(nowExpanded);
160 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800161 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800162 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Chris Wren698b1702016-05-23 11:16:32 -0400163 MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
164 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800165 }
166 }
167 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700168 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700169 private boolean mDismissed;
170 private boolean mKeepInParent;
171 private boolean mRemoved;
Mady Mellorb0a82462016-04-30 17:31:02 -0700172 private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
173 new FloatProperty<ExpandableNotificationRow>("translate") {
174 @Override
175 public void setValue(ExpandableNotificationRow object, float value) {
176 object.setTranslation(value);
177 }
178
179 @Override
180 public Float get(ExpandableNotificationRow object) {
181 return object.getTranslation();
182 }
183 };
184
185 public boolean isGroupExpansionChanging() {
186 if (isChildInGroup()) {
187 return mNotificationParent.isGroupExpansionChanging();
188 }
189 return mGroupExpansionChanging;
190 }
191
192 public void setGroupExpansionChanging(boolean changing) {
193 mGroupExpansionChanging = changing;
194 }
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700195
Selim Cinek8d490d42015-04-10 00:05:50 -0700196 public NotificationContentView getPrivateLayout() {
197 return mPrivateLayout;
198 }
199
200 public NotificationContentView getPublicLayout() {
201 return mPublicLayout;
202 }
203
Selim Cinekcab4a602014-09-03 14:47:57 +0200204 public void setIconAnimationRunning(boolean running) {
205 setIconAnimationRunning(running, mPublicLayout);
206 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800207 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700208 setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
Selim Cinek5a175d92015-11-23 18:01:33 -0800209 List<ExpandableNotificationRow> notificationChildren =
210 mChildrenContainer.getNotificationChildren();
211 for (int i = 0; i < notificationChildren.size(); i++) {
212 ExpandableNotificationRow child = notificationChildren.get(i);
213 child.setIconAnimationRunning(running);
214 }
215 }
216 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200217 }
218
219 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
220 if (layout != null) {
221 View contractedChild = layout.getContractedChild();
222 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700223 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200224 setIconAnimationRunningForChild(running, contractedChild);
225 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700226 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200227 }
228 }
229
230 private void setIconAnimationRunningForChild(boolean running, View child) {
231 if (child != null) {
232 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
233 setIconRunning(icon, running);
234 ImageView rightIcon = (ImageView) child.findViewById(
235 com.android.internal.R.id.right_icon);
236 setIconRunning(rightIcon, running);
237 }
238 }
239
240 private void setIconRunning(ImageView imageView, boolean running) {
241 if (imageView != null) {
242 Drawable drawable = imageView.getDrawable();
243 if (drawable instanceof AnimationDrawable) {
244 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
245 if (running) {
246 animationDrawable.start();
247 } else {
248 animationDrawable.stop();
249 }
250 } else if (drawable instanceof AnimatedVectorDrawable) {
251 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
252 if (running) {
253 animationDrawable.start();
254 } else {
255 animationDrawable.stop();
256 }
257 }
258 }
259 }
260
Selim Cinekda42d652015-12-04 15:51:16 -0800261 public void onNotificationUpdated(NotificationData.Entry entry) {
262 mEntry = entry;
263 mStatusBarNotification = entry.notification;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800264 mPrivateLayout.onNotificationUpdated(entry);
265 mPublicLayout.onNotificationUpdated(entry);
Selim Cinek757d8792016-01-28 16:21:08 -0800266 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700267 updateNotificationColor();
Selim Cinek757d8792016-01-28 16:21:08 -0800268 updateClearability();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800269 if (mIsSummaryWithChildren) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700270 mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
Selim Cinekc897bd32016-03-18 17:32:31 -0700271 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800272 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800273 if (mIconAnimationRunning) {
274 setIconAnimationRunning(true);
275 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800276 if (mNotificationParent != null) {
277 mNotificationParent.updateChildrenHeaderAppearance();
278 }
Selim Cinek263398f2015-10-21 17:40:23 -0700279 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800280 // The public layouts expand button is always visible
281 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800282 updateLimits();
283 }
284
285 private void updateLimits() {
Selim Cineka1744872016-03-11 15:36:06 -0800286 updateLimitsForView(mPrivateLayout);
287 updateLimitsForView(mPublicLayout);
288 }
289
290 private void updateLimitsForView(NotificationContentView layout) {
291 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800292 != com.android.internal.R.id.status_bar_latest_event_content;
293 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
294 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
295 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800296 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
297 layout.getHeadsUpChild().getId()
298 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek77019c72015-12-09 10:18:02 -0800299 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
300 : mMaxHeadsUpHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800301 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200302 }
303
304 public StatusBarNotification getStatusBarNotification() {
305 return mStatusBarNotification;
306 }
307
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700308 public boolean isHeadsUp() {
309 return mIsHeadsUp;
310 }
311
Selim Cinek1a521f32014-11-03 17:39:29 +0100312 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700313 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100314 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700315 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700316 if (mIsSummaryWithChildren) {
317 // The overflow might change since we allow more lines as HUN.
318 mChildrenContainer.updateGroupOverflow();
319 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700320 if (intrinsicBefore != getIntrinsicHeight()) {
321 notifyHeightChanged(false /* needsAnimation */);
322 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100323 }
324
Selim Cinekb5605e52015-02-20 18:21:41 +0100325 public void setGroupManager(NotificationGroupManager groupManager) {
326 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700327 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100328 }
329
Adrian Roosb88b1a12015-12-09 18:51:05 -0800330 public void setRemoteInputController(RemoteInputController r) {
331 mPrivateLayout.setRemoteInputController(r);
332 }
333
Mady Mellor3fd273e2016-03-15 21:08:14 -0700334 public void setAppName(String appName) {
335 mAppName = appName;
336 if (mSettingsIconRow != null) {
337 mSettingsIconRow.setAppName(mAppName);
338 }
339 }
340
Selim Cinekb5605e52015-02-20 18:21:41 +0100341 public void addChildNotification(ExpandableNotificationRow row) {
342 addChildNotification(row, -1);
343 }
344
345 /**
346 * Add a child notification to this view.
347 *
348 * @param row the row to add
349 * @param childIndex the index to add it at, if -1 it will be added at the end
350 */
351 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
352 if (mChildrenContainer == null) {
353 mChildrenContainerStub.inflate();
354 }
355 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700356 onChildrenCountChanged();
357 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100358 }
359
360 public void removeChildNotification(ExpandableNotificationRow row) {
361 if (mChildrenContainer != null) {
362 mChildrenContainer.removeNotification(row);
363 }
Selim Cinek263398f2015-10-21 17:40:23 -0700364 onChildrenCountChanged();
365 row.setIsChildInGroup(false, null);
366 }
367
368 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700369 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700370 }
371
Selim Cinek388df6d2015-10-22 13:25:11 -0700372 public ExpandableNotificationRow getNotificationParent() {
373 return mNotificationParent;
374 }
375
Selim Cinek263398f2015-10-21 17:40:23 -0700376 /**
377 * @param isChildInGroup Is this notification now in a group
378 * @param parent the new parent notification
379 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700380 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
381 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
382 mNotificationParent = childInGroup ? parent : null;
383 mPrivateLayout.setIsChildInGroup(childInGroup);
Mady Mellorb0a82462016-04-30 17:31:02 -0700384 updateBackgroundForGroupState();
385 if (mNotificationParent != null) {
386 mNotificationParent.updateBackgroundForGroupState();
387 }
Selim Cinek34d93b02015-10-22 12:30:38 -0700388 }
389
390 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800391 public boolean onTouchEvent(MotionEvent event) {
392 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
393 || !isChildInGroup() || isGroupExpanded()) {
394 return super.onTouchEvent(event);
395 } else {
396 return false;
397 }
398 }
399
400 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800401 protected boolean handleSlideBack() {
402 if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
403 animateTranslateNotification(0 /* targetLeft */);
404 return true;
405 }
406 return false;
407 }
408
409 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700410 protected boolean shouldHideBackground() {
411 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700412 }
413
414 @Override
415 public boolean isSummaryWithChildren() {
416 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100417 }
418
419 @Override
420 public boolean areChildrenExpanded() {
421 return mChildrenExpanded;
422 }
423
424 public List<ExpandableNotificationRow> getNotificationChildren() {
425 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
426 }
427
Selim Cinekeef84282015-10-30 16:28:00 -0700428 public int getNumberOfNotificationChildren() {
429 if (mChildrenContainer == null) {
430 return 0;
431 }
432 return mChildrenContainer.getNotificationChildren().size();
433 }
434
Selim Cinekb5605e52015-02-20 18:21:41 +0100435 /**
436 * Apply the order given in the list to the children.
437 *
438 * @param childOrder the new list order
439 * @return whether the list order has changed
440 */
441 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
442 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
443 }
444
445 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700446 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100447 StackViewState parentState = resultState.getViewStateForView(this);
448 mChildrenContainer.getState(resultState, parentState);
449 }
450 }
451
452 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700453 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100454 mChildrenContainer.applyState(state);
455 }
456 }
457
458 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700459 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100460 mChildrenContainer.prepareExpansionChanged(state);
461 }
462 }
463
464 public void startChildAnimation(StackScrollState finalState,
Selim Cinek99695592016-01-12 17:51:35 -0800465 StackStateAnimator stateAnimator, long delay, long duration) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700466 if (mIsSummaryWithChildren) {
Selim Cinek99695592016-01-12 17:51:35 -0800467 mChildrenContainer.startAnimationToState(finalState, stateAnimator, delay,
Selim Cinekb5605e52015-02-20 18:21:41 +0100468 duration);
469 }
470 }
471
472 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800473 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100474 return this;
475 } else {
476 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
477 return view == null ? this : view;
478 }
479 }
480
Selim Cinekab29aeb2015-02-20 18:18:32 +0100481 public NotificationGuts getGuts() {
482 return mGuts;
483 }
484
Selim Cinek684a4422015-04-15 16:18:39 -0700485 /**
486 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
487 * the notification will be rendered on top of the screen.
488 *
489 * @param pinned whether it is pinned
490 */
491 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700492 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700493 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700494 if (intrinsicHeight != getIntrinsicHeight()) {
495 notifyHeightChanged(false);
496 }
Selim Cinek31aada42015-12-18 17:51:15 -0800497 if (pinned) {
498 setIconAnimationRunning(true);
499 mExpandedWhenPinned = false;
500 } else if (mExpandedWhenPinned) {
501 setUserExpanded(true);
502 }
Selim Cinek98713a42015-09-21 15:47:20 +0200503 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700504 }
505
Selim Cinek684a4422015-04-15 16:18:39 -0700506 public boolean isPinned() {
507 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700508 }
509
Selim Cinek31aada42015-12-18 17:51:15 -0800510 /**
511 * @param atLeastMinHeight should the value returned be at least the minimum height.
512 * Used to avoid cyclic calls
513 * @return the height of the heads up notification when pinned
514 */
515 public int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800516 if (mIsSummaryWithChildren) {
517 return mChildrenContainer.getIntrinsicHeight();
518 }
Selim Cinek31aada42015-12-18 17:51:15 -0800519 if(mExpandedWhenPinned) {
520 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
521 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700522 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800523 } else {
524 return mHeadsUpHeight;
525 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700526 }
527
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700528 /**
529 * Mark whether this notification was just clicked, i.e. the user has just clicked this
530 * notification in this frame.
531 */
532 public void setJustClicked(boolean justClicked) {
533 mJustClicked = justClicked;
534 }
535
536 /**
537 * @return true if this notification has been clicked in this frame, false otherwise
538 */
539 public boolean wasJustClicked() {
540 return mJustClicked;
541 }
542
Selim Cinek98713a42015-09-21 15:47:20 +0200543 public void setChronometerRunning(boolean running) {
544 mLastChronometerRunning = running;
545 setChronometerRunning(running, mPrivateLayout);
546 setChronometerRunning(running, mPublicLayout);
547 if (mChildrenContainer != null) {
548 List<ExpandableNotificationRow> notificationChildren =
549 mChildrenContainer.getNotificationChildren();
550 for (int i = 0; i < notificationChildren.size(); i++) {
551 ExpandableNotificationRow child = notificationChildren.get(i);
552 child.setChronometerRunning(running);
553 }
554 }
555 }
556
557 private void setChronometerRunning(boolean running, NotificationContentView layout) {
558 if (layout != null) {
559 running = running || isPinned();
560 View contractedChild = layout.getContractedChild();
561 View expandedChild = layout.getExpandedChild();
562 View headsUpChild = layout.getHeadsUpChild();
563 setChronometerRunningForChild(running, contractedChild);
564 setChronometerRunningForChild(running, expandedChild);
565 setChronometerRunningForChild(running, headsUpChild);
566 }
567 }
568
569 private void setChronometerRunningForChild(boolean running, View child) {
570 if (child != null) {
571 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
572 if (chronometer instanceof Chronometer) {
573 ((Chronometer) chronometer).setStarted(running);
574 }
575 }
576 }
577
Selim Cinekea4bef72015-12-02 15:51:10 -0800578 public NotificationHeaderView getNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700579 if (mIsSummaryWithChildren) {
580 return mChildrenContainer.getHeaderView();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700581 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800582 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700583 }
584
Selim Cinek34eda5e2016-02-18 17:10:43 -0800585 private NotificationHeaderView getVisibleNotificationHeader() {
Mady Mellorb0a82462016-04-30 17:31:02 -0700586 if (mIsSummaryWithChildren) {
587 return mChildrenContainer.getHeaderView();
Selim Cinek34eda5e2016-02-18 17:10:43 -0800588 }
589 return getShowingLayout().getVisibleNotificationHeader();
590 }
591
Selim Cinek570981d2015-12-01 11:37:01 -0800592 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
593 mOnExpandClickListener = onExpandClickListener;
594 }
595
Selim Cinek31aada42015-12-18 17:51:15 -0800596 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
597 mHeadsUpManager = headsUpManager;
598 }
599
Selim Cinek01af3342016-02-09 19:25:31 -0800600 public void reInflateViews() {
601 initDimens();
602 if (mIsSummaryWithChildren) {
Selim Cinek01af3342016-02-09 19:25:31 -0800603 if (mChildrenContainer != null) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700604 mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
Selim Cinek01af3342016-02-09 19:25:31 -0800605 }
606 }
607 if (mGuts != null) {
608 View oldGuts = mGuts;
609 int index = indexOfChild(oldGuts);
610 removeView(oldGuts);
611 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
612 R.layout.notification_guts, this, false);
613 mGuts.setVisibility(oldGuts.getVisibility());
614 addView(mGuts, index);
615 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800616 if (mSettingsIconRow != null) {
617 View oldSettings = mSettingsIconRow;
618 int settingsIndex = indexOfChild(oldSettings);
619 removeView(oldSettings);
620 mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
621 R.layout.notification_settings_icon_row, this, false);
622 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700623 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800624 mSettingsIconRow.setVisibility(oldSettings.getVisibility());
625 addView(mSettingsIconRow, settingsIndex);
626
627 }
Selim Cinekde33a4a2016-02-11 16:43:41 -0800628 mPrivateLayout.reInflateViews();
629 mPublicLayout.reInflateViews();
Selim Cinek01af3342016-02-09 19:25:31 -0800630 }
631
Selim Cinekc3179332016-03-04 14:44:56 -0800632 public void setContentBackground(int customBackgroundColor, boolean animate,
633 NotificationContentView notificationContentView) {
634 if (getShowingLayout() == notificationContentView) {
635 setTintColor(customBackgroundColor, animate);
636 }
637 }
638
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700639 public void closeRemoteInput() {
640 mPrivateLayout.closeRemoteInput();
641 mPublicLayout.closeRemoteInput();
642 }
643
Selim Cinekc897bd32016-03-18 17:32:31 -0700644 /**
645 * Set by how much the single line view should be indented.
646 */
647 public void setSingleLineWidthIndention(int indention) {
648 mPrivateLayout.setSingleLineWidthIndention(indention);
649 }
650
651 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700652 return mNotificationColor;
653 }
654
655 private void updateNotificationColor() {
656 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
657 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700658 }
659
660 public HybridNotificationView getSingleLineView() {
661 return mPrivateLayout.getSingleLineView();
662 }
663
Selim Cinekf07d0622016-03-21 19:52:52 -0700664 public boolean isOnKeyguard() {
665 return mOnKeyguard;
666 }
667
Selim Cinekc1e389d2016-04-07 11:02:57 -0700668 public void removeAllChildren() {
669 List<ExpandableNotificationRow> notificationChildren
670 = mChildrenContainer.getNotificationChildren();
671 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
672 for (int i = 0; i < clonedList.size(); i++) {
673 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700674 if (row.keepInParent()) {
675 continue;
676 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700677 mChildrenContainer.removeNotification(row);
Selim Cinekc1e389d2016-04-07 11:02:57 -0700678 row.setIsChildInGroup(false, null);
679 }
680 onChildrenCountChanged();
681 }
682
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700683 public void setForceUnlocked(boolean forceUnlocked) {
684 mForceUnlocked = forceUnlocked;
685 if (mIsSummaryWithChildren) {
686 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
687 for (ExpandableNotificationRow child : notificationChildren) {
688 child.setForceUnlocked(forceUnlocked);
689 }
690 }
691 }
692
Selim Cinek3f19f602016-05-02 18:01:56 -0700693 public void setDismissed(boolean dismissed) {
694 mDismissed = dismissed;
695 }
696
697 public boolean isDismissed() {
698 return mDismissed;
699 }
700
701 public boolean keepInParent() {
702 return mKeepInParent;
703 }
704
705 public void setKeepInParent(boolean keepInParent) {
706 mKeepInParent = keepInParent;
707 }
708
709 public boolean isRemoved() {
710 return mRemoved;
711 }
712
Adrian Roosd009ab12016-05-20 17:58:53 -0700713 public void setRemoved() {
714 mRemoved = true;
715
716 mPrivateLayout.setRemoved();
717 if (mChildrenContainer != null) {
718 mChildrenContainer.setRemoved();
719 }
Selim Cinek3f19f602016-05-02 18:01:56 -0700720 }
721
Selim Cinekd1395642016-04-28 12:22:42 -0700722 public NotificationChildrenContainer getChildrenContainer() {
723 return mChildrenContainer;
724 }
725
Chris Wren78403d72014-07-28 10:23:24 +0100726 public interface ExpansionLogger {
727 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
728 }
Selim Cinek1685e632014-04-08 02:27:49 +0200729
Chris Wren51c75102013-07-16 20:49:17 -0400730 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
731 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700732 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -0800733 initDimens();
734 }
735
736 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800737 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
738 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
739 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
740 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -0800741 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800742 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
Mady Mellorb0a82462016-04-30 17:31:02 -0700743 mIncreasedPaddingBetweenElements = getResources()
744 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800745 }
746
747 /**
748 * @param dimenId the dimen to look up
749 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
750 */
751 private int getFontScaledHeight(int dimenId) {
752 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
753 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
754 getResources().getDisplayMetrics().density);
755 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -0400756 }
757
Christoph Studera7fe6312014-06-27 19:32:44 +0200758 /**
759 * Resets this view so it can be re-used for an updated notification.
760 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200761 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200762 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200763 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +0100764 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +0200765 mExpandable = false;
766 mHasUserChangedExpansion = false;
767 mUserLocked = false;
768 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200769 mSensitive = false;
770 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200771 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700772 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -0800773 mPublicLayout.reset();
774 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +0200775 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -0800776 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +0200777 logExpansionEvent(false, wasExpanded);
778 }
779
780 public void resetHeight() {
Christoph Studera7fe6312014-06-27 19:32:44 +0200781 mMaxExpandHeight = 0;
Selim Cinek8d490d42015-04-10 00:05:50 -0700782 mHeadsUpHeight = 0;
Selim Cinek31094df2014-08-14 19:28:15 +0200783 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200784 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200785 }
786
Jorim Jaggi251957d2014-04-09 04:24:09 +0200787 @Override
788 protected void onFinishInflate() {
789 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200790 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800791 mPublicLayout.setContainingNotification(this);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200792 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800793 mPrivateLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800794 mPrivateLayout.setContainingNotification(this);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800795 mPublicLayout.setExpandClickListener(mExpandClickListener);
Mady Mellor4b80b102016-01-22 08:03:58 -0800796 mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
797 mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
798 @Override
799 public void onInflate(ViewStub stub, View inflated) {
800 mSettingsIconRow = (NotificationSettingsIconRow) inflated;
801 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700802 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800803 }
804 });
Selim Cinekab29aeb2015-02-20 18:18:32 +0100805 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
806 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200807 @Override
808 public void onInflate(ViewStub stub, View inflated) {
809 mGuts = (NotificationGuts) inflated;
810 mGuts.setClipTopAmount(getClipTopAmount());
811 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100812 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200813 }
814 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100815 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
816 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
817
818 @Override
819 public void onInflate(ViewStub stub, View inflated) {
820 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -0700821 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -0700822 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -0800823 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +0100824 }
825 });
Selim Cinek863834b2014-05-20 04:20:25 +0200826 mVetoButton = findViewById(R.id.veto);
Mady Mellor4b80b102016-01-22 08:03:58 -0800827
828 // Add the views that we translate to reveal the gear
829 mTranslateableViews = new ArrayList<View>();
830 for (int i = 0; i < getChildCount(); i++) {
831 mTranslateableViews.add(getChildAt(i));
832 }
833 // Remove views that don't translate
834 mTranslateableViews.remove(mVetoButton);
835 mTranslateableViews.remove(mSettingsIconRowStub);
836 mTranslateableViews.remove(mChildrenContainerStub);
837 mTranslateableViews.remove(mGutsStub);
838 }
839
Mady Mellor4b80b102016-01-22 08:03:58 -0800840 public void resetTranslation() {
841 if (mTranslateableViews != null) {
842 for (int i = 0; i < mTranslateableViews.size(); i++) {
843 mTranslateableViews.get(i).setTranslationX(0);
844 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800845 }
Mady Mellorb0a82462016-04-30 17:31:02 -0700846 invalidateOutline();
Mady Mellor4b80b102016-01-22 08:03:58 -0800847 if (mSettingsIconRow != null) {
848 mSettingsIconRow.resetState();
849 }
850 }
851
852 public void animateTranslateNotification(final float leftTarget) {
853 if (mTranslateAnim != null) {
854 mTranslateAnim.cancel();
855 }
Mady Mellorb0a82462016-04-30 17:31:02 -0700856 mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
Mady Mellor34958fa2016-02-23 09:52:17 -0800857 if (mTranslateAnim != null) {
858 mTranslateAnim.start();
859 }
860 }
861
862 @Override
863 public void setTranslation(float translationX) {
864 if (areGutsExposed()) {
865 // Don't translate if guts are showing.
866 return;
867 }
868 // Translate the group of views
869 for (int i = 0; i < mTranslateableViews.size(); i++) {
870 if (mTranslateableViews.get(i) != null) {
871 mTranslateableViews.get(i).setTranslationX(translationX);
872 }
873 }
Mady Mellorb0a82462016-04-30 17:31:02 -0700874 invalidateOutline();
Mady Mellor34958fa2016-02-23 09:52:17 -0800875 if (mSettingsIconRow != null) {
876 mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
877 }
878 }
879
880 @Override
881 public float getTranslation() {
882 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
883 // All of the views in the list should have same translation, just use first one.
884 return mTranslateableViews.get(0).getTranslationX();
885 }
886 return 0;
887 }
888
889 public Animator getTranslateViewAnimator(final float leftTarget,
890 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -0700891 if (mTranslateAnim != null) {
892 mTranslateAnim.cancel();
893 }
Mady Mellor34958fa2016-02-23 09:52:17 -0800894 if (areGutsExposed()) {
895 // No translation if guts are exposed.
896 return null;
897 }
Mady Mellorb0a82462016-04-30 17:31:02 -0700898 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
899 leftTarget);
900 if (listener != null) {
901 translateAnim.addUpdateListener(listener);
Mady Mellor4b80b102016-01-22 08:03:58 -0800902 }
Mady Mellorb0a82462016-04-30 17:31:02 -0700903 translateAnim.addListener(new AnimatorListenerAdapter() {
904 boolean cancelled = false;
905
906 @Override
907 public void onAnimationCancel(Animator anim) {
908 cancelled = true;
909 }
910
911 @Override
912 public void onAnimationEnd(Animator anim) {
913 if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
914 mSettingsIconRow.resetState();
915 mTranslateAnim = null;
916 }
917 }
918 });
919 mTranslateAnim = translateAnim;
920 return translateAnim;
Mady Mellor4b80b102016-01-22 08:03:58 -0800921 }
922
923 public float getSpaceForGear() {
924 if (mSettingsIconRow != null) {
925 return mSettingsIconRow.getSpaceForGear();
926 }
927 return 0;
928 }
929
930 public NotificationSettingsIconRow getSettingsRow() {
931 if (mSettingsIconRow == null) {
932 mSettingsIconRowStub.inflate();
933 }
934 return mSettingsIconRow;
935 }
936
Selim Cinekab29aeb2015-02-20 18:18:32 +0100937 public void inflateGuts() {
938 if (mGuts == null) {
939 mGutsStub.inflate();
940 }
941 }
942
Selim Cinekda42d652015-12-04 15:51:16 -0800943 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -0800944 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
945 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -0800946 if (mChildrenContainer != null) {
947 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
948 : INVISIBLE);
Mady Mellorb0a82462016-04-30 17:31:02 -0700949 mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
950 ? VISIBLE
Selim Cinekef5127e2015-12-21 16:55:58 -0800951 : INVISIBLE);
952 }
Selim Cinekda42d652015-12-04 15:51:16 -0800953 // The limits might have changed if the view suddenly became a group or vice versa
954 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +0100955 }
956
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200957 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800958 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
959 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200960 // Add a record for the entire layout since its content is somehow small.
961 // The event comes from a leaf view that is interacted with.
962 AccessibilityEvent record = AccessibilityEvent.obtain();
963 onInitializeAccessibilityEvent(record);
964 dispatchPopulateAccessibilityEvent(record);
965 event.appendRecord(record);
966 return true;
967 }
968 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200969 }
Chris Wren51c75102013-07-16 20:49:17 -0400970
John Spurlocke15452b2014-08-21 09:44:39 -0400971 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100972 public void setDark(boolean dark, boolean fade, long delay) {
973 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400974 final NotificationContentView showing = getShowingLayout();
975 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100976 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400977 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800978 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -0700979 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -0800980 }
John Spurlocke15452b2014-08-21 09:44:39 -0400981 }
982
Chris Wren51c75102013-07-16 20:49:17 -0400983 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -0700984 if (mIsSummaryWithChildren && !mShowingPublic) {
985 return !mChildrenExpanded;
986 }
Chris Wren51c75102013-07-16 20:49:17 -0400987 return mExpandable;
988 }
989
990 public void setExpandable(boolean expandable) {
991 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800992 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -0400993 }
994
Selim Cinek4ffd6362015-12-29 15:12:23 +0100995 @Override
996 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -0800997 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
998 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +0100999 }
1000
Selim Cinek1685e632014-04-08 02:27:49 +02001001 /**
1002 * @return whether the user has changed the expansion state
1003 */
1004 public boolean hasUserChangedExpansion() {
1005 return mHasUserChangedExpansion;
1006 }
1007
Chris Wren51c75102013-07-16 20:49:17 -04001008 public boolean isUserExpanded() {
1009 return mUserExpanded;
1010 }
1011
Selim Cinek1685e632014-04-08 02:27:49 +02001012 /**
1013 * Set this notification to be expanded by the user
1014 *
1015 * @param userExpanded whether the user wants this notification to be expanded
1016 */
Chris Wren51c75102013-07-16 20:49:17 -04001017 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001018 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1019 }
1020
1021 /**
1022 * Set this notification to be expanded by the user
1023 *
1024 * @param userExpanded whether the user wants this notification to be expanded
1025 * @param allowChildExpansion whether a call to this method allows expanding children
1026 */
1027 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001028 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -07001029 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
Chris Wren698b1702016-05-23 11:16:32 -04001030 final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinek388df6d2015-10-22 13:25:11 -07001031 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
Chris Wren698b1702016-05-23 11:16:32 -04001032 logExpansionEvent(true /* userAction */, wasExpanded);
Selim Cinek388df6d2015-10-22 13:25:11 -07001033 return;
1034 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001035 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001036 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001037 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001038 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001039 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001040 }
1041
Selim Cinekccd14fb2014-08-12 18:53:24 +02001042 public void resetUserExpansion() {
1043 mHasUserChangedExpansion = false;
1044 mUserExpanded = false;
1045 }
1046
Chris Wren51c75102013-07-16 20:49:17 -04001047 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001048 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001049 }
1050
1051 public void setUserLocked(boolean userLocked) {
1052 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001053 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001054 if (mIsSummaryWithChildren) {
1055 mChildrenContainer.setUserLocked(userLocked);
Mady Mellorb0a82462016-04-30 17:31:02 -07001056 if (userLocked) {
1057 updateBackgroundForGroupState();
1058 }
Selim Cinek42357e02016-02-24 18:48:01 -08001059 }
Chris Wren51c75102013-07-16 20:49:17 -04001060 }
1061
Selim Cinek1685e632014-04-08 02:27:49 +02001062 /**
1063 * @return has the system set this notification to be expanded
1064 */
1065 public boolean isSystemExpanded() {
1066 return mIsSystemExpanded;
1067 }
1068
1069 /**
1070 * Set this notification to be expanded by the system.
1071 *
1072 * @param expand whether the system wants this notification to be expanded.
1073 */
1074 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001075 if (expand != mIsSystemExpanded) {
1076 final boolean wasExpanded = isExpanded();
1077 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001078 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001079 logExpansionEvent(false, wasExpanded);
Selim Cinekc897bd32016-03-18 17:32:31 -07001080 if (mChildrenContainer != null) {
1081 mChildrenContainer.updateGroupOverflow();
1082 }
Selim Cinek31094df2014-08-14 19:28:15 +02001083 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001084 }
1085
1086 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001087 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001088 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001089 public void setOnKeyguard(boolean onKeyguard) {
1090 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001091 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001092 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001093 logExpansionEvent(false, wasExpanded);
1094 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001095 if (mIsSummaryWithChildren) {
1096 mChildrenContainer.updateGroupOverflow();
1097 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001098 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001099 }
1100 }
Selim Cinek1685e632014-04-08 02:27:49 +02001101 }
1102
1103 /**
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001104 * @return Can the underlying notification be cleared?
1105 */
1106 public boolean isClearable() {
Selim Cineka37774f2014-11-11 19:16:18 +01001107 return mStatusBarNotification != null && mStatusBarNotification.isClearable();
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001108 }
1109
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001110 @Override
1111 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001112 if (isUserLocked()) {
1113 return getActualHeight();
1114 }
Selim Cinekd84a5932015-12-15 11:45:36 -08001115 if (mGuts != null && mGuts.areGutsExposed()) {
1116 return mGuts.getHeight();
1117 } else if ((isChildInGroup() && !isGroupExpanded())) {
1118 return mPrivateLayout.getMinHeight();
1119 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1120 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001121 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001122 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek60122be2015-04-15 18:16:50 -07001123 } else if (mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001124 if (isPinned()) {
1125 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1126 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001127 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001128 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001129 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001130 }
Selim Cinek31aada42015-12-18 17:51:15 -08001131 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001132 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001133 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001134 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001135 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001136 }
Selim Cinek1685e632014-04-08 02:27:49 +02001137
Mady Mellorb0a82462016-04-30 17:31:02 -07001138 public boolean isGroupExpanded() {
Selim Cinekeef84282015-10-30 16:28:00 -07001139 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001140 }
1141
Selim Cinek263398f2015-10-21 17:40:23 -07001142 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001143 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Mady Mellorb0a82462016-04-30 17:31:02 -07001144 && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
1145 if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
1146 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
1147 mEntry.notification);
Selim Cinek263398f2015-10-21 17:40:23 -07001148 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001149 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001150 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001151 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001152 }
1153
Mady Mellorb0a82462016-04-30 17:31:02 -07001154 public void updateChildrenHeaderAppearance() {
1155 if (mChildrenContainer != null) {
1156 mChildrenContainer.updateChildrenHeaderAppearance();
1157 }
1158 }
1159
Selim Cinek1685e632014-04-08 02:27:49 +02001160 /**
1161 * Check whether the view state is currently expanded. This is given by the system in {@link
1162 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1163 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1164 * view can differ from this state, if layout params are modified from outside.
1165 *
1166 * @return whether the view state is currently expanded.
1167 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001168 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001169 return isExpanded(false /* allowOnKeyguard */);
1170 }
1171
1172 public boolean isExpanded(boolean allowOnKeyguard) {
1173 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001174 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1175 || isUserExpanded());
1176 }
1177
1178 private boolean isSystemChildExpanded() {
1179 return mIsSystemChildExpanded;
1180 }
1181
1182 public void setSystemChildExpanded(boolean expanded) {
1183 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001184 }
1185
1186 @Override
1187 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1188 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001189 updateMaxHeights();
Mady Mellora6edc872016-04-26 11:01:03 -07001190 if (mSettingsIconRow != null) {
1191 mSettingsIconRow.updateVerticalLocation();
1192 }
Selim Cinek1685e632014-04-08 02:27:49 +02001193 }
1194
Selim Cinek8d490d42015-04-10 00:05:50 -07001195 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001196 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001197 View expandedChild = mPrivateLayout.getExpandedChild();
1198 if (expandedChild == null) {
1199 expandedChild = mPrivateLayout.getContractedChild();
1200 }
1201 mMaxExpandHeight = expandedChild.getHeight();
1202 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001203 if (headsUpChild == null) {
1204 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001205 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001206 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001207 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001208 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001209 }
1210 }
1211
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001212 @Override
1213 public void notifyHeightChanged(boolean needsAnimation) {
1214 super.notifyHeightChanged(needsAnimation);
1215 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1216 }
1217
Selim Cinek3c76d502016-02-19 15:16:33 -08001218 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001219 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001220 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001221 }
1222
1223 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001224 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001225 if (mIsSummaryWithChildren) {
1226 List<ExpandableNotificationRow> notificationChildren =
1227 mChildrenContainer.getNotificationChildren();
1228 for (int i = 0; i < notificationChildren.size(); i++) {
1229 ExpandableNotificationRow child = notificationChildren.get(i);
1230 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1231 }
1232 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001233 }
1234
1235 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1236 long duration) {
1237 boolean oldShowingPublic = mShowingPublic;
1238 mShowingPublic = mSensitive && hideSensitive;
1239 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1240 return;
1241 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001242
1243 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001244 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001245
Jorim Jaggiae441282014-08-01 02:45:18 +02001246 if (!animated) {
1247 mPublicLayout.animate().cancel();
1248 mPrivateLayout.animate().cancel();
1249 mPublicLayout.setAlpha(1f);
1250 mPrivateLayout.setAlpha(1f);
1251 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001252 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001253 } else {
1254 animateShowingPublic(delay, duration);
1255 }
Selim Cinekc3179332016-03-04 14:44:56 -08001256 NotificationContentView showingLayout = getShowingLayout();
1257 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001258 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinek757d8792016-01-28 16:21:08 -08001259 updateClearability();
Jorim Jaggiae441282014-08-01 02:45:18 +02001260 mShowingPublicInitialized = true;
1261 }
1262
1263 private void animateShowingPublic(long delay, long duration) {
Mady Mellorb0a82462016-04-30 17:31:02 -07001264 View[] privateViews = mIsSummaryWithChildren
1265 ? new View[] {mChildrenContainer}
Selim Cinekd84a5932015-12-15 11:45:36 -08001266 : new View[] {mPrivateLayout};
1267 View[] publicViews = new View[] {mPublicLayout};
1268 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1269 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1270 for (final View hiddenView : hiddenChildren) {
1271 hiddenView.setVisibility(View.VISIBLE);
1272 hiddenView.animate().cancel();
1273 hiddenView.animate()
1274 .alpha(0f)
1275 .setStartDelay(delay)
1276 .setDuration(duration)
1277 .withEndAction(new Runnable() {
1278 @Override
1279 public void run() {
1280 hiddenView.setVisibility(View.INVISIBLE);
1281 }
1282 });
1283 }
1284 for (View showView : shownChildren) {
1285 showView.setVisibility(View.VISIBLE);
1286 showView.setAlpha(0f);
1287 showView.animate().cancel();
1288 showView.animate()
1289 .alpha(1f)
1290 .setStartDelay(delay)
1291 .setDuration(duration);
1292 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001293 }
1294
Selim Cinek3776fe02016-02-04 13:32:43 -08001295 public boolean mustStayOnScreen() {
1296 return mIsHeadsUp;
1297 }
1298
Selim Cinek757d8792016-01-28 16:21:08 -08001299 private void updateClearability() {
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001300 // public versions cannot be dismissed
Selim Cinek3c76d502016-02-19 15:16:33 -08001301 mVetoButton.setVisibility(isClearable() && (!mShowingPublic
1302 || !mSensitiveHiddenInGeneral) ? View.VISIBLE : View.GONE);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001303 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001304
Ricky Waicd35def2016-05-03 11:07:07 +01001305 public void makeActionsVisibile() {
1306 setUserExpanded(true, true);
1307 if (isChildInGroup()) {
1308 mGroupManager.setGroupExpanded(mStatusBarNotification, true);
1309 }
1310 notifyHeightChanged(false);
1311 }
1312
Selim Cinekb5605e52015-02-20 18:21:41 +01001313 public void setChildrenExpanded(boolean expanded, boolean animate) {
1314 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -07001315 if (mChildrenContainer != null) {
1316 mChildrenContainer.setChildrenExpanded(expanded);
1317 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001318 }
1319
Selim Cinekb5605e52015-02-20 18:21:41 +01001320 public static void applyTint(View v, int color) {
1321 int alpha;
1322 if (color != 0) {
1323 alpha = COLORED_DIVIDER_ALPHA;
1324 } else {
1325 color = 0xff000000;
1326 alpha = DEFAULT_DIVIDER_ALPHA;
1327 }
1328 if (v.getBackground() instanceof ColorDrawable) {
1329 ColorDrawable background = (ColorDrawable) v.getBackground();
1330 background.mutate();
1331 background.setColor(color);
1332 background.setAlpha(alpha);
1333 }
1334 }
1335
Selim Cinek1685e632014-04-08 02:27:49 +02001336 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001337 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001338 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001339
Mady Mellor34958fa2016-02-23 09:52:17 -08001340 public boolean areGutsExposed() {
1341 return (mGuts != null && mGuts.areGutsExposed());
1342 }
1343
Jorim Jaggibe565df2014-04-28 17:51:23 +02001344 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001345 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001346 NotificationContentView showingLayout = getShowingLayout();
1347 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001348 }
1349
1350 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001351 protected View getContentView() {
Selim Cineka5703182016-05-11 21:23:16 -04001352 if (mIsSummaryWithChildren) {
1353 return mChildrenContainer;
1354 }
Selim Cinek560e64d2015-06-09 19:58:11 -07001355 return getShowingLayout();
1356 }
1357
1358 @Override
Mady Mellorb0a82462016-04-30 17:31:02 -07001359 public int getExtraBottomPadding() {
1360 if (mIsSummaryWithChildren && isGroupExpanded()) {
1361 return mIncreasedPaddingBetweenElements;
1362 }
1363 return 0;
1364 }
1365
1366 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001367 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001368 super.setActualHeight(height, notifyListeners);
Mady Mellorb53bc272016-02-11 18:28:23 -08001369 if (mGuts != null && mGuts.areGutsExposed()) {
1370 mGuts.setActualHeight(height);
1371 return;
1372 }
Selim Cinekeef84282015-10-30 16:28:00 -07001373 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +01001374 mPrivateLayout.setContentHeight(contentHeight);
1375 mPublicLayout.setContentHeight(contentHeight);
Selim Cinek42357e02016-02-24 18:48:01 -08001376 if (mIsSummaryWithChildren) {
1377 mChildrenContainer.setActualHeight(height);
1378 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001379 if (mGuts != null) {
1380 mGuts.setActualHeight(height);
1381 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001382 }
1383
1384 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001385 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001386 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001387 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001388 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001389 NotificationContentView showingLayout = getShowingLayout();
1390 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001391 }
1392
1393 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001394 public int getMinHeight() {
Selim Cinek31aada42015-12-18 17:51:15 -08001395 if (mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
1396 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1397 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001398 return mChildrenContainer.getMinHeight();
Selim Cinek31aada42015-12-18 17:51:15 -08001399 } else if (mIsHeadsUp) {
1400 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001401 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001402 NotificationContentView showingLayout = getShowingLayout();
1403 return showingLayout.getMinHeight();
1404 }
1405
1406 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001407 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001408 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001409 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001410 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001411 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001412 }
1413
1414 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001415 public void setClipTopAmount(int clipTopAmount) {
1416 super.setClipTopAmount(clipTopAmount);
1417 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001418 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001419 if (mGuts != null) {
1420 mGuts.setClipTopAmount(clipTopAmount);
1421 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001422 }
1423
Selim Cinek31094df2014-08-14 19:28:15 +02001424 public boolean isMaxExpandHeightInitialized() {
1425 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001426 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001427
Selim Cinek42357e02016-02-24 18:48:01 -08001428 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001429 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1430 }
Chris Wren78403d72014-07-28 10:23:24 +01001431
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001432 @Override
1433 public void setShowingLegacyBackground(boolean showing) {
1434 super.setShowingLegacyBackground(showing);
1435 mPrivateLayout.setShowingLegacyBackground(showing);
1436 mPublicLayout.setShowingLegacyBackground(showing);
1437 }
1438
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001439 @Override
1440 protected void updateBackgroundTint() {
1441 super.updateBackgroundTint();
Mady Mellorb0a82462016-04-30 17:31:02 -07001442 updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001443 if (mIsSummaryWithChildren) {
1444 List<ExpandableNotificationRow> notificationChildren =
1445 mChildrenContainer.getNotificationChildren();
1446 for (int i = 0; i < notificationChildren.size(); i++) {
1447 ExpandableNotificationRow child = notificationChildren.get(i);
Mady Mellorb0a82462016-04-30 17:31:02 -07001448 child.updateBackgroundForGroupState();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001449 }
1450 }
1451 }
1452
Mady Mellorb0a82462016-04-30 17:31:02 -07001453 /**
1454 * Called when a group has finished animating from collapsed or expanded state.
1455 */
1456 public void onFinishedExpansionChange() {
1457 mGroupExpansionChanging = false;
1458 updateBackgroundForGroupState();
1459 }
1460
1461 /**
1462 * Updates the parent and children backgrounds in a group based on the expansion state.
1463 */
1464 public void updateBackgroundForGroupState() {
1465 if (mIsSummaryWithChildren) {
1466 // Only when the group has finished expanding do we hide its background.
1467 mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
1468 mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
1469 List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
1470 for (int i = 0; i < children.size(); i++) {
1471 children.get(i).updateBackgroundForGroupState();
1472 }
1473 } else if (isChildInGroup()) {
1474 final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
1475 // Only show a background if the group is expanded OR if it is expanding / collapsing
1476 // and has a custom background color
1477 final boolean showBackground = isGroupExpanded()
1478 || ((mNotificationParent.isGroupExpansionChanging()
1479 || mNotificationParent.isUserLocked()) && childColor != 0);
1480 mShowNoBackground = !showBackground;
1481 } else {
1482 // Only children or parents ever need no background.
1483 mShowNoBackground = false;
1484 }
1485 updateOutline();
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001486 updateBackground();
1487 }
1488
Chris Wren78403d72014-07-28 10:23:24 +01001489 public void setExpansionLogger(ExpansionLogger logger, String key) {
1490 mLogger = logger;
1491 mLoggingKey = key;
1492 }
1493
Selim Cinek6183d122016-01-14 18:48:41 -08001494 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001495 public float getIncreasedPaddingAmount() {
1496 if (mIsSummaryWithChildren) {
1497 if (isGroupExpanded()) {
1498 return 1.0f;
1499 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001500 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001501 }
1502 }
1503 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001504 }
1505
1506 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001507 protected boolean disallowSingleClick(MotionEvent event) {
1508 float x = event.getX();
1509 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001510 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001511 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001512 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001513 }
1514 return super.disallowSingleClick(event);
1515 }
1516
Chris Wren78403d72014-07-28 10:23:24 +01001517 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
Chris Wren698b1702016-05-23 11:16:32 -04001518 boolean nowExpanded = isExpanded();
1519 if (mIsSummaryWithChildren) {
1520 nowExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
1521 }
Chris Wren78403d72014-07-28 10:23:24 +01001522 if (wasExpanded != nowExpanded && mLogger != null) {
1523 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1524 }
1525 }
Selim Cinek570981d2015-12-01 11:37:01 -08001526
1527 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001528 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001529 }
Chris Wren51c75102013-07-16 20:49:17 -04001530}