blob: 874b76aaf2bdf72616766bbd91fdc45934d9ce2a [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;
Selim Cinekda42d652015-12-04 15:51:16 -080025import android.os.Build;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020026import android.service.notification.StatusBarNotification;
Chris Wren51c75102013-07-16 20:49:17 -040027import android.util.AttributeSet;
Selim Cinek1a521f32014-11-03 17:39:29 +010028import android.view.MotionEvent;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080029import android.view.NotificationHeaderView;
Dan Sandlera5e0f412014-01-23 15:11:54 -050030import android.view.View;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020031import android.view.ViewStub;
Jorim Jaggife40f7d2014-04-28 15:20:04 +020032import android.view.accessibility.AccessibilityEvent;
Selim Cinekb5605e52015-02-20 18:21:41 +010033import android.view.animation.LinearInterpolator;
Selim Cinek98713a42015-09-21 15:47:20 +020034import android.widget.Chronometer;
Selim Cinekcab4a602014-09-03 14:47:57 +020035import android.widget.ImageView;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080036import android.widget.RemoteViews;
Selim Cinekb5605e52015-02-20 18:21:41 +010037
Dan Sandlera5e0f412014-01-23 15:11:54 -050038import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070039import com.android.systemui.classifier.FalsingManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010040import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +010041import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
42import com.android.systemui.statusbar.stack.StackScrollState;
43import com.android.systemui.statusbar.stack.StackStateAnimator;
44import com.android.systemui.statusbar.stack.StackViewState;
45
46import java.util.List;
Dan Sandlera5e0f412014-01-23 15:11:54 -050047
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020048public class ExpandableNotificationRow extends ActivatableNotificationView {
Selim Cinekb5605e52015-02-20 18:21:41 +010049
50 private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
51 private static final int COLORED_DIVIDER_ALPHA = 0x7B;
52 private final LinearInterpolator mLinearInterpolator = new LinearInterpolator();
Selim Cinekda42d652015-12-04 15:51:16 -080053 private final int mNotificationMinHeightLegacy;
Selim Cinek77019c72015-12-09 10:18:02 -080054 private final int mMaxHeadsUpHeightLegacy;
55 private final int mMaxHeadsUpHeight;
Selim Cinekda42d652015-12-04 15:51:16 -080056 private final int mNotificationMinHeight;
57 private final int mNotificationMaxHeight;
Selim Cinek1685e632014-04-08 02:27:49 +020058 private int mRowMinHeight;
Chris Wren51c75102013-07-16 20:49:17 -040059
Selim Cinek1685e632014-04-08 02:27:49 +020060 /** Does this row contain layouts that can adapt to row expansion */
Chris Wren51c75102013-07-16 20:49:17 -040061 private boolean mExpandable;
Selim Cinek1685e632014-04-08 02:27:49 +020062 /** Has the user actively changed the expansion state of this row */
63 private boolean mHasUserChangedExpansion;
64 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
Chris Wren51c75102013-07-16 20:49:17 -040065 private boolean mUserExpanded;
Selim Cinek1685e632014-04-08 02:27:49 +020066 /** Is the user touching this row */
Chris Wren51c75102013-07-16 20:49:17 -040067 private boolean mUserLocked;
Selim Cinek1685e632014-04-08 02:27:49 +020068 /** Are we showing the "public" version */
Dan Sandlera5e0f412014-01-23 15:11:54 -050069 private boolean mShowingPublic;
Jorim Jaggiae441282014-08-01 02:45:18 +020070 private boolean mSensitive;
71 private boolean mShowingPublicInitialized;
Selim Cinek60122be2015-04-15 18:16:50 -070072 private boolean mHideSensitiveForIntrinsicHeight;
Chris Wren51c75102013-07-16 20:49:17 -040073
Selim Cinek1685e632014-04-08 02:27:49 +020074 /**
75 * Is this notification expanded by the system. The expansion state can be overridden by the
76 * user expansion.
77 */
78 private boolean mIsSystemExpanded;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020079
80 /**
Selim Cinek83bc7832015-10-22 13:26:54 -070081 * Whether the notification is on the keyguard and the expansion is disabled.
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020082 */
Selim Cinek83bc7832015-10-22 13:26:54 -070083 private boolean mOnKeyguard;
Jorim Jaggidce3c4c2014-04-29 23:12:24 +020084
Jorim Jaggibe565df2014-04-28 17:51:23 +020085 private NotificationContentView mPublicLayout;
86 private NotificationContentView mPrivateLayout;
Selim Cinek1685e632014-04-08 02:27:49 +020087 private int mMaxExpandHeight;
Selim Cinek8d490d42015-04-10 00:05:50 -070088 private int mHeadsUpHeight;
Selim Cinek863834b2014-05-20 04:20:25 +020089 private View mVetoButton;
Dan Sandler0d3e62f2014-07-14 17:13:50 -040090 private boolean mClearable;
Chris Wren78403d72014-07-28 10:23:24 +010091 private ExpansionLogger mLogger;
92 private String mLoggingKey;
Selim Cineka5e211b2014-08-11 17:35:48 +020093 private boolean mWasReset;
Selim Cinek8d490d42015-04-10 00:05:50 -070094 private NotificationGuts mGuts;
Selim Cinekda42d652015-12-04 15:51:16 -080095 private NotificationData.Entry mEntry;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +020096 private StatusBarNotification mStatusBarNotification;
Selim Cinek1a521f32014-11-03 17:39:29 +010097 private boolean mIsHeadsUp;
Selim Cinek98713a42015-09-21 15:47:20 +020098 private boolean mLastChronometerRunning = true;
Selim Cinekeef84282015-10-30 16:28:00 -070099 private NotificationHeaderView mNotificationHeader;
Selim Cinek9c7712d2015-12-08 19:19:48 -0800100 private NotificationViewWrapper mNotificationHeaderWrapper;
Selim Cinekb5605e52015-02-20 18:21:41 +0100101 private ViewStub mChildrenContainerStub;
102 private NotificationGroupManager mGroupManager;
Selim Cinekb5605e52015-02-20 18:21:41 +0100103 private boolean mChildrenExpanded;
Selim Cinek263398f2015-10-21 17:40:23 -0700104 private boolean mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100105 private NotificationChildrenContainer mChildrenContainer;
Selim Cinekab29aeb2015-02-20 18:18:32 +0100106 private ViewStub mGutsStub;
Selim Cinekb5605e52015-02-20 18:21:41 +0100107 private boolean mIsSystemChildExpanded;
Selim Cinek684a4422015-04-15 16:18:39 -0700108 private boolean mIsPinned;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700109 private FalsingManager mFalsingManager;
Selim Cinekea4bef72015-12-02 15:51:10 -0800110 private NotificationHeaderUtil mHeaderUtil = new NotificationHeaderUtil(this);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200111
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700112 private boolean mJustClicked;
Selim Cinek5a175d92015-11-23 18:01:33 -0800113 private boolean mIconAnimationRunning;
Selim Cinek34d93b02015-10-22 12:30:38 -0700114 private boolean mShowNoBackground;
Selim Cinek388df6d2015-10-22 13:25:11 -0700115 private ExpandableNotificationRow mNotificationParent;
Selim Cinek570981d2015-12-01 11:37:01 -0800116 private OnExpandClickListener mOnExpandClickListener;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800117 private OnClickListener mExpandClickListener = new OnClickListener() {
118 @Override
119 public void onClick(View v) {
120 if (mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
121 mGroupManager.toggleGroupExpansion(mStatusBarNotification);
Selim Cinek570981d2015-12-01 11:37:01 -0800122 mOnExpandClickListener.onExpandClicked(ExpandableNotificationRow.this,
123 mGroupManager.isGroupExpanded(mStatusBarNotification));
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800124 } else {
Selim Cinek570981d2015-12-01 11:37:01 -0800125 boolean nowExpanded = !isExpanded();
126 setUserExpanded(nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800127 notifyHeightChanged(true);
Selim Cinek570981d2015-12-01 11:37:01 -0800128 mOnExpandClickListener.onExpandClicked(ExpandableNotificationRow.this,
129 nowExpanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800130 }
131 }
132 };
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700133
Selim Cinek8d490d42015-04-10 00:05:50 -0700134 public NotificationContentView getPrivateLayout() {
135 return mPrivateLayout;
136 }
137
138 public NotificationContentView getPublicLayout() {
139 return mPublicLayout;
140 }
141
Selim Cinekcab4a602014-09-03 14:47:57 +0200142 public void setIconAnimationRunning(boolean running) {
143 setIconAnimationRunning(running, mPublicLayout);
144 setIconAnimationRunning(running, mPrivateLayout);
Selim Cinek5a175d92015-11-23 18:01:33 -0800145 setIconAnimationRunningForChild(running, mNotificationHeader);
146 if (mIsSummaryWithChildren) {
147 List<ExpandableNotificationRow> notificationChildren =
148 mChildrenContainer.getNotificationChildren();
149 for (int i = 0; i < notificationChildren.size(); i++) {
150 ExpandableNotificationRow child = notificationChildren.get(i);
151 child.setIconAnimationRunning(running);
152 }
153 }
154 mIconAnimationRunning = running;
Selim Cinekcab4a602014-09-03 14:47:57 +0200155 }
156
157 private void setIconAnimationRunning(boolean running, NotificationContentView layout) {
158 if (layout != null) {
159 View contractedChild = layout.getContractedChild();
160 View expandedChild = layout.getExpandedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700161 View headsUpChild = layout.getHeadsUpChild();
Selim Cinekcab4a602014-09-03 14:47:57 +0200162 setIconAnimationRunningForChild(running, contractedChild);
163 setIconAnimationRunningForChild(running, expandedChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700164 setIconAnimationRunningForChild(running, headsUpChild);
Selim Cinekcab4a602014-09-03 14:47:57 +0200165 }
166 }
167
168 private void setIconAnimationRunningForChild(boolean running, View child) {
169 if (child != null) {
170 ImageView icon = (ImageView) child.findViewById(com.android.internal.R.id.icon);
171 setIconRunning(icon, running);
172 ImageView rightIcon = (ImageView) child.findViewById(
173 com.android.internal.R.id.right_icon);
174 setIconRunning(rightIcon, running);
175 }
176 }
177
178 private void setIconRunning(ImageView imageView, boolean running) {
179 if (imageView != null) {
180 Drawable drawable = imageView.getDrawable();
181 if (drawable instanceof AnimationDrawable) {
182 AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
183 if (running) {
184 animationDrawable.start();
185 } else {
186 animationDrawable.stop();
187 }
188 } else if (drawable instanceof AnimatedVectorDrawable) {
189 AnimatedVectorDrawable animationDrawable = (AnimatedVectorDrawable) drawable;
190 if (running) {
191 animationDrawable.start();
192 } else {
193 animationDrawable.stop();
194 }
195 }
196 }
197 }
198
Selim Cinekda42d652015-12-04 15:51:16 -0800199 public void onNotificationUpdated(NotificationData.Entry entry) {
200 mEntry = entry;
201 mStatusBarNotification = entry.notification;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800202 mPrivateLayout.onNotificationUpdated(entry);
203 mPublicLayout.onNotificationUpdated(entry);
Selim Cineka37774f2014-11-11 19:16:18 +0100204 updateVetoButton();
Selim Cinek8fc93c92015-11-23 17:48:07 -0800205 if (mIsSummaryWithChildren) {
206 recreateNotificationHeader();
207 }
Selim Cinek5a175d92015-11-23 18:01:33 -0800208 if (mIconAnimationRunning) {
209 setIconAnimationRunning(true);
210 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800211 if (mNotificationParent != null) {
212 mNotificationParent.updateChildrenHeaderAppearance();
213 }
Selim Cinek263398f2015-10-21 17:40:23 -0700214 onChildrenCountChanged();
Selim Cinekda42d652015-12-04 15:51:16 -0800215 updateLimits();
216 }
217
218 private void updateLimits() {
219 boolean customView = getPrivateLayout().getContractedChild().getId()
220 != com.android.internal.R.id.status_bar_latest_event_content;
221 boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
222 int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
223 mNotificationMinHeightLegacy : mNotificationMinHeight;
Selim Cinek77019c72015-12-09 10:18:02 -0800224 boolean headsUpCustom = getPrivateLayout().getHeadsUpChild() != null &&
225 getPrivateLayout().getHeadsUpChild().getId()
226 != com.android.internal.R.id.status_bar_latest_event_content;
227 int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
228 : mMaxHeadsUpHeight;
Selim Cinekda42d652015-12-04 15:51:16 -0800229 mRowMinHeight = minHeight;
230 mMaxViewHeight = mNotificationMaxHeight;
Selim Cinek77019c72015-12-09 10:18:02 -0800231 mPrivateLayout.setHeights(mRowMinHeight, headsUpheight);
232 mPublicLayout.setHeights(mRowMinHeight, headsUpheight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200233 }
234
235 public StatusBarNotification getStatusBarNotification() {
236 return mStatusBarNotification;
237 }
238
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700239 public boolean isHeadsUp() {
240 return mIsHeadsUp;
241 }
242
Selim Cinek1a521f32014-11-03 17:39:29 +0100243 public void setHeadsUp(boolean isHeadsUp) {
Selim Cinekc80fdb12015-04-13 15:09:08 -0700244 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek1a521f32014-11-03 17:39:29 +0100245 mIsHeadsUp = isHeadsUp;
Selim Cinek8d490d42015-04-10 00:05:50 -0700246 mPrivateLayout.setHeadsUp(isHeadsUp);
Selim Cinekc80fdb12015-04-13 15:09:08 -0700247 if (intrinsicBefore != getIntrinsicHeight()) {
248 notifyHeightChanged(false /* needsAnimation */);
249 }
Selim Cinek1a521f32014-11-03 17:39:29 +0100250 }
251
Selim Cinekb5605e52015-02-20 18:21:41 +0100252 public void setGroupManager(NotificationGroupManager groupManager) {
253 mGroupManager = groupManager;
Selim Cinek83bc7832015-10-22 13:26:54 -0700254 mPrivateLayout.setGroupManager(groupManager);
Selim Cinekb5605e52015-02-20 18:21:41 +0100255 }
256
Adrian Roosb88b1a12015-12-09 18:51:05 -0800257 public void setRemoteInputController(RemoteInputController r) {
258 mPrivateLayout.setRemoteInputController(r);
259 }
260
Selim Cinekb5605e52015-02-20 18:21:41 +0100261 public void addChildNotification(ExpandableNotificationRow row) {
262 addChildNotification(row, -1);
263 }
264
265 /**
266 * Add a child notification to this view.
267 *
268 * @param row the row to add
269 * @param childIndex the index to add it at, if -1 it will be added at the end
270 */
271 public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
272 if (mChildrenContainer == null) {
273 mChildrenContainerStub.inflate();
274 }
275 mChildrenContainer.addNotification(row, childIndex);
Selim Cinek263398f2015-10-21 17:40:23 -0700276 onChildrenCountChanged();
277 row.setIsChildInGroup(true, this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100278 }
279
280 public void removeChildNotification(ExpandableNotificationRow row) {
281 if (mChildrenContainer != null) {
282 mChildrenContainer.removeNotification(row);
283 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800284 mHeaderUtil.restoreNotificationHeader(row);
Selim Cinek263398f2015-10-21 17:40:23 -0700285 onChildrenCountChanged();
286 row.setIsChildInGroup(false, null);
287 }
288
289 public boolean isChildInGroup() {
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700290 return mNotificationParent != null;
Selim Cinek263398f2015-10-21 17:40:23 -0700291 }
292
Selim Cinek388df6d2015-10-22 13:25:11 -0700293 public ExpandableNotificationRow getNotificationParent() {
294 return mNotificationParent;
295 }
296
Selim Cinek263398f2015-10-21 17:40:23 -0700297 /**
298 * @param isChildInGroup Is this notification now in a group
299 * @param parent the new parent notification
300 */
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700301 public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
302 boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
303 mNotificationParent = childInGroup ? parent : null;
304 mPrivateLayout.setIsChildInGroup(childInGroup);
305 updateNoBackgroundState();
Selim Cinek34d93b02015-10-22 12:30:38 -0700306 }
307
308 @Override
309 protected boolean shouldHideBackground() {
310 return super.shouldHideBackground() || mShowNoBackground;
Selim Cinek263398f2015-10-21 17:40:23 -0700311 }
312
313 @Override
314 public boolean isSummaryWithChildren() {
315 return mIsSummaryWithChildren;
Selim Cinekb5605e52015-02-20 18:21:41 +0100316 }
317
318 @Override
319 public boolean areChildrenExpanded() {
320 return mChildrenExpanded;
321 }
322
323 public List<ExpandableNotificationRow> getNotificationChildren() {
324 return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
325 }
326
Selim Cinekeef84282015-10-30 16:28:00 -0700327 public int getNumberOfNotificationChildren() {
328 if (mChildrenContainer == null) {
329 return 0;
330 }
331 return mChildrenContainer.getNotificationChildren().size();
332 }
333
Selim Cinekb5605e52015-02-20 18:21:41 +0100334 /**
335 * Apply the order given in the list to the children.
336 *
337 * @param childOrder the new list order
338 * @return whether the list order has changed
339 */
340 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
341 return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
342 }
343
344 public void getChildrenStates(StackScrollState resultState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700345 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100346 StackViewState parentState = resultState.getViewStateForView(this);
347 mChildrenContainer.getState(resultState, parentState);
348 }
349 }
350
351 public void applyChildrenState(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700352 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100353 mChildrenContainer.applyState(state);
354 }
355 }
356
357 public void prepareExpansionChanged(StackScrollState state) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700358 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100359 mChildrenContainer.prepareExpansionChanged(state);
360 }
361 }
362
363 public void startChildAnimation(StackScrollState finalState,
364 StackStateAnimator stateAnimator, boolean withDelays, long delay, long duration) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700365 if (mIsSummaryWithChildren) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100366 mChildrenContainer.startAnimationToState(finalState, stateAnimator, withDelays, delay,
367 duration);
368 }
369 }
370
371 public ExpandableNotificationRow getViewAtPosition(float y) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700372 if (!mIsSummaryWithChildren || !mChildrenExpanded) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100373 return this;
374 } else {
375 ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
376 return view == null ? this : view;
377 }
378 }
379
Selim Cinekab29aeb2015-02-20 18:18:32 +0100380 public NotificationGuts getGuts() {
381 return mGuts;
382 }
383
Selim Cinek684a4422015-04-15 16:18:39 -0700384 /**
385 * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
386 * the notification will be rendered on top of the screen.
387 *
388 * @param pinned whether it is pinned
389 */
390 public void setPinned(boolean pinned) {
391 mIsPinned = pinned;
Selim Cinek98713a42015-09-21 15:47:20 +0200392 setChronometerRunning(mLastChronometerRunning);
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700393 }
394
Selim Cinek684a4422015-04-15 16:18:39 -0700395 public boolean isPinned() {
396 return mIsPinned;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700397 }
398
399 public int getHeadsUpHeight() {
Selim Cinek77019c72015-12-09 10:18:02 -0800400 if (mIsSummaryWithChildren) {
401 return mChildrenContainer.getIntrinsicHeight();
402 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700403 return mHeadsUpHeight;
Selim Cinekb8f09cf2015-03-16 17:09:28 -0700404 }
405
Jorim Jaggi5eb67c22015-08-19 19:50:49 -0700406 /**
407 * Mark whether this notification was just clicked, i.e. the user has just clicked this
408 * notification in this frame.
409 */
410 public void setJustClicked(boolean justClicked) {
411 mJustClicked = justClicked;
412 }
413
414 /**
415 * @return true if this notification has been clicked in this frame, false otherwise
416 */
417 public boolean wasJustClicked() {
418 return mJustClicked;
419 }
420
Selim Cinek98713a42015-09-21 15:47:20 +0200421 public void setChronometerRunning(boolean running) {
422 mLastChronometerRunning = running;
423 setChronometerRunning(running, mPrivateLayout);
424 setChronometerRunning(running, mPublicLayout);
425 if (mChildrenContainer != null) {
426 List<ExpandableNotificationRow> notificationChildren =
427 mChildrenContainer.getNotificationChildren();
428 for (int i = 0; i < notificationChildren.size(); i++) {
429 ExpandableNotificationRow child = notificationChildren.get(i);
430 child.setChronometerRunning(running);
431 }
432 }
433 }
434
435 private void setChronometerRunning(boolean running, NotificationContentView layout) {
436 if (layout != null) {
437 running = running || isPinned();
438 View contractedChild = layout.getContractedChild();
439 View expandedChild = layout.getExpandedChild();
440 View headsUpChild = layout.getHeadsUpChild();
441 setChronometerRunningForChild(running, contractedChild);
442 setChronometerRunningForChild(running, expandedChild);
443 setChronometerRunningForChild(running, headsUpChild);
444 }
445 }
446
447 private void setChronometerRunningForChild(boolean running, View child) {
448 if (child != null) {
449 View chronometer = child.findViewById(com.android.internal.R.id.chronometer);
450 if (chronometer instanceof Chronometer) {
451 ((Chronometer) chronometer).setStarted(running);
452 }
453 }
454 }
455
Selim Cinekea4bef72015-12-02 15:51:10 -0800456 public NotificationHeaderView getNotificationHeader() {
457 if (mNotificationHeader != null) {
458 return mNotificationHeader;
Selim Cinek8d6440d2015-10-22 13:00:05 -0700459 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800460 return mPrivateLayout.getNotificationHeader();
Selim Cinek8d6440d2015-10-22 13:00:05 -0700461 }
462
Selim Cinek570981d2015-12-01 11:37:01 -0800463 public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
464 mOnExpandClickListener = onExpandClickListener;
465 }
466
Chris Wren78403d72014-07-28 10:23:24 +0100467 public interface ExpansionLogger {
468 public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
469 }
Selim Cinek1685e632014-04-08 02:27:49 +0200470
Chris Wren51c75102013-07-16 20:49:17 -0400471 public ExpandableNotificationRow(Context context, AttributeSet attrs) {
472 super(context, attrs);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700473 mFalsingManager = FalsingManager.getInstance(context);
Selim Cinekda42d652015-12-04 15:51:16 -0800474 mNotificationMinHeightLegacy = getResources().getDimensionPixelSize(
475 R.dimen.notification_min_height_legacy);
476 mNotificationMinHeight = getResources().getDimensionPixelSize(
477 R.dimen.notification_min_height);
478 mNotificationMaxHeight = getResources().getDimensionPixelSize(
479 R.dimen.notification_max_height);
Selim Cinek77019c72015-12-09 10:18:02 -0800480 mMaxHeadsUpHeightLegacy = getResources().getDimensionPixelSize(
481 R.dimen.notification_max_heads_up_height_legacy);
482 mMaxHeadsUpHeight = getResources().getDimensionPixelSize(
483 R.dimen.notification_max_heads_up_height);
Chris Wren51c75102013-07-16 20:49:17 -0400484 }
485
Christoph Studera7fe6312014-06-27 19:32:44 +0200486 /**
487 * Resets this view so it can be re-used for an updated notification.
488 */
Christoph Studer22f2ee52014-07-29 22:57:21 +0200489 @Override
Christoph Studera7fe6312014-06-27 19:32:44 +0200490 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200491 super.reset();
Christoph Studera7fe6312014-06-27 19:32:44 +0200492 mRowMinHeight = 0;
Chris Wren78403d72014-07-28 10:23:24 +0100493 final boolean wasExpanded = isExpanded();
Selim Cinek379ff8f2015-02-20 17:03:16 +0100494 mMaxViewHeight = 0;
Christoph Studera7fe6312014-06-27 19:32:44 +0200495 mExpandable = false;
496 mHasUserChangedExpansion = false;
497 mUserLocked = false;
498 mShowingPublic = false;
Jorim Jaggiae441282014-08-01 02:45:18 +0200499 mSensitive = false;
500 mShowingPublicInitialized = false;
Christoph Studera7fe6312014-06-27 19:32:44 +0200501 mIsSystemExpanded = false;
Selim Cinek83bc7832015-10-22 13:26:54 -0700502 mOnKeyguard = false;
Selim Cinek1a521f32014-11-03 17:39:29 +0100503 mPublicLayout.reset(mIsHeadsUp);
504 mPrivateLayout.reset(mIsHeadsUp);
Selim Cinek31094df2014-08-14 19:28:15 +0200505 resetHeight();
506 logExpansionEvent(false, wasExpanded);
507 }
508
509 public void resetHeight() {
Selim Cinek1a521f32014-11-03 17:39:29 +0100510 if (mIsHeadsUp) {
511 resetActualHeight();
512 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200513 mMaxExpandHeight = 0;
Selim Cinek8d490d42015-04-10 00:05:50 -0700514 mHeadsUpHeight = 0;
Selim Cineka5e211b2014-08-11 17:35:48 +0200515 mWasReset = true;
Selim Cinek31094df2014-08-14 19:28:15 +0200516 onHeightReset();
Selim Cinek6e28a672014-09-05 14:43:28 +0200517 requestLayout();
Christoph Studera7fe6312014-06-27 19:32:44 +0200518 }
519
Jorim Jaggi251957d2014-04-09 04:24:09 +0200520 @Override
Selim Cinek1a521f32014-11-03 17:39:29 +0100521 protected boolean filterMotionEvent(MotionEvent event) {
522 return mIsHeadsUp || super.filterMotionEvent(event);
523 }
524
525 @Override
Jorim Jaggi251957d2014-04-09 04:24:09 +0200526 protected void onFinishInflate() {
527 super.onFinishInflate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200528 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
529 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800530 mPrivateLayout.setExpandClickListener(mExpandClickListener);
531 mPublicLayout.setExpandClickListener(mExpandClickListener);
Selim Cinekab29aeb2015-02-20 18:18:32 +0100532 mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
533 mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200534 @Override
535 public void onInflate(ViewStub stub, View inflated) {
536 mGuts = (NotificationGuts) inflated;
537 mGuts.setClipTopAmount(getClipTopAmount());
538 mGuts.setActualHeight(getActualHeight());
Selim Cinekab29aeb2015-02-20 18:18:32 +0100539 mGutsStub = null;
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200540 }
541 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100542 mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
543 mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
544
545 @Override
546 public void onInflate(ViewStub stub, View inflated) {
547 mChildrenContainer = (NotificationChildrenContainer) inflated;
Selim Cinek388df6d2015-10-22 13:25:11 -0700548 mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
Selim Cinekb5605e52015-02-20 18:21:41 +0100549 }
550 });
Selim Cinek863834b2014-05-20 04:20:25 +0200551 mVetoButton = findViewById(R.id.veto);
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200552 }
553
Selim Cinekab29aeb2015-02-20 18:18:32 +0100554 public void inflateGuts() {
555 if (mGuts == null) {
556 mGutsStub.inflate();
557 }
558 }
559
Selim Cinekda42d652015-12-04 15:51:16 -0800560 private void updateChildrenVisibility() {
Selim Cinekb5605e52015-02-20 18:21:41 +0100561 if (mChildrenContainer == null) {
562 return;
563 }
Selim Cinekeef84282015-10-30 16:28:00 -0700564 mChildrenContainer.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800565 mNotificationHeader.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekeef84282015-10-30 16:28:00 -0700566 mPrivateLayout.setVisibility(!mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
Selim Cinekda42d652015-12-04 15:51:16 -0800567 // The limits might have changed if the view suddenly became a group or vice versa
568 updateLimits();
Selim Cinekb5605e52015-02-20 18:21:41 +0100569 }
570
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200571 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800572 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
573 if (super.onRequestSendAccessibilityEventInternal(child, event)) {
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200574 // Add a record for the entire layout since its content is somehow small.
575 // The event comes from a leaf view that is interacted with.
576 AccessibilityEvent record = AccessibilityEvent.obtain();
577 onInitializeAccessibilityEvent(record);
578 dispatchPopulateAccessibilityEvent(record);
579 event.appendRecord(record);
580 return true;
581 }
582 return false;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200583 }
Chris Wren51c75102013-07-16 20:49:17 -0400584
John Spurlocke15452b2014-08-21 09:44:39 -0400585 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100586 public void setDark(boolean dark, boolean fade, long delay) {
587 super.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400588 final NotificationContentView showing = getShowingLayout();
589 if (showing != null) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100590 showing.setDark(dark, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400591 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800592 if (mIsSummaryWithChildren) {
593 mChildrenContainer.setDark(dark, fade, delay);
594 mNotificationHeaderWrapper.setDark(dark, fade, delay);
595 }
John Spurlocke15452b2014-08-21 09:44:39 -0400596 }
597
Chris Wren51c75102013-07-16 20:49:17 -0400598 public boolean isExpandable() {
Selim Cinek388df6d2015-10-22 13:25:11 -0700599 if (mIsSummaryWithChildren && !mShowingPublic) {
600 return !mChildrenExpanded;
601 }
Chris Wren51c75102013-07-16 20:49:17 -0400602 return mExpandable;
603 }
604
605 public void setExpandable(boolean expandable) {
606 mExpandable = expandable;
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800607 mPrivateLayout.updateExpandButtons(isExpandable());
Chris Wren51c75102013-07-16 20:49:17 -0400608 }
609
Selim Cinek1685e632014-04-08 02:27:49 +0200610 /**
611 * @return whether the user has changed the expansion state
612 */
613 public boolean hasUserChangedExpansion() {
614 return mHasUserChangedExpansion;
615 }
616
Chris Wren51c75102013-07-16 20:49:17 -0400617 public boolean isUserExpanded() {
618 return mUserExpanded;
619 }
620
Selim Cinek1685e632014-04-08 02:27:49 +0200621 /**
622 * Set this notification to be expanded by the user
623 *
624 * @param userExpanded whether the user wants this notification to be expanded
625 */
Chris Wren51c75102013-07-16 20:49:17 -0400626 public void setUserExpanded(boolean userExpanded) {
Selim Cinek388df6d2015-10-22 13:25:11 -0700627 setUserExpanded(userExpanded, false /* allowChildExpansion */);
628 }
629
630 /**
631 * Set this notification to be expanded by the user
632 *
633 * @param userExpanded whether the user wants this notification to be expanded
634 * @param allowChildExpansion whether a call to this method allows expanding children
635 */
636 public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700637 mFalsingManager.setNotificationExpanded();
Selim Cinek388df6d2015-10-22 13:25:11 -0700638 if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
639 mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
640 return;
641 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200642 if (userExpanded && !mExpandable) return;
Chris Wren78403d72014-07-28 10:23:24 +0100643 final boolean wasExpanded = isExpanded();
Selim Cinek1685e632014-04-08 02:27:49 +0200644 mHasUserChangedExpansion = true;
Chris Wren51c75102013-07-16 20:49:17 -0400645 mUserExpanded = userExpanded;
Chris Wren78403d72014-07-28 10:23:24 +0100646 logExpansionEvent(true, wasExpanded);
Chris Wren51c75102013-07-16 20:49:17 -0400647 }
648
Selim Cinekccd14fb2014-08-12 18:53:24 +0200649 public void resetUserExpansion() {
650 mHasUserChangedExpansion = false;
651 mUserExpanded = false;
652 }
653
Chris Wren51c75102013-07-16 20:49:17 -0400654 public boolean isUserLocked() {
655 return mUserLocked;
656 }
657
658 public void setUserLocked(boolean userLocked) {
659 mUserLocked = userLocked;
660 }
661
Selim Cinek1685e632014-04-08 02:27:49 +0200662 /**
663 * @return has the system set this notification to be expanded
664 */
665 public boolean isSystemExpanded() {
666 return mIsSystemExpanded;
667 }
668
669 /**
670 * Set this notification to be expanded by the system.
671 *
672 * @param expand whether the system wants this notification to be expanded.
673 */
674 public void setSystemExpanded(boolean expand) {
Selim Cinek31094df2014-08-14 19:28:15 +0200675 if (expand != mIsSystemExpanded) {
676 final boolean wasExpanded = isExpanded();
677 mIsSystemExpanded = expand;
Selim Cinekb5605e52015-02-20 18:21:41 +0100678 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +0200679 logExpansionEvent(false, wasExpanded);
Selim Cinek83bc7832015-10-22 13:26:54 -0700680 if (mChildrenContainer != null) {
681 mChildrenContainer.updateGroupOverflow();
682 }
Selim Cinek31094df2014-08-14 19:28:15 +0200683 }
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200684 }
685
686 /**
Selim Cinek83bc7832015-10-22 13:26:54 -0700687 * @param onKeyguard whether to prevent notification expansion
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200688 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700689 public void setOnKeyguard(boolean onKeyguard) {
690 if (onKeyguard != mOnKeyguard) {
Selim Cinek31094df2014-08-14 19:28:15 +0200691 final boolean wasExpanded = isExpanded();
Selim Cinek83bc7832015-10-22 13:26:54 -0700692 mOnKeyguard = onKeyguard;
Selim Cinek31094df2014-08-14 19:28:15 +0200693 logExpansionEvent(false, wasExpanded);
694 if (wasExpanded != isExpanded()) {
Selim Cinek2108fe02015-12-10 12:56:13 -0800695 if (mIsSummaryWithChildren) {
696 mChildrenContainer.updateGroupOverflow();
697 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100698 notifyHeightChanged(false /* needsAnimation */);
Selim Cinek31094df2014-08-14 19:28:15 +0200699 }
700 }
Selim Cinek1685e632014-04-08 02:27:49 +0200701 }
702
703 /**
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400704 * @return Can the underlying notification be cleared?
705 */
706 public boolean isClearable() {
Selim Cineka37774f2014-11-11 19:16:18 +0100707 return mStatusBarNotification != null && mStatusBarNotification.isClearable();
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400708 }
709
710 /**
Selim Cinek1685e632014-04-08 02:27:49 +0200711 * Apply an expansion state to the layout.
Selim Cinek1685e632014-04-08 02:27:49 +0200712 */
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200713 public void applyExpansionToLayout() {
714 boolean expand = isExpanded();
Chris Wren51c75102013-07-16 20:49:17 -0400715 if (expand && mExpandable) {
Selim Cinekeef84282015-10-30 16:28:00 -0700716 setActualHeight(mMaxExpandHeight);
Chris Wren51c75102013-07-16 20:49:17 -0400717 } else {
Selim Cinekeef84282015-10-30 16:28:00 -0700718 setActualHeight(mRowMinHeight);
Chris Wren51c75102013-07-16 20:49:17 -0400719 }
Chris Wren51c75102013-07-16 20:49:17 -0400720 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500721
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200722 @Override
723 public int getIntrinsicHeight() {
Jorim Jaggibe565df2014-04-28 17:51:23 +0200724 if (isUserLocked()) {
725 return getActualHeight();
726 }
Selim Cinek1685e632014-04-08 02:27:49 +0200727 boolean inExpansionState = isExpanded();
Selim Cinek60122be2015-04-15 18:16:50 -0700728 if (mSensitive && mHideSensitiveForIntrinsicHeight) {
729 return mRowMinHeight;
Selim Cinek83bc7832015-10-22 13:26:54 -0700730 } else if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800731 return mChildrenContainer.getIntrinsicHeight();
Selim Cinek60122be2015-04-15 18:16:50 -0700732 } else if (mIsHeadsUp) {
Selim Cinek8d490d42015-04-10 00:05:50 -0700733 if (inExpansionState) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700734 return Math.max(mMaxExpandHeight, mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -0700735 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -0700736 return Math.max(mRowMinHeight, mHeadsUpHeight);
Selim Cinek8d490d42015-04-10 00:05:50 -0700737 }
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700738 } else if (!inExpansionState || (isChildInGroup() && !isGroupExpanded())) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700739 return getMinHeight();
Selim Cinekb5605e52015-02-20 18:21:41 +0100740 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -0700741 return getMaxExpandHeight();
Selim Cinek1685e632014-04-08 02:27:49 +0200742 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100743 }
Selim Cinek1685e632014-04-08 02:27:49 +0200744
Selim Cinekeef84282015-10-30 16:28:00 -0700745 private boolean isGroupExpanded() {
746 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Selim Cinekb5605e52015-02-20 18:21:41 +0100747 }
748
Selim Cinekeef84282015-10-30 16:28:00 -0700749 /**
750 * @return whether this view has a header on the top of the content
751 */
752 private boolean hasNotificationHeader() {
753 return mIsSummaryWithChildren;
Selim Cinek1685e632014-04-08 02:27:49 +0200754 }
755
Selim Cinek263398f2015-10-21 17:40:23 -0700756 private void onChildrenCountChanged() {
Selim Cinek8fc93c92015-11-23 17:48:07 -0800757 mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
Selim Cinek263398f2015-10-21 17:40:23 -0700758 && mGroupManager.hasGroupChildren(mStatusBarNotification);
Selim Cinek8fc93c92015-11-23 17:48:07 -0800759 if (mIsSummaryWithChildren) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800760 if (mChildrenContainer == null) {
761 mChildrenContainerStub.inflate();
762 }
Selim Cinek8fc93c92015-11-23 17:48:07 -0800763 if (mNotificationHeader == null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800764 recreateNotificationHeader();
765 }
Selim Cinek263398f2015-10-21 17:40:23 -0700766 }
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800767 mPrivateLayout.updateExpandButtons(isExpandable());
Selim Cinekea4bef72015-12-02 15:51:10 -0800768 updateChildrenHeaderAppearance();
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800769 updateHeaderChildCount();
Selim Cinekda42d652015-12-04 15:51:16 -0800770 updateChildrenVisibility();
Selim Cinek263398f2015-10-21 17:40:23 -0700771 }
772
Selim Cinek1685e632014-04-08 02:27:49 +0200773 /**
774 * Check whether the view state is currently expanded. This is given by the system in {@link
775 * #setSystemExpanded(boolean)} and can be overridden by user expansion or
776 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
777 * view can differ from this state, if layout params are modified from outside.
778 *
779 * @return whether the view state is currently expanded.
780 */
Selim Cinek83bc7832015-10-22 13:26:54 -0700781 public boolean isExpanded() {
782 return !mOnKeyguard
Selim Cinekb5605e52015-02-20 18:21:41 +0100783 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
784 || isUserExpanded());
785 }
786
787 private boolean isSystemChildExpanded() {
788 return mIsSystemChildExpanded;
789 }
790
791 public void setSystemChildExpanded(boolean expanded) {
792 mIsSystemChildExpanded = expanded;
Selim Cinek1685e632014-04-08 02:27:49 +0200793 }
794
795 @Override
796 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
797 super.onLayout(changed, left, top, right, bottom);
Selim Cineka5e211b2014-08-11 17:35:48 +0200798 boolean updateExpandHeight = mMaxExpandHeight == 0 && !mWasReset;
Selim Cinek8d490d42015-04-10 00:05:50 -0700799 updateMaxHeights();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200800 if (updateExpandHeight) {
Jorim Jaggidce3c4c2014-04-29 23:12:24 +0200801 applyExpansionToLayout();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200802 }
Selim Cineka5e211b2014-08-11 17:35:48 +0200803 mWasReset = false;
Selim Cinek1685e632014-04-08 02:27:49 +0200804 }
805
Selim Cinek8d490d42015-04-10 00:05:50 -0700806 private void updateMaxHeights() {
Selim Cinekd2319fb2014-09-01 19:41:54 +0200807 int intrinsicBefore = getIntrinsicHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -0700808 View expandedChild = mPrivateLayout.getExpandedChild();
809 if (expandedChild == null) {
810 expandedChild = mPrivateLayout.getContractedChild();
811 }
812 mMaxExpandHeight = expandedChild.getHeight();
813 View headsUpChild = mPrivateLayout.getHeadsUpChild();
Selim Cinek1f3f5442015-04-10 17:54:46 -0700814 if (headsUpChild == null) {
815 headsUpChild = mPrivateLayout.getContractedChild();
Selim Cinek8d490d42015-04-10 00:05:50 -0700816 }
Selim Cinek1f3f5442015-04-10 17:54:46 -0700817 mHeadsUpHeight = headsUpChild.getHeight();
Selim Cinekd2319fb2014-09-01 19:41:54 +0200818 if (intrinsicBefore != getIntrinsicHeight()) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100819 notifyHeightChanged(false /* needsAnimation */);
Selim Cinekd2319fb2014-09-01 19:41:54 +0200820 }
821 }
822
Jorim Jaggiae441282014-08-01 02:45:18 +0200823 public void setSensitive(boolean sensitive) {
824 mSensitive = sensitive;
825 }
826
827 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
Selim Cinek60122be2015-04-15 18:16:50 -0700828 mHideSensitiveForIntrinsicHeight = hideSensitive;
Jorim Jaggiae441282014-08-01 02:45:18 +0200829 }
830
831 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
832 long duration) {
833 boolean oldShowingPublic = mShowingPublic;
834 mShowingPublic = mSensitive && hideSensitive;
835 if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
836 return;
837 }
Dan Sandlera5e0f412014-01-23 15:11:54 -0500838
839 // bail out if no public version
Selim Cinek1685e632014-04-08 02:27:49 +0200840 if (mPublicLayout.getChildCount() == 0) return;
Dan Sandlera5e0f412014-01-23 15:11:54 -0500841
Jorim Jaggiae441282014-08-01 02:45:18 +0200842 if (!animated) {
843 mPublicLayout.animate().cancel();
844 mPrivateLayout.animate().cancel();
845 mPublicLayout.setAlpha(1f);
846 mPrivateLayout.setAlpha(1f);
847 mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
Selim Cinek263398f2015-10-21 17:40:23 -0700848 mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? View.VISIBLE
849 : View.INVISIBLE);
Jorim Jaggiae441282014-08-01 02:45:18 +0200850 } else {
851 animateShowingPublic(delay, duration);
852 }
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400853
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800854 mPrivateLayout.updateExpandButtons(isExpandable());
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400855 updateVetoButton();
Jorim Jaggiae441282014-08-01 02:45:18 +0200856 mShowingPublicInitialized = true;
857 }
858
859 private void animateShowingPublic(long delay, long duration) {
860 final View source = mShowingPublic ? mPrivateLayout : mPublicLayout;
861 View target = mShowingPublic ? mPublicLayout : mPrivateLayout;
862 source.setVisibility(View.VISIBLE);
863 target.setVisibility(View.VISIBLE);
864 target.setAlpha(0f);
865 source.animate().cancel();
866 target.animate().cancel();
867 source.animate()
868 .alpha(0f)
Jorim Jaggiae441282014-08-01 02:45:18 +0200869 .setStartDelay(delay)
870 .setDuration(duration)
871 .withEndAction(new Runnable() {
872 @Override
873 public void run() {
874 source.setVisibility(View.INVISIBLE);
875 }
876 });
877 target.animate()
878 .alpha(1f)
Jorim Jaggiae441282014-08-01 02:45:18 +0200879 .setStartDelay(delay)
880 .setDuration(duration);
Dan Sandler0d3e62f2014-07-14 17:13:50 -0400881 }
882
883 private void updateVetoButton() {
884 // public versions cannot be dismissed
885 mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE);
Dan Sandlera5e0f412014-01-23 15:11:54 -0500886 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200887
Selim Cinekb5605e52015-02-20 18:21:41 +0100888 public void setChildrenExpanded(boolean expanded, boolean animate) {
889 mChildrenExpanded = expanded;
Selim Cinek7b836392015-12-04 20:02:59 -0800890 if (mNotificationHeader != null) {
891 mNotificationHeader.setExpanded(expanded);
892 }
Selim Cinek83bc7832015-10-22 13:26:54 -0700893 if (mChildrenContainer != null) {
894 mChildrenContainer.setChildrenExpanded(expanded);
895 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100896 }
897
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800898 public void updateHeaderChildCount() {
899 if (mIsSummaryWithChildren) {
900 mNotificationHeader.setChildCount(
901 mChildrenContainer.getNotificationChildren().size());
Selim Cinekb5605e52015-02-20 18:21:41 +0100902 }
Selim Cinekb5605e52015-02-20 18:21:41 +0100903 }
904
905 public static void applyTint(View v, int color) {
906 int alpha;
907 if (color != 0) {
908 alpha = COLORED_DIVIDER_ALPHA;
909 } else {
910 color = 0xff000000;
911 alpha = DEFAULT_DIVIDER_ALPHA;
912 }
913 if (v.getBackground() instanceof ColorDrawable) {
914 ColorDrawable background = (ColorDrawable) v.getBackground();
915 background.mutate();
916 background.setColor(color);
917 background.setAlpha(alpha);
918 }
919 }
920
Selim Cinek1685e632014-04-08 02:27:49 +0200921 public int getMaxExpandHeight() {
Selim Cinekb5605e52015-02-20 18:21:41 +0100922 return mMaxExpandHeight;
Chris Wren51c75102013-07-16 20:49:17 -0400923 }
Jorim Jaggi584a7aa2014-04-10 23:26:13 +0200924
Jorim Jaggibe565df2014-04-28 17:51:23 +0200925 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200926 public boolean isContentExpandable() {
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200927 NotificationContentView showingLayout = getShowingLayout();
928 return showingLayout.isContentExpandable();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200929 }
930
931 @Override
Selim Cinek560e64d2015-06-09 19:58:11 -0700932 protected View getContentView() {
933 return getShowingLayout();
934 }
935
936 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200937 public void setActualHeight(int height, boolean notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100938 super.setActualHeight(height, notifyListeners);
Selim Cinekeef84282015-10-30 16:28:00 -0700939 int contentHeight = Math.max(getMinHeight(), height);
Selim Cinekb5605e52015-02-20 18:21:41 +0100940 mPrivateLayout.setContentHeight(contentHeight);
941 mPublicLayout.setContentHeight(contentHeight);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200942 if (mGuts != null) {
943 mGuts.setActualHeight(height);
944 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200945 invalidate();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200946 }
947
948 @Override
Selim Cinekb5605e52015-02-20 18:21:41 +0100949 public int getMaxContentHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700950 if (mIsSummaryWithChildren && !mShowingPublic) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800951 return mChildrenContainer.getMaxContentHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700952 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200953 NotificationContentView showingLayout = getShowingLayout();
954 return showingLayout.getMaxHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200955 }
956
957 @Override
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200958 public int getMinHeight() {
Selim Cinek816c8e42015-11-19 12:00:45 -0800959 NotificationContentView showingLayout = getShowingLayout();
960 return showingLayout.getMinHeight();
961 }
962
963 @Override
964 public int getMinExpandHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700965 if (mIsSummaryWithChildren && !mOnKeyguard) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800966 return mChildrenContainer.getMinHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700967 }
Selim Cinek816c8e42015-11-19 12:00:45 -0800968 return getMinHeight();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200969 }
970
971 @Override
Selim Cinek263398f2015-10-21 17:40:23 -0700972 protected boolean shouldLimitViewHeight() {
973 return !mIsSummaryWithChildren;
974 }
975
976 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +0200977 public void setClipTopAmount(int clipTopAmount) {
978 super.setClipTopAmount(clipTopAmount);
979 mPrivateLayout.setClipTopAmount(clipTopAmount);
Selim Cinek2f0df8a2014-06-10 17:40:42 +0200980 mPublicLayout.setClipTopAmount(clipTopAmount);
Jorim Jaggib1cd3c12014-09-08 19:55:17 +0200981 if (mGuts != null) {
982 mGuts.setClipTopAmount(clipTopAmount);
983 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200984 }
985
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800986 private void recreateNotificationHeader() {
987 final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
988 getStatusBarNotification().getNotification());
989 final RemoteViews header = builder.makeNotificationHeader();
990 if (mNotificationHeader == null) {
991 mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
992 final View expandButton = mNotificationHeader.findViewById(
993 com.android.internal.R.id.expand_button);
994 expandButton.setVisibility(VISIBLE);
995 mNotificationHeader.setOnClickListener(mExpandClickListener);
Selim Cinek9c7712d2015-12-08 19:19:48 -0800996 mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
997 mNotificationHeader);
Selim Cinekb5a83612015-12-11 14:14:39 -0800998 addView(mNotificationHeader, indexOfChild(mChildrenContainer) + 1);
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800999 } else {
1000 header.reapply(getContext(), mNotificationHeader);
Selim Cinek9c7712d2015-12-08 19:19:48 -08001001 mNotificationHeaderWrapper.notifyContentUpdated();
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001002 }
Selim Cinek7b836392015-12-04 20:02:59 -08001003 updateHeaderExpandButton();
Selim Cinekea4bef72015-12-02 15:51:10 -08001004 updateChildrenHeaderAppearance();
Selim Cinek8fc93c92015-11-23 17:48:07 -08001005 updateHeaderChildCount();
Selim Cinek343e6e22014-04-11 21:23:30 +02001006 }
Selim Cinek7d447722014-06-10 15:51:59 +02001007
Selim Cinek7b836392015-12-04 20:02:59 -08001008 private void updateHeaderExpandButton() {
1009 if (mIsSummaryWithChildren) {
1010 mNotificationHeader.setIsGroupHeader(true /* isGroupHeader*/);
1011 }
1012 }
1013
Selim Cinekea4bef72015-12-02 15:51:10 -08001014 public void updateChildrenHeaderAppearance() {
1015 if (mIsSummaryWithChildren) {
1016 mHeaderUtil.updateChildrenHeaderAppearance();
1017 }
1018 }
1019
Selim Cinek31094df2014-08-14 19:28:15 +02001020 public boolean isMaxExpandHeightInitialized() {
1021 return mMaxExpandHeight != 0;
Selim Cinek7d447722014-06-10 15:51:59 +02001022 }
Selim Cinek2f0df8a2014-06-10 17:40:42 +02001023
1024 private NotificationContentView getShowingLayout() {
1025 return mShowingPublic ? mPublicLayout : mPrivateLayout;
1026 }
Chris Wren78403d72014-07-28 10:23:24 +01001027
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001028 @Override
1029 public void setShowingLegacyBackground(boolean showing) {
1030 super.setShowingLegacyBackground(showing);
1031 mPrivateLayout.setShowingLegacyBackground(showing);
1032 mPublicLayout.setShowingLegacyBackground(showing);
1033 }
1034
Selim Cineka6c6bfb2015-10-29 16:27:08 -07001035 @Override
1036 protected void updateBackgroundTint() {
1037 super.updateBackgroundTint();
1038 updateNoBackgroundState();
1039 if (mIsSummaryWithChildren) {
1040 List<ExpandableNotificationRow> notificationChildren =
1041 mChildrenContainer.getNotificationChildren();
1042 for (int i = 0; i < notificationChildren.size(); i++) {
1043 ExpandableNotificationRow child = notificationChildren.get(i);
1044 child.updateNoBackgroundState();
1045 }
1046 }
1047 }
1048
1049 private void updateNoBackgroundState() {
1050 mShowNoBackground = isChildInGroup() && hasSameBgColor(mNotificationParent);
1051 updateBackground();
1052 }
1053
Chris Wren78403d72014-07-28 10:23:24 +01001054 public void setExpansionLogger(ExpansionLogger logger, String key) {
1055 mLogger = logger;
1056 mLoggingKey = key;
1057 }
1058
Chris Wren78403d72014-07-28 10:23:24 +01001059 private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
1060 final boolean nowExpanded = isExpanded();
1061 if (wasExpanded != nowExpanded && mLogger != null) {
1062 mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
1063 }
1064 }
Selim Cinek570981d2015-12-01 11:37:01 -08001065
1066 public interface OnExpandClickListener {
1067 void onExpandClicked(View clickedView, boolean nowExpanded);
1068 }
Chris Wren51c75102013-07-16 20:49:17 -04001069}