blob: af48c9f901d92f468338cba523a52d1c7381f353 [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 Cinek3f19f602016-05-02 18:01:56 -0700159 private boolean mDismissed;
160 private boolean mKeepInParent;
161 private boolean mRemoved;
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700162
Selim Cinek8d490d42015-04-10 00:05:50 -0700163 public NotificationContentView getPrivateLayout() {
164 return mPrivateLayout;
165 }
166
167 public NotificationContentView getPublicLayout() {
168 return mPublicLayout;
169 }
170
Selim Cinekcab4a602014-09-03 14:47:57 +0200171 public void setIconAnimationRunning(boolean running) {
172 setIconAnimationRunning(running, mPublicLayout);
173 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800174 setIconAnimationRunningForChild(running, mNotificationHeader);
175 if (mIsSummaryWithChildren) {
176 List<ExpandableNotificationRow> notificationChildren =
177 mChildrenContainer.getNotificationChildren();
178 for (int i = 0; i < notificationChildren.size(); i++) {
179 ExpandableNotificationRow child = notificationChildren.get(i);
180 child.setIconAnimationRunning(running);
181 }
182 }
183 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200184 }
185
186 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
187 if (layout != null) {
188 View contractedChild = layout.getContractedChild();
189 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700190 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200191 setIconAnimationRunningForChild(running, contractedChild);
192 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700193 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200194 }
195 }
196
197 private void setIconAnimationRunningForChild(boolean running, View child) {
198 if (child != null) {
199 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
200 setIconRunning(icon, running);
201 ImageView rightIcon = (ImageView) child.findViewById(
202 com.android.internal.R.id.right_icon);
203 setIconRunning(rightIcon, running);
204 }
205 }
206
207 private void setIconRunning(ImageView imageView, boolean running) {
208 if (imageView != null) {
209 Drawable drawable = imageView.getDrawable();
210 if (drawable instanceof AnimationDrawable) {
211 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
212 if (running) {
213 animationDrawable.start();
214 } else {
215 animationDrawable.stop();
216 }
217 } else if (drawable instanceof AnimatedVectorDrawable) {
218 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
219 if (running) {
220 animationDrawable.start();
221 } else {
222 animationDrawable.stop();
223 }
224 }
225 }
226 }
227
Selim Cinekda42d652015-12-04 15:51:16 -0800228 public void onNotificationUpdated(NotificationData.Entry entry) {
229 mEntry = entry;
230 mStatusBarNotification = entry.notification;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800231 mPrivateLayout.onNotificationUpdated(entry);
232 mPublicLayout.onNotificationUpdated(entry);
Selim Cinek757d8792016-01-28 16:21:08 -0800233 mShowingPublicInitialized = false;
Selim Cinek4bb59342016-04-08 19:29:35 -0700234 updateNotificationColor();
Selim Cinek757d8792016-01-28 16:21:08 -0800235 updateClearability();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800236 if (mIsSummaryWithChildren) {
237 recreateNotificationHeader();
Selim Cinekc897bd32016-03-18 17:32:31 -0700238 mChildrenContainer.onNotificationUpdated();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800239 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800240 if (mIconAnimationRunning) {
241 setIconAnimationRunning(true);
242 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800243 if (mNotificationParent != null) {
244 mNotificationParent.updateChildrenHeaderAppearance();
245 }
Selim Cinek263398f2015-10-21 17:40:23 -0700246 onChildrenCountChanged();
Selim Cinek624c02db2015-12-14 21:00:02 -0800247 // The public layouts expand button is always visible
248 mPublicLayout.updateExpandButtons(true);
Selim Cinekda42d652015-12-04 15:51:16 -0800249 updateLimits();
250 }
251
252 private void updateLimits() {
Selim Cineka1744872016-03-11 15:36:06 -0800253 updateLimitsForView(mPrivateLayout);
254 updateLimitsForView(mPublicLayout);
255 }
256
257 private void updateLimitsForView(NotificationContentView layout) {
258 boolean customView = layout.getContractedChild().getId()
Selim Cinekda42d652015-12-04 15:51:16 -0800259 != com.android.internal.R.id.status_bar_latest_event_content;
260 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
261 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
262 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800263 boolean headsUpCustom = layout.getHeadsUpChild() != null &&
264 layout.getHeadsUpChild().getId()
265 != com.android.internal.R.id.status_bar_latest_event_content;
Selim Cinek77019c72015-12-09 10:18:02 -0800266 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
267 : mMaxHeadsUpHeight;
Selim Cineka1744872016-03-11 15:36:06 -0800268 layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200269 }
270
271 public StatusBarNotification getStatusBarNotification() {
272 return mStatusBarNotification;
273 }
274
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700275 public boolean isHeadsUp() {
276 return mIsHeadsUp;
277 }
278
Selim Cinek1a521f32014-11-03 17:39:29 +0100279 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700280 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100281 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700282 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekb41b2f62016-04-26 14:03:29 -0700283 if (mIsSummaryWithChildren) {
284 // The overflow might change since we allow more lines as HUN.
285 mChildrenContainer.updateGroupOverflow();
286 }
Selim Cinekc80fdb12015-04-13 15:09:08 -0700287 if (intrinsicBefore != getIntrinsicHeight()) {
288 notifyHeightChanged(false /* needsAnimation */);
289 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100290 }
291
Selim Cinekb5605e52015-02-20 18:21:41 +0100292 public void setGroupManager(NotificationGroupManager groupManager) {
293 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700294 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100295 }
296
Adrian Roosb88b1a12015-12-09 18:51:05 -0800297 public void setRemoteInputController(RemoteInputController r) {
298 mPrivateLayout.setRemoteInputController(r);
299 }
300
Mady Mellor3fd273e2016-03-15 21:08:14 -0700301 public void setAppName(String appName) {
302 mAppName = appName;
303 if (mSettingsIconRow != null) {
304 mSettingsIconRow.setAppName(mAppName);
305 }
306 }
307
Selim Cinekb5605e52015-02-20 18:21:41 +0100308 public void addChildNotification(ExpandableNotificationRow row) {
309 addChildNotification(row, -1);
310 }
311
312 /**
313 * Add a child notification to this view.
314 *
315 * @param row the row to add
316 * @param childIndex the index to add it at, if -1 it will be added at the end
317 */
318 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
319 if (mChildrenContainer == null) {
320 mChildrenContainerStub.inflate();
321 }
322 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700323 onChildrenCountChanged();
324 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100325 }
326
327 public void removeChildNotification(ExpandableNotificationRow row) {
328 if (mChildrenContainer != null) {
329 mChildrenContainer.removeNotification(row);
330 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800331 mHeaderUtil.restoreNotificationHeader(row);
Selim Cinek263398f2015-10-21 17:40:23 -0700332 onChildrenCountChanged();
333 row.setIsChildInGroup(false, null);
334 }
335
336 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700337 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700338 }
339
Selim Cinek388df6d2015-10-22 13:25:11 -0700340 public ExpandableNotificationRow getNotificationParent() {
341 return mNotificationParent;
342 }
343
Selim Cinek263398f2015-10-21 17:40:23 -0700344 /**
345 * @param isChildInGroup Is this notification now in a group
346 * @param parent the new parent notification
347 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700348 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
349 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
350 mNotificationParent = childInGroup ? parent : null;
351 mPrivateLayout.setIsChildInGroup(childInGroup);
352 updateNoBackgroundState();
Selim Cinek34d93b02015-10-22 12:30:38 -0700353 }
354
355 @Override
Selim Cinek72109472016-01-15 16:33:22 -0800356 public boolean onTouchEvent(MotionEvent event) {
357 if (event.getActionMasked() != MotionEvent.ACTION_DOWN
358 || !isChildInGroup() || isGroupExpanded()) {
359 return super.onTouchEvent(event);
360 } else {
361 return false;
362 }
363 }
364
365 @Override
Mady Mellorf0625802016-02-11 18:03:48 -0800366 protected boolean handleSlideBack() {
367 if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
368 animateTranslateNotification(0 /* targetLeft */);
369 return true;
370 }
371 return false;
372 }
373
374 @Override
Selim Cinek34d93b02015-10-22 12:30:38 -0700375 protected boolean shouldHideBackground() {
376 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700377 }
378
379 @Override
380 public boolean isSummaryWithChildren() {
381 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100382 }
383
384 @Override
385 public boolean areChildrenExpanded() {
386 return mChildrenExpanded;
387 }
388
389 public List<ExpandableNotificationRow> getNotificationChildren() {
390 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
391 }
392
Selim Cinekeef84282015-10-30 16:28:00 -0700393 public int getNumberOfNotificationChildren() {
394 if (mChildrenContainer == null) {
395 return 0;
396 }
397 return mChildrenContainer.getNotificationChildren().size();
398 }
399
Selim Cinekb5605e52015-02-20 18:21:41 +0100400 /**
401 * Apply the order given in the list to the children.
402 *
403 * @param childOrder the new list order
404 * @return whether the list order has changed
405 */
406 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
407 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
408 }
409
410 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700411 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100412 StackViewState parentState = resultState.getViewStateForView(this);
413 mChildrenContainer.getState(resultState, parentState);
414 }
415 }
416
417 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700418 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100419 mChildrenContainer.applyState(state);
420 }
421 }
422
423 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700424 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100425 mChildrenContainer.prepareExpansionChanged(state);
426 }
427 }
428
429 public void startChildAnimation(StackScrollState finalState,
Selim Cinek99695592016-01-12 17:51:35 -0800430 StackStateAnimator stateAnimator, long delay, long duration) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700431 if (mIsSummaryWithChildren) {
Selim Cinek99695592016-01-12 17:51:35 -0800432 mChildrenContainer.startAnimationToState(finalState, stateAnimator, delay,
Selim Cinekb5605e52015-02-20 18:21:41 +0100433 duration);
434 }
435 }
436
437 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek43d30f02016-03-04 10:51:32 -0800438 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100439 return this;
440 } else {
441 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
442 return view == null ? this : view;
443 }
444 }
445
Selim Cinekab29aeb2015-02-20 18:18:32 +0100446 public NotificationGuts getGuts() {
447 return mGuts;
448 }
449
Selim Cinek684a4422015-04-15 16:18:39 -0700450 /**
451 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
452 * the notification will be rendered on top of the screen.
453 *
454 * @param pinned whether it is pinned
455 */
456 public void setPinned(boolean pinned) {
457 mIsPinned = pinned;
Selim Cinek31aada42015-12-18 17:51:15 -0800458 if (pinned) {
459 setIconAnimationRunning(true);
460 mExpandedWhenPinned = false;
461 } else if (mExpandedWhenPinned) {
462 setUserExpanded(true);
463 }
Selim Cinek98713a42015-09-21 15:47:20 +0200464 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700465 }
466
Selim Cinek684a4422015-04-15 16:18:39 -0700467 public boolean isPinned() {
468 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700469 }
470
Selim Cinek31aada42015-12-18 17:51:15 -0800471 /**
472 * @param atLeastMinHeight should the value returned be at least the minimum height.
473 * Used to avoid cyclic calls
474 * @return the height of the heads up notification when pinned
475 */
476 public int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
Selim Cinek77019c72015-12-09 10:18:02 -0800477 if (mIsSummaryWithChildren) {
478 return mChildrenContainer.getIntrinsicHeight();
479 }
Selim Cinek31aada42015-12-18 17:51:15 -0800480 if(mExpandedWhenPinned) {
481 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
482 } else if (atLeastMinHeight) {
Selim Cinek567e8452016-03-24 10:54:56 -0700483 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek31aada42015-12-18 17:51:15 -0800484 } else {
485 return mHeadsUpHeight;
486 }
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700487 }
488
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700489 /**
490 * Mark whether this notification was just clicked, i.e. the user has just clicked this
491 * notification in this frame.
492 */
493 public void setJustClicked(boolean justClicked) {
494 mJustClicked = justClicked;
495 }
496
497 /**
498 * @return true if this notification has been clicked in this frame, false otherwise
499 */
500 public boolean wasJustClicked() {
501 return mJustClicked;
502 }
503
Selim Cinek98713a42015-09-21 15:47:20 +0200504 public void setChronometerRunning(boolean running) {
505 mLastChronometerRunning = running;
506 setChronometerRunning(running, mPrivateLayout);
507 setChronometerRunning(running, mPublicLayout);
508 if (mChildrenContainer != null) {
509 List<ExpandableNotificationRow> notificationChildren =
510 mChildrenContainer.getNotificationChildren();
511 for (int i = 0; i < notificationChildren.size(); i++) {
512 ExpandableNotificationRow child = notificationChildren.get(i);
513 child.setChronometerRunning(running);
514 }
515 }
516 }
517
518 private void setChronometerRunning(boolean running, NotificationContentView layout) {
519 if (layout != null) {
520 running = running || isPinned();
521 View contractedChild = layout.getContractedChild();
522 View expandedChild = layout.getExpandedChild();
523 View headsUpChild = layout.getHeadsUpChild();
524 setChronometerRunningForChild(running, contractedChild);
525 setChronometerRunningForChild(running, expandedChild);
526 setChronometerRunningForChild(running, headsUpChild);
527 }
528 }
529
530 private void setChronometerRunningForChild(boolean running, View child) {
531 if (child != null) {
532 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
533 if (chronometer instanceof Chronometer) {
534 ((Chronometer) chronometer).setStarted(running);
535 }
536 }
537 }
538
Selim Cinekea4bef72015-12-02 15:51:10 -0800539 public NotificationHeaderView getNotificationHeader() {
540 if (mNotificationHeader != null) {
541 return mNotificationHeader;
Selim Cinek8d6440d2015-10-22 13:00:05 -0700542 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800543 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700544 }
545
Selim Cinek34eda5e2016-02-18 17:10:43 -0800546 private NotificationHeaderView getVisibleNotificationHeader() {
547 if (mNotificationHeader != null) {
548 return mNotificationHeader;
549 }
550 return getShowingLayout().getVisibleNotificationHeader();
551 }
552
Selim Cinek570981d2015-12-01 11:37:01 -0800553 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
554 mOnExpandClickListener = onExpandClickListener;
555 }
556
Selim Cinek31aada42015-12-18 17:51:15 -0800557 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
558 mHeadsUpManager = headsUpManager;
559 }
560
Selim Cinek01af3342016-02-09 19:25:31 -0800561 public void reInflateViews() {
562 initDimens();
563 if (mIsSummaryWithChildren) {
564 removeView(mNotificationHeader);
565 mNotificationHeader = null;
566 recreateNotificationHeader();
567 if (mChildrenContainer != null) {
568 mChildrenContainer.reInflateViews();
569 }
570 }
571 if (mGuts != null) {
572 View oldGuts = mGuts;
573 int index = indexOfChild(oldGuts);
574 removeView(oldGuts);
575 mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
576 R.layout.notification_guts, this, false);
577 mGuts.setVisibility(oldGuts.getVisibility());
578 addView(mGuts, index);
579 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800580 if (mSettingsIconRow != null) {
581 View oldSettings = mSettingsIconRow;
582 int settingsIndex = indexOfChild(oldSettings);
583 removeView(oldSettings);
584 mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
585 R.layout.notification_settings_icon_row, this, false);
586 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700587 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800588 mSettingsIconRow.setVisibility(oldSettings.getVisibility());
589 addView(mSettingsIconRow, settingsIndex);
590
591 }
Selim Cinekde33a4a2016-02-11 16:43:41 -0800592 mPrivateLayout.reInflateViews();
593 mPublicLayout.reInflateViews();
Selim Cinek01af3342016-02-09 19:25:31 -0800594 }
595
Selim Cinekc3179332016-03-04 14:44:56 -0800596 public void setContentBackground(int customBackgroundColor, boolean animate,
597 NotificationContentView notificationContentView) {
598 if (getShowingLayout() == notificationContentView) {
599 setTintColor(customBackgroundColor, animate);
600 }
601 }
602
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700603 public void closeRemoteInput() {
604 mPrivateLayout.closeRemoteInput();
605 mPublicLayout.closeRemoteInput();
606 }
607
Selim Cinekc897bd32016-03-18 17:32:31 -0700608 /**
609 * Set by how much the single line view should be indented.
610 */
611 public void setSingleLineWidthIndention(int indention) {
612 mPrivateLayout.setSingleLineWidthIndention(indention);
613 }
614
615 public int getNotificationColor() {
Selim Cinek4bb59342016-04-08 19:29:35 -0700616 return mNotificationColor;
617 }
618
619 private void updateNotificationColor() {
620 mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
621 getStatusBarNotification().getNotification().color);
Selim Cinekc897bd32016-03-18 17:32:31 -0700622 }
623
624 public HybridNotificationView getSingleLineView() {
625 return mPrivateLayout.getSingleLineView();
626 }
627
Selim Cinekf07d0622016-03-21 19:52:52 -0700628 public boolean isOnKeyguard() {
629 return mOnKeyguard;
630 }
631
Selim Cinekc1e389d2016-04-07 11:02:57 -0700632 public void removeAllChildren() {
633 List<ExpandableNotificationRow> notificationChildren
634 = mChildrenContainer.getNotificationChildren();
635 ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren);
636 for (int i = 0; i < clonedList.size(); i++) {
637 ExpandableNotificationRow row = clonedList.get(i);
Selim Cinek3f19f602016-05-02 18:01:56 -0700638 if (row.keepInParent()) {
639 continue;
640 }
Selim Cinekc1e389d2016-04-07 11:02:57 -0700641 mChildrenContainer.removeNotification(row);
642 mHeaderUtil.restoreNotificationHeader(row);
643 row.setIsChildInGroup(false, null);
644 }
645 onChildrenCountChanged();
646 }
647
Selim Cinek3f19f602016-05-02 18:01:56 -0700648 public void setDismissed(boolean dismissed) {
649 mDismissed = dismissed;
650 }
651
652 public boolean isDismissed() {
653 return mDismissed;
654 }
655
656 public boolean keepInParent() {
657 return mKeepInParent;
658 }
659
660 public void setKeepInParent(boolean keepInParent) {
661 mKeepInParent = keepInParent;
662 }
663
664 public boolean isRemoved() {
665 return mRemoved;
666 }
667
668 public void setRemoved(boolean removed) {
669 mRemoved = removed;
670 }
671
Chris Wren78403d72014-07-28 10:23:24 +0100672 public interface ExpansionLogger {
673 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
674 }
Selim Cinek1685e632014-04-08 02:27:49 +0200675
Chris Wren51c75102013-07-16 20:49:17 -0400676 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
677 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700678 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinek01af3342016-02-09 19:25:31 -0800679 initDimens();
680 }
681
682 private void initDimens() {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800683 mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
684 mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
685 mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
686 mMaxHeadsUpHeightLegacy = getFontScaledHeight(
Selim Cinek77019c72015-12-09 10:18:02 -0800687 R.dimen.notification_max_heads_up_height_legacy);
Selim Cinekf619ffc2016-02-17 14:53:05 -0800688 mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
689 }
690
691 /**
692 * @param dimenId the dimen to look up
693 * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
694 */
695 private int getFontScaledHeight(int dimenId) {
696 int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
697 float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
698 getResources().getDisplayMetrics().density);
699 return (int) (dimensionPixelSize * factor);
Chris Wren51c75102013-07-16 20:49:17 -0400700 }
701
Christoph Studera7fe6312014-06-27 19:32:44 +0200702 /**
703 * Resets this view so it can be re-used for an updated notification.
704 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200705 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200706 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200707 super.reset();
Chris Wren78403d72014-07-28 10:23:24 +0100708 final boolean wasExpanded = isExpanded();
Christoph Studera7fe6312014-06-27 19:32:44 +0200709 mExpandable = false;
710 mHasUserChangedExpansion = false;
711 mUserLocked = false;
712 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200713 mSensitive = false;
714 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200715 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700716 mOnKeyguard = false;
Selim Cinek51d94912016-03-02 15:34:28 -0800717 mPublicLayout.reset();
718 mPrivateLayout.reset();
Selim Cinek31094df2014-08-14 19:28:15 +0200719 resetHeight();
Mady Mellor4b80b102016-01-22 08:03:58 -0800720 resetTranslation();
Selim Cinek31094df2014-08-14 19:28:15 +0200721 logExpansionEvent(false, wasExpanded);
722 }
723
724 public void resetHeight() {
Christoph Studera7fe6312014-06-27 19:32:44 +0200725 mMaxExpandHeight = 0;
Selim Cinek8d490d42015-04-10 00:05:50 -0700726 mHeadsUpHeight = 0;
Selim Cinek31094df2014-08-14 19:28:15 +0200727 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200728 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200729 }
730
Jorim Jaggi251957d2014-04-09 04:24:09 +0200731 @Override
732 protected void onFinishInflate() {
733 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200734 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800735 mPublicLayout.setContainingNotification(this);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200736 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800737 mPrivateLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800738 mPrivateLayout.setContainingNotification(this);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800739 mPublicLayout.setExpandClickListener(mExpandClickListener);
Mady Mellor4b80b102016-01-22 08:03:58 -0800740 mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
741 mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
742 @Override
743 public void onInflate(ViewStub stub, View inflated) {
744 mSettingsIconRow = (NotificationSettingsIconRow) inflated;
745 mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
Mady Mellor3fd273e2016-03-15 21:08:14 -0700746 mSettingsIconRow.setAppName(mAppName);
Mady Mellor4b80b102016-01-22 08:03:58 -0800747 }
748 });
Selim Cinekab29aeb2015-02-20 18:18:32 +0100749 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
750 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200751 @Override
752 public void onInflate(ViewStub stub, View inflated) {
753 mGuts = (NotificationGuts) inflated;
754 mGuts.setClipTopAmount(getClipTopAmount());
755 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100756 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200757 }
758 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100759 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
760 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
761
762 @Override
763 public void onInflate(ViewStub stub, View inflated) {
764 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -0700765 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekc897bd32016-03-18 17:32:31 -0700766 mChildrenContainer.onNotificationUpdated();
Mady Mellor4b80b102016-01-22 08:03:58 -0800767 mTranslateableViews.add(mChildrenContainer);
Selim Cinekb5605e52015-02-20 18:21:41 +0100768 }
769 });
Selim Cinek863834b2014-05-20 04:20:25 +0200770 mVetoButton = findViewById(R.id.veto);
Mady Mellor4b80b102016-01-22 08:03:58 -0800771
772 // Add the views that we translate to reveal the gear
773 mTranslateableViews = new ArrayList<View>();
774 for (int i = 0; i < getChildCount(); i++) {
775 mTranslateableViews.add(getChildAt(i));
776 }
777 // Remove views that don't translate
778 mTranslateableViews.remove(mVetoButton);
779 mTranslateableViews.remove(mSettingsIconRowStub);
780 mTranslateableViews.remove(mChildrenContainerStub);
781 mTranslateableViews.remove(mGutsStub);
782 }
783
Mady Mellor34958fa2016-02-23 09:52:17 -0800784 private void setTranslationForOutline(float translationX) {
Mady Mellor4b80b102016-01-22 08:03:58 -0800785 setOutlineRect(false, translationX, getTop(), getRight() + translationX, getBottom());
786 }
787
788 public void resetTranslation() {
789 if (mTranslateableViews != null) {
790 for (int i = 0; i < mTranslateableViews.size(); i++) {
791 mTranslateableViews.get(i).setTranslationX(0);
792 }
793 setTranslationForOutline(0);
794 }
795 if (mSettingsIconRow != null) {
796 mSettingsIconRow.resetState();
797 }
798 }
799
800 public void animateTranslateNotification(final float leftTarget) {
801 if (mTranslateAnim != null) {
802 mTranslateAnim.cancel();
803 }
Mady Mellor34958fa2016-02-23 09:52:17 -0800804 mTranslateAnim = (AnimatorSet) getTranslateViewAnimator(leftTarget,
805 null /* updateListener */);
806 if (mTranslateAnim != null) {
807 mTranslateAnim.start();
808 }
809 }
810
811 @Override
812 public void setTranslation(float translationX) {
813 if (areGutsExposed()) {
814 // Don't translate if guts are showing.
815 return;
816 }
817 // Translate the group of views
818 for (int i = 0; i < mTranslateableViews.size(); i++) {
819 if (mTranslateableViews.get(i) != null) {
820 mTranslateableViews.get(i).setTranslationX(translationX);
821 }
822 }
823 setTranslationForOutline(translationX);
824 if (mSettingsIconRow != null) {
825 mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
826 }
827 }
828
829 @Override
830 public float getTranslation() {
831 if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
832 // All of the views in the list should have same translation, just use first one.
833 return mTranslateableViews.get(0).getTranslationX();
834 }
835 return 0;
836 }
837
838 public Animator getTranslateViewAnimator(final float leftTarget,
839 AnimatorUpdateListener listener) {
Mady Mellor723f1f92016-03-13 15:54:06 -0700840 if (mTranslateAnim != null) {
841 mTranslateAnim.cancel();
842 }
Mady Mellor34958fa2016-02-23 09:52:17 -0800843 if (areGutsExposed()) {
844 // No translation if guts are exposed.
845 return null;
846 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800847 AnimatorSet set = new AnimatorSet();
848 if (mTranslateableViews != null) {
849 for (int i = 0; i < mTranslateableViews.size(); i++) {
850 final View animView = mTranslateableViews.get(i);
851 final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(
852 animView, "translationX", leftTarget);
853 if (i == 0) {
854 translateAnim.addUpdateListener(new AnimatorUpdateListener() {
855 @Override
856 public void onAnimationUpdate(ValueAnimator animation) {
857 setTranslationForOutline((float) animation.getAnimatedValue());
Mady Mellor34958fa2016-02-23 09:52:17 -0800858 if (mSettingsIconRow != null) {
859 mSettingsIconRow.updateSettingsIcons(
860 (float) animation.getAnimatedValue(), getMeasuredWidth());
861 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800862 }
863 });
Mady Mellor34958fa2016-02-23 09:52:17 -0800864 if (listener != null) {
865 translateAnim.addUpdateListener(listener);
866 }
Mady Mellor723f1f92016-03-13 15:54:06 -0700867 translateAnim.addListener(new AnimatorListenerAdapter() {
868 boolean cancelled = false;
869
870 @Override
871 public void onAnimationCancel(Animator anim) {
872 cancelled = true;
Mady Mellor4b80b102016-01-22 08:03:58 -0800873 }
Mady Mellor723f1f92016-03-13 15:54:06 -0700874
875 @Override
876 public void onAnimationEnd(Animator anim) {
877 if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
878 mSettingsIconRow.resetState();
879 mTranslateAnim = null;
880 }
881 }
882 });
883 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800884 set.play(translateAnim);
885 }
886 }
Mady Mellor723f1f92016-03-13 15:54:06 -0700887 mTranslateAnim = set;
Mady Mellor34958fa2016-02-23 09:52:17 -0800888 return set;
Mady Mellor4b80b102016-01-22 08:03:58 -0800889 }
890
891 public float getSpaceForGear() {
892 if (mSettingsIconRow != null) {
893 return mSettingsIconRow.getSpaceForGear();
894 }
895 return 0;
896 }
897
898 public NotificationSettingsIconRow getSettingsRow() {
899 if (mSettingsIconRow == null) {
900 mSettingsIconRowStub.inflate();
901 }
902 return mSettingsIconRow;
903 }
904
Selim Cinekab29aeb2015-02-20 18:18:32 +0100905 public void inflateGuts() {
906 if (mGuts == null) {
907 mGutsStub.inflate();
908 }
909 }
910
Selim Cinekda42d652015-12-04 15:51:16 -0800911 private void updateChildrenVisibility() {
Selim Cinekd84a5932015-12-15 11:45:36 -0800912 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
913 : INVISIBLE);
Selim Cinekef5127e2015-12-21 16:55:58 -0800914 if (mChildrenContainer != null) {
915 mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
916 : INVISIBLE);
Selim Cinekb5605e52015-02-20 18:21:41 +0100917 }
Selim Cinekef5127e2015-12-21 16:55:58 -0800918 if (mNotificationHeader != null) {
919 mNotificationHeader.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
920 : INVISIBLE);
921 }
Selim Cinekda42d652015-12-04 15:51:16 -0800922 // The limits might have changed if the view suddenly became a group or vice versa
923 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +0100924 }
925
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200926 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800927 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
928 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200929 // Add a record for the entire layout since its content is somehow small.
930 // The event comes from a leaf view that is interacted with.
931 AccessibilityEvent record = AccessibilityEvent.obtain();
932 onInitializeAccessibilityEvent(record);
933 dispatchPopulateAccessibilityEvent(record);
934 event.appendRecord(record);
935 return true;
936 }
937 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200938 }
Chris Wren51c75102013-07-16 20:49:17 -0400939
John Spurlocke15452b2014-08-21 09:44:39 -0400940 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100941 public void setDark(boolean dark, boolean fade, long delay) {
942 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400943 final NotificationContentView showing = getShowingLayout();
944 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100945 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400946 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800947 if (mIsSummaryWithChildren) {
Selim Cinekc897bd32016-03-18 17:32:31 -0700948 mChildrenContainer.setDark(dark, fade, delay);
Selim Cinek9c7712d2015-12-08 19:19:48 -0800949 mNotificationHeaderWrapper.setDark(dark, fade, delay);
950 }
John Spurlocke15452b2014-08-21 09:44:39 -0400951 }
952
Chris Wren51c75102013-07-16 20:49:17 -0400953 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -0700954 if (mIsSummaryWithChildren && !mShowingPublic) {
955 return !mChildrenExpanded;
956 }
Chris Wren51c75102013-07-16 20:49:17 -0400957 return mExpandable;
958 }
959
960 public void setExpandable(boolean expandable) {
961 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800962 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -0400963 }
964
Selim Cinek4ffd6362015-12-29 15:12:23 +0100965 @Override
966 public void setClipToActualHeight(boolean clipToActualHeight) {
Selim Cinek084c16b2016-01-22 17:48:22 -0800967 super.setClipToActualHeight(clipToActualHeight || isUserLocked());
968 getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
Selim Cinek4ffd6362015-12-29 15:12:23 +0100969 }
970
Selim Cinek1685e632014-04-08 02:27:49 +0200971 /**
972 * @return whether the user has changed the expansion state
973 */
974 public boolean hasUserChangedExpansion() {
975 return mHasUserChangedExpansion;
976 }
977
Chris Wren51c75102013-07-16 20:49:17 -0400978 public boolean isUserExpanded() {
979 return mUserExpanded;
980 }
981
Selim Cinek1685e632014-04-08 02:27:49 +0200982 /**
983 * Set this notification to be expanded by the user
984 *
985 * @param userExpanded whether the user wants this notification to be expanded
986 */
Chris Wren51c75102013-07-16 20:49:17 -0400987 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -0700988 setUserExpanded(userExpanded, false /* allowChildExpansion */);
989 }
990
991 /**
992 * Set this notification to be expanded by the user
993 *
994 * @param userExpanded whether the user wants this notification to be expanded
995 * @param allowChildExpansion whether a call to this method allows expanding children
996 */
997 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700998 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -0700999 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
1000 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
1001 return;
1002 }
Christoph Studera7fe6312014-06-27 19:32:44 +02001003 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +01001004 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +02001005 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -04001006 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +01001007 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -04001008 }
1009
Selim Cinekccd14fb2014-08-12 18:53:24 +02001010 public void resetUserExpansion() {
1011 mHasUserChangedExpansion = false;
1012 mUserExpanded = false;
1013 }
1014
Chris Wren51c75102013-07-16 20:49:17 -04001015 public boolean isUserLocked() {
1016 return mUserLocked;
1017 }
1018
1019 public void setUserLocked(boolean userLocked) {
1020 mUserLocked = userLocked;
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001021 mPrivateLayout.setUserExpanding(userLocked);
Selim Cinek42357e02016-02-24 18:48:01 -08001022 if (mIsSummaryWithChildren) {
1023 mChildrenContainer.setUserLocked(userLocked);
1024 }
Chris Wren51c75102013-07-16 20:49:17 -04001025 }
1026
Selim Cinek1685e632014-04-08 02:27:49 +02001027 /**
1028 * @return has the system set this notification to be expanded
1029 */
1030 public boolean isSystemExpanded() {
1031 return mIsSystemExpanded;
1032 }
1033
1034 /**
1035 * Set this notification to be expanded by the system.
1036 *
1037 * @param expand whether the system wants this notification to be expanded.
1038 */
1039 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +02001040 if (expand != mIsSystemExpanded) {
1041 final boolean wasExpanded = isExpanded();
1042 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +01001043 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001044 logExpansionEvent(false, wasExpanded);
Selim Cinekc897bd32016-03-18 17:32:31 -07001045 if (mChildrenContainer != null) {
1046 mChildrenContainer.updateGroupOverflow();
1047 }
Selim Cinek31094df2014-08-14 19:28:15 +02001048 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001049 }
1050
1051 /**
Selim Cinek83bc7832015-10-22 13:26:54 -07001052 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +02001053 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001054 public void setOnKeyguard(boolean onKeyguard) {
1055 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +02001056 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -07001057 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +02001058 logExpansionEvent(false, wasExpanded);
1059 if (wasExpanded != isExpanded()) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001060 if (mIsSummaryWithChildren) {
1061 mChildrenContainer.updateGroupOverflow();
1062 }
Mady Mellor4b80b102016-01-22 08:03:58 -08001063 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +02001064 }
1065 }
Selim Cinek1685e632014-04-08 02:27:49 +02001066 }
1067
1068 /**
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001069 * @return Can the underlying notification be cleared?
1070 */
1071 public boolean isClearable() {
Selim Cineka37774f2014-11-11 19:16:18 +01001072 return mStatusBarNotification != null && mStatusBarNotification.isClearable();
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001073 }
1074
Jorim Jaggi9cbadd32014-05-01 20:18:31 +02001075 @Override
1076 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +02001077 if (isUserLocked()) {
1078 return getActualHeight();
1079 }
Selim Cinekd84a5932015-12-15 11:45:36 -08001080 if (mGuts != null && mGuts.areGutsExposed()) {
1081 return mGuts.getHeight();
1082 } else if ((isChildInGroup() && !isGroupExpanded())) {
1083 return mPrivateLayout.getMinHeight();
1084 } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
1085 return getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001086 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001087 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek60122be2015-04-15 18:16:50 -07001088 } else if (mIsHeadsUp) {
Selim Cinek31aada42015-12-18 17:51:15 -08001089 if (isPinned()) {
1090 return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
1091 } else if (isExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001092 return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001093 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001094 return Math.max(getCollapsedHeight(), mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -07001095 }
Selim Cinek31aada42015-12-18 17:51:15 -08001096 } else if (isExpanded()) {
Selim Cinek83bc7832015-10-22 13:26:54 -07001097 return getMaxExpandHeight();
Selim Cinekd84a5932015-12-15 11:45:36 -08001098 } else {
Selim Cinek567e8452016-03-24 10:54:56 -07001099 return getCollapsedHeight();
Selim Cinek1685e632014-04-08 02:27:49 +02001100 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001101 }
Selim Cinek1685e632014-04-08 02:27:49 +02001102
Selim Cinekeef84282015-10-30 16:28:00 -07001103 private boolean isGroupExpanded() {
1104 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +01001105 }
1106
Selim Cinekeef84282015-10-30 16:28:00 -07001107 /**
1108 * @return whether this view has a header on the top of the content
1109 */
1110 private boolean hasNotificationHeader() {
1111 return mIsSummaryWithChildren;
Selim Cinek1685e632014-04-08 02:27:49 +02001112 }
1113
Selim Cinek263398f2015-10-21 17:40:23 -07001114 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001115 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Selim Cinek2a739342016-03-17 10:28:55 -07001116 && mChildrenContainer != null && mChildrenContainer.getChildCount() > 0;
Selim Cinek8fc93c92015-11-23 17:48:07 -08001117 if (mIsSummaryWithChildren) {
Selim Cinek8fc93c92015-11-23 17:48:07 -08001118 if (mNotificationHeader == null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001119 recreateNotificationHeader();
1120 }
Selim Cinek263398f2015-10-21 17:40:23 -07001121 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001122 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -08001123 updateChildrenHeaderAppearance();
Selim Cinekda42d652015-12-04 15:51:16 -08001124 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -07001125 }
1126
Selim Cinek1685e632014-04-08 02:27:49 +02001127 /**
1128 * Check whether the view state is currently expanded. This is given by the system in {@link
1129 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1130 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1131 * view can differ from this state, if layout params are modified from outside.
1132 *
1133 * @return whether the view state is currently expanded.
1134 */
Selim Cinek83bc7832015-10-22 13:26:54 -07001135 public boolean isExpanded() {
Selim Cineke81b82b2016-03-04 11:22:28 -08001136 return isExpanded(false /* allowOnKeyguard */);
1137 }
1138
1139 public boolean isExpanded(boolean allowOnKeyguard) {
1140 return (!mOnKeyguard || allowOnKeyguard)
Selim Cinekb5605e52015-02-20 18:21:41 +01001141 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
1142 || isUserExpanded());
1143 }
1144
1145 private boolean isSystemChildExpanded() {
1146 return mIsSystemChildExpanded;
1147 }
1148
1149 public void setSystemChildExpanded(boolean expanded) {
1150 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +02001151 }
1152
1153 @Override
1154 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1155 super.onLayout(changed, left, top, right, bottom);
Selim Cinek8d490d42015-04-10 00:05:50 -07001156 updateMaxHeights();
Mady Mellora6edc872016-04-26 11:01:03 -07001157 if (mSettingsIconRow != null) {
1158 mSettingsIconRow.updateVerticalLocation();
1159 }
Selim Cinek1685e632014-04-08 02:27:49 +02001160 }
1161
Selim Cinek8d490d42015-04-10 00:05:50 -07001162 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +02001163 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -07001164 View expandedChild = mPrivateLayout.getExpandedChild();
1165 if (expandedChild == null) {
1166 expandedChild = mPrivateLayout.getContractedChild();
1167 }
1168 mMaxExpandHeight = expandedChild.getHeight();
1169 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -07001170 if (headsUpChild == null) {
1171 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -07001172 }
Selim Cinek1f3f5442015-04-10 17:54:46 -07001173 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +02001174 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001175 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +02001176 }
1177 }
1178
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001179 @Override
1180 public void notifyHeightChanged(boolean needsAnimation) {
1181 super.notifyHeightChanged(needsAnimation);
1182 getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
1183 }
1184
Selim Cinek3c76d502016-02-19 15:16:33 -08001185 public void setSensitive(boolean sensitive, boolean hideSensitive) {
Jorim Jaggiae441282014-08-01 02:45:18 +02001186 mSensitive = sensitive;
Selim Cinek3c76d502016-02-19 15:16:33 -08001187 mSensitiveHiddenInGeneral = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +02001188 }
1189
1190 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -07001191 mHideSensitiveForIntrinsicHeight = hideSensitive;
Selim Cineka52f6a12016-02-29 15:35:58 -08001192 if (mIsSummaryWithChildren) {
1193 List<ExpandableNotificationRow> notificationChildren =
1194 mChildrenContainer.getNotificationChildren();
1195 for (int i = 0; i < notificationChildren.size(); i++) {
1196 ExpandableNotificationRow child = notificationChildren.get(i);
1197 child.setHideSensitiveForIntrinsicHeight(hideSensitive);
1198 }
1199 }
Jorim Jaggiae441282014-08-01 02:45:18 +02001200 }
1201
1202 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
1203 long duration) {
1204 boolean oldShowingPublic = mShowingPublic;
1205 mShowingPublic = mSensitive && hideSensitive;
1206 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
1207 return;
1208 }
Dan Sandlera5e0f412014-01-23 15:11:54 -05001209
1210 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +02001211 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -05001212
Jorim Jaggiae441282014-08-01 02:45:18 +02001213 if (!animated) {
1214 mPublicLayout.animate().cancel();
1215 mPrivateLayout.animate().cancel();
1216 mPublicLayout.setAlpha(1f);
1217 mPrivateLayout.setAlpha(1f);
1218 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinekd84a5932015-12-15 11:45:36 -08001219 updateChildrenVisibility();
Jorim Jaggiae441282014-08-01 02:45:18 +02001220 } else {
1221 animateShowingPublic(delay, duration);
1222 }
Selim Cinekc3179332016-03-04 14:44:56 -08001223 NotificationContentView showingLayout = getShowingLayout();
1224 showingLayout.updateBackgroundColor(animated);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001225 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinek757d8792016-01-28 16:21:08 -08001226 updateClearability();
Jorim Jaggiae441282014-08-01 02:45:18 +02001227 mShowingPublicInitialized = true;
1228 }
1229
1230 private void animateShowingPublic(long delay, long duration) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001231 View[] privateViews = mIsSummaryWithChildren ?
1232 new View[] {mChildrenContainer, mNotificationHeader}
1233 : new View[] {mPrivateLayout};
1234 View[] publicViews = new View[] {mPublicLayout};
1235 View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
1236 View[] shownChildren = mShowingPublic ? publicViews : privateViews;
1237 for (final View hiddenView : hiddenChildren) {
1238 hiddenView.setVisibility(View.VISIBLE);
1239 hiddenView.animate().cancel();
1240 hiddenView.animate()
1241 .alpha(0f)
1242 .setStartDelay(delay)
1243 .setDuration(duration)
1244 .withEndAction(new Runnable() {
1245 @Override
1246 public void run() {
1247 hiddenView.setVisibility(View.INVISIBLE);
1248 }
1249 });
1250 }
1251 for (View showView : shownChildren) {
1252 showView.setVisibility(View.VISIBLE);
1253 showView.setAlpha(0f);
1254 showView.animate().cancel();
1255 showView.animate()
1256 .alpha(1f)
1257 .setStartDelay(delay)
1258 .setDuration(duration);
1259 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001260 }
1261
Selim Cinek3776fe02016-02-04 13:32:43 -08001262 public boolean mustStayOnScreen() {
1263 return mIsHeadsUp;
1264 }
1265
Selim Cinek757d8792016-01-28 16:21:08 -08001266 private void updateClearability() {
Dan Sandler0d3e62f2014-07-14 17:13:50 -04001267 // public versions cannot be dismissed
Selim Cinek3c76d502016-02-19 15:16:33 -08001268 mVetoButton.setVisibility(isClearable() && (!mShowingPublic
1269 || !mSensitiveHiddenInGeneral) ? View.VISIBLE : View.GONE);
Dan Sandlera5e0f412014-01-23 15:11:54 -05001270 }
Jorim Jaggi251957d2014-04-09 04:24:09 +02001271
Selim Cinekb5605e52015-02-20 18:21:41 +01001272 public void setChildrenExpanded(boolean expanded, boolean animate) {
1273 mChildrenExpanded = expanded;
Selim Cinek7b836392015-12-04 20:02:59 -08001274 if (mNotificationHeader != null) {
1275 mNotificationHeader.setExpanded(expanded);
1276 }
Selim Cinek83bc7832015-10-22 13:26:54 -07001277 if (mChildrenContainer != null) {
1278 mChildrenContainer.setChildrenExpanded(expanded);
1279 }
Selim Cinekb5605e52015-02-20 18:21:41 +01001280 }
1281
Selim Cinekb5605e52015-02-20 18:21:41 +01001282 public static void applyTint(View v, int color) {
1283 int alpha;
1284 if (color != 0) {
1285 alpha = COLORED_DIVIDER_ALPHA;
1286 } else {
1287 color = 0xff000000;
1288 alpha = DEFAULT_DIVIDER_ALPHA;
1289 }
1290 if (v.getBackground() instanceof ColorDrawable) {
1291 ColorDrawable background = (ColorDrawable) v.getBackground();
1292 background.mutate();
1293 background.setColor(color);
1294 background.setAlpha(alpha);
1295 }
1296 }
1297
Selim Cinek1685e632014-04-08 02:27:49 +02001298 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +01001299 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -04001300 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +02001301
Mady Mellor34958fa2016-02-23 09:52:17 -08001302 public boolean areGutsExposed() {
1303 return (mGuts != null && mGuts.areGutsExposed());
1304 }
1305
Jorim Jaggibe565df2014-04-28 17:51:23 +02001306 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001307 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001308 NotificationContentView showingLayout = getShowingLayout();
1309 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001310 }
1311
1312 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -07001313 protected View getContentView() {
1314 return getShowingLayout();
1315 }
1316
1317 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +02001318 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +01001319 super.setActualHeight(height, notifyListeners);
Mady Mellorb53bc272016-02-11 18:28:23 -08001320 if (mGuts != null && mGuts.areGutsExposed()) {
1321 mGuts.setActualHeight(height);
1322 return;
1323 }
Selim Cinekeef84282015-10-30 16:28:00 -07001324 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +01001325 mPrivateLayout.setContentHeight(contentHeight);
1326 mPublicLayout.setContentHeight(contentHeight);
Selim Cinek42357e02016-02-24 18:48:01 -08001327 if (mIsSummaryWithChildren) {
1328 mChildrenContainer.setActualHeight(height);
1329 }
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001330 if (mGuts != null) {
1331 mGuts.setActualHeight(height);
1332 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001333 }
1334
1335 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +01001336 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -07001337 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001338 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001339 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001340 NotificationContentView showingLayout = getShowingLayout();
1341 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +02001342 }
1343
1344 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001345 public int getMinHeight() {
Selim Cinek31aada42015-12-18 17:51:15 -08001346 if (mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
1347 return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
1348 } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
Selim Cinekb55386d2015-12-16 17:26:49 -08001349 return mChildrenContainer.getMinHeight();
Selim Cinek31aada42015-12-18 17:51:15 -08001350 } else if (mIsHeadsUp) {
1351 return mHeadsUpHeight;
Selim Cinekb55386d2015-12-16 17:26:49 -08001352 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001353 NotificationContentView showingLayout = getShowingLayout();
1354 return showingLayout.getMinHeight();
1355 }
1356
1357 @Override
Selim Cinek567e8452016-03-24 10:54:56 -07001358 public int getCollapsedHeight() {
Selim Cinek2c584612016-02-29 16:14:25 -08001359 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinek567e8452016-03-24 10:54:56 -07001360 return mChildrenContainer.getCollapsedHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -07001361 }
Selim Cinek816c8e42015-11-19 12:00:45 -08001362 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001363 }
1364
1365 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +02001366 public void setClipTopAmount(int clipTopAmount) {
1367 super.setClipTopAmount(clipTopAmount);
1368 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001369 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +02001370 if (mGuts != null) {
1371 mGuts.setClipTopAmount(clipTopAmount);
1372 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001373 }
1374
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001375 private void recreateNotificationHeader() {
1376 final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
1377 getStatusBarNotification().getNotification());
1378 final RemoteViews header = builder.makeNotificationHeader();
1379 if (mNotificationHeader == null) {
1380 mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
1381 final View expandButton = mNotificationHeader.findViewById(
1382 com.android.internal.R.id.expand_button);
1383 expandButton.setVisibility(VISIBLE);
1384 mNotificationHeader.setOnClickListener(mExpandClickListener);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001385 mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
Selim Cinek7d1c63e2016-04-21 15:26:10 -07001386 mNotificationHeader, this);
Selim Cinekb5a83612015-12-11 14:14:39 -08001387 addView(mNotificationHeader, indexOfChild(mChildrenContainer) + 1);
Mady Mellor4b80b102016-01-22 08:03:58 -08001388 mTranslateableViews.add(mNotificationHeader);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001389 } else {
1390 header.reapply(getContext(), mNotificationHeader);
Selim Cinek4ffd6362015-12-29 15:12:23 +01001391 mNotificationHeaderWrapper.notifyContentUpdated(mEntry.notification);
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001392 }
Selim Cinekea4bef72015-12-02 15:51:10 -08001393 updateChildrenHeaderAppearance();
Selim Cinek343e6e22014-04-11 21:23:30 +02001394 }
Selim Cinek7d447722014-06-10 15:51:59 +02001395
Selim Cinekea4bef72015-12-02 15:51:10 -08001396 public void updateChildrenHeaderAppearance() {
1397 if (mIsSummaryWithChildren) {
1398 mHeaderUtil.updateChildrenHeaderAppearance();
1399 }
1400 }
1401
Selim Cinek31094df2014-08-14 19:28:15 +02001402 public boolean isMaxExpandHeightInitialized() {
1403 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001404 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001405
Selim Cinek42357e02016-02-24 18:48:01 -08001406 public NotificationContentView getShowingLayout() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001407 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1408 }
Chris Wren78403d72014-07-28 10:23:24 +01001409
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001410 @Override
1411 public void setShowingLegacyBackground(boolean showing) {
1412 super.setShowingLegacyBackground(showing);
1413 mPrivateLayout.setShowingLegacyBackground(showing);
1414 mPublicLayout.setShowingLegacyBackground(showing);
1415 }
1416
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001417 @Override
1418 protected void updateBackgroundTint() {
1419 super.updateBackgroundTint();
1420 updateNoBackgroundState();
1421 if (mIsSummaryWithChildren) {
1422 List<ExpandableNotificationRow> notificationChildren =
1423 mChildrenContainer.getNotificationChildren();
1424 for (int i = 0; i < notificationChildren.size(); i++) {
1425 ExpandableNotificationRow child = notificationChildren.get(i);
1426 child.updateNoBackgroundState();
1427 }
1428 }
1429 }
1430
1431 private void updateNoBackgroundState() {
1432 mShowNoBackground = isChildInGroup() && hasSameBgColor(mNotificationParent);
1433 updateBackground();
1434 }
1435
Chris Wren78403d72014-07-28 10:23:24 +01001436 public void setExpansionLogger(ExpansionLogger logger, String key) {
1437 mLogger = logger;
1438 mLoggingKey = key;
1439 }
1440
Selim Cinek6183d122016-01-14 18:48:41 -08001441 @Override
Selim Cinek42357e02016-02-24 18:48:01 -08001442 public float getIncreasedPaddingAmount() {
1443 if (mIsSummaryWithChildren) {
1444 if (isGroupExpanded()) {
1445 return 1.0f;
1446 } else if (isUserLocked()) {
Selim Cinekf07d0622016-03-21 19:52:52 -07001447 return mChildrenContainer.getGroupExpandFraction();
Selim Cinek42357e02016-02-24 18:48:01 -08001448 }
1449 }
1450 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -08001451 }
1452
1453 @Override
Selim Cinek6183d122016-01-14 18:48:41 -08001454 protected boolean disallowSingleClick(MotionEvent event) {
1455 float x = event.getX();
1456 float y = event.getY();
Selim Cinek34eda5e2016-02-18 17:10:43 -08001457 NotificationHeaderView header = getVisibleNotificationHeader();
Selim Cinek6183d122016-01-14 18:48:41 -08001458 if (header != null) {
Mady Mellora8833512016-03-09 09:50:18 -08001459 return header.isInTouchRect(x - getTranslation(), y);
Selim Cinek6183d122016-01-14 18:48:41 -08001460 }
1461 return super.disallowSingleClick(event);
1462 }
1463
Chris Wren78403d72014-07-28 10:23:24 +01001464 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
1465 final boolean nowExpanded = isExpanded();
1466 if (wasExpanded != nowExpanded && mLogger != null) {
1467 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1468 }
1469 }
Selim Cinek570981d2015-12-01 11:37:01 -08001470
1471 public interface OnExpandClickListener {
Selim Cinek31aada42015-12-18 17:51:15 -08001472 void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
Selim Cinek570981d2015-12-01 11:37:01 -08001473 }
Chris Wren51c75102013-07-16 20:49:17 -04001474}