blob: 1a34dd79d63ae9be18e1a219267c14e7b133dc8b [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;
Selim Cineka6c6bfb2015-10-29 16:27:08 -070025import android.app.Notification;
Chris Wren51c75102013-07-16 20:49:17 -040026import android.content.Context;
Selim Cinekcab4a602014-09-03 14:47:57 +020027import android.graphics.drawable.AnimatedVectorDrawable;
28import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010029import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020030import android.graphics.drawable.Drawable;
Selim Cinekda42d652015-12-04 15:51:16 -080031import android.os.Build;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020032import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040033import android.util.AttributeSet;
Selim Cinek01af3342016-02-09 19:25:31 -080034import android.view.LayoutInflater;
Selim Cinek6183d122016-01-14 18:48:41 -080035import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080036import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050037import android.view.View;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020038import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020039import android.view.accessibility.AccessibilityEvent;
Selim Cinek98713a42015-09-21 15:47:20 +020040import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020041import android.widget.ImageView;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080042import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010043
Selim Cinek4bb59342016-04-08 19:29:35 -070044import com.android.internal.util.NotificationColorUtil;
Dan Sandlera5e0f412014-01-23 15:11:54 -050045import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070046import com.android.systemui.classifier.FalsingManager;
Selim Cinekc897bd32016-03-18 17:32:31 -070047import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinek0ffbda62016-01-01 20:29:12 +010048import com.android.systemui.statusbar.notification.NotificationViewWrapper;
Selim Cinekb5605e52015-02-20 18:21:41 +010049import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinek31aada42015-12-18 17:51:15 -080050import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010051import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
52import com.android.systemui.statusbar.stack.StackScrollState;
53import com.android.systemui.statusbar.stack.StackStateAnimator;
54import com.android.systemui.statusbar.stack.StackViewState;
55
Mady Mellor4b80b102016-01-22 08:03:58 -080056import java.util.ArrayList;
Selim Cinekb5605e52015-02-20 18:21:41 +010057import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050058
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020059public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010060
61 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
62 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
Selim Cinek01af3342016-02-09 19:25:31 -080063 private int mNotificationMinHeightLegacy;
64 private int mMaxHeadsUpHeightLegacy;
65 private int mMaxHeadsUpHeight;
66 private int mNotificationMinHeight;
67 private int mNotificationMaxHeight;
Chris Wren51c75102013-07-16 20:49:17 -040068
Selim Cinek1685e632014-04-08 02:27:49 +020069 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040070 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020071 /** Has the user actively changed the expansion state of this row */
72 private boolean mHasUserChangedExpansion;
73 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040074 private boolean mUserExpanded;
Selim Cinek31aada42015-12-18 17:51:15 -080075
76 /**
77 * Has this notification been expanded while it was pinned
78 */
79 private boolean mExpandedWhenPinned;
Selim Cinek1685e632014-04-08 02:27:49 +020080 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040081 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020082 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050083 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020084 private boolean mSensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -080085 private boolean mSensitiveHiddenInGeneral;
Jorim Jaggiae441282014-08-01 02:45:18 +020086 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -070087 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -040088
Selim Cinek1685e632014-04-08 02:27:49 +020089 /**
90 * Is this notification expanded by the system. The expansion state can be overridden by the
91 * user expansion.
92 */
93 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020094
95 /**
Selim Cinek83bc7832015-10-22 13:26:54 -070096 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020097 */
Selim Cinek83bc7832015-10-22 13:26:54 -070098 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020099
Mady Mellor4b80b102016-01-22 08:03:58 -0800100 private AnimatorSet mTranslateAnim;
101 private ArrayList<View> mTranslateableViews;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200102 private NotificationContentView mPublicLayout;
103 private NotificationContentView mPrivateLayout;
Selim Cinek1685e632014-04-08 02:27:49 +0200104 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -0700105 private int mHeadsUpHeight;
Selim Cinek863834b2014-05-20 04:20:25 +0200106 private View mVetoButton;
Selim Cinek4bb59342016-04-08 19:29:35 -0700107 private int mNotificationColor;
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400108 private boolean mClearable;
Chris Wren78403d72014-07-28 10:23:24 +0100109 private ExpansionLogger mLogger;
110 private String mLoggingKey;
Mady Mellor4b80b102016-01-22 08:03:58 -0800111 private NotificationSettingsIconRow mSettingsIconRow;
Selim Cinek8d490d42015-04-10 00:05:50 -0700112 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -0800113 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200114 private StatusBarNotification mStatusBarNotification;
Mady Mellor3fd273e2016-03-15 21:08:14 -0700115 private String mAppName;
Selim Cinek1a521f32014-11-03 17:39:29 +0100116 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +0200117 private boolean mLastChronometerRunning = true;
Selim Cinekeef84282015-10-30 16:28:00 -0700118 private NotificationHeaderView mNotificationHeader;
Selim Cinek9c7712d2015-12-08 19:19:48 -0800119 private NotificationViewWrapper mNotificationHeaderWrapper;
Selim Cinekb5605e52015-02-20 18:21:41 +0100120 private ViewStub mChildrenContainerStub;
121 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100122 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700123 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100124 private NotificationChildrenContainer mChildrenContainer;
Mady Mellor4b80b102016-01-22 08:03:58 -0800125 private ViewStub mSettingsIconRowStub;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100126 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100127 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700128 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700129 private FalsingManager mFalsingManager;
Selim Cinek31aada42015-12-18 17:51:15 -0800130 private HeadsUpManager mHeadsUpManager;
Selim Cinekea4bef72015-12-02 15:51:10 -0800131 private NotificationHeaderUtil mHeaderUtil = new NotificationHeaderUtil(this);
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;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800138 private OnClickListener mExpandClickListener = new OnClickListener() {
139 @Override
140 public void onClick(View v) {
Selim Cinek624c02db2015-12-14 21:00:02 -0800141 if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800142 mGroupManager.toggleGroupExpansion(mStatusBarNotification);
Selim Cinek31aada42015-12-18 17:51:15 -0800143 mOnExpandClickListener.onExpandClicked(mEntry,
Selim Cinek570981d2015-12-01 11:37:01 -0800144 mGroupManager.isGroupExpanded(mStatusBarNotification));
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800145 } else {
Selim Cinek31aada42015-12-18 17:51:15 -0800146 boolean nowExpanded;
147 if (isPinned()) {
148 nowExpanded = !mExpandedWhenPinned;
149 mExpandedWhenPinned = nowExpanded;
150 } else {
151 nowExpanded = !isExpanded();
152 setUserExpanded(nowExpanded);
153 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800154 notifyHeightChanged(true);
Selim Cinek31aada42015-12-18 17:51:15 -0800155 mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800156 }
157 }
158 };
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700159 private boolean mForceUnlocked;
Selim Cinek3f19f602016-05-02 18:01:56 -0700160 private boolean mDismissed;
161 private boolean mKeepInParent;
162 private boolean mRemoved;
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700163
Selim Cinek8d490d42015-04-10 00:05:50 -0700164 public NotificationContentView getPrivateLayout() {
165 return mPrivateLayout;
166 }
167
168 public NotificationContentView getPublicLayout() {
169 return mPublicLayout;
170 }
171
Selim Cinekcab4a602014-09-03 14:47:57 +0200172 public void setIconAnimationRunning(boolean running) {
173 setIconAnimationRunning(running, mPublicLayout);
174 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800175 setIconAnimationRunningForChild(running, mNotificationHeader);
176 if (mIsSummaryWithChildren) {
177 List<ExpandableNotificationRow> notificationChildren =
178 mChildrenContainer.getNotificationChildren();
179 for (int i = 0; i < notificationChildren.size(); i++) {
180 ExpandableNotificationRow child = notificationChildren.get(i);
181 child.setIconAnimationRunning(running);
182 }
183 }
184 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200185 }
186
187 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
188 if (layout != null) {
189 View contractedChild = layout.getContractedChild();
190 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700191 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200192 setIconAnimationRunningForChild(running, contractedChild);
193 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700194 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200195 }
196 }
197
198 private void setIconAnimationRunningForChild(boolean running, View child) {
199 if (child != null) {
200 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
201 setIconRunning(icon, running);
202 ImageView rightIcon = (ImageView) child.findViewById(
203 com.android.internal.R.id.right_icon);
204 setIconRunning(rightIcon, running);
205 }
206 }
207
208 private void setIconRunning(ImageView imageView, boolean running) {
209 if (imageView != null) {
210 Drawable drawable = imageView.getDrawable();
211 if (drawable instanceof AnimationDrawable) {
212 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
213 if (running) {
214 animationDrawable.start();
215 } else {
216 animationDrawable.stop();
217 }
218 } else if (drawable instanceof AnimatedVectorDrawable) {
219 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
220 if (running) {
221 animationDrawable.start();
222 } else {
223 animationDrawable.stop();
224 }
225 }
226 }
227 }
228
Selim Cinekda42d652015-12-04 15:51:16 -0800229 public void onNotificationUpdated(NotificationData.Entry entry) {
230 mEntry = entry;
231 mStatusBarNotification = entry.notification;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800232 mPrivateLayout.onNotificationUpdated(entry);
233 mPublicLayout.onNotificationUpdated(entry);
Selim Cinek757d8792016-01-28 16:21:08 -0800234 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700235 updateNotificationColor();
Selim Cinek757d8792016-01-28 16:21:08 -0800236 updateClearability();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800237 if (mIsSummaryWithChildren) {
238 recreateNotificationHeader();
Selim Cinekc897bd32016-03-18 17:32:31 -0700239 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800240 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800241 if (mIconAnimationRunning) {
242 setIconAnimationRunning(true);
243 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800244 if (mNotificationParent != null) {
245 mNotificationParent.updateChildrenHeaderAppearance();
246 }
Selim Cinek263398f2015-10-21 17:40:23 -0700247 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800248 // The public layouts expand button is always visible
249 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800250 updateLimits();
251 }
252
253 private void updateLimits() {
Selim Cineka1744872016-03-11 15:36:06 -0800254 updateLimitsForView(mPrivateLayout);
255 updateLimitsForView(mPublicLayout);
256 }
257
258 private void updateLimitsForView(NotificationContentView layout) {
259 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800260 != com.android.internal.R.id.status_bar_latest_event_content;
261 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
262 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
263 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800264 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
265 layout.getHeadsUpChild().getId()
266 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek77019c72015-12-09 10:18:02 -0800267 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
268 : mMaxHeadsUpHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800269 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200270 }
271
272 public StatusBarNotification getStatusBarNotification() {
273 return mStatusBarNotification;
274 }
275
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700276 public boolean isHeadsUp() {
277 return mIsHeadsUp;
278 }
279
Selim Cinek1a521f32014-11-03 17:39:29 +0100280 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700281 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100282 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700283 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700284 if (mIsSummaryWithChildren) {
285 // The overflow might change since we allow more lines as HUN.
286 mChildrenContainer.updateGroupOverflow();
287 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700288 if (intrinsicBefore != getIntrinsicHeight()) {
289 notifyHeightChanged(false /* needsAnimation */);
290 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100291 }
292
Selim Cinekb5605e52015-02-20 18:21:41 +0100293 public void setGroupManager(NotificationGroupManager groupManager) {
294 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700295 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100296 }
297
Adrian Roosb88b1a12015-12-09 18:51:05 -0800298 public void setRemoteInputController(RemoteInputController r) {
299 mPrivateLayout.setRemoteInputController(r);
300 }
301
Mady Mellor3fd273e2016-03-15 21:08:14 -0700302 public void setAppName(String appName) {
303 mAppName = appName;
304 if (mSettingsIconRow != null) {
305 mSettingsIconRow.setAppName(mAppName);
306 }
307 }
308
Selim Cinekb5605e52015-02-20 18:21:41 +0100309 public void addChildNotification(ExpandableNotificationRow row) {
310 addChildNotification(row, -1);
311 }
312
313 /**
314 * Add a child notification to this view.
315 *
316 * @param row the row to add
317 * @param childIndex the index to add it at, if -1 it will be added at the end
318 */
319 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
320 if (mChildrenContainer == null) {
321 mChildrenContainerStub.inflate();
322 }
323 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700324 onChildrenCountChanged();
325 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100326 }
327
328 public void removeChildNotification(ExpandableNotificationRow row) {
329 if (mChildrenContainer != null) {
330 mChildrenContainer.removeNotification(row);
331 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800332 mHeaderUtil.restoreNotificationHeader(row);
Selim Cinek263398f2015-10-21 17:40:23 -0700333 onChildrenCountChanged();
334 row.setIsChildInGroup(false, null);
335 }
336
337 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700338 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700339 }
340
Selim Cinek388df6d2015-10-22 13:25:11 -0700341 public ExpandableNotificationRow getNotificationParent() {
342 return mNotificationParent;
343 }
344
Selim Cinek263398f2015-10-21 17:40:23 -0700345 /**
346 * @param isChildInGroup Is this notification now in a group
347 * @param parent the new parent notification
348 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700349 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
350 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
351 mNotificationParent = childInGroup ? parent : null;
352 mPrivateLayout.setIsChildInGroup(childInGroup);
353 updateNoBackgroundState();
Selim Cinek34d93b02015-10-22 12:30:38 -0700354 }
355
356 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800357 public boolean onTouchEvent(MotionEvent event) {
358 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
359 || !isChildInGroup() || isGroupExpanded()) {
360 return super.onTouchEvent(event);
361 } else {
362 return false;
363 }
364 }
365
366 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800367 protected boolean handleSlideBack() {
368 if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
369 animateTranslateNotification(0 /* targetLeft */);
370 return true;
371 }
372 return false;
373 }
374
375 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700376 protected boolean shouldHideBackground() {
377 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700378 }
379
380 @Override
381 public boolean isSummaryWithChildren() {
382 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100383 }
384
385 @Override
386 public boolean areChildrenExpanded() {
387 return mChildrenExpanded;
388 }
389
390 public List<ExpandableNotificationRow> getNotificationChildren() {
391 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
392 }
393
Selim Cinekeef84282015-10-30 16:28:00 -0700394 public int getNumberOfNotificationChildren() {
395 if (mChildrenContainer == null) {
396 return 0;
397 }
398 return mChildrenContainer.getNotificationChildren().size();
399 }
400
Selim Cinekb5605e52015-02-20 18:21:41 +0100401 /**
402 * Apply the order given in the list to the children.
403 *
404 * @param childOrder the new list order
405 * @return whether the list order has changed
406 */
407 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
408 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
409 }
410
411 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700412 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100413 StackViewState parentState = resultState.getViewStateForView(this);
414 mChildrenContainer.getState(resultState, parentState);
415 }
416 }
417
418 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700419 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100420 mChildrenContainer.applyState(state);
421 }
422 }
423
424 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700425 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100426 mChildrenContainer.prepareExpansionChanged(state);
427 }
428 }
429
430 public void startChildAnimation(StackScrollState finalState,
Selim Cinek99695592016-01-12 17:51:35 -0800431 StackStateAnimator stateAnimator, long delay, long duration) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700432 if (mIsSummaryWithChildren) {
Selim Cinek99695592016-01-12 17:51:35 -0800433 mChildrenContainer.startAnimationToState(finalState, stateAnimator, delay,
Selim Cinekb5605e52015-02-20 18:21:41 +0100434 duration);
435 }
436 }
437
438 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800439 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100440 return this;
441 } else {
442 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
443 return view == null ? this : view;
444 }
445 }
446
Selim Cinekab29aeb2015-02-20 18:18:32 +0100447 public NotificationGuts getGuts() {
448 return mGuts;
449 }
450
Selim Cinek684a4422015-04-15 16:18:39 -0700451 /**
452 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
453 * the notification will be rendered on top of the screen.
454 *
455 * @param pinned whether it is pinned
456 */
457 public void setPinned(boolean pinned) {
Selim Cinekdef35a82016-05-03 15:52:51 -0700458 int intrinsicHeight = getIntrinsicHeight();
Selim Cinek684a4422015-04-15 16:18:39 -0700459 mIsPinned = pinned;
Selim Cinekdef35a82016-05-03 15:52:51 -0700460 if (intrinsicHeight != getIntrinsicHeight()) {
461 notifyHeightChanged(false);
462 }
Selim Cinek31aada42015-12-18 17:51:15 -0800463 if (pinned) {
464 setIconAnimationRunning(true);
465 mExpandedWhenPinned = false;
466 } else if (mExpandedWhenPinned) {
467 setUserExpanded(true);
468 }
Selim Cinek98713a42015-09-21 15:47:20 +0200469 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700470 }
471
Selim Cinek684a4422015-04-15 16:18:39 -0700472 public boolean isPinned() {
473 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700474 }
475
Selim Cinek31aada42015-12-18 17:51:15 -0800476 /**
477 * @param atLeastMinHeight should the value returned be at least the minimum height.
478 * Used to avoid cyclic calls
479 * @return the height of the heads up notification when pinned
480 */
481 public int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800482 if (mIsSummaryWithChildren) {
483 return mChildrenContainer.getIntrinsicHeight();
484 }
Selim Cinek31aada42015-12-18 17:51:15 -0800485 if(mExpandedWhenPinned) {
486 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
487 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700488 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800489 } else {
490 return mHeadsUpHeight;
491 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700492 }
493
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700494 /**
495 * Mark whether this notification was just clicked, i.e. the user has just clicked this
496 * notification in this frame.
497 */
498 public void setJustClicked(boolean justClicked) {
499 mJustClicked = justClicked;
500 }
501
502 /**
503 * @return true if this notification has been clicked in this frame, false otherwise
504 */
505 public boolean wasJustClicked() {
506 return mJustClicked;
507 }
508
Selim Cinek98713a42015-09-21 15:47:20 +0200509 public void setChronometerRunning(boolean running) {
510 mLastChronometerRunning = running;
511 setChronometerRunning(running, mPrivateLayout);
512 setChronometerRunning(running, mPublicLayout);
513 if (mChildrenContainer != null) {
514 List<ExpandableNotificationRow> notificationChildren =
515 mChildrenContainer.getNotificationChildren();
516 for (int i = 0; i < notificationChildren.size(); i++) {
517 ExpandableNotificationRow child = notificationChildren.get(i);
518 child.setChronometerRunning(running);
519 }
520 }
521 }
522
523 private void setChronometerRunning(boolean running, NotificationContentView layout) {
524 if (layout != null) {
525 running = running || isPinned();
526 View contractedChild = layout.getContractedChild();
527 View expandedChild = layout.getExpandedChild();
528 View headsUpChild = layout.getHeadsUpChild();
529 setChronometerRunningForChild(running, contractedChild);
530 setChronometerRunningForChild(running, expandedChild);
531 setChronometerRunningForChild(running, headsUpChild);
532 }
533 }
534
535 private void setChronometerRunningForChild(boolean running, View child) {
536 if (child != null) {
537 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
538 if (chronometer instanceof Chronometer) {
539 ((Chronometer) chronometer).setStarted(running);
540 }
541 }
542 }
543
Selim Cinekea4bef72015-12-02 15:51:10 -0800544 public NotificationHeaderView getNotificationHeader() {
545 if (mNotificationHeader != null) {
546 return mNotificationHeader;
Selim Cinek8d6440d2015-10-22 13:00:05 -0700547 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800548 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700549 }
550
Selim Cinek34eda5e2016-02-18 17:10:43 -0800551 private NotificationHeaderView getVisibleNotificationHeader() {
552 if (mNotificationHeader != null) {
553 return mNotificationHeader;
554 }
555 return getShowingLayout().getVisibleNotificationHeader();
556 }
557
Selim Cinek570981d2015-12-01 11:37:01 -0800558 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
559 mOnExpandClickListener = onExpandClickListener;
560 }
561
Selim Cinek31aada42015-12-18 17:51:15 -0800562 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
563 mHeadsUpManager = headsUpManager;
564 }
565
Selim Cinek01af3342016-02-09 19:25:31 -0800566 public void reInflateViews() {
567 initDimens();
568 if (mIsSummaryWithChildren) {
569 removeView(mNotificationHeader);
570 mNotificationHeader = null;
571 recreateNotificationHeader();
572 if (mChildrenContainer != null) {
573 mChildrenContainer.reInflateViews();
574 }
575 }
576 if (mGuts != null) {
577 View oldGuts = mGuts;
578 int index = indexOfChild(oldGuts);
579 removeView(oldGuts);
580 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
581 R.layout.notification_guts, this, false);
582 mGuts.setVisibility(oldGuts.getVisibility());
583 addView(mGuts, index);
584 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800585 if (mSettingsIconRow != null) {
586 View oldSettings = mSettingsIconRow;
587 int settingsIndex = indexOfChild(oldSettings);
588 removeView(oldSettings);
589 mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
590 R.layout.notification_settings_icon_row, this, false);
591 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700592 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800593 mSettingsIconRow.setVisibility(oldSettings.getVisibility());
594 addView(mSettingsIconRow, settingsIndex);
595
596 }
Selim Cinekde33a4a2016-02-11 16:43:41 -0800597 mPrivateLayout.reInflateViews();
598 mPublicLayout.reInflateViews();
Selim Cinek01af3342016-02-09 19:25:31 -0800599 }
600
Selim Cinekc3179332016-03-04 14:44:56 -0800601 public void setContentBackground(int customBackgroundColor, boolean animate,
602 NotificationContentView notificationContentView) {
603 if (getShowingLayout() == notificationContentView) {
604 setTintColor(customBackgroundColor, animate);
605 }
606 }
607
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700608 public void closeRemoteInput() {
609 mPrivateLayout.closeRemoteInput();
610 mPublicLayout.closeRemoteInput();
611 }
612
Selim Cinekc897bd32016-03-18 17:32:31 -0700613 /**
614 * Set by how much the single line view should be indented.
615 */
616 public void setSingleLineWidthIndention(int indention) {
617 mPrivateLayout.setSingleLineWidthIndention(indention);
618 }
619
620 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700621 return mNotificationColor;
622 }
623
624 private void updateNotificationColor() {
625 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
626 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700627 }
628
629 public HybridNotificationView getSingleLineView() {
630 return mPrivateLayout.getSingleLineView();
631 }
632
Selim Cinekf07d0622016-03-21 19:52:52 -0700633 public boolean isOnKeyguard() {
634 return mOnKeyguard;
635 }
636
Selim Cinekc1e389d2016-04-07 11:02:57 -0700637 public void removeAllChildren() {
638 List<ExpandableNotificationRow> notificationChildren
639 = mChildrenContainer.getNotificationChildren();
640 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
641 for (int i = 0; i < clonedList.size(); i++) {
642 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700643 if (row.keepInParent()) {
644 continue;
645 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700646 mChildrenContainer.removeNotification(row);
647 mHeaderUtil.restoreNotificationHeader(row);
648 row.setIsChildInGroup(false, null);
649 }
650 onChildrenCountChanged();
651 }
652
Selim Cinek1b2a05e2016-04-28 14:20:39 -0700653 public void setForceUnlocked(boolean forceUnlocked) {
654 mForceUnlocked = forceUnlocked;
655 if (mIsSummaryWithChildren) {
656 List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
657 for (ExpandableNotificationRow child : notificationChildren) {
658 child.setForceUnlocked(forceUnlocked);
659 }
660 }
661 }
662
Selim Cinek3f19f602016-05-02 18:01:56 -0700663 public void setDismissed(boolean dismissed) {
664 mDismissed = dismissed;
665 }
666
667 public boolean isDismissed() {
668 return mDismissed;
669 }
670
671 public boolean keepInParent() {
672 return mKeepInParent;
673 }
674
675 public void setKeepInParent(boolean keepInParent) {
676 mKeepInParent = keepInParent;
677 }
678
679 public boolean isRemoved() {
680 return mRemoved;
681 }
682
683 public void setRemoved(boolean removed) {
684 mRemoved = removed;
685 }
686
Selim Cinekd1395642016-04-28 12:22:42 -0700687 public NotificationChildrenContainer getChildrenContainer() {
688 return mChildrenContainer;
689 }
690
Chris Wren78403d72014-07-28 10:23:24 +0100691 public interface ExpansionLogger {
692 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
693 }
Selim Cinek1685e632014-04-08 02:27:49 +0200694
Chris Wren51c75102013-07-16 20:49:17 -0400695 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
696 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700697 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -0800698 initDimens();
699 }
700
701 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800702 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
703 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
704 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
705 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -0800706 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800707 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
708 }
709
710 /**
711 * @param dimenId the dimen to look up
712 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
713 */
714 private int getFontScaledHeight(int dimenId) {
715 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
716 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
717 getResources().getDisplayMetrics().density);
718 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -0400719 }
720
Christoph Studera7fe6312014-06-27 19:32:44 +0200721 /**
722 * Resets this view so it can be re-used for an updated notification.
723 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200724 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200725 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200726 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +0100727 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +0200728 mExpandable = false;
729 mHasUserChangedExpansion = false;
730 mUserLocked = false;
731 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200732 mSensitive = false;
733 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200734 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700735 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -0800736 mPublicLayout.reset();
737 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +0200738 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -0800739 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +0200740 logExpansionEvent(false, wasExpanded);
741 }
742
743 public void resetHeight() {
Christoph Studera7fe6312014-06-27 19:32:44 +0200744 mMaxExpandHeight = 0;
Selim Cinek8d490d42015-04-10 00:05:50 -0700745 mHeadsUpHeight = 0;
Selim Cinek31094df2014-08-14 19:28:15 +0200746 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200747 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200748 }
749
Jorim Jaggi251957d2014-04-09 04:24:09 +0200750 @Override
751 protected void onFinishInflate() {
752 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200753 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800754 mPublicLayout.setContainingNotification(this);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200755 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800756 mPrivateLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800757 mPrivateLayout.setContainingNotification(this);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800758 mPublicLayout.setExpandClickListener(mExpandClickListener);
Mady Mellor4b80b102016-01-22 08:03:58 -0800759 mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
760 mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
761 @Override
762 public void onInflate(ViewStub stub, View inflated) {
763 mSettingsIconRow = (NotificationSettingsIconRow) inflated;
764 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700765 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800766 }
767 });
Selim Cinekab29aeb2015-02-20 18:18:32 +0100768 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
769 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200770 @Override
771 public void onInflate(ViewStub stub, View inflated) {
772 mGuts = (NotificationGuts) inflated;
773 mGuts.setClipTopAmount(getClipTopAmount());
774 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100775 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200776 }
777 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100778 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
779 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
780
781 @Override
782 public void onInflate(ViewStub stub, View inflated) {
783 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -0700784 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -0700785 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -0800786 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +0100787 }
788 });
Selim Cinek863834b2014-05-20 04:20:25 +0200789 mVetoButton = findViewById(R.id.veto);
Mady Mellor4b80b102016-01-22 08:03:58 -0800790
791 // Add the views that we translate to reveal the gear
792 mTranslateableViews = new ArrayList<View>();
793 for (int i = 0; i < getChildCount(); i++) {
794 mTranslateableViews.add(getChildAt(i));
795 }
796 // Remove views that don't translate
797 mTranslateableViews.remove(mVetoButton);
798 mTranslateableViews.remove(mSettingsIconRowStub);
799 mTranslateableViews.remove(mChildrenContainerStub);
800 mTranslateableViews.remove(mGutsStub);
801 }
802
Mady Mellor34958fa2016-02-23 09:52:17 -0800803 private void setTranslationForOutline(float translationX) {
Mady Mellor4b80b102016-01-22 08:03:58 -0800804 setOutlineRect(false, translationX, getTop(), getRight() + translationX, getBottom());
805 }
806
807 public void resetTranslation() {
808 if (mTranslateableViews != null) {
809 for (int i = 0; i < mTranslateableViews.size(); i++) {
810 mTranslateableViews.get(i).setTranslationX(0);
811 }
812 setTranslationForOutline(0);
813 }
814 if (mSettingsIconRow != null) {
815 mSettingsIconRow.resetState();
816 }
817 }
818
819 public void animateTranslateNotification(final float leftTarget) {
820 if (mTranslateAnim != null) {
821 mTranslateAnim.cancel();
822 }
Mady Mellor34958fa2016-02-23 09:52:17 -0800823 mTranslateAnim = (AnimatorSet) getTranslateViewAnimator(leftTarget,
824 null /* updateListener */);
825 if (mTranslateAnim != null) {
826 mTranslateAnim.start();
827 }
828 }
829
830 @Override
831 public void setTranslation(float translationX) {
832 if (areGutsExposed()) {
833 // Don't translate if guts are showing.
834 return;
835 }
836 // Translate the group of views
837 for (int i = 0; i < mTranslateableViews.size(); i++) {
838 if (mTranslateableViews.get(i) != null) {
839 mTranslateableViews.get(i).setTranslationX(translationX);
840 }
841 }
842 setTranslationForOutline(translationX);
843 if (mSettingsIconRow != null) {
844 mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
845 }
846 }
847
848 @Override
849 public float getTranslation() {
850 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
851 // All of the views in the list should have same translation, just use first one.
852 return mTranslateableViews.get(0).getTranslationX();
853 }
854 return 0;
855 }
856
857 public Animator getTranslateViewAnimator(final float leftTarget,
858 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -0700859 if (mTranslateAnim != null) {
860 mTranslateAnim.cancel();
861 }
Mady Mellor34958fa2016-02-23 09:52:17 -0800862 if (areGutsExposed()) {
863 // No translation if guts are exposed.
864 return null;
865 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800866 AnimatorSet set = new AnimatorSet();
867 if (mTranslateableViews != null) {
868 for (int i = 0; i < mTranslateableViews.size(); i++) {
869 final View animView = mTranslateableViews.get(i);
870 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(
871 animView, "translationX", leftTarget);
872 if (i == 0) {
873 translateAnim.addUpdateListener(new AnimatorUpdateListener() {
874 @Override
875 public void onAnimationUpdate(ValueAnimator animation) {
876 setTranslationForOutline((float) animation.getAnimatedValue());
Mady Mellor34958fa2016-02-23 09:52:17 -0800877 if (mSettingsIconRow != null) {
878 mSettingsIconRow.updateSettingsIcons(
879 (float) animation.getAnimatedValue(), getMeasuredWidth());
880 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800881 }
882 });
Mady Mellor34958fa2016-02-23 09:52:17 -0800883 if (listener != null) {
884 translateAnim.addUpdateListener(listener);
885 }
Mady Mellor723f1f92016-03-13 15:54:06 -0700886 translateAnim.addListener(new AnimatorListenerAdapter() {
887 boolean cancelled = false;
888
889 @Override
890 public void onAnimationCancel(Animator anim) {
891 cancelled = true;
Mady Mellor4b80b102016-01-22 08:03:58 -0800892 }
Mady Mellor723f1f92016-03-13 15:54:06 -0700893
894 @Override
895 public void onAnimationEnd(Animator anim) {
896 if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
897 mSettingsIconRow.resetState();
898 mTranslateAnim = null;
899 }
900 }
901 });
902 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800903 set.play(translateAnim);
904 }
905 }
Mady Mellor723f1f92016-03-13 15:54:06 -0700906 mTranslateAnim = set;
Mady Mellor34958fa2016-02-23 09:52:17 -0800907 return set;
Mady Mellor4b80b102016-01-22 08:03:58 -0800908 }
909
910 public float getSpaceForGear() {
911 if (mSettingsIconRow != null) {
912 return mSettingsIconRow.getSpaceForGear();
913 }
914 return 0;
915 }
916
917 public NotificationSettingsIconRow getSettingsRow() {
918 if (mSettingsIconRow == null) {
919 mSettingsIconRowStub.inflate();
920 }
921 return mSettingsIconRow;
922 }
923
Selim Cinekab29aeb2015-02-20 18:18:32 +0100924 public void inflateGuts() {
925 if (mGuts == null) {
926 mGutsStub.inflate();
927 }
928 }
929
Selim Cinekda42d652015-12-04 15:51:16 -0800930 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -0800931 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
932 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -0800933 if (mChildrenContainer != null) {
934 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
935 : INVISIBLE);
Selim Cinekb5605e52015-02-20 18:21:41 +0100936 }
Selim Cinekef5127e2015-12-21 16:55:58 -0800937 if (mNotificationHeader != null) {
938 mNotificationHeader.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
939 : INVISIBLE);
940 }
Selim Cinekda42d652015-12-04 15:51:16 -0800941 // The limits might have changed if the view suddenly became a group or vice versa
942 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +0100943 }
944
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200945 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800946 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
947 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200948 // Add a record for the entire layout since its content is somehow small.
949 // The event comes from a leaf view that is interacted with.
950 AccessibilityEvent record = AccessibilityEvent.obtain();
951 onInitializeAccessibilityEvent(record);
952 dispatchPopulateAccessibilityEvent(record);
953 event.appendRecord(record);
954 return true;
955 }
956 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200957 }
Chris Wren51c75102013-07-16 20:49:17 -0400958
John Spurlocke15452b2014-08-21 09:44:39 -0400959 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100960 public void setDark(boolean dark, boolean fade, long delay) {
961 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400962 final NotificationContentView showing = getShowingLayout();
963 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100964 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400965 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800966 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -0700967 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -0800968 mNotificationHeaderWrapper.setDark(dark, fade, delay);
969 }
John Spurlocke15452b2014-08-21 09:44:39 -0400970 }
971
Chris Wren51c75102013-07-16 20:49:17 -0400972 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -0700973 if (mIsSummaryWithChildren && !mShowingPublic) {
974 return !mChildrenExpanded;
975 }
Chris Wren51c75102013-07-16 20:49:17 -0400976 return mExpandable;
977 }
978
979 public void setExpandable(boolean expandable) {
980 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800981 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -0400982 }
983
Selim Cinek4ffd6362015-12-29 15:12:23 +0100984 @Override
985 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -0800986 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
987 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +0100988 }
989
Selim Cinek1685e632014-04-08 02:27:49 +0200990 /**
991 * @return whether the user has changed the expansion state
992 */
993 public boolean hasUserChangedExpansion() {
994 return mHasUserChangedExpansion;
995 }
996
Chris Wren51c75102013-07-16 20:49:17 -0400997 public boolean isUserExpanded() {
998 return mUserExpanded;
999 }
1000
Selim Cinek1685e632014-04-08 02:27:49 +02001001 /**
1002 * Set this notification to be expanded by the user
1003 *
1004 * @param userExpanded whether the user wants this notification to be expanded
1005 */
Chris Wren51c75102013-07-16 20:49:17 -04001006 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -07001007 setUserExpanded(userExpanded, false /* allowChildExpansion */);
1008 }
1009
1010 /**
1011 * Set this notification to be expanded by the user
1012 *
1013 * @param userExpanded whether the user wants this notification to be expanded
1014 * @param allowChildExpansion whether a call to this method allows expanding children
1015 */
1016 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001017 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -07001018 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
1019 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
1020 return;
1021 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001022 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001023 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001024 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001025 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001026 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001027 }
1028
Selim Cinekccd14fb2014-08-12 18:53:24 +02001029 public void resetUserExpansion() {
1030 mHasUserChangedExpansion = false;
1031 mUserExpanded = false;
1032 }
1033
Chris Wren51c75102013-07-16 20:49:17 -04001034 public boolean isUserLocked() {
Selim Cinek1b2a05e2016-04-28 14:20:39 -07001035 return mUserLocked && !mForceUnlocked;
Chris Wren51c75102013-07-16 20:49:17 -04001036 }
1037
1038 public void setUserLocked(boolean userLocked) {
1039 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001040 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001041 if (mIsSummaryWithChildren) {
1042 mChildrenContainer.setUserLocked(userLocked);
1043 }
Chris Wren51c75102013-07-16 20:49:17 -04001044 }
1045
Selim Cinek1685e632014-04-08 02:27:49 +02001046 /**
1047 * @return has the system set this notification to be expanded
1048 */
1049 public boolean isSystemExpanded() {
1050 return mIsSystemExpanded;
1051 }
1052
1053 /**
1054 * Set this notification to be expanded by the system.
1055 *
1056 * @param expand whether the system wants this notification to be expanded.
1057 */
1058 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001059 if (expand != mIsSystemExpanded) {
1060 final boolean wasExpanded = isExpanded();
1061 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001062 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001063 logExpansionEvent(false, wasExpanded);
Selim Cinekc897bd32016-03-18 17:32:31 -07001064 if (mChildrenContainer != null) {
1065 mChildrenContainer.updateGroupOverflow();
1066 }
Selim Cinek31094df2014-08-14 19:28:15 +02001067 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001068 }
1069
1070 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001071 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001072 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001073 public void setOnKeyguard(boolean onKeyguard) {
1074 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001075 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001076 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001077 logExpansionEvent(false, wasExpanded);
1078 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001079 if (mIsSummaryWithChildren) {
1080 mChildrenContainer.updateGroupOverflow();
1081 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001082 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001083 }
1084 }
Selim Cinek1685e632014-04-08 02:27:49 +02001085 }
1086
1087 /**
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001088 * @return Can the underlying notification be cleared?
1089 */
1090 public boolean isClearable() {
Selim Cineka37774f2014-11-11 19:16:18 +01001091 return mStatusBarNotification != null && mStatusBarNotification.isClearable();
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001092 }
1093
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001094 @Override
1095 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001096 if (isUserLocked()) {
1097 return getActualHeight();
1098 }
Selim Cinekd84a5932015-12-15 11:45:36 -08001099 if (mGuts != null && mGuts.areGutsExposed()) {
1100 return mGuts.getHeight();
1101 } else if ((isChildInGroup() && !isGroupExpanded())) {
1102 return mPrivateLayout.getMinHeight();
1103 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1104 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001105 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001106 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek60122be2015-04-15 18:16:50 -07001107 } else if (mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001108 if (isPinned()) {
1109 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1110 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001111 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001112 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001113 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001114 }
Selim Cinek31aada42015-12-18 17:51:15 -08001115 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001116 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001117 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001118 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001119 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001120 }
Selim Cinek1685e632014-04-08 02:27:49 +02001121
Selim Cinekeef84282015-10-30 16:28:00 -07001122 private boolean isGroupExpanded() {
1123 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001124 }
1125
Selim Cinekeef84282015-10-30 16:28:00 -07001126 /**
1127 * @return whether this view has a header on the top of the content
1128 */
1129 private boolean hasNotificationHeader() {
1130 return mIsSummaryWithChildren;
Selim Cinek1685e632014-04-08 02:27:49 +02001131 }
1132
Selim Cinek263398f2015-10-21 17:40:23 -07001133 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001134 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Selim Cinek2a739342016-03-17 10:28:55 -07001135 && mChildrenContainer != null && mChildrenContainer.getChildCount() > 0;
Selim Cinek8fc93c92015-11-23 17:48:07 -08001136 if (mIsSummaryWithChildren) {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001137 if (mNotificationHeader == null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001138 recreateNotificationHeader();
1139 }
Selim Cinek263398f2015-10-21 17:40:23 -07001140 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001141 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001142 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001143 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001144 }
1145
Selim Cinek1685e632014-04-08 02:27:49 +02001146 /**
1147 * Check whether the view state is currently expanded. This is given by the system in {@link
1148 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1149 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1150 * view can differ from this state, if layout params are modified from outside.
1151 *
1152 * @return whether the view state is currently expanded.
1153 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001154 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001155 return isExpanded(false /* allowOnKeyguard */);
1156 }
1157
1158 public boolean isExpanded(boolean allowOnKeyguard) {
1159 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001160 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1161 || isUserExpanded());
1162 }
1163
1164 private boolean isSystemChildExpanded() {
1165 return mIsSystemChildExpanded;
1166 }
1167
1168 public void setSystemChildExpanded(boolean expanded) {
1169 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001170 }
1171
1172 @Override
1173 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1174 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001175 updateMaxHeights();
Mady Mellora6edc872016-04-26 11:01:03 -07001176 if (mSettingsIconRow != null) {
1177 mSettingsIconRow.updateVerticalLocation();
1178 }
Selim Cinek1685e632014-04-08 02:27:49 +02001179 }
1180
Selim Cinek8d490d42015-04-10 00:05:50 -07001181 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001182 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001183 View expandedChild = mPrivateLayout.getExpandedChild();
1184 if (expandedChild == null) {
1185 expandedChild = mPrivateLayout.getContractedChild();
1186 }
1187 mMaxExpandHeight = expandedChild.getHeight();
1188 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001189 if (headsUpChild == null) {
1190 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001191 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001192 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001193 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001194 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001195 }
1196 }
1197
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001198 @Override
1199 public void notifyHeightChanged(boolean needsAnimation) {
1200 super.notifyHeightChanged(needsAnimation);
1201 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1202 }
1203
Selim Cinek3c76d502016-02-19 15:16:33 -08001204 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001205 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001206 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001207 }
1208
1209 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001210 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001211 if (mIsSummaryWithChildren) {
1212 List<ExpandableNotificationRow> notificationChildren =
1213 mChildrenContainer.getNotificationChildren();
1214 for (int i = 0; i < notificationChildren.size(); i++) {
1215 ExpandableNotificationRow child = notificationChildren.get(i);
1216 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1217 }
1218 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001219 }
1220
1221 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1222 long duration) {
1223 boolean oldShowingPublic = mShowingPublic;
1224 mShowingPublic = mSensitive && hideSensitive;
1225 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1226 return;
1227 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001228
1229 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001230 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001231
Jorim Jaggiae441282014-08-01 02:45:18 +02001232 if (!animated) {
1233 mPublicLayout.animate().cancel();
1234 mPrivateLayout.animate().cancel();
1235 mPublicLayout.setAlpha(1f);
1236 mPrivateLayout.setAlpha(1f);
1237 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001238 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001239 } else {
1240 animateShowingPublic(delay, duration);
1241 }
Selim Cinekc3179332016-03-04 14:44:56 -08001242 NotificationContentView showingLayout = getShowingLayout();
1243 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001244 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinek757d8792016-01-28 16:21:08 -08001245 updateClearability();
Jorim Jaggiae441282014-08-01 02:45:18 +02001246 mShowingPublicInitialized = true;
1247 }
1248
1249 private void animateShowingPublic(long delay, long duration) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001250 View[] privateViews = mIsSummaryWithChildren ?
1251 new View[] {mChildrenContainer, mNotificationHeader}
1252 : new View[] {mPrivateLayout};
1253 View[] publicViews = new View[] {mPublicLayout};
1254 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1255 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1256 for (final View hiddenView : hiddenChildren) {
1257 hiddenView.setVisibility(View.VISIBLE);
1258 hiddenView.animate().cancel();
1259 hiddenView.animate()
1260 .alpha(0f)
1261 .setStartDelay(delay)
1262 .setDuration(duration)
1263 .withEndAction(new Runnable() {
1264 @Override
1265 public void run() {
1266 hiddenView.setVisibility(View.INVISIBLE);
1267 }
1268 });
1269 }
1270 for (View showView : shownChildren) {
1271 showView.setVisibility(View.VISIBLE);
1272 showView.setAlpha(0f);
1273 showView.animate().cancel();
1274 showView.animate()
1275 .alpha(1f)
1276 .setStartDelay(delay)
1277 .setDuration(duration);
1278 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001279 }
1280
Selim Cinek3776fe02016-02-04 13:32:43 -08001281 public boolean mustStayOnScreen() {
1282 return mIsHeadsUp;
1283 }
1284
Selim Cinek757d8792016-01-28 16:21:08 -08001285 private void updateClearability() {
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001286 // public versions cannot be dismissed
Selim Cinek3c76d502016-02-19 15:16:33 -08001287 mVetoButton.setVisibility(isClearable() && (!mShowingPublic
1288 || !mSensitiveHiddenInGeneral) ? View.VISIBLE : View.GONE);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001289 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001290
Selim Cinekb5605e52015-02-20 18:21:41 +01001291 public void setChildrenExpanded(boolean expanded, boolean animate) {
1292 mChildrenExpanded = expanded;
Selim Cinek7b836392015-12-04 20:02:59 -08001293 if (mNotificationHeader != null) {
1294 mNotificationHeader.setExpanded(expanded);
1295 }
Selim Cinek83bc7832015-10-22 13:26:54 -07001296 if (mChildrenContainer != null) {
1297 mChildrenContainer.setChildrenExpanded(expanded);
1298 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001299 }
1300
Selim Cinekb5605e52015-02-20 18:21:41 +01001301 public static void applyTint(View v, int color) {
1302 int alpha;
1303 if (color != 0) {
1304 alpha = COLORED_DIVIDER_ALPHA;
1305 } else {
1306 color = 0xff000000;
1307 alpha = DEFAULT_DIVIDER_ALPHA;
1308 }
1309 if (v.getBackground() instanceof ColorDrawable) {
1310 ColorDrawable background = (ColorDrawable) v.getBackground();
1311 background.mutate();
1312 background.setColor(color);
1313 background.setAlpha(alpha);
1314 }
1315 }
1316
Selim Cinek1685e632014-04-08 02:27:49 +02001317 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001318 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001319 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001320
Mady Mellor34958fa2016-02-23 09:52:17 -08001321 public boolean areGutsExposed() {
1322 return (mGuts != null && mGuts.areGutsExposed());
1323 }
1324
Jorim Jaggibe565df2014-04-28 17:51:23 +02001325 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001326 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001327 NotificationContentView showingLayout = getShowingLayout();
1328 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001329 }
1330
1331 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001332 protected View getContentView() {
1333 return getShowingLayout();
1334 }
1335
1336 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001337 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001338 super.setActualHeight(height, notifyListeners);
Mady Mellorb53bc272016-02-11 18:28:23 -08001339 if (mGuts != null && mGuts.areGutsExposed()) {
1340 mGuts.setActualHeight(height);
1341 return;
1342 }
Selim Cinekeef84282015-10-30 16:28:00 -07001343 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +01001344 mPrivateLayout.setContentHeight(contentHeight);
1345 mPublicLayout.setContentHeight(contentHeight);
Selim Cinek42357e02016-02-24 18:48:01 -08001346 if (mIsSummaryWithChildren) {
1347 mChildrenContainer.setActualHeight(height);
1348 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001349 if (mGuts != null) {
1350 mGuts.setActualHeight(height);
1351 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001352 }
1353
1354 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001355 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001356 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001357 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001358 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001359 NotificationContentView showingLayout = getShowingLayout();
1360 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001361 }
1362
1363 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001364 public int getMinHeight() {
Selim Cinek31aada42015-12-18 17:51:15 -08001365 if (mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
1366 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1367 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001368 return mChildrenContainer.getMinHeight();
Selim Cinek31aada42015-12-18 17:51:15 -08001369 } else if (mIsHeadsUp) {
1370 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001371 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001372 NotificationContentView showingLayout = getShowingLayout();
1373 return showingLayout.getMinHeight();
1374 }
1375
1376 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001377 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001378 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001379 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001380 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001381 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001382 }
1383
1384 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001385 public void setClipTopAmount(int clipTopAmount) {
1386 super.setClipTopAmount(clipTopAmount);
1387 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001388 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001389 if (mGuts != null) {
1390 mGuts.setClipTopAmount(clipTopAmount);
1391 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001392 }
1393
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001394 private void recreateNotificationHeader() {
1395 final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
1396 getStatusBarNotification().getNotification());
1397 final RemoteViews header = builder.makeNotificationHeader();
1398 if (mNotificationHeader == null) {
1399 mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
1400 final View expandButton = mNotificationHeader.findViewById(
1401 com.android.internal.R.id.expand_button);
1402 expandButton.setVisibility(VISIBLE);
1403 mNotificationHeader.setOnClickListener(mExpandClickListener);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001404 mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
Selim Cinek7d1c63e2016-04-21 15:26:10 -07001405 mNotificationHeader, this);
Selim Cinekb5a83612015-12-11 14:14:39 -08001406 addView(mNotificationHeader, indexOfChild(mChildrenContainer) + 1);
Mady Mellor4b80b102016-01-22 08:03:58 -08001407 mTranslateableViews.add(mNotificationHeader);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001408 } else {
1409 header.reapply(getContext(), mNotificationHeader);
Selim Cinek4ffd6362015-12-29 15:12:23 +01001410 mNotificationHeaderWrapper.notifyContentUpdated(mEntry.notification);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001411 }
Selim Cinekea4bef72015-12-02 15:51:10 -08001412 updateChildrenHeaderAppearance();
Selim Cinek343e6e22014-04-11 21:23:30 +02001413 }
Selim Cinek7d447722014-06-10 15:51:59 +02001414
Selim Cinekea4bef72015-12-02 15:51:10 -08001415 public void updateChildrenHeaderAppearance() {
1416 if (mIsSummaryWithChildren) {
1417 mHeaderUtil.updateChildrenHeaderAppearance();
1418 }
1419 }
1420
Selim Cinek31094df2014-08-14 19:28:15 +02001421 public boolean isMaxExpandHeightInitialized() {
1422 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001423 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001424
Selim Cinek42357e02016-02-24 18:48:01 -08001425 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001426 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1427 }
Chris Wren78403d72014-07-28 10:23:24 +01001428
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001429 @Override
1430 public void setShowingLegacyBackground(boolean showing) {
1431 super.setShowingLegacyBackground(showing);
1432 mPrivateLayout.setShowingLegacyBackground(showing);
1433 mPublicLayout.setShowingLegacyBackground(showing);
1434 }
1435
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001436 @Override
1437 protected void updateBackgroundTint() {
1438 super.updateBackgroundTint();
1439 updateNoBackgroundState();
1440 if (mIsSummaryWithChildren) {
1441 List<ExpandableNotificationRow> notificationChildren =
1442 mChildrenContainer.getNotificationChildren();
1443 for (int i = 0; i < notificationChildren.size(); i++) {
1444 ExpandableNotificationRow child = notificationChildren.get(i);
1445 child.updateNoBackgroundState();
1446 }
1447 }
1448 }
1449
1450 private void updateNoBackgroundState() {
1451 mShowNoBackground = isChildInGroup() && hasSameBgColor(mNotificationParent);
1452 updateBackground();
1453 }
1454
Chris Wren78403d72014-07-28 10:23:24 +01001455 public void setExpansionLogger(ExpansionLogger logger, String key) {
1456 mLogger = logger;
1457 mLoggingKey = key;
1458 }
1459
Selim Cinek6183d122016-01-14 18:48:41 -08001460 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001461 public float getIncreasedPaddingAmount() {
1462 if (mIsSummaryWithChildren) {
1463 if (isGroupExpanded()) {
1464 return 1.0f;
1465 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001466 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001467 }
1468 }
1469 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001470 }
1471
1472 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001473 protected boolean disallowSingleClick(MotionEvent event) {
1474 float x = event.getX();
1475 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001476 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001477 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001478 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001479 }
1480 return super.disallowSingleClick(event);
1481 }
1482
Chris Wren78403d72014-07-28 10:23:24 +01001483 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
1484 final boolean nowExpanded = isExpanded();
1485 if (wasExpanded != nowExpanded && mLogger != null) {
1486 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1487 }
1488 }
Selim Cinek570981d2015-12-01 11:37:01 -08001489
1490 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001491 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001492 }
Chris Wren51c75102013-07-16 20:49:17 -04001493}