blob: 4ea3a9747bad949f8188b40e7904e9fb2a2b81bd [file] [log] [blame]
Chris Wren51c75102013-07-16 20:49:17 -04001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar;
18
Selim Cineka6c6bfb2015-10-29 16:27:08 -070019import android.app.Notification;
Chris Wren51c75102013-07-16 20:49:17 -040020import android.content.Context;
Selim Cinekcab4a602014-09-03 14:47:57 +020021import android.graphics.drawable.AnimatedVectorDrawable;
22import android.graphics.drawable.AnimationDrawable;
Selim Cinekb5605e52015-02-20 18:21:41 +010023import android.graphics.drawable.ColorDrawable;
Selim Cinekcab4a602014-09-03 14:47:57 +020024import android.graphics.drawable.Drawable;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020025import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040026import android.util.AttributeSet;
Selim Cinek1a521f32014-11-03 17:39:29 +010027import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080028import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050029import android.view.View;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020030import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020031import android.view.accessibility.AccessibilityEvent;
Selim Cinekb5605e52015-02-20 18:21:41 +010032import android.view.animation.LinearInterpolator;
Selim Cinek98713a42015-09-21 15:47:20 +020033import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020034import android.widget.ImageView;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080035import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010036
Dan Sandlera5e0f412014-01-23 15:11:54 -050037import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070038import com.android.systemui.classifier.FalsingManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010039import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010040import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
41import com.android.systemui.statusbar.stack.StackScrollState;
42import com.android.systemui.statusbar.stack.StackStateAnimator;
43import com.android.systemui.statusbar.stack.StackViewState;
44
45import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050046
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020047public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010048
49 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
50 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
51 private final LinearInterpolator mLinearInterpolator = new LinearInterpolator();
Selim Cinek1685e632014-04-08 02:27:49 +020052 private int mRowMinHeight;
Chris Wren51c75102013-07-16 20:49:17 -040053
Selim Cinek1685e632014-04-08 02:27:49 +020054 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040055 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020056 /** Has the user actively changed the expansion state of this row */
57 private boolean mHasUserChangedExpansion;
58 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040059 private boolean mUserExpanded;
Selim Cinek1685e632014-04-08 02:27:49 +020060 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040061 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020062 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050063 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020064 private boolean mSensitive;
65 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -070066 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -040067
Selim Cinek1685e632014-04-08 02:27:49 +020068 /**
69 * Is this notification expanded by the system. The expansion state can be overridden by the
70 * user expansion.
71 */
72 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020073
74 /**
Selim Cinek83bc7832015-10-22 13:26:54 -070075 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020076 */
Selim Cinek83bc7832015-10-22 13:26:54 -070077 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020078
Jorim Jaggibe565df2014-04-28 17:51:23 +020079 private NotificationContentView mPublicLayout;
80 private NotificationContentView mPrivateLayout;
Selim Cinek1685e632014-04-08 02:27:49 +020081 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -070082 private int mHeadsUpHeight;
Selim Cinek863834b2014-05-20 04:20:25 +020083 private View mVetoButton;
Dan Sandler0d3e62f2014-07-14 17:13:50 -040084 private boolean mClearable;
Chris Wren78403d72014-07-28 10:23:24 +010085 private ExpansionLogger mLogger;
86 private String mLoggingKey;
Selim Cineka5e211b2014-08-11 17:35:48 +020087 private boolean mWasReset;
Selim Cinek8d490d42015-04-10 00:05:50 -070088 private NotificationGuts mGuts;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020089 private StatusBarNotification mStatusBarNotification;
Selim Cinek1a521f32014-11-03 17:39:29 +010090 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +020091 private boolean mLastChronometerRunning = true;
Selim Cinekeef84282015-10-30 16:28:00 -070092 private NotificationHeaderView mNotificationHeader;
Selim Cinekb5605e52015-02-20 18:21:41 +010093 private ViewStub mChildrenContainerStub;
94 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010095 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -070096 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +010097 private NotificationChildrenContainer mChildrenContainer;
Selim Cinekab29aeb2015-02-20 18:18:32 +010098 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +010099 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700100 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700101 private FalsingManager mFalsingManager;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200102
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700103 private boolean mJustClicked;
Selim Cinek34d93b02015-10-22 12:30:38 -0700104 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700105 private ExpandableNotificationRow mNotificationParent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800106 private OnClickListener mExpandClickListener = new OnClickListener() {
107 @Override
108 public void onClick(View v) {
109 if (mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
110 mGroupManager.toggleGroupExpansion(mStatusBarNotification);
111 } else {
112 setUserExpanded(!isExpanded());
113 notifyHeightChanged(true);
114 }
115 }
116 };
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700117
Selim Cinek8d490d42015-04-10 00:05:50 -0700118 public NotificationContentView getPrivateLayout() {
119 return mPrivateLayout;
120 }
121
122 public NotificationContentView getPublicLayout() {
123 return mPublicLayout;
124 }
125
Selim Cinekcab4a602014-09-03 14:47:57 +0200126 public void setIconAnimationRunning(boolean running) {
127 setIconAnimationRunning(running, mPublicLayout);
128 setIconAnimationRunning(running, mPrivateLayout);
129 }
130
131 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
132 if (layout != null) {
133 View contractedChild = layout.getContractedChild();
134 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700135 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200136 setIconAnimationRunningForChild(running, contractedChild);
137 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700138 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200139 }
140 }
141
142 private void setIconAnimationRunningForChild(boolean running, View child) {
143 if (child != null) {
144 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
145 setIconRunning(icon, running);
146 ImageView rightIcon = (ImageView) child.findViewById(
147 com.android.internal.R.id.right_icon);
148 setIconRunning(rightIcon, running);
149 }
150 }
151
152 private void setIconRunning(ImageView imageView, boolean running) {
153 if (imageView != null) {
154 Drawable drawable = imageView.getDrawable();
155 if (drawable instanceof AnimationDrawable) {
156 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
157 if (running) {
158 animationDrawable.start();
159 } else {
160 animationDrawable.stop();
161 }
162 } else if (drawable instanceof AnimatedVectorDrawable) {
163 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
164 if (running) {
165 animationDrawable.start();
166 } else {
167 animationDrawable.stop();
168 }
169 }
170 }
171 }
172
Selim Cinek8fc93c92015-11-23 17:48:07 -0800173 public void updateStatusBarNotification(StatusBarNotification statusBarNotification) {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200174 mStatusBarNotification = statusBarNotification;
Selim Cinek8fc93c92015-11-23 17:48:07 -0800175 mPrivateLayout.onNotificationUpdated(statusBarNotification);
176 mPublicLayout.onNotificationUpdated(statusBarNotification);
Selim Cineka37774f2014-11-11 19:16:18 +0100177 updateVetoButton();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800178 if (mIsSummaryWithChildren) {
179 recreateNotificationHeader();
180 }
Selim Cinek263398f2015-10-21 17:40:23 -0700181 onChildrenCountChanged();
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200182 }
183
184 public StatusBarNotification getStatusBarNotification() {
185 return mStatusBarNotification;
186 }
187
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700188 public boolean isHeadsUp() {
189 return mIsHeadsUp;
190 }
191
Selim Cinek1a521f32014-11-03 17:39:29 +0100192 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700193 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100194 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700195 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekc80fdb12015-04-13 15:09:08 -0700196 if (intrinsicBefore != getIntrinsicHeight()) {
197 notifyHeightChanged(false /* needsAnimation */);
198 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100199 }
200
Selim Cinekb5605e52015-02-20 18:21:41 +0100201 public void setGroupManager(NotificationGroupManager groupManager) {
202 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700203 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100204 }
205
206 public void addChildNotification(ExpandableNotificationRow row) {
207 addChildNotification(row, -1);
208 }
209
210 /**
211 * Add a child notification to this view.
212 *
213 * @param row the row to add
214 * @param childIndex the index to add it at, if -1 it will be added at the end
215 */
216 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
217 if (mChildrenContainer == null) {
218 mChildrenContainerStub.inflate();
219 }
220 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700221 onChildrenCountChanged();
222 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100223 }
224
225 public void removeChildNotification(ExpandableNotificationRow row) {
226 if (mChildrenContainer != null) {
227 mChildrenContainer.removeNotification(row);
228 }
Selim Cinek263398f2015-10-21 17:40:23 -0700229 onChildrenCountChanged();
230 row.setIsChildInGroup(false, null);
231 }
232
233 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700234 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700235 }
236
Selim Cinek388df6d2015-10-22 13:25:11 -0700237 public ExpandableNotificationRow getNotificationParent() {
238 return mNotificationParent;
239 }
240
Selim Cinek263398f2015-10-21 17:40:23 -0700241 /**
242 * @param isChildInGroup Is this notification now in a group
243 * @param parent the new parent notification
244 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700245 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
246 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
247 mNotificationParent = childInGroup ? parent : null;
248 mPrivateLayout.setIsChildInGroup(childInGroup);
249 updateNoBackgroundState();
Selim Cinek34d93b02015-10-22 12:30:38 -0700250 }
251
252 @Override
253 protected boolean shouldHideBackground() {
254 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700255 }
256
257 @Override
258 public boolean isSummaryWithChildren() {
259 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100260 }
261
262 @Override
263 public boolean areChildrenExpanded() {
264 return mChildrenExpanded;
265 }
266
267 public List<ExpandableNotificationRow> getNotificationChildren() {
268 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
269 }
270
Selim Cinekeef84282015-10-30 16:28:00 -0700271 public int getNumberOfNotificationChildren() {
272 if (mChildrenContainer == null) {
273 return 0;
274 }
275 return mChildrenContainer.getNotificationChildren().size();
276 }
277
Selim Cinekb5605e52015-02-20 18:21:41 +0100278 /**
279 * Apply the order given in the list to the children.
280 *
281 * @param childOrder the new list order
282 * @return whether the list order has changed
283 */
284 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
285 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
286 }
287
288 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700289 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100290 StackViewState parentState = resultState.getViewStateForView(this);
291 mChildrenContainer.getState(resultState, parentState);
292 }
293 }
294
295 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700296 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100297 mChildrenContainer.applyState(state);
298 }
299 }
300
301 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700302 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100303 mChildrenContainer.prepareExpansionChanged(state);
304 }
305 }
306
307 public void startChildAnimation(StackScrollState finalState,
308 StackStateAnimator stateAnimator, boolean withDelays, long delay, long duration) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700309 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100310 mChildrenContainer.startAnimationToState(finalState, stateAnimator, withDelays, delay,
311 duration);
312 }
313 }
314
315 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700316 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100317 return this;
318 } else {
319 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
320 return view == null ? this : view;
321 }
322 }
323
Selim Cinekab29aeb2015-02-20 18:18:32 +0100324 public NotificationGuts getGuts() {
325 return mGuts;
326 }
327
Selim Cinek684a4422015-04-15 16:18:39 -0700328 /**
329 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
330 * the notification will be rendered on top of the screen.
331 *
332 * @param pinned whether it is pinned
333 */
334 public void setPinned(boolean pinned) {
335 mIsPinned = pinned;
Selim Cinek98713a42015-09-21 15:47:20 +0200336 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700337 }
338
Selim Cinek684a4422015-04-15 16:18:39 -0700339 public boolean isPinned() {
340 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700341 }
342
343 public int getHeadsUpHeight() {
Selim Cinek8d490d42015-04-10 00:05:50 -0700344 return mHeadsUpHeight;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700345 }
346
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700347 /**
348 * Mark whether this notification was just clicked, i.e. the user has just clicked this
349 * notification in this frame.
350 */
351 public void setJustClicked(boolean justClicked) {
352 mJustClicked = justClicked;
353 }
354
355 /**
356 * @return true if this notification has been clicked in this frame, false otherwise
357 */
358 public boolean wasJustClicked() {
359 return mJustClicked;
360 }
361
Selim Cinek98713a42015-09-21 15:47:20 +0200362 public void setChronometerRunning(boolean running) {
363 mLastChronometerRunning = running;
364 setChronometerRunning(running, mPrivateLayout);
365 setChronometerRunning(running, mPublicLayout);
366 if (mChildrenContainer != null) {
367 List<ExpandableNotificationRow> notificationChildren =
368 mChildrenContainer.getNotificationChildren();
369 for (int i = 0; i < notificationChildren.size(); i++) {
370 ExpandableNotificationRow child = notificationChildren.get(i);
371 child.setChronometerRunning(running);
372 }
373 }
374 }
375
376 private void setChronometerRunning(boolean running, NotificationContentView layout) {
377 if (layout != null) {
378 running = running || isPinned();
379 View contractedChild = layout.getContractedChild();
380 View expandedChild = layout.getExpandedChild();
381 View headsUpChild = layout.getHeadsUpChild();
382 setChronometerRunningForChild(running, contractedChild);
383 setChronometerRunningForChild(running, expandedChild);
384 setChronometerRunningForChild(running, headsUpChild);
385 }
386 }
387
388 private void setChronometerRunningForChild(boolean running, View child) {
389 if (child != null) {
390 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
391 if (chronometer instanceof Chronometer) {
392 ((Chronometer) chronometer).setStarted(running);
393 }
394 }
395 }
396
Selim Cinek8d6440d2015-10-22 13:00:05 -0700397 public CharSequence getSubText() {
398 Notification notification = mStatusBarNotification.getNotification();
399 CharSequence subText = notification.extras.getCharSequence(Notification.EXTRA_SUMMARY_TEXT);
400 if (subText == null) {
401 subText = notification.extras.getCharSequence(Notification.EXTRA_SUB_TEXT);
402 }
403 return subText;
404 }
405
406 public void setContentSubTextVisible(boolean visible) {
407 mPrivateLayout.setSubTextVisible(visible);
408 }
409
Chris Wren78403d72014-07-28 10:23:24 +0100410 public interface ExpansionLogger {
411 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
412 }
Selim Cinek1685e632014-04-08 02:27:49 +0200413
Chris Wren51c75102013-07-16 20:49:17 -0400414 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
415 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700416 mFalsingManager = FalsingManager.getInstance(context);
Chris Wren51c75102013-07-16 20:49:17 -0400417 }
418
Christoph Studera7fe6312014-06-27 19:32:44 +0200419 /**
420 * Resets this view so it can be re-used for an updated notification.
421 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200422 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200423 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200424 super.reset();
Christoph Studera7fe6312014-06-27 19:32:44 +0200425 mRowMinHeight = 0;
Chris Wren78403d72014-07-28 10:23:24 +0100426 final boolean wasExpanded = isExpanded();
Selim Cinek379ff8f2015-02-20 17:03:16 +0100427 mMaxViewHeight = 0;
Christoph Studera7fe6312014-06-27 19:32:44 +0200428 mExpandable = false;
429 mHasUserChangedExpansion = false;
430 mUserLocked = false;
431 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200432 mSensitive = false;
433 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200434 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700435 mOnKeyguard = false;
Selim Cinek1a521f32014-11-03 17:39:29 +0100436 mPublicLayout.reset(mIsHeadsUp);
437 mPrivateLayout.reset(mIsHeadsUp);
Selim Cinek31094df2014-08-14 19:28:15 +0200438 resetHeight();
439 logExpansionEvent(false, wasExpanded);
440 }
441
442 public void resetHeight() {
Selim Cinek1a521f32014-11-03 17:39:29 +0100443 if (mIsHeadsUp) {
444 resetActualHeight();
445 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200446 mMaxExpandHeight = 0;
Selim Cinek8d490d42015-04-10 00:05:50 -0700447 mHeadsUpHeight = 0;
Selim Cineka5e211b2014-08-11 17:35:48 +0200448 mWasReset = true;
Selim Cinek31094df2014-08-14 19:28:15 +0200449 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200450 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200451 }
452
Jorim Jaggi251957d2014-04-09 04:24:09 +0200453 @Override
Selim Cinek1a521f32014-11-03 17:39:29 +0100454 protected boolean filterMotionEvent(MotionEvent event) {
455 return mIsHeadsUp || super.filterMotionEvent(event);
456 }
457
458 @Override
Jorim Jaggi251957d2014-04-09 04:24:09 +0200459 protected void onFinishInflate() {
460 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200461 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
462 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800463 mPrivateLayout.setExpandClickListener(mExpandClickListener);
464 mPublicLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekab29aeb2015-02-20 18:18:32 +0100465 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
466 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200467 @Override
468 public void onInflate(ViewStub stub, View inflated) {
469 mGuts = (NotificationGuts) inflated;
470 mGuts.setClipTopAmount(getClipTopAmount());
471 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100472 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200473 }
474 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100475 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
476 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
477
478 @Override
479 public void onInflate(ViewStub stub, View inflated) {
480 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -0700481 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100482 }
483 });
Selim Cinek863834b2014-05-20 04:20:25 +0200484 mVetoButton = findViewById(R.id.veto);
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200485 }
486
Selim Cinekab29aeb2015-02-20 18:18:32 +0100487 public void inflateGuts() {
488 if (mGuts == null) {
489 mGutsStub.inflate();
490 }
491 }
492
Selim Cinekb5605e52015-02-20 18:21:41 +0100493 private void updateChildrenVisibility(boolean animated) {
494 if (mChildrenContainer == null) {
495 return;
496 }
Selim Cinekeef84282015-10-30 16:28:00 -0700497 mChildrenContainer.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800498 mNotificationHeader.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekeef84282015-10-30 16:28:00 -0700499 mPrivateLayout.setVisibility(!mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekb5605e52015-02-20 18:21:41 +0100500 }
501
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200502 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800503 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
504 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200505 // Add a record for the entire layout since its content is somehow small.
506 // The event comes from a leaf view that is interacted with.
507 AccessibilityEvent record = AccessibilityEvent.obtain();
508 onInitializeAccessibilityEvent(record);
509 dispatchPopulateAccessibilityEvent(record);
510 event.appendRecord(record);
511 return true;
512 }
513 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200514 }
Chris Wren51c75102013-07-16 20:49:17 -0400515
John Spurlocke15452b2014-08-21 09:44:39 -0400516 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100517 public void setDark(boolean dark, boolean fade, long delay) {
518 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400519 final NotificationContentView showing = getShowingLayout();
520 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100521 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400522 }
523 }
524
Selim Cinek1685e632014-04-08 02:27:49 +0200525 public void setHeightRange(int rowMinHeight, int rowMaxHeight) {
526 mRowMinHeight = rowMinHeight;
Selim Cinek379ff8f2015-02-20 17:03:16 +0100527 mMaxViewHeight = rowMaxHeight;
Selim Cinek816c8e42015-11-19 12:00:45 -0800528 mPrivateLayout.setSmallHeight(mRowMinHeight);
529 mPublicLayout.setSmallHeight(mRowMinHeight);
Chris Wren51c75102013-07-16 20:49:17 -0400530 }
531
532 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -0700533 if (mIsSummaryWithChildren && !mShowingPublic) {
534 return !mChildrenExpanded;
535 }
Chris Wren51c75102013-07-16 20:49:17 -0400536 return mExpandable;
537 }
538
539 public void setExpandable(boolean expandable) {
540 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800541 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -0400542 }
543
Selim Cinek1685e632014-04-08 02:27:49 +0200544 /**
545 * @return whether the user has changed the expansion state
546 */
547 public boolean hasUserChangedExpansion() {
548 return mHasUserChangedExpansion;
549 }
550
Chris Wren51c75102013-07-16 20:49:17 -0400551 public boolean isUserExpanded() {
552 return mUserExpanded;
553 }
554
Selim Cinek1685e632014-04-08 02:27:49 +0200555 /**
556 * Set this notification to be expanded by the user
557 *
558 * @param userExpanded whether the user wants this notification to be expanded
559 */
Chris Wren51c75102013-07-16 20:49:17 -0400560 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -0700561 setUserExpanded(userExpanded, false /* allowChildExpansion */);
562 }
563
564 /**
565 * Set this notification to be expanded by the user
566 *
567 * @param userExpanded whether the user wants this notification to be expanded
568 * @param allowChildExpansion whether a call to this method allows expanding children
569 */
570 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700571 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -0700572 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
573 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
574 return;
575 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200576 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +0100577 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +0200578 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -0400579 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +0100580 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -0400581 }
582
Selim Cinekccd14fb2014-08-12 18:53:24 +0200583 public void resetUserExpansion() {
584 mHasUserChangedExpansion = false;
585 mUserExpanded = false;
586 }
587
Chris Wren51c75102013-07-16 20:49:17 -0400588 public boolean isUserLocked() {
589 return mUserLocked;
590 }
591
592 public void setUserLocked(boolean userLocked) {
593 mUserLocked = userLocked;
594 }
595
Selim Cinek1685e632014-04-08 02:27:49 +0200596 /**
597 * @return has the system set this notification to be expanded
598 */
599 public boolean isSystemExpanded() {
600 return mIsSystemExpanded;
601 }
602
603 /**
604 * Set this notification to be expanded by the system.
605 *
606 * @param expand whether the system wants this notification to be expanded.
607 */
608 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +0200609 if (expand != mIsSystemExpanded) {
610 final boolean wasExpanded = isExpanded();
611 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +0100612 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +0200613 logExpansionEvent(false, wasExpanded);
Selim Cinek83bc7832015-10-22 13:26:54 -0700614 if (mChildrenContainer != null) {
615 mChildrenContainer.updateGroupOverflow();
616 }
Selim Cinek31094df2014-08-14 19:28:15 +0200617 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200618 }
619
620 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700621 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200622 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700623 public void setOnKeyguard(boolean onKeyguard) {
624 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +0200625 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -0700626 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +0200627 logExpansionEvent(false, wasExpanded);
628 if (wasExpanded != isExpanded()) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100629 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +0200630 }
631 }
Selim Cinek1685e632014-04-08 02:27:49 +0200632 }
633
634 /**
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400635 * @return Can the underlying notification be cleared?
636 */
637 public boolean isClearable() {
Selim Cineka37774f2014-11-11 19:16:18 +0100638 return mStatusBarNotification != null && mStatusBarNotification.isClearable();
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400639 }
640
641 /**
Selim Cinek1685e632014-04-08 02:27:49 +0200642 * Apply an expansion state to the layout.
Selim Cinek1685e632014-04-08 02:27:49 +0200643 */
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200644 public void applyExpansionToLayout() {
645 boolean expand = isExpanded();
Chris Wren51c75102013-07-16 20:49:17 -0400646 if (expand && mExpandable) {
Selim Cinekeef84282015-10-30 16:28:00 -0700647 setActualHeight(mMaxExpandHeight);
Chris Wren51c75102013-07-16 20:49:17 -0400648 } else {
Selim Cinekeef84282015-10-30 16:28:00 -0700649 setActualHeight(mRowMinHeight);
Chris Wren51c75102013-07-16 20:49:17 -0400650 }
Chris Wren51c75102013-07-16 20:49:17 -0400651 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500652
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200653 @Override
654 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +0200655 if (isUserLocked()) {
656 return getActualHeight();
657 }
Selim Cinek1685e632014-04-08 02:27:49 +0200658 boolean inExpansionState = isExpanded();
Selim Cinek60122be2015-04-15 18:16:50 -0700659 if (mSensitive && mHideSensitiveForIntrinsicHeight) {
660 return mRowMinHeight;
Selim Cinek83bc7832015-10-22 13:26:54 -0700661 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800662 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek60122be2015-04-15 18:16:50 -0700663 } else if (mIsHeadsUp) {
Selim Cinek8d490d42015-04-10 00:05:50 -0700664 if (inExpansionState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700665 return Math.max(mMaxExpandHeight, mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -0700666 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -0700667 return Math.max(mRowMinHeight, mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -0700668 }
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700669 } else if (!inExpansionState || (isChildInGroup() && !isGroupExpanded())) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700670 return getMinHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +0100671 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -0700672 return getMaxExpandHeight();
Selim Cinek1685e632014-04-08 02:27:49 +0200673 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100674 }
Selim Cinek1685e632014-04-08 02:27:49 +0200675
Selim Cinekeef84282015-10-30 16:28:00 -0700676 private boolean isGroupExpanded() {
677 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +0100678 }
679
Selim Cinekeef84282015-10-30 16:28:00 -0700680 /**
681 * @return whether this view has a header on the top of the content
682 */
683 private boolean hasNotificationHeader() {
684 return mIsSummaryWithChildren;
Selim Cinek1685e632014-04-08 02:27:49 +0200685 }
686
Selim Cinek263398f2015-10-21 17:40:23 -0700687 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -0800688 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Selim Cinek263398f2015-10-21 17:40:23 -0700689 && mGroupManager.hasGroupChildren(mStatusBarNotification);
Selim Cinek8fc93c92015-11-23 17:48:07 -0800690 if (mIsSummaryWithChildren) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800691 if (mChildrenContainer == null) {
692 mChildrenContainerStub.inflate();
693 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800694 if (mNotificationHeader == null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800695 recreateNotificationHeader();
696 }
Selim Cinek263398f2015-10-21 17:40:23 -0700697 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800698 mPrivateLayout.updateExpandButtons(isExpandable());
699 updateHeaderChildCount();
Selim Cinek263398f2015-10-21 17:40:23 -0700700 updateChildrenVisibility(true);
701 }
702
Selim Cinek1685e632014-04-08 02:27:49 +0200703 /**
704 * Check whether the view state is currently expanded. This is given by the system in {@link
705 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
706 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
707 * view can differ from this state, if layout params are modified from outside.
708 *
709 * @return whether the view state is currently expanded.
710 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700711 public boolean isExpanded() {
712 return !mOnKeyguard
Selim Cinekb5605e52015-02-20 18:21:41 +0100713 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
714 || isUserExpanded());
715 }
716
717 private boolean isSystemChildExpanded() {
718 return mIsSystemChildExpanded;
719 }
720
721 public void setSystemChildExpanded(boolean expanded) {
722 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +0200723 }
724
725 @Override
726 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
727 super.onLayout(changed, left, top, right, bottom);
Selim Cineka5e211b2014-08-11 17:35:48 +0200728 boolean updateExpandHeight = mMaxExpandHeight == 0 && !mWasReset;
Selim Cinek8d490d42015-04-10 00:05:50 -0700729 updateMaxHeights();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200730 if (updateExpandHeight) {
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200731 applyExpansionToLayout();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200732 }
Selim Cineka5e211b2014-08-11 17:35:48 +0200733 mWasReset = false;
Selim Cinek1685e632014-04-08 02:27:49 +0200734 }
735
Selim Cinek8d490d42015-04-10 00:05:50 -0700736 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +0200737 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -0700738 View expandedChild = mPrivateLayout.getExpandedChild();
739 if (expandedChild == null) {
740 expandedChild = mPrivateLayout.getContractedChild();
741 }
742 mMaxExpandHeight = expandedChild.getHeight();
743 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -0700744 if (headsUpChild == null) {
745 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700746 }
Selim Cinek1f3f5442015-04-10 17:54:46 -0700747 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +0200748 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100749 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +0200750 }
751 }
752
Jorim Jaggiae441282014-08-01 02:45:18 +0200753 public void setSensitive(boolean sensitive) {
754 mSensitive = sensitive;
755 }
756
757 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -0700758 mHideSensitiveForIntrinsicHeight = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +0200759 }
760
761 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
762 long duration) {
763 boolean oldShowingPublic = mShowingPublic;
764 mShowingPublic = mSensitive && hideSensitive;
765 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
766 return;
767 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500768
769 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +0200770 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500771
Jorim Jaggiae441282014-08-01 02:45:18 +0200772 if (!animated) {
773 mPublicLayout.animate().cancel();
774 mPrivateLayout.animate().cancel();
775 mPublicLayout.setAlpha(1f);
776 mPrivateLayout.setAlpha(1f);
777 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinek263398f2015-10-21 17:40:23 -0700778 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? View.VISIBLE
779 : View.INVISIBLE);
Jorim Jaggiae441282014-08-01 02:45:18 +0200780 } else {
781 animateShowingPublic(delay, duration);
782 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400783
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800784 mPrivateLayout.updateExpandButtons(isExpandable());
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400785 updateVetoButton();
Jorim Jaggiae441282014-08-01 02:45:18 +0200786 mShowingPublicInitialized = true;
787 }
788
789 private void animateShowingPublic(long delay, long duration) {
790 final View source = mShowingPublic ? mPrivateLayout : mPublicLayout;
791 View target = mShowingPublic ? mPublicLayout : mPrivateLayout;
792 source.setVisibility(View.VISIBLE);
793 target.setVisibility(View.VISIBLE);
794 target.setAlpha(0f);
795 source.animate().cancel();
796 target.animate().cancel();
797 source.animate()
798 .alpha(0f)
Jorim Jaggiae441282014-08-01 02:45:18 +0200799 .setStartDelay(delay)
800 .setDuration(duration)
801 .withEndAction(new Runnable() {
802 @Override
803 public void run() {
804 source.setVisibility(View.INVISIBLE);
805 }
806 });
807 target.animate()
808 .alpha(1f)
Jorim Jaggiae441282014-08-01 02:45:18 +0200809 .setStartDelay(delay)
810 .setDuration(duration);
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400811 }
812
813 private void updateVetoButton() {
814 // public versions cannot be dismissed
815 mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE);
Dan Sandlera5e0f412014-01-23 15:11:54 -0500816 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200817
Selim Cinekb5605e52015-02-20 18:21:41 +0100818 public void setChildrenExpanded(boolean expanded, boolean animate) {
819 mChildrenExpanded = expanded;
Selim Cinek83bc7832015-10-22 13:26:54 -0700820 if (mChildrenContainer != null) {
821 mChildrenContainer.setChildrenExpanded(expanded);
822 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100823 }
824
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800825 public void updateHeaderChildCount() {
826 if (mIsSummaryWithChildren) {
827 mNotificationHeader.setChildCount(
828 mChildrenContainer.getNotificationChildren().size());
Selim Cinekb5605e52015-02-20 18:21:41 +0100829 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100830 }
831
832 public static void applyTint(View v, int color) {
833 int alpha;
834 if (color != 0) {
835 alpha = COLORED_DIVIDER_ALPHA;
836 } else {
837 color = 0xff000000;
838 alpha = DEFAULT_DIVIDER_ALPHA;
839 }
840 if (v.getBackground() instanceof ColorDrawable) {
841 ColorDrawable background = (ColorDrawable) v.getBackground();
842 background.mutate();
843 background.setColor(color);
844 background.setAlpha(alpha);
845 }
846 }
847
Selim Cinek1685e632014-04-08 02:27:49 +0200848 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +0100849 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400850 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +0200851
Jorim Jaggibe565df2014-04-28 17:51:23 +0200852 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200853 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200854 NotificationContentView showingLayout = getShowingLayout();
855 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200856 }
857
858 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -0700859 protected View getContentView() {
860 return getShowingLayout();
861 }
862
863 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200864 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100865 super.setActualHeight(height, notifyListeners);
Selim Cinekeef84282015-10-30 16:28:00 -0700866 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +0100867 mPrivateLayout.setContentHeight(contentHeight);
868 mPublicLayout.setContentHeight(contentHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200869 if (mGuts != null) {
870 mGuts.setActualHeight(height);
871 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200872 invalidate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200873 }
874
875 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +0100876 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700877 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800878 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700879 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200880 NotificationContentView showingLayout = getShowingLayout();
881 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200882 }
883
884 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200885 public int getMinHeight() {
Selim Cinek816c8e42015-11-19 12:00:45 -0800886 NotificationContentView showingLayout = getShowingLayout();
887 return showingLayout.getMinHeight();
888 }
889
890 @Override
891 public int getMinExpandHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700892 if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800893 return mChildrenContainer.getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700894 }
Selim Cinek816c8e42015-11-19 12:00:45 -0800895 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200896 }
897
898 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700899 protected boolean shouldLimitViewHeight() {
900 return !mIsSummaryWithChildren;
901 }
902
903 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +0200904 public void setClipTopAmount(int clipTopAmount) {
905 super.setClipTopAmount(clipTopAmount);
906 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200907 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200908 if (mGuts != null) {
909 mGuts.setClipTopAmount(clipTopAmount);
910 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200911 }
912
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800913 private void recreateNotificationHeader() {
914 final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
915 getStatusBarNotification().getNotification());
916 final RemoteViews header = builder.makeNotificationHeader();
917 if (mNotificationHeader == null) {
918 mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
919 final View expandButton = mNotificationHeader.findViewById(
920 com.android.internal.R.id.expand_button);
921 expandButton.setVisibility(VISIBLE);
922 mNotificationHeader.setOnClickListener(mExpandClickListener);
923 addView(mNotificationHeader);
924 } else {
925 header.reapply(getContext(), mNotificationHeader);
926 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800927 updateHeaderChildCount();
Selim Cinek343e6e22014-04-11 21:23:30 +0200928 }
Selim Cinek7d447722014-06-10 15:51:59 +0200929
Selim Cinek31094df2014-08-14 19:28:15 +0200930 public boolean isMaxExpandHeightInitialized() {
931 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +0200932 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200933
934 private NotificationContentView getShowingLayout() {
935 return mShowingPublic ? mPublicLayout : mPrivateLayout;
936 }
Chris Wren78403d72014-07-28 10:23:24 +0100937
Jorim Jaggi59ec3042015-06-05 15:18:43 -0700938 @Override
939 public void setShowingLegacyBackground(boolean showing) {
940 super.setShowingLegacyBackground(showing);
941 mPrivateLayout.setShowingLegacyBackground(showing);
942 mPublicLayout.setShowingLegacyBackground(showing);
943 }
944
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700945 @Override
946 protected void updateBackgroundTint() {
947 super.updateBackgroundTint();
948 updateNoBackgroundState();
949 if (mIsSummaryWithChildren) {
950 List<ExpandableNotificationRow> notificationChildren =
951 mChildrenContainer.getNotificationChildren();
952 for (int i = 0; i < notificationChildren.size(); i++) {
953 ExpandableNotificationRow child = notificationChildren.get(i);
954 child.updateNoBackgroundState();
955 }
956 }
957 }
958
959 private void updateNoBackgroundState() {
960 mShowNoBackground = isChildInGroup() && hasSameBgColor(mNotificationParent);
961 updateBackground();
962 }
963
Chris Wren78403d72014-07-28 10:23:24 +0100964 public void setExpansionLogger(ExpansionLogger logger, String key) {
965 mLogger = logger;
966 mLoggingKey = key;
967 }
968
Chris Wren78403d72014-07-28 10:23:24 +0100969 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
970 final boolean nowExpanded = isExpanded();
971 if (wasExpanded != nowExpanded && mLogger != null) {
972 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
973 }
974 }
Chris Wren51c75102013-07-16 20:49:17 -0400975}