blob: a4c17e3681b016329071117529a01b0e76585aa2 [file] [log] [blame]
Jorim Jaggibe565df2014-04-28 17:51:23 +02001/*
2 * Copyright (C) 2014 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
Adrian Roosb88b1a12015-12-09 18:51:05 -080019import android.app.Notification;
Adrian Roos4c1fcc82016-03-31 14:39:39 -070020import android.app.PendingIntent;
Adrian Roosb88b1a12015-12-09 18:51:05 -080021import android.app.RemoteInput;
Jorim Jaggibe565df2014-04-28 17:51:23 +020022import android.content.Context;
23import android.graphics.Rect;
Selim Cinek860b6da2015-12-16 19:02:19 -080024import android.os.Build;
Petr Cermak7997d7a2018-01-18 15:52:10 +000025import android.provider.Settings;
Selim Cinek83bc7832015-10-22 13:26:54 -070026import android.service.notification.StatusBarNotification;
Jorim Jaggibe565df2014-04-28 17:51:23 +020027import android.util.AttributeSet;
Selim Cinek011bde92017-11-22 05:53:38 -080028import android.util.Log;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080029import android.view.NotificationHeaderView;
Jorim Jaggibe565df2014-04-28 17:51:23 +020030import android.view.View;
Selim Cinek8d490d42015-04-10 00:05:50 -070031import android.view.ViewGroup;
Selim Cinekbb3d1cf2014-10-31 00:12:56 +010032import android.view.ViewTreeObserver;
Selim Cinekc9c00ae2014-05-20 03:33:40 +020033import android.widget.FrameLayout;
Selim Cineke9bad242016-06-15 11:46:37 -070034import android.widget.ImageView;
Petr Cermak7997d7a2018-01-18 15:52:10 +000035import android.widget.LinearLayout;
Selim Cinek8d490d42015-04-10 00:05:50 -070036
Adrian Roose18033c2017-01-17 15:22:49 -080037import com.android.internal.annotations.VisibleForTesting;
Adrian Roos4ff3b122016-02-01 12:26:13 -080038import com.android.internal.util.NotificationColorUtil;
Jorim Jaggibe565df2014-04-28 17:51:23 +020039import com.android.systemui.R;
Selim Cinekc897bd32016-03-18 17:32:31 -070040import com.android.systemui.statusbar.notification.HybridGroupManager;
Selim Cinek011bde92017-11-22 05:53:38 -080041import com.android.systemui.statusbar.notification.HybridNotificationView;
Selim Cinek0ffbda62016-01-01 20:29:12 +010042import com.android.systemui.statusbar.notification.NotificationCustomViewWrapper;
Selim Cinekc3179332016-03-04 14:44:56 -080043import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cinek0ffbda62016-01-01 20:29:12 +010044import com.android.systemui.statusbar.notification.NotificationViewWrapper;
Selim Cinek83bc7832015-10-22 13:26:54 -070045import com.android.systemui.statusbar.phone.NotificationGroupManager;
Adrian Roosb88b1a12015-12-09 18:51:05 -080046import com.android.systemui.statusbar.policy.RemoteInputView;
Petr Cermak7997d7a2018-01-18 15:52:10 +000047import com.android.systemui.statusbar.policy.SmartReplyView;
Jorim Jaggibe565df2014-04-28 17:51:23 +020048
49/**
Selim Cinek684a4422015-04-15 16:18:39 -070050 * A frame layout containing the actual payload of the notification, including the contracted,
51 * expanded and heads up layout. This class is responsible for clipping the content and and
52 * switching between the expanded, contracted and the heads up view depending on its clipped size.
Jorim Jaggibe565df2014-04-28 17:51:23 +020053 */
Selim Cinekc9c00ae2014-05-20 03:33:40 +020054public class NotificationContentView extends FrameLayout {
Jorim Jaggibe565df2014-04-28 17:51:23 +020055
Selim Cinek011bde92017-11-22 05:53:38 -080056 private static final String TAG = "NotificationContentView";
Selim Cinek131f1a42017-06-05 17:50:19 -070057 public static final int VISIBLE_TYPE_CONTRACTED = 0;
58 public static final int VISIBLE_TYPE_EXPANDED = 1;
59 public static final int VISIBLE_TYPE_HEADSUP = 2;
Selim Cinek83bc7832015-10-22 13:26:54 -070060 private static final int VISIBLE_TYPE_SINGLELINE = 3;
Selim Cinek131f1a42017-06-05 17:50:19 -070061 public static final int VISIBLE_TYPE_AMBIENT = 4;
Adrian Roos6f6e1592017-05-02 16:22:53 -070062 private static final int VISIBLE_TYPE_AMBIENT_SINGLELINE = 5;
Selim Cinekc3179332016-03-04 14:44:56 -080063 public static final int UNDEFINED = -1;
Jorim Jaggi11298832014-05-24 16:18:38 +020064
Jorim Jaggibe565df2014-04-28 17:51:23 +020065 private final Rect mClipBounds = new Rect();
66
Selim Cinek9b49f6d2017-11-13 18:19:35 -080067 private int mMinContractedHeight;
68 private int mNotificationContentMarginEnd;
Jorim Jaggibe565df2014-04-28 17:51:23 +020069 private View mContractedChild;
70 private View mExpandedChild;
Selim Cinek8d490d42015-04-10 00:05:50 -070071 private View mHeadsUpChild;
Selim Cinek83bc7832015-10-22 13:26:54 -070072 private HybridNotificationView mSingleLineView;
Adrian Roos0aac04f2016-12-08 15:59:29 -080073 private View mAmbientChild;
Adrian Roos6f6e1592017-05-02 16:22:53 -070074 private HybridNotificationView mAmbientSingleLineChild;
Jorim Jaggibe565df2014-04-28 17:51:23 +020075
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070076 private RemoteInputView mExpandedRemoteInput;
77 private RemoteInputView mHeadsUpRemoteInput;
Petr Cermak7997d7a2018-01-18 15:52:10 +000078 private SmartReplyView mExpandedSmartReplyView;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070079
Jorim Jaggi4e857f42014-11-17 19:14:04 +010080 private NotificationViewWrapper mContractedWrapper;
Jorim Jaggibe4116a2015-05-20 20:04:08 -070081 private NotificationViewWrapper mExpandedWrapper;
82 private NotificationViewWrapper mHeadsUpWrapper;
Adrian Roos0aac04f2016-12-08 15:59:29 -080083 private NotificationViewWrapper mAmbientWrapper;
Selim Cinekc897bd32016-03-18 17:32:31 -070084 private HybridGroupManager mHybridGroupManager;
Selim Cinekc9c00ae2014-05-20 03:33:40 +020085 private int mClipTopAmount;
Selim Cinekb5605e52015-02-20 18:21:41 +010086 private int mContentHeight;
Selim Cinek684a4422015-04-15 16:18:39 -070087 private int mVisibleType = VISIBLE_TYPE_CONTRACTED;
John Spurlocke15452b2014-08-21 09:44:39 -040088 private boolean mDark;
Selim Cinekbb3d1cf2014-10-31 00:12:56 +010089 private boolean mAnimate;
Selim Cinek684a4422015-04-15 16:18:39 -070090 private boolean mIsHeadsUp;
Selim Cinek1a48bab2017-02-17 19:38:40 -080091 private boolean mLegacy;
Selim Cinek83bc7832015-10-22 13:26:54 -070092 private boolean mIsChildInGroup;
Selim Cinek816c8e42015-11-19 12:00:45 -080093 private int mSmallHeight;
Selim Cinek77019c72015-12-09 10:18:02 -080094 private int mHeadsUpHeight;
Selim Cinekd84a5932015-12-15 11:45:36 -080095 private int mNotificationMaxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -080096 private int mNotificationAmbientHeight;
Selim Cinek83bc7832015-10-22 13:26:54 -070097 private StatusBarNotification mStatusBarNotification;
Selim Cinek65b2e7c2015-10-26 14:11:31 -070098 private NotificationGroupManager mGroupManager;
Adrian Roosb88b1a12015-12-09 18:51:05 -080099 private RemoteInputController mRemoteInputController;
Adrian Roos4320e892017-01-24 12:50:34 -0800100 private Runnable mExpandedVisibleListener;
Jorim Jaggi59ec3042015-06-05 15:18:43 -0700101
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700102 private final ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100103 = new ViewTreeObserver.OnPreDrawListener() {
104 @Override
105 public boolean onPreDraw() {
Selim Cinekd1ad9ab2016-03-01 17:52:20 -0800106 // We need to post since we don't want the notification to animate on the very first
107 // frame
108 post(new Runnable() {
109 @Override
110 public void run() {
111 mAnimate = true;
112 }
113 });
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100114 getViewTreeObserver().removeOnPreDrawListener(this);
115 return true;
116 }
117 };
Jorim Jaggi11298832014-05-24 16:18:38 +0200118
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800119 private OnClickListener mExpandClickListener;
Selim Cinek860b6da2015-12-16 19:02:19 -0800120 private boolean mBeforeN;
Selim Cinek98be3f32015-12-17 16:39:06 -0800121 private boolean mExpandable;
Selim Cinek4ffd6362015-12-29 15:12:23 +0100122 private boolean mClipToActualHeight = true;
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800123 private ExpandableNotificationRow mContainingNotification;
Adrian Roos599be342016-06-13 14:54:39 -0700124 /** The visible type at the start of a touch driven transformation */
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800125 private int mTransformationStartVisibleType;
Adrian Roos599be342016-06-13 14:54:39 -0700126 /** The visible type at the start of an animation driven transformation */
127 private int mAnimationStartVisibleType = UNDEFINED;
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800128 private boolean mUserExpanding;
Selim Cinekc897bd32016-03-18 17:32:31 -0700129 private int mSingleLineWidthIndention;
Selim Cinek589fd3e2016-04-26 18:17:57 -0700130 private boolean mForceSelectNextLayout = true;
Adrian Roos4c1fcc82016-03-31 14:39:39 -0700131 private PendingIntent mPreviousExpandedRemoteInputIntent;
132 private PendingIntent mPreviousHeadsUpRemoteInputIntent;
Adrian Roos7813dd72016-09-23 17:12:17 -0700133 private RemoteInputView mCachedExpandedRemoteInput;
134 private RemoteInputView mCachedHeadsUpRemoteInput;
Selim Cinek98be3f32015-12-17 16:39:06 -0800135
Adrian Roos599be342016-06-13 14:54:39 -0700136 private int mContentHeightAtAnimationStart = UNDEFINED;
Selim Cineke9bad242016-06-15 11:46:37 -0700137 private boolean mFocusOnVisibilityChange;
Selim Cinekcafa87f2016-10-26 17:00:17 -0700138 private boolean mHeadsUpAnimatingAway;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700139 private boolean mIconsVisible;
Selim Cineka686b2c2016-10-26 13:58:27 -0700140 private int mClipBottomAmount;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800141 private boolean mIsLowPriority;
Selim Cinekc0ac4af2017-03-03 15:13:48 -0800142 private boolean mIsContentExpandable;
Adrian Roos599be342016-06-13 14:54:39 -0700143
144
Jorim Jaggibe565df2014-04-28 17:51:23 +0200145 public NotificationContentView(Context context, AttributeSet attrs) {
146 super(context, attrs);
Selim Cinekc897bd32016-03-18 17:32:31 -0700147 mHybridGroupManager = new HybridGroupManager(getContext(), this);
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800148 initView();
149 }
150
151 public void initView() {
Selim Cinek860b6da2015-12-16 19:02:19 -0800152 mMinContractedHeight = getResources().getDimensionPixelSize(
153 R.dimen.min_notification_layout_height);
Selim Cinek6ecc8102016-01-26 18:26:19 -0800154 mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
155 com.android.internal.R.dimen.notification_content_margin_end);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200156 }
157
Adrian Roos0aac04f2016-12-08 15:59:29 -0800158 public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight,
159 int ambientHeight) {
Selim Cinek816c8e42015-11-19 12:00:45 -0800160 mSmallHeight = smallHeight;
Selim Cinek77019c72015-12-09 10:18:02 -0800161 mHeadsUpHeight = headsUpMaxHeight;
Selim Cinekd84a5932015-12-15 11:45:36 -0800162 mNotificationMaxHeight = maxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800163 mNotificationAmbientHeight = ambientHeight;
Selim Cinek816c8e42015-11-19 12:00:45 -0800164 }
165
Jorim Jaggibe565df2014-04-28 17:51:23 +0200166 @Override
Selim Cinek8d490d42015-04-10 00:05:50 -0700167 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
168 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
169 boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
170 boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
171 int maxSize = Integer.MAX_VALUE;
Selim Cinekc897bd32016-03-18 17:32:31 -0700172 int width = MeasureSpec.getSize(widthMeasureSpec);
Selim Cinek8d490d42015-04-10 00:05:50 -0700173 if (hasFixedHeight || isHeightLimited) {
174 maxSize = MeasureSpec.getSize(heightMeasureSpec);
175 }
176 int maxChildHeight = 0;
Selim Cinek6ecc8102016-01-26 18:26:19 -0800177 if (mExpandedChild != null) {
178 int size = Math.min(maxSize, mNotificationMaxHeight);
179 ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800180 boolean useExactly = false;
Selim Cinek6ecc8102016-01-26 18:26:19 -0800181 if (layoutParams.height >= 0) {
182 // An actual height is set
183 size = Math.min(maxSize, layoutParams.height);
Selim Cinek6743c0b2017-01-18 18:24:01 -0800184 useExactly = true;
Selim Cinek6ecc8102016-01-26 18:26:19 -0800185 }
186 int spec = size == Integer.MAX_VALUE
187 ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
Selim Cinek6743c0b2017-01-18 18:24:01 -0800188 : MeasureSpec.makeMeasureSpec(size, useExactly
189 ? MeasureSpec.EXACTLY
190 : MeasureSpec.AT_MOST);
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800191 measureChildWithMargins(mExpandedChild, widthMeasureSpec, 0, spec, 0);
Selim Cinek6ecc8102016-01-26 18:26:19 -0800192 maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
193 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700194 if (mContractedChild != null) {
Selim Cinek860b6da2015-12-16 19:02:19 -0800195 int heightSpec;
Selim Cinekf619ffc2016-02-17 14:53:05 -0800196 int size = Math.min(maxSize, mSmallHeight);
Selim Cinek6743c0b2017-01-18 18:24:01 -0800197 ViewGroup.LayoutParams layoutParams = mContractedChild.getLayoutParams();
198 boolean useExactly = false;
199 if (layoutParams.height >= 0) {
200 // An actual height is set
201 size = Math.min(size, layoutParams.height);
202 useExactly = true;
203 }
204 if (shouldContractedBeFixedSize() || useExactly) {
Selim Cinek860b6da2015-12-16 19:02:19 -0800205 heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
206 } else {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800207 heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
Selim Cinek860b6da2015-12-16 19:02:19 -0800208 }
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800209 measureChildWithMargins(mContractedChild, widthMeasureSpec, 0, heightSpec, 0);
Selim Cinek860b6da2015-12-16 19:02:19 -0800210 int measuredHeight = mContractedChild.getMeasuredHeight();
211 if (measuredHeight < mMinContractedHeight) {
212 heightSpec = MeasureSpec.makeMeasureSpec(mMinContractedHeight, MeasureSpec.EXACTLY);
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800213 measureChildWithMargins(mContractedChild, widthMeasureSpec, 0, heightSpec, 0);
Selim Cinek860b6da2015-12-16 19:02:19 -0800214 }
215 maxChildHeight = Math.max(maxChildHeight, measuredHeight);
Selim Cinek6ecc8102016-01-26 18:26:19 -0800216 if (updateContractedHeaderWidth()) {
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800217 measureChildWithMargins(mContractedChild, widthMeasureSpec, 0, heightSpec, 0);
Selim Cinek8d490d42015-04-10 00:05:50 -0700218 }
Selim Cinek1ba41d12016-04-21 16:14:46 -0700219 if (mExpandedChild != null
220 && mContractedChild.getMeasuredHeight() > mExpandedChild.getMeasuredHeight()) {
221 // the Expanded child is smaller then the collapsed. Let's remeasure it.
222 heightSpec = MeasureSpec.makeMeasureSpec(mContractedChild.getMeasuredHeight(),
223 MeasureSpec.EXACTLY);
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800224 measureChildWithMargins(mExpandedChild, widthMeasureSpec, 0, heightSpec, 0);
Selim Cinek1ba41d12016-04-21 16:14:46 -0700225 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700226 }
227 if (mHeadsUpChild != null) {
228 int size = Math.min(maxSize, mHeadsUpHeight);
229 ViewGroup.LayoutParams layoutParams = mHeadsUpChild.getLayoutParams();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800230 boolean useExactly = false;
Selim Cinek8d490d42015-04-10 00:05:50 -0700231 if (layoutParams.height >= 0) {
232 // An actual height is set
Selim Cinek77019c72015-12-09 10:18:02 -0800233 size = Math.min(size, layoutParams.height);
Selim Cinek6743c0b2017-01-18 18:24:01 -0800234 useExactly = true;
Selim Cinek8d490d42015-04-10 00:05:50 -0700235 }
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800236 measureChildWithMargins(mHeadsUpChild, widthMeasureSpec, 0,
Selim Cinek6743c0b2017-01-18 18:24:01 -0800237 MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800238 : MeasureSpec.AT_MOST), 0);
Selim Cinek8d490d42015-04-10 00:05:50 -0700239 maxChildHeight = Math.max(maxChildHeight, mHeadsUpChild.getMeasuredHeight());
240 }
Selim Cinek83bc7832015-10-22 13:26:54 -0700241 if (mSingleLineView != null) {
Selim Cinekc897bd32016-03-18 17:32:31 -0700242 int singleLineWidthSpec = widthMeasureSpec;
243 if (mSingleLineWidthIndention != 0
244 && MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
245 singleLineWidthSpec = MeasureSpec.makeMeasureSpec(
246 width - mSingleLineWidthIndention + mSingleLineView.getPaddingEnd(),
Selim Cinek09b7dea2016-08-30 11:28:19 -0700247 MeasureSpec.EXACTLY);
Selim Cinekc897bd32016-03-18 17:32:31 -0700248 }
249 mSingleLineView.measure(singleLineWidthSpec,
Selim Cinek7b836392015-12-04 20:02:59 -0800250 MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST));
Selim Cinek83bc7832015-10-22 13:26:54 -0700251 maxChildHeight = Math.max(maxChildHeight, mSingleLineView.getMeasuredHeight());
252 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800253 if (mAmbientChild != null) {
254 int size = Math.min(maxSize, mNotificationAmbientHeight);
255 ViewGroup.LayoutParams layoutParams = mAmbientChild.getLayoutParams();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800256 boolean useExactly = false;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800257 if (layoutParams.height >= 0) {
258 // An actual height is set
259 size = Math.min(size, layoutParams.height);
Selim Cinek6743c0b2017-01-18 18:24:01 -0800260 useExactly = true;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800261 }
262 mAmbientChild.measure(widthMeasureSpec,
Selim Cinek6743c0b2017-01-18 18:24:01 -0800263 MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
264 : MeasureSpec.AT_MOST));
Adrian Roos0aac04f2016-12-08 15:59:29 -0800265 maxChildHeight = Math.max(maxChildHeight, mAmbientChild.getMeasuredHeight());
266 }
Adrian Roos6f6e1592017-05-02 16:22:53 -0700267 if (mAmbientSingleLineChild != null) {
268 int size = Math.min(maxSize, mNotificationAmbientHeight);
269 ViewGroup.LayoutParams layoutParams = mAmbientSingleLineChild.getLayoutParams();
270 boolean useExactly = false;
271 if (layoutParams.height >= 0) {
272 // An actual height is set
273 size = Math.min(size, layoutParams.height);
274 useExactly = true;
275 }
276 int ambientSingleLineWidthSpec = widthMeasureSpec;
277 if (mSingleLineWidthIndention != 0
278 && MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
279 ambientSingleLineWidthSpec = MeasureSpec.makeMeasureSpec(
280 width - mSingleLineWidthIndention + mAmbientSingleLineChild.getPaddingEnd(),
281 MeasureSpec.EXACTLY);
282 }
283 mAmbientSingleLineChild.measure(ambientSingleLineWidthSpec,
284 MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
285 : MeasureSpec.AT_MOST));
286 maxChildHeight = Math.max(maxChildHeight, mAmbientSingleLineChild.getMeasuredHeight());
287 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700288 int ownHeight = Math.min(maxChildHeight, maxSize);
Selim Cinek8d490d42015-04-10 00:05:50 -0700289 setMeasuredDimension(width, ownHeight);
290 }
291
Selim Cinek6ecc8102016-01-26 18:26:19 -0800292 private boolean updateContractedHeaderWidth() {
293 // We need to update the expanded and the collapsed header to have exactly the same with to
294 // have the expand buttons laid out at the same location.
295 NotificationHeaderView contractedHeader = mContractedWrapper.getNotificationHeader();
296 if (contractedHeader != null) {
297 if (mExpandedChild != null
298 && mExpandedWrapper.getNotificationHeader() != null) {
299 NotificationHeaderView expandedHeader = mExpandedWrapper.getNotificationHeader();
300 int expandedSize = expandedHeader.getMeasuredWidth()
301 - expandedHeader.getPaddingEnd();
302 int collapsedSize = contractedHeader.getMeasuredWidth()
303 - expandedHeader.getPaddingEnd();
304 if (expandedSize != collapsedSize) {
305 int paddingEnd = contractedHeader.getMeasuredWidth() - expandedSize;
306 contractedHeader.setPadding(
Selim Cinekcb445682016-01-29 16:13:12 -0800307 contractedHeader.isLayoutRtl()
308 ? paddingEnd
309 : contractedHeader.getPaddingLeft(),
Selim Cinek6ecc8102016-01-26 18:26:19 -0800310 contractedHeader.getPaddingTop(),
Selim Cinekcb445682016-01-29 16:13:12 -0800311 contractedHeader.isLayoutRtl()
312 ? contractedHeader.getPaddingLeft()
313 : paddingEnd,
Selim Cinek6ecc8102016-01-26 18:26:19 -0800314 contractedHeader.getPaddingBottom());
315 contractedHeader.setShowWorkBadgeAtEnd(true);
316 return true;
317 }
318 } else {
319 int paddingEnd = mNotificationContentMarginEnd;
320 if (contractedHeader.getPaddingEnd() != paddingEnd) {
321 contractedHeader.setPadding(
Selim Cinekcb445682016-01-29 16:13:12 -0800322 contractedHeader.isLayoutRtl()
323 ? paddingEnd
324 : contractedHeader.getPaddingLeft(),
Selim Cinek6ecc8102016-01-26 18:26:19 -0800325 contractedHeader.getPaddingTop(),
Selim Cinekcb445682016-01-29 16:13:12 -0800326 contractedHeader.isLayoutRtl()
327 ? contractedHeader.getPaddingLeft()
328 : paddingEnd,
Selim Cinek6ecc8102016-01-26 18:26:19 -0800329 contractedHeader.getPaddingBottom());
330 contractedHeader.setShowWorkBadgeAtEnd(false);
331 return true;
332 }
333 }
334 }
335 return false;
336 }
337
Selim Cinek860b6da2015-12-16 19:02:19 -0800338 private boolean shouldContractedBeFixedSize() {
339 return mBeforeN && mContractedWrapper instanceof NotificationCustomViewWrapper;
340 }
341
Selim Cinek8d490d42015-04-10 00:05:50 -0700342 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +0200343 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Adrian Roos599be342016-06-13 14:54:39 -0700344 int previousHeight = 0;
345 if (mExpandedChild != null) {
346 previousHeight = mExpandedChild.getHeight();
347 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200348 super.onLayout(changed, left, top, right, bottom);
Adrian Roos599be342016-06-13 14:54:39 -0700349 if (previousHeight != 0 && mExpandedChild.getHeight() != previousHeight) {
350 mContentHeightAtAnimationStart = previousHeight;
351 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200352 updateClipping();
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700353 invalidateOutline();
Selim Cinek589fd3e2016-04-26 18:17:57 -0700354 selectLayout(false /* animate */, mForceSelectNextLayout /* force */);
355 mForceSelectNextLayout = false;
Selim Cinek5f56d852016-05-24 16:55:13 -0700356 updateExpandButtons(mExpandable);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200357 }
358
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100359 @Override
Selim Cinek7b8157e2014-11-20 16:00:32 +0100360 protected void onAttachedToWindow() {
361 super.onAttachedToWindow();
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100362 updateVisibility();
363 }
364
Selim Cinekcab4a602014-09-03 14:47:57 +0200365 public View getContractedChild() {
366 return mContractedChild;
367 }
368
369 public View getExpandedChild() {
370 return mExpandedChild;
371 }
372
Selim Cinek8d490d42015-04-10 00:05:50 -0700373 public View getHeadsUpChild() {
374 return mHeadsUpChild;
375 }
376
Adrian Roos0aac04f2016-12-08 15:59:29 -0800377 public View getAmbientChild() {
378 return mAmbientChild;
379 }
380
Adrian Roos6f6e1592017-05-02 16:22:53 -0700381 public HybridNotificationView getAmbientSingleLineChild() {
382 return mAmbientSingleLineChild;
383 }
384
Jorim Jaggibe565df2014-04-28 17:51:23 +0200385 public void setContractedChild(View child) {
386 if (mContractedChild != null) {
Jorim Jaggi0d9f35d2014-08-20 17:06:55 +0200387 mContractedChild.animate().cancel();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200388 removeView(mContractedChild);
389 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200390 addView(child);
391 mContractedChild = child;
Selim Cinek7d1c63e2016-04-21 15:26:10 -0700392 mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child,
393 mContainingNotification);
Jorim Jaggi10ad7612014-12-08 18:41:11 +0100394 mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800395 }
396
397 private NotificationViewWrapper getWrapperForView(View child) {
398 if (child == mContractedChild) {
399 return mContractedWrapper;
400 }
401 if (child == mExpandedChild) {
402 return mExpandedWrapper;
403 }
404 if (child == mHeadsUpChild) {
405 return mHeadsUpWrapper;
406 }
407 if (child == mAmbientChild) {
408 return mAmbientWrapper;
409 }
410 return null;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200411 }
412
413 public void setExpandedChild(View child) {
414 if (mExpandedChild != null) {
Selim Cinek1a48bab2017-02-17 19:38:40 -0800415 mPreviousExpandedRemoteInputIntent = null;
416 if (mExpandedRemoteInput != null) {
417 mExpandedRemoteInput.onNotificationUpdateOrReset();
418 if (mExpandedRemoteInput.isActive()) {
419 mPreviousExpandedRemoteInputIntent = mExpandedRemoteInput.getPendingIntent();
420 mCachedExpandedRemoteInput = mExpandedRemoteInput;
421 mExpandedRemoteInput.dispatchStartTemporaryDetach();
422 ((ViewGroup)mExpandedRemoteInput.getParent()).removeView(mExpandedRemoteInput);
423 }
424 }
Jorim Jaggi0d9f35d2014-08-20 17:06:55 +0200425 mExpandedChild.animate().cancel();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200426 removeView(mExpandedChild);
Selim Cinek1a48bab2017-02-17 19:38:40 -0800427 mExpandedRemoteInput = null;
428 }
429 if (child == null) {
430 mExpandedChild = null;
431 mExpandedWrapper = null;
432 if (mVisibleType == VISIBLE_TYPE_EXPANDED) {
433 mVisibleType = VISIBLE_TYPE_CONTRACTED;
434 }
435 if (mTransformationStartVisibleType == VISIBLE_TYPE_EXPANDED) {
436 mTransformationStartVisibleType = UNDEFINED;
437 }
438 return;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200439 }
440 addView(child);
441 mExpandedChild = child;
Selim Cinek7d1c63e2016-04-21 15:26:10 -0700442 mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child,
443 mContainingNotification);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200444 }
445
Selim Cinek8d490d42015-04-10 00:05:50 -0700446 public void setHeadsUpChild(View child) {
447 if (mHeadsUpChild != null) {
Selim Cinek1a48bab2017-02-17 19:38:40 -0800448 mPreviousHeadsUpRemoteInputIntent = null;
449 if (mHeadsUpRemoteInput != null) {
450 mHeadsUpRemoteInput.onNotificationUpdateOrReset();
451 if (mHeadsUpRemoteInput.isActive()) {
452 mPreviousHeadsUpRemoteInputIntent = mHeadsUpRemoteInput.getPendingIntent();
453 mCachedHeadsUpRemoteInput = mHeadsUpRemoteInput;
454 mHeadsUpRemoteInput.dispatchStartTemporaryDetach();
455 ((ViewGroup)mHeadsUpRemoteInput.getParent()).removeView(mHeadsUpRemoteInput);
456 }
457 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700458 mHeadsUpChild.animate().cancel();
459 removeView(mHeadsUpChild);
Selim Cinek1a48bab2017-02-17 19:38:40 -0800460 mHeadsUpRemoteInput = null;
461 }
462 if (child == null) {
463 mHeadsUpChild = null;
464 mHeadsUpWrapper = null;
465 if (mVisibleType == VISIBLE_TYPE_HEADSUP) {
466 mVisibleType = VISIBLE_TYPE_CONTRACTED;
467 }
468 if (mTransformationStartVisibleType == VISIBLE_TYPE_HEADSUP) {
469 mTransformationStartVisibleType = UNDEFINED;
470 }
471 return;
Selim Cinek8d490d42015-04-10 00:05:50 -0700472 }
473 addView(child);
474 mHeadsUpChild = child;
Selim Cinek7d1c63e2016-04-21 15:26:10 -0700475 mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child,
476 mContainingNotification);
Selim Cinek8d490d42015-04-10 00:05:50 -0700477 }
478
Adrian Roos0aac04f2016-12-08 15:59:29 -0800479 public void setAmbientChild(View child) {
480 if (mAmbientChild != null) {
481 mAmbientChild.animate().cancel();
482 removeView(mAmbientChild);
483 }
Adrian Roos1a1ecfc2017-04-17 11:17:59 -0700484 if (child == null) {
485 return;
486 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800487 addView(child);
488 mAmbientChild = child;
489 mAmbientWrapper = NotificationViewWrapper.wrap(getContext(), child,
490 mContainingNotification);
491 }
492
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100493 @Override
494 protected void onVisibilityChanged(View changedView, int visibility) {
495 super.onVisibilityChanged(changedView, visibility);
496 updateVisibility();
497 }
498
499 private void updateVisibility() {
500 setVisible(isShown());
501 }
502
Jorim Jaggi38b5ec92016-04-12 01:39:49 -0700503 @Override
504 protected void onDetachedFromWindow() {
505 super.onDetachedFromWindow();
506 getViewTreeObserver().removeOnPreDrawListener(mEnableAnimationPredrawListener);
507 }
508
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100509 private void setVisible(final boolean isVisible) {
510 if (isVisible) {
Selim Cinekf1614a62016-05-26 16:57:20 -0700511 // This call can happen multiple times, but removing only removes a single one.
512 // We therefore need to remove the old one.
513 getViewTreeObserver().removeOnPreDrawListener(mEnableAnimationPredrawListener);
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100514 // We only animate if we are drawn at least once, otherwise the view might animate when
515 // it's shown the first time
516 getViewTreeObserver().addOnPreDrawListener(mEnableAnimationPredrawListener);
517 } else {
518 getViewTreeObserver().removeOnPreDrawListener(mEnableAnimationPredrawListener);
519 mAnimate = false;
520 }
521 }
522
Selim Cineke9bad242016-06-15 11:46:37 -0700523 private void focusExpandButtonIfNecessary() {
524 if (mFocusOnVisibilityChange) {
525 NotificationHeaderView header = getVisibleNotificationHeader();
526 if (header != null) {
527 ImageView expandButton = header.getExpandButton();
528 if (expandButton != null) {
529 expandButton.requestAccessibilityFocus();
530 }
531 }
532 mFocusOnVisibilityChange = false;
533 }
534 }
535
Selim Cinekb5605e52015-02-20 18:21:41 +0100536 public void setContentHeight(int contentHeight) {
Mady Mellorb0a82462016-04-30 17:31:02 -0700537 mContentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight());
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100538 selectLayout(mAnimate /* animate */, false /* force */);
Adrian Roos181385c2016-05-05 17:45:44 -0400539
540 int minHeightHint = getMinContentHeightHint();
541
542 NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
543 if (wrapper != null) {
544 wrapper.setContentHeight(mContentHeight, minHeightHint);
545 }
546
547 wrapper = getVisibleWrapper(mTransformationStartVisibleType);
548 if (wrapper != null) {
549 wrapper.setContentHeight(mContentHeight, minHeightHint);
550 }
551
Jorim Jaggibe565df2014-04-28 17:51:23 +0200552 updateClipping();
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700553 invalidateOutline();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200554 }
555
Adrian Roos181385c2016-05-05 17:45:44 -0400556 /**
557 * @return the minimum apparent height that the wrapper should allow for the purpose
558 * of aligning elements at the bottom edge. If this is larger than the content
559 * height, the notification is clipped instead of being further shrunk.
560 */
561 private int getMinContentHeightHint() {
Adrian Roos599be342016-06-13 14:54:39 -0700562 if (mIsChildInGroup && isVisibleOrTransitioning(VISIBLE_TYPE_SINGLELINE)) {
Adrian Roos181385c2016-05-05 17:45:44 -0400563 return mContext.getResources().getDimensionPixelSize(
564 com.android.internal.R.dimen.notification_action_list_height);
565 }
Adrian Roos599be342016-06-13 14:54:39 -0700566
567 // Transition between heads-up & expanded, or pinned.
568 if (mHeadsUpChild != null && mExpandedChild != null) {
569 boolean transitioningBetweenHunAndExpanded =
570 isTransitioningFromTo(VISIBLE_TYPE_HEADSUP, VISIBLE_TYPE_EXPANDED) ||
571 isTransitioningFromTo(VISIBLE_TYPE_EXPANDED, VISIBLE_TYPE_HEADSUP);
Selim Cinek73cf02a2016-06-17 13:08:00 -0700572 boolean pinned = !isVisibleOrTransitioning(VISIBLE_TYPE_CONTRACTED)
Selim Cinekc494e382017-01-31 16:09:23 -0800573 && (mIsHeadsUp || mHeadsUpAnimatingAway)
574 && !mContainingNotification.isOnKeyguard();
Adrian Roos599be342016-06-13 14:54:39 -0700575 if (transitioningBetweenHunAndExpanded || pinned) {
576 return Math.min(mHeadsUpChild.getHeight(), mExpandedChild.getHeight());
577 }
578 }
579
580 // Size change of the expanded version
581 if ((mVisibleType == VISIBLE_TYPE_EXPANDED) && mContentHeightAtAnimationStart >= 0
582 && mExpandedChild != null) {
583 return Math.min(mContentHeightAtAnimationStart, mExpandedChild.getHeight());
584 }
585
Adrian Roosbb73e9c62016-05-26 12:06:40 -0700586 int hint;
Adrian Roos05d3d002017-01-26 15:28:07 -0800587 if (mAmbientChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_AMBIENT)) {
588 hint = mAmbientChild.getHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -0700589 } else if (mAmbientSingleLineChild != null && isVisibleOrTransitioning(
590 VISIBLE_TYPE_AMBIENT_SINGLELINE)) {
591 hint = mAmbientSingleLineChild.getHeight();
Adrian Roos05d3d002017-01-26 15:28:07 -0800592 } else if (mHeadsUpChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_HEADSUP)) {
Adrian Roosbb73e9c62016-05-26 12:06:40 -0700593 hint = mHeadsUpChild.getHeight();
Adrian Roos599be342016-06-13 14:54:39 -0700594 } else if (mExpandedChild != null) {
595 hint = mExpandedChild.getHeight();
Adrian Roos181385c2016-05-05 17:45:44 -0400596 } else {
Adrian Roosbb73e9c62016-05-26 12:06:40 -0700597 hint = mContractedChild.getHeight() + mContext.getResources().getDimensionPixelSize(
598 com.android.internal.R.dimen.notification_action_list_height);
Adrian Roos181385c2016-05-05 17:45:44 -0400599 }
Adrian Roos599be342016-06-13 14:54:39 -0700600
601 if (mExpandedChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_EXPANDED)) {
Adrian Roosbb73e9c62016-05-26 12:06:40 -0700602 hint = Math.min(hint, mExpandedChild.getHeight());
603 }
604 return hint;
Adrian Roos181385c2016-05-05 17:45:44 -0400605 }
606
Adrian Roos599be342016-06-13 14:54:39 -0700607 private boolean isTransitioningFromTo(int from, int to) {
608 return (mTransformationStartVisibleType == from || mAnimationStartVisibleType == from)
609 && mVisibleType == to;
610 }
611
612 private boolean isVisibleOrTransitioning(int type) {
613 return mVisibleType == type || mTransformationStartVisibleType == type
614 || mAnimationStartVisibleType == type;
615 }
616
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800617 private void updateContentTransformation() {
618 int visibleType = calculateVisibleType();
619 if (visibleType != mVisibleType) {
620 // A new transformation starts
621 mTransformationStartVisibleType = mVisibleType;
622 final TransformableView shownView = getTransformableViewForVisibleType(visibleType);
623 final TransformableView hiddenView = getTransformableViewForVisibleType(
624 mTransformationStartVisibleType);
625 shownView.transformFrom(hiddenView, 0.0f);
626 getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
627 hiddenView.transformTo(shownView, 0.0f);
628 mVisibleType = visibleType;
Selim Cinekc3179332016-03-04 14:44:56 -0800629 updateBackgroundColor(true /* animate */);
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800630 }
Selim Cineke8578872016-05-03 16:42:50 -0700631 if (mForceSelectNextLayout) {
632 forceUpdateVisibilities();
633 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800634 if (mTransformationStartVisibleType != UNDEFINED
Selim Cinek589fd3e2016-04-26 18:17:57 -0700635 && mVisibleType != mTransformationStartVisibleType
636 && getViewForVisibleType(mTransformationStartVisibleType) != null) {
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800637 final TransformableView shownView = getTransformableViewForVisibleType(mVisibleType);
638 final TransformableView hiddenView = getTransformableViewForVisibleType(
639 mTransformationStartVisibleType);
640 float transformationAmount = calculateTransformationAmount();
641 shownView.transformFrom(hiddenView, transformationAmount);
642 hiddenView.transformTo(shownView, transformationAmount);
Selim Cinekc3179332016-03-04 14:44:56 -0800643 updateBackgroundTransformation(transformationAmount);
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800644 } else {
645 updateViewVisibilities(visibleType);
Selim Cinekc3179332016-03-04 14:44:56 -0800646 updateBackgroundColor(false);
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800647 }
648 }
649
Selim Cinekc3179332016-03-04 14:44:56 -0800650 private void updateBackgroundTransformation(float transformationAmount) {
651 int endColor = getBackgroundColor(mVisibleType);
652 int startColor = getBackgroundColor(mTransformationStartVisibleType);
653 if (endColor != startColor) {
654 if (startColor == 0) {
655 startColor = mContainingNotification.getBackgroundColorWithoutTint();
656 }
657 if (endColor == 0) {
658 endColor = mContainingNotification.getBackgroundColorWithoutTint();
659 }
660 endColor = NotificationUtils.interpolateColors(startColor, endColor,
661 transformationAmount);
662 }
Mady Mellorc7d65b42016-05-04 11:44:57 -0400663 mContainingNotification.updateBackgroundAlpha(transformationAmount);
Selim Cinekc3179332016-03-04 14:44:56 -0800664 mContainingNotification.setContentBackground(endColor, false, this);
665 }
666
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800667 private float calculateTransformationAmount() {
668 int startHeight = getViewForVisibleType(mTransformationStartVisibleType).getHeight();
669 int endHeight = getViewForVisibleType(mVisibleType).getHeight();
670 int progress = Math.abs(mContentHeight - startHeight);
671 int totalDistance = Math.abs(endHeight - startHeight);
Selim Cinek011bde92017-11-22 05:53:38 -0800672 if (totalDistance == 0) {
673 Log.wtf(TAG, "the total transformation distance is 0"
674 + "\n StartType: " + mTransformationStartVisibleType + " height: " + startHeight
675 + "\n VisibleType: " + mVisibleType + " height: " + endHeight
676 + "\n mContentHeight: " + mContentHeight);
677 return 1.0f;
678 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800679 float amount = (float) progress / (float) totalDistance;
680 return Math.min(1.0f, amount);
681 }
682
Selim Cinekb5605e52015-02-20 18:21:41 +0100683 public int getContentHeight() {
684 return mContentHeight;
685 }
686
Jorim Jaggibe565df2014-04-28 17:51:23 +0200687 public int getMaxHeight() {
Adrian Roos6f6e1592017-05-02 16:22:53 -0700688 if (mContainingNotification.isShowingAmbient()) {
689 return getShowingAmbientView().getHeight();
690 } else if (mExpandedChild != null) {
Selim Cinek8d490d42015-04-10 00:05:50 -0700691 return mExpandedChild.getHeight();
Selim Cinekc494e382017-01-31 16:09:23 -0800692 } else if (mIsHeadsUp && mHeadsUpChild != null && !mContainingNotification.isOnKeyguard()) {
Selim Cinek77019c72015-12-09 10:18:02 -0800693 return mHeadsUpChild.getHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -0700694 }
Selim Cinek860b6da2015-12-16 19:02:19 -0800695 return mContractedChild.getHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200696 }
697
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200698 public int getMinHeight() {
Selim Cinek42357e02016-02-24 18:48:01 -0800699 return getMinHeight(false /* likeGroupExpanded */);
700 }
701
702 public int getMinHeight(boolean likeGroupExpanded) {
Adrian Roos6f6e1592017-05-02 16:22:53 -0700703 if (mContainingNotification.isShowingAmbient()) {
704 return getShowingAmbientView().getHeight();
705 } else if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
Selim Cinek860b6da2015-12-16 19:02:19 -0800706 return mContractedChild.getHeight();
Selim Cinek42357e02016-02-24 18:48:01 -0800707 } else {
708 return mSingleLineView.getHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700709 }
710 }
711
Adrian Roos6f6e1592017-05-02 16:22:53 -0700712 public View getShowingAmbientView() {
713 View v = mIsChildInGroup ? mAmbientSingleLineChild : mAmbientChild;
714 if (v != null) {
715 return v;
716 } else {
717 return mContractedChild;
718 }
719 }
720
Selim Cinek83bc7832015-10-22 13:26:54 -0700721 private boolean isGroupExpanded() {
722 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200723 }
724
Jorim Jaggibe565df2014-04-28 17:51:23 +0200725 public void setClipTopAmount(int clipTopAmount) {
Selim Cinekc9c00ae2014-05-20 03:33:40 +0200726 mClipTopAmount = clipTopAmount;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200727 updateClipping();
728 }
729
Selim Cineka686b2c2016-10-26 13:58:27 -0700730
731 public void setClipBottomAmount(int clipBottomAmount) {
732 mClipBottomAmount = clipBottomAmount;
733 updateClipping();
734 }
735
Selim Cinek875a3a12016-11-18 17:52:16 -0800736 @Override
737 public void setTranslationY(float translationY) {
738 super.setTranslationY(translationY);
739 updateClipping();
740 }
741
Jorim Jaggibe565df2014-04-28 17:51:23 +0200742 private void updateClipping() {
Selim Cinek4ffd6362015-12-29 15:12:23 +0100743 if (mClipToActualHeight) {
Selim Cinek875a3a12016-11-18 17:52:16 -0800744 int top = (int) (mClipTopAmount - getTranslationY());
745 int bottom = (int) (mContentHeight - mClipBottomAmount - getTranslationY());
Selim Cineka686b2c2016-10-26 13:58:27 -0700746 bottom = Math.max(top, bottom);
747 mClipBounds.set(0, top, getWidth(), bottom);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100748 setClipBounds(mClipBounds);
749 } else {
750 setClipBounds(null);
751 }
752 }
753
754 public void setClipToActualHeight(boolean clipToActualHeight) {
755 mClipToActualHeight = clipToActualHeight;
756 updateClipping();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200757 }
758
Jorim Jaggi11298832014-05-24 16:18:38 +0200759 private void selectLayout(boolean animate, boolean force) {
760 if (mContractedChild == null) {
761 return;
762 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800763 if (mUserExpanding) {
764 updateContentTransformation();
Selim Cinek589fd3e2016-04-26 18:17:57 -0700765 } else {
766 int visibleType = calculateVisibleType();
Selim Cineke9bad242016-06-15 11:46:37 -0700767 boolean changedType = visibleType != mVisibleType;
768 if (changedType || force) {
Adrian Roos181385c2016-05-05 17:45:44 -0400769 View visibleView = getViewForVisibleType(visibleType);
770 if (visibleView != null) {
771 visibleView.setVisibility(VISIBLE);
772 transferRemoteInputFocus(visibleType);
773 }
Adrian Roos4c1fcc82016-03-31 14:39:39 -0700774
Selim Cinek589fd3e2016-04-26 18:17:57 -0700775 if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
776 || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
777 || (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null)
778 || visibleType == VISIBLE_TYPE_CONTRACTED)) {
779 animateToVisibleType(visibleType);
780 } else {
781 updateViewVisibilities(visibleType);
782 }
783 mVisibleType = visibleType;
Selim Cineke9bad242016-06-15 11:46:37 -0700784 if (changedType) {
785 focusExpandButtonIfNecessary();
786 }
Adrian Roos05d3d002017-01-26 15:28:07 -0800787 NotificationViewWrapper visibleWrapper = getVisibleWrapper(visibleType);
788 if (visibleWrapper != null) {
789 visibleWrapper.setContentHeight(mContentHeight, getMinContentHeightHint());
790 }
Selim Cinek589fd3e2016-04-26 18:17:57 -0700791 updateBackgroundColor(animate);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200792 }
Selim Cinek589fd3e2016-04-26 18:17:57 -0700793 }
Selim Cinek589fd3e2016-04-26 18:17:57 -0700794 }
795
796 private void forceUpdateVisibilities() {
Adrian Roos0aac04f2016-12-08 15:59:29 -0800797 forceUpdateVisibility(VISIBLE_TYPE_CONTRACTED, mContractedChild, mContractedWrapper);
798 forceUpdateVisibility(VISIBLE_TYPE_EXPANDED, mExpandedChild, mExpandedWrapper);
799 forceUpdateVisibility(VISIBLE_TYPE_HEADSUP, mHeadsUpChild, mHeadsUpWrapper);
800 forceUpdateVisibility(VISIBLE_TYPE_SINGLELINE, mSingleLineView, mSingleLineView);
801 forceUpdateVisibility(VISIBLE_TYPE_AMBIENT, mAmbientChild, mAmbientWrapper);
Adrian Roos6f6e1592017-05-02 16:22:53 -0700802 forceUpdateVisibility(VISIBLE_TYPE_AMBIENT_SINGLELINE, mAmbientSingleLineChild,
803 mAmbientSingleLineChild);
Adrian Roos4320e892017-01-24 12:50:34 -0800804 fireExpandedVisibleListenerIfVisible();
Adrian Roose18033c2017-01-17 15:22:49 -0800805 // forceUpdateVisibilities cancels outstanding animations without updating the
806 // mAnimationStartVisibleType. Do so here instead.
807 mAnimationStartVisibleType = UNDEFINED;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800808 }
809
Adrian Roos4320e892017-01-24 12:50:34 -0800810 private void fireExpandedVisibleListenerIfVisible() {
811 if (mExpandedVisibleListener != null && mExpandedChild != null && isShown()
812 && mExpandedChild.getVisibility() == VISIBLE) {
813 Runnable listener = mExpandedVisibleListener;
814 mExpandedVisibleListener = null;
815 listener.run();
816 }
817 }
818
Adrian Roos0aac04f2016-12-08 15:59:29 -0800819 private void forceUpdateVisibility(int type, View view, TransformableView wrapper) {
820 if (view == null) {
821 return;
822 }
823 boolean visible = mVisibleType == type
824 || mTransformationStartVisibleType == type;
825 if (!visible) {
826 view.setVisibility(INVISIBLE);
Selim Cinek589fd3e2016-04-26 18:17:57 -0700827 } else {
Adrian Roos0aac04f2016-12-08 15:59:29 -0800828 wrapper.setVisible(true);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200829 }
Jorim Jaggi11298832014-05-24 16:18:38 +0200830 }
831
Selim Cinekc3179332016-03-04 14:44:56 -0800832 public void updateBackgroundColor(boolean animate) {
833 int customBackgroundColor = getBackgroundColor(mVisibleType);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400834 mContainingNotification.resetBackgroundAlpha();
Selim Cinekc3179332016-03-04 14:44:56 -0800835 mContainingNotification.setContentBackground(customBackgroundColor, animate, this);
836 }
837
Mady Mellorb0a82462016-04-30 17:31:02 -0700838 public int getVisibleType() {
839 return mVisibleType;
840 }
841
842 public int getBackgroundColorForExpansionState() {
843 // When expanding or user locked we want the new type, when collapsing we want
844 // the original type
845 final int visibleType = (mContainingNotification.isGroupExpanded()
846 || mContainingNotification.isUserLocked())
847 ? calculateVisibleType()
848 : getVisibleType();
849 return getBackgroundColor(visibleType);
850 }
851
852 public int getBackgroundColor(int visibleType) {
Selim Cinekc3179332016-03-04 14:44:56 -0800853 NotificationViewWrapper currentVisibleWrapper = getVisibleWrapper(visibleType);
854 int customBackgroundColor = 0;
855 if (currentVisibleWrapper != null) {
856 customBackgroundColor = currentVisibleWrapper.getCustomBackgroundColor();
857 }
858 return customBackgroundColor;
859 }
860
Selim Cinek684a4422015-04-15 16:18:39 -0700861 private void updateViewVisibilities(int visibleType) {
Adrian Roos0aac04f2016-12-08 15:59:29 -0800862 updateViewVisibility(visibleType, VISIBLE_TYPE_CONTRACTED,
863 mContractedChild, mContractedWrapper);
864 updateViewVisibility(visibleType, VISIBLE_TYPE_EXPANDED,
865 mExpandedChild, mExpandedWrapper);
866 updateViewVisibility(visibleType, VISIBLE_TYPE_HEADSUP,
867 mHeadsUpChild, mHeadsUpWrapper);
868 updateViewVisibility(visibleType, VISIBLE_TYPE_SINGLELINE,
869 mSingleLineView, mSingleLineView);
870 updateViewVisibility(visibleType, VISIBLE_TYPE_AMBIENT,
871 mAmbientChild, mAmbientWrapper);
Adrian Roos6f6e1592017-05-02 16:22:53 -0700872 updateViewVisibility(visibleType, VISIBLE_TYPE_AMBIENT_SINGLELINE,
873 mAmbientSingleLineChild, mAmbientSingleLineChild);
Adrian Roos4320e892017-01-24 12:50:34 -0800874 fireExpandedVisibleListenerIfVisible();
Adrian Roose18033c2017-01-17 15:22:49 -0800875 // updateViewVisibilities cancels outstanding animations without updating the
876 // mAnimationStartVisibleType. Do so here instead.
877 mAnimationStartVisibleType = UNDEFINED;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800878 }
879
880 private void updateViewVisibility(int visibleType, int type, View view,
881 TransformableView wrapper) {
882 if (view != null) {
883 wrapper.setVisible(visibleType == type);
Selim Cinek83bc7832015-10-22 13:26:54 -0700884 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700885 }
886
Selim Cinek4ffd6362015-12-29 15:12:23 +0100887 private void animateToVisibleType(int visibleType) {
888 final TransformableView shownView = getTransformableViewForVisibleType(visibleType);
889 final TransformableView hiddenView = getTransformableViewForVisibleType(mVisibleType);
Selim Cinek589fd3e2016-04-26 18:17:57 -0700890 if (shownView == hiddenView || hiddenView == null) {
Selim Cinek51d94912016-03-02 15:34:28 -0800891 shownView.setVisible(true);
892 return;
893 }
Adrian Roos599be342016-06-13 14:54:39 -0700894 mAnimationStartVisibleType = mVisibleType;
Selim Cinek4ffd6362015-12-29 15:12:23 +0100895 shownView.transformFrom(hiddenView);
896 getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
897 hiddenView.transformTo(shownView, new Runnable() {
898 @Override
899 public void run() {
Selim Cinek51d94912016-03-02 15:34:28 -0800900 if (hiddenView != getTransformableViewForVisibleType(mVisibleType)) {
901 hiddenView.setVisible(false);
902 }
Adrian Roos599be342016-06-13 14:54:39 -0700903 mAnimationStartVisibleType = UNDEFINED;
Selim Cinek4ffd6362015-12-29 15:12:23 +0100904 }
905 });
Adrian Roos4320e892017-01-24 12:50:34 -0800906 fireExpandedVisibleListenerIfVisible();
Jorim Jaggi11298832014-05-24 16:18:38 +0200907 }
908
Adrian Roos4c1fcc82016-03-31 14:39:39 -0700909 private void transferRemoteInputFocus(int visibleType) {
910 if (visibleType == VISIBLE_TYPE_HEADSUP
911 && mHeadsUpRemoteInput != null
912 && (mExpandedRemoteInput != null && mExpandedRemoteInput.isActive())) {
913 mHeadsUpRemoteInput.stealFocusFrom(mExpandedRemoteInput);
914 }
915 if (visibleType == VISIBLE_TYPE_EXPANDED
916 && mExpandedRemoteInput != null
917 && (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isActive())) {
918 mExpandedRemoteInput.stealFocusFrom(mHeadsUpRemoteInput);
919 }
920 }
921
Selim Cinek684a4422015-04-15 16:18:39 -0700922 /**
923 * @param visibleType one of the static enum types in this view
Selim Cinek4ffd6362015-12-29 15:12:23 +0100924 * @return the corresponding transformable view according to the given visible type
925 */
926 private TransformableView getTransformableViewForVisibleType(int visibleType) {
927 switch (visibleType) {
928 case VISIBLE_TYPE_EXPANDED:
929 return mExpandedWrapper;
930 case VISIBLE_TYPE_HEADSUP:
931 return mHeadsUpWrapper;
932 case VISIBLE_TYPE_SINGLELINE:
933 return mSingleLineView;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800934 case VISIBLE_TYPE_AMBIENT:
935 return mAmbientWrapper;
Adrian Roos6f6e1592017-05-02 16:22:53 -0700936 case VISIBLE_TYPE_AMBIENT_SINGLELINE:
937 return mAmbientSingleLineChild;
Selim Cinek4ffd6362015-12-29 15:12:23 +0100938 default:
939 return mContractedWrapper;
940 }
941 }
942
943 /**
944 * @param visibleType one of the static enum types in this view
Selim Cinek684a4422015-04-15 16:18:39 -0700945 * @return the corresponding view according to the given visible type
946 */
947 private View getViewForVisibleType(int visibleType) {
948 switch (visibleType) {
949 case VISIBLE_TYPE_EXPANDED:
Selim Cinek8d490d42015-04-10 00:05:50 -0700950 return mExpandedChild;
Selim Cinek684a4422015-04-15 16:18:39 -0700951 case VISIBLE_TYPE_HEADSUP:
Selim Cinek8d490d42015-04-10 00:05:50 -0700952 return mHeadsUpChild;
Selim Cinek83bc7832015-10-22 13:26:54 -0700953 case VISIBLE_TYPE_SINGLELINE:
954 return mSingleLineView;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800955 case VISIBLE_TYPE_AMBIENT:
956 return mAmbientChild;
Adrian Roos6f6e1592017-05-02 16:22:53 -0700957 case VISIBLE_TYPE_AMBIENT_SINGLELINE:
958 return mAmbientSingleLineChild;
Selim Cinek684a4422015-04-15 16:18:39 -0700959 default:
960 return mContractedChild;
Selim Cinek8d490d42015-04-10 00:05:50 -0700961 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700962 }
963
Selim Cinek131f1a42017-06-05 17:50:19 -0700964 public NotificationViewWrapper getVisibleWrapper(int visibleType) {
Selim Cinekc3179332016-03-04 14:44:56 -0800965 switch (visibleType) {
Selim Cinek34eda5e2016-02-18 17:10:43 -0800966 case VISIBLE_TYPE_EXPANDED:
967 return mExpandedWrapper;
968 case VISIBLE_TYPE_HEADSUP:
969 return mHeadsUpWrapper;
970 case VISIBLE_TYPE_CONTRACTED:
971 return mContractedWrapper;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800972 case VISIBLE_TYPE_AMBIENT:
973 return mAmbientWrapper;
Selim Cinek34eda5e2016-02-18 17:10:43 -0800974 default:
975 return null;
976 }
977 }
978
Selim Cinek684a4422015-04-15 16:18:39 -0700979 /**
980 * @return one of the static enum types in this view, calculated form the current state
981 */
Mady Mellorb0a82462016-04-30 17:31:02 -0700982 public int calculateVisibleType() {
Adrian Roos6f6e1592017-05-02 16:22:53 -0700983 if (mContainingNotification.isShowingAmbient()) {
984 if (mIsChildInGroup && mAmbientSingleLineChild != null) {
985 return VISIBLE_TYPE_AMBIENT_SINGLELINE;
986 } else if (mAmbientChild != null) {
987 return VISIBLE_TYPE_AMBIENT;
988 } else {
989 return VISIBLE_TYPE_CONTRACTED;
990 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800991 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800992 if (mUserExpanding) {
Selim Cinek42357e02016-02-24 18:48:01 -0800993 int height = !mIsChildInGroup || isGroupExpanded()
Selim Cineke81b82b2016-03-04 11:22:28 -0800994 || mContainingNotification.isExpanded(true /* allowOnKeyguard */)
Selim Cinek42357e02016-02-24 18:48:01 -0800995 ? mContainingNotification.getMaxContentHeight()
996 : mContainingNotification.getShowingLayout().getMinHeight();
Selim Cinek51d94912016-03-02 15:34:28 -0800997 if (height == 0) {
998 height = mContentHeight;
999 }
Selim Cinek42357e02016-02-24 18:48:01 -08001000 int expandedVisualType = getVisualTypeForHeight(height);
Selim Cinek414ad332017-02-24 19:06:12 -08001001 int collapsedVisualType = mIsChildInGroup && !isGroupExpanded()
Selim Cinek589fd3e2016-04-26 18:17:57 -07001002 ? VISIBLE_TYPE_SINGLELINE
1003 : getVisualTypeForHeight(mContainingNotification.getCollapsedHeight());
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001004 return mTransformationStartVisibleType == collapsedVisualType
1005 ? expandedVisualType
1006 : collapsedVisualType;
1007 }
Selim Cinek51d94912016-03-02 15:34:28 -08001008 int intrinsicHeight = mContainingNotification.getIntrinsicHeight();
1009 int viewHeight = mContentHeight;
1010 if (intrinsicHeight != 0) {
1011 // the intrinsicHeight might be 0 because it was just reset.
1012 viewHeight = Math.min(mContentHeight, intrinsicHeight);
1013 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001014 return getVisualTypeForHeight(viewHeight);
1015 }
1016
1017 private int getVisualTypeForHeight(float viewHeight) {
1018 boolean noExpandedChild = mExpandedChild == null;
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001019 if (!noExpandedChild && viewHeight == mExpandedChild.getHeight()) {
Adrian Roos777ef562015-12-01 17:37:14 -08001020 return VISIBLE_TYPE_EXPANDED;
1021 }
Selim Cinek414ad332017-02-24 19:06:12 -08001022 if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001023 return VISIBLE_TYPE_SINGLELINE;
1024 }
Adrian Roos777ef562015-12-01 17:37:14 -08001025
Selim Cinekc494e382017-01-31 16:09:23 -08001026 if ((mIsHeadsUp || mHeadsUpAnimatingAway) && mHeadsUpChild != null
1027 && !mContainingNotification.isOnKeyguard()) {
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001028 if (viewHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
Selim Cinek684a4422015-04-15 16:18:39 -07001029 return VISIBLE_TYPE_HEADSUP;
Selim Cinek8d490d42015-04-10 00:05:50 -07001030 } else {
Selim Cinek684a4422015-04-15 16:18:39 -07001031 return VISIBLE_TYPE_EXPANDED;
Selim Cinek8d490d42015-04-10 00:05:50 -07001032 }
1033 } else {
Selim Cineka4091502016-02-11 17:21:16 -08001034 if (noExpandedChild || (viewHeight <= mContractedChild.getHeight()
Selim Cinek6ac3fa82016-05-10 17:11:54 -04001035 && (!mIsChildInGroup || isGroupExpanded()
Selim Cineke81b82b2016-03-04 11:22:28 -08001036 || !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) {
Selim Cinek684a4422015-04-15 16:18:39 -07001037 return VISIBLE_TYPE_CONTRACTED;
Selim Cinek8d490d42015-04-10 00:05:50 -07001038 } else {
Selim Cinek684a4422015-04-15 16:18:39 -07001039 return VISIBLE_TYPE_EXPANDED;
Selim Cinek8d490d42015-04-10 00:05:50 -07001040 }
1041 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001042 }
1043
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001044 public boolean isContentExpandable() {
Selim Cinekc0ac4af2017-03-03 15:13:48 -08001045 return mIsContentExpandable;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001046 }
John Spurlocke15452b2014-08-21 09:44:39 -04001047
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001048 public void setDark(boolean dark, boolean fade, long delay) {
Selim Cinekb88b9842016-02-26 09:25:33 -08001049 if (mContractedChild == null) {
Selim Cinek0934bd92016-02-19 12:22:33 -08001050 return;
1051 }
John Spurlocke15452b2014-08-21 09:44:39 -04001052 mDark = dark;
Selim Cinek19ba7052016-01-27 20:04:27 -08001053 if (mVisibleType == VISIBLE_TYPE_CONTRACTED || !dark) {
Selim Cinek30e387d2016-01-11 18:01:47 -08001054 mContractedWrapper.setDark(dark, fade, delay);
1055 }
Selim Cinek19ba7052016-01-27 20:04:27 -08001056 if (mVisibleType == VISIBLE_TYPE_EXPANDED || (mExpandedChild != null && !dark)) {
Selim Cinek30e387d2016-01-11 18:01:47 -08001057 mExpandedWrapper.setDark(dark, fade, delay);
1058 }
Selim Cinek19ba7052016-01-27 20:04:27 -08001059 if (mVisibleType == VISIBLE_TYPE_HEADSUP || (mHeadsUpChild != null && !dark)) {
Selim Cinek30e387d2016-01-11 18:01:47 -08001060 mHeadsUpWrapper.setDark(dark, fade, delay);
1061 }
Selim Cinek19ba7052016-01-27 20:04:27 -08001062 if (mSingleLineView != null && (mVisibleType == VISIBLE_TYPE_SINGLELINE || !dark)) {
Selim Cinek9c7712d2015-12-08 19:19:48 -08001063 mSingleLineView.setDark(dark, fade, delay);
1064 }
Adrian Roos0aac04f2016-12-08 15:59:29 -08001065 selectLayout(!dark && fade /* animate */, false /* force */);
John Spurlocke15452b2014-08-21 09:44:39 -04001066 }
1067
Selim Cinek8d490d42015-04-10 00:05:50 -07001068 public void setHeadsUp(boolean headsUp) {
1069 mIsHeadsUp = headsUp;
1070 selectLayout(false /* animate */, true /* force */);
Selim Cinek98be3f32015-12-17 16:39:06 -08001071 updateExpandButtons(mExpandable);
Selim Cinek8d490d42015-04-10 00:05:50 -07001072 }
1073
Jorim Jaggiaa92ffb2014-09-10 23:29:28 +02001074 @Override
1075 public boolean hasOverlappingRendering() {
1076
1077 // This is not really true, but good enough when fading from the contracted to the expanded
1078 // layout, and saves us some layers.
1079 return false;
1080 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001081
Selim Cinek1a48bab2017-02-17 19:38:40 -08001082 public void setLegacy(boolean legacy) {
1083 mLegacy = legacy;
1084 updateLegacy();
Selim Cinekc3179332016-03-04 14:44:56 -08001085 }
1086
Selim Cinek1a48bab2017-02-17 19:38:40 -08001087 private void updateLegacy() {
Selim Cinekc3179332016-03-04 14:44:56 -08001088 if (mContractedChild != null) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08001089 mContractedWrapper.setLegacy(mLegacy);
Selim Cinekc3179332016-03-04 14:44:56 -08001090 }
1091 if (mExpandedChild != null) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08001092 mExpandedWrapper.setLegacy(mLegacy);
Selim Cinekc3179332016-03-04 14:44:56 -08001093 }
1094 if (mHeadsUpChild != null) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08001095 mHeadsUpWrapper.setLegacy(mLegacy);
Selim Cinekc3179332016-03-04 14:44:56 -08001096 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001097 }
Selim Cinek8d6440d2015-10-22 13:00:05 -07001098
Selim Cinek83bc7832015-10-22 13:26:54 -07001099 public void setIsChildInGroup(boolean isChildInGroup) {
1100 mIsChildInGroup = isChildInGroup;
Selim Cinek414ad332017-02-24 19:06:12 -08001101 if (mContractedChild != null) {
1102 mContractedWrapper.setIsChildInGroup(mIsChildInGroup);
1103 }
1104 if (mExpandedChild != null) {
1105 mExpandedWrapper.setIsChildInGroup(mIsChildInGroup);
1106 }
1107 if (mHeadsUpChild != null) {
1108 mHeadsUpWrapper.setIsChildInGroup(mIsChildInGroup);
1109 }
1110 if (mAmbientChild != null) {
1111 mAmbientWrapper.setIsChildInGroup(mIsChildInGroup);
1112 }
Adrian Roos6f6e1592017-05-02 16:22:53 -07001113 updateAllSingleLineViews();
Selim Cinek83bc7832015-10-22 13:26:54 -07001114 }
1115
Adrian Roosb88b1a12015-12-09 18:51:05 -08001116 public void onNotificationUpdated(NotificationData.Entry entry) {
1117 mStatusBarNotification = entry.notification;
Selim Cinek860b6da2015-12-16 19:02:19 -08001118 mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
Adrian Roos6f6e1592017-05-02 16:22:53 -07001119 updateAllSingleLineViews();
Selim Cinek8fc93c92015-11-23 17:48:07 -08001120 if (mContractedChild != null) {
Selim Cinek131f1a42017-06-05 17:50:19 -07001121 mContractedWrapper.onContentUpdated(entry.row);
Selim Cinek8fc93c92015-11-23 17:48:07 -08001122 }
1123 if (mExpandedChild != null) {
Selim Cinek131f1a42017-06-05 17:50:19 -07001124 mExpandedWrapper.onContentUpdated(entry.row);
Selim Cinek8fc93c92015-11-23 17:48:07 -08001125 }
1126 if (mHeadsUpChild != null) {
Selim Cinek131f1a42017-06-05 17:50:19 -07001127 mHeadsUpWrapper.onContentUpdated(entry.row);
Selim Cinek8fc93c92015-11-23 17:48:07 -08001128 }
Adrian Roos0aac04f2016-12-08 15:59:29 -08001129 if (mAmbientChild != null) {
Selim Cinek131f1a42017-06-05 17:50:19 -07001130 mAmbientWrapper.onContentUpdated(entry.row);
Adrian Roos0aac04f2016-12-08 15:59:29 -08001131 }
Petr Cermak7997d7a2018-01-18 15:52:10 +00001132 applyRemoteInputAndSmartReply(entry);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001133 updateLegacy();
Selim Cinek589fd3e2016-04-26 18:17:57 -07001134 mForceSelectNextLayout = true;
Selim Cinekb88b9842016-02-26 09:25:33 -08001135 setDark(mDark, false /* animate */, 0 /* delay */);
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001136 mPreviousExpandedRemoteInputIntent = null;
1137 mPreviousHeadsUpRemoteInputIntent = null;
Selim Cinek83bc7832015-10-22 13:26:54 -07001138 }
1139
Adrian Roos6f6e1592017-05-02 16:22:53 -07001140 private void updateAllSingleLineViews() {
1141 updateSingleLineView();
1142 updateAmbientSingleLineView();
1143 }
Selim Cinek83bc7832015-10-22 13:26:54 -07001144 private void updateSingleLineView() {
1145 if (mIsChildInGroup) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001146 mSingleLineView = mHybridGroupManager.bindFromNotification(
Selim Cinek83bc7832015-10-22 13:26:54 -07001147 mSingleLineView, mStatusBarNotification.getNotification());
Selim Cinekde33a4a2016-02-11 16:43:41 -08001148 } else if (mSingleLineView != null) {
1149 removeView(mSingleLineView);
1150 mSingleLineView = null;
Selim Cinek83bc7832015-10-22 13:26:54 -07001151 }
1152 }
1153
Adrian Roos6f6e1592017-05-02 16:22:53 -07001154 private void updateAmbientSingleLineView() {
1155 if (mIsChildInGroup) {
1156 mAmbientSingleLineChild = mHybridGroupManager.bindAmbientFromNotification(
1157 mAmbientSingleLineChild, mStatusBarNotification.getNotification());
1158 } else if (mAmbientSingleLineChild != null) {
1159 removeView(mAmbientSingleLineChild);
1160 mAmbientSingleLineChild = null;
1161 }
1162 }
1163
Petr Cermak7997d7a2018-01-18 15:52:10 +00001164 private void applyRemoteInputAndSmartReply(final NotificationData.Entry entry) {
Adrian Roosb88b1a12015-12-09 18:51:05 -08001165 if (mRemoteInputController == null) {
1166 return;
1167 }
1168
Petr Cermak7997d7a2018-01-18 15:52:10 +00001169 boolean enableSmartReplies = Settings.Global.getInt(mContext.getContentResolver(),
1170 Settings.Global.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS, 0) != 0;
1171
Adrian Roosb88b1a12015-12-09 18:51:05 -08001172 boolean hasRemoteInput = false;
Petr Cermak7997d7a2018-01-18 15:52:10 +00001173 RemoteInput remoteInputWithChoices = null;
1174 PendingIntent pendingIntentWithChoices = null;
Adrian Roosb88b1a12015-12-09 18:51:05 -08001175
1176 Notification.Action[] actions = entry.notification.getNotification().actions;
1177 if (actions != null) {
1178 for (Notification.Action a : actions) {
1179 if (a.getRemoteInputs() != null) {
1180 for (RemoteInput ri : a.getRemoteInputs()) {
Petr Cermak7997d7a2018-01-18 15:52:10 +00001181 boolean showRemoteInputView = ri.getAllowFreeFormInput();
1182 boolean showSmartReplyView = enableSmartReplies && ri.getChoices() != null
1183 && ri.getChoices().length > 0;
1184 if (showRemoteInputView) {
Adrian Roosb88b1a12015-12-09 18:51:05 -08001185 hasRemoteInput = true;
Petr Cermak7997d7a2018-01-18 15:52:10 +00001186 }
1187 if (showSmartReplyView) {
1188 remoteInputWithChoices = ri;
1189 pendingIntentWithChoices = a.actionIntent;
1190 }
1191 if (showRemoteInputView || showSmartReplyView) {
Adrian Roosb88b1a12015-12-09 18:51:05 -08001192 break;
1193 }
1194 }
1195 }
1196 }
1197 }
1198
Petr Cermak7997d7a2018-01-18 15:52:10 +00001199 applyRemoteInput(entry, hasRemoteInput);
1200 applySmartReplyView(remoteInputWithChoices, pendingIntentWithChoices);
1201 }
1202
1203 private void applyRemoteInput(NotificationData.Entry entry, boolean hasRemoteInput) {
Adrian Roosb88b1a12015-12-09 18:51:05 -08001204 View bigContentView = mExpandedChild;
1205 if (bigContentView != null) {
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001206 mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput,
Adrian Roos7b9ed0d2017-01-24 15:55:18 -08001207 mPreviousExpandedRemoteInputIntent, mCachedExpandedRemoteInput,
1208 mExpandedWrapper);
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001209 } else {
1210 mExpandedRemoteInput = null;
Adrian Roosb88b1a12015-12-09 18:51:05 -08001211 }
Adrian Roos7813dd72016-09-23 17:12:17 -07001212 if (mCachedExpandedRemoteInput != null
1213 && mCachedExpandedRemoteInput != mExpandedRemoteInput) {
1214 // We had a cached remote input but didn't reuse it. Clean up required.
1215 mCachedExpandedRemoteInput.dispatchFinishTemporaryDetach();
1216 }
1217 mCachedExpandedRemoteInput = null;
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001218
Adrian Roosb88b1a12015-12-09 18:51:05 -08001219 View headsUpContentView = mHeadsUpChild;
1220 if (headsUpContentView != null) {
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001221 mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput,
Adrian Roos7b9ed0d2017-01-24 15:55:18 -08001222 mPreviousHeadsUpRemoteInputIntent, mCachedHeadsUpRemoteInput, mHeadsUpWrapper);
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001223 } else {
1224 mHeadsUpRemoteInput = null;
Adrian Roosb88b1a12015-12-09 18:51:05 -08001225 }
Adrian Roos7813dd72016-09-23 17:12:17 -07001226 if (mCachedHeadsUpRemoteInput != null
1227 && mCachedHeadsUpRemoteInput != mHeadsUpRemoteInput) {
1228 // We had a cached remote input but didn't reuse it. Clean up required.
1229 mCachedHeadsUpRemoteInput.dispatchFinishTemporaryDetach();
1230 }
1231 mCachedHeadsUpRemoteInput = null;
Adrian Roosb88b1a12015-12-09 18:51:05 -08001232 }
1233
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001234 private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry,
Adrian Roos7813dd72016-09-23 17:12:17 -07001235 boolean hasRemoteInput, PendingIntent existingPendingIntent,
Adrian Roos7b9ed0d2017-01-24 15:55:18 -08001236 RemoteInputView cachedView, NotificationViewWrapper wrapper) {
Adrian Roosb88b1a12015-12-09 18:51:05 -08001237 View actionContainerCandidate = view.findViewById(
1238 com.android.internal.R.id.actions_container);
1239 if (actionContainerCandidate instanceof FrameLayout) {
1240 RemoteInputView existing = (RemoteInputView)
1241 view.findViewWithTag(RemoteInputView.VIEW_TAG);
1242
1243 if (existing != null) {
Adrian Roos0789ee02016-06-01 11:34:58 -07001244 existing.onNotificationUpdateOrReset();
Adrian Roosb88b1a12015-12-09 18:51:05 -08001245 }
1246
1247 if (existing == null && hasRemoteInput) {
1248 ViewGroup actionContainer = (FrameLayout) actionContainerCandidate;
Adrian Roos7813dd72016-09-23 17:12:17 -07001249 if (cachedView == null) {
1250 RemoteInputView riv = RemoteInputView.inflate(
1251 mContext, actionContainer, entry, mRemoteInputController);
Adrian Roosb88b1a12015-12-09 18:51:05 -08001252
Adrian Roos7813dd72016-09-23 17:12:17 -07001253 riv.setVisibility(View.INVISIBLE);
1254 actionContainer.addView(riv, new LayoutParams(
1255 ViewGroup.LayoutParams.MATCH_PARENT,
1256 ViewGroup.LayoutParams.MATCH_PARENT)
1257 );
1258 existing = riv;
1259 } else {
1260 actionContainer.addView(cachedView);
1261 cachedView.dispatchFinishTemporaryDetach();
1262 cachedView.requestFocus();
1263 existing = cachedView;
1264 }
Adrian Roos4ff3b122016-02-01 12:26:13 -08001265 }
1266 if (hasRemoteInput) {
Adrian Roosb88b1a12015-12-09 18:51:05 -08001267 int color = entry.notification.getNotification().color;
1268 if (color == Notification.COLOR_DEFAULT) {
1269 color = mContext.getColor(R.color.default_remote_input_background);
1270 }
Adrian Roos4ff3b122016-02-01 12:26:13 -08001271 existing.setBackgroundColor(NotificationColorUtil.ensureTextBackgroundColor(color,
Adrian Roos25ea5b82016-04-27 16:34:35 -07001272 mContext.getColor(R.color.remote_input_text_enabled),
Adrian Roos4ff3b122016-02-01 12:26:13 -08001273 mContext.getColor(R.color.remote_input_hint)));
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001274
Adrian Roos7b9ed0d2017-01-24 15:55:18 -08001275 existing.setWrapper(wrapper);
1276
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001277 if (existingPendingIntent != null || existing.isActive()) {
1278 // The current action could be gone, or the pending intent no longer valid.
1279 // If we find a matching action in the new notification, focus, otherwise close.
1280 Notification.Action[] actions = entry.notification.getNotification().actions;
1281 if (existingPendingIntent != null) {
1282 existing.setPendingIntent(existingPendingIntent);
1283 }
1284 if (existing.updatePendingIntentFromActions(actions)) {
1285 if (!existing.isActive()) {
1286 existing.focus();
1287 }
1288 } else {
1289 if (existing.isActive()) {
1290 existing.close();
1291 }
1292 }
1293 }
Adrian Roosb88b1a12015-12-09 18:51:05 -08001294 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001295 return existing;
1296 }
1297 return null;
1298 }
1299
Petr Cermak7997d7a2018-01-18 15:52:10 +00001300 private void applySmartReplyView(RemoteInput remoteInput, PendingIntent pendingIntent) {
1301 mExpandedSmartReplyView = mExpandedChild == null ?
1302 null : applySmartReplyView(mExpandedChild, remoteInput, pendingIntent);
1303 }
1304
1305 private SmartReplyView applySmartReplyView(
1306 View view, RemoteInput remoteInput, PendingIntent pendingIntent) {
1307 View smartReplyContainerCandidate = view.findViewById(
1308 com.android.internal.R.id.smart_reply_container);
1309 if (!(smartReplyContainerCandidate instanceof LinearLayout)) {
1310 return null;
1311 }
1312 LinearLayout smartReplyContainer = (LinearLayout) smartReplyContainerCandidate;
1313 if (remoteInput == null || pendingIntent == null) {
1314 smartReplyContainer.setVisibility(View.GONE);
1315 return null;
1316 }
1317 SmartReplyView smartReplyView = null;
1318 if (smartReplyContainer.getChildCount() == 0) {
1319 smartReplyView = SmartReplyView.inflate(mContext, smartReplyContainer);
1320 smartReplyContainer.addView(smartReplyView);
1321 } else if (smartReplyContainer.getChildCount() == 1) {
1322 View child = smartReplyContainer.getChildAt(0);
1323 if (child instanceof SmartReplyView) {
1324 smartReplyView = (SmartReplyView) child;
1325 }
1326 }
1327 if (smartReplyView != null) {
1328 smartReplyView.setRepliesFromRemoteInput(remoteInput, pendingIntent);
1329 smartReplyContainer.setVisibility(View.VISIBLE);
1330 }
1331 return smartReplyView;
1332 }
1333
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001334 public void closeRemoteInput() {
1335 if (mHeadsUpRemoteInput != null) {
1336 mHeadsUpRemoteInput.close();
1337 }
1338 if (mExpandedRemoteInput != null) {
1339 mExpandedRemoteInput.close();
Adrian Roosb88b1a12015-12-09 18:51:05 -08001340 }
1341 }
1342
Selim Cinek83bc7832015-10-22 13:26:54 -07001343 public void setGroupManager(NotificationGroupManager groupManager) {
1344 mGroupManager = groupManager;
1345 }
Selim Cinek65b2e7c2015-10-26 14:11:31 -07001346
Adrian Roosb88b1a12015-12-09 18:51:05 -08001347 public void setRemoteInputController(RemoteInputController r) {
1348 mRemoteInputController = r;
1349 }
1350
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001351 public void setExpandClickListener(OnClickListener expandClickListener) {
1352 mExpandClickListener = expandClickListener;
1353 }
1354
1355 public void updateExpandButtons(boolean expandable) {
Selim Cinek98be3f32015-12-17 16:39:06 -08001356 mExpandable = expandable;
1357 // if the expanded child has the same height as the collapsed one we hide it.
Selim Cinek8ea2d5f2016-04-20 17:10:40 -07001358 if (mExpandedChild != null && mExpandedChild.getHeight() != 0) {
Selim Cinek4ca6c632017-02-23 18:03:37 -08001359 if ((!mIsHeadsUp && !mHeadsUpAnimatingAway)
1360 || mHeadsUpChild == null || mContainingNotification.isOnKeyguard()) {
Selim Cinek9635cf32017-03-03 16:59:03 -08001361 if (mExpandedChild.getHeight() <= mContractedChild.getHeight()) {
Selim Cinek8ea2d5f2016-04-20 17:10:40 -07001362 expandable = false;
1363 }
Selim Cinek9635cf32017-03-03 16:59:03 -08001364 } else if (mExpandedChild.getHeight() <= mHeadsUpChild.getHeight()) {
Selim Cinek8ea2d5f2016-04-20 17:10:40 -07001365 expandable = false;
1366 }
Selim Cinek98be3f32015-12-17 16:39:06 -08001367 }
Selim Cinek65b2e7c2015-10-26 14:11:31 -07001368 if (mExpandedChild != null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001369 mExpandedWrapper.updateExpandability(expandable, mExpandClickListener);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07001370 }
1371 if (mContractedChild != null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001372 mContractedWrapper.updateExpandability(expandable, mExpandClickListener);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07001373 }
1374 if (mHeadsUpChild != null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001375 mHeadsUpWrapper.updateExpandability(expandable, mExpandClickListener);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07001376 }
Selim Cinekc0ac4af2017-03-03 15:13:48 -08001377 mIsContentExpandable = expandable;
Selim Cinek65b2e7c2015-10-26 14:11:31 -07001378 }
Selim Cinekea4bef72015-12-02 15:51:10 -08001379
1380 public NotificationHeaderView getNotificationHeader() {
1381 NotificationHeaderView header = null;
1382 if (mContractedChild != null) {
1383 header = mContractedWrapper.getNotificationHeader();
1384 }
1385 if (header == null && mExpandedChild != null) {
1386 header = mExpandedWrapper.getNotificationHeader();
1387 }
1388 if (header == null && mHeadsUpChild != null) {
1389 header = mHeadsUpWrapper.getNotificationHeader();
1390 }
Adrian Roos0aac04f2016-12-08 15:59:29 -08001391 if (header == null && mAmbientChild != null) {
1392 header = mAmbientWrapper.getNotificationHeader();
1393 }
Selim Cinekea4bef72015-12-02 15:51:10 -08001394 return header;
1395 }
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001396
Selim Cinekb26afa32017-06-29 10:28:17 +02001397
1398 public NotificationHeaderView getContractedNotificationHeader() {
1399 if (mContractedChild != null) {
1400 return mContractedWrapper.getNotificationHeader();
1401 }
1402 return null;
1403 }
1404
Selim Cinek34eda5e2016-02-18 17:10:43 -08001405 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekc3179332016-03-04 14:44:56 -08001406 NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
Selim Cinek34eda5e2016-02-18 17:10:43 -08001407 return wrapper == null ? null : wrapper.getNotificationHeader();
1408 }
1409
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001410 public void setContainingNotification(ExpandableNotificationRow containingNotification) {
1411 mContainingNotification = containingNotification;
1412 }
1413
1414 public void requestSelectLayout(boolean needsAnimation) {
1415 selectLayout(needsAnimation, false);
1416 }
Selim Cinekde33a4a2016-02-11 16:43:41 -08001417
1418 public void reInflateViews() {
1419 if (mIsChildInGroup && mSingleLineView != null) {
1420 removeView(mSingleLineView);
1421 mSingleLineView = null;
Adrian Roos6f6e1592017-05-02 16:22:53 -07001422 updateAllSingleLineViews();
Selim Cinekde33a4a2016-02-11 16:43:41 -08001423 }
1424 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001425
1426 public void setUserExpanding(boolean userExpanding) {
1427 mUserExpanding = userExpanding;
1428 if (userExpanding) {
1429 mTransformationStartVisibleType = mVisibleType;
1430 } else {
1431 mTransformationStartVisibleType = UNDEFINED;
1432 mVisibleType = calculateVisibleType();
1433 updateViewVisibilities(mVisibleType);
Selim Cinekc3179332016-03-04 14:44:56 -08001434 updateBackgroundColor(false);
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001435 }
1436 }
Selim Cinekc897bd32016-03-18 17:32:31 -07001437
1438 /**
1439 * Set by how much the single line view should be indented. Used when a overflow indicator is
1440 * present and only during measuring
1441 */
1442 public void setSingleLineWidthIndention(int singleLineWidthIndention) {
1443 if (singleLineWidthIndention != mSingleLineWidthIndention) {
1444 mSingleLineWidthIndention = singleLineWidthIndention;
1445 mContainingNotification.forceLayout();
1446 forceLayout();
1447 }
1448 }
1449
1450 public HybridNotificationView getSingleLineView() {
1451 return mSingleLineView;
1452 }
Adrian Roosd009ab12016-05-20 17:58:53 -07001453
1454 public void setRemoved() {
1455 if (mExpandedRemoteInput != null) {
1456 mExpandedRemoteInput.setRemoved();
1457 }
1458 if (mHeadsUpRemoteInput != null) {
1459 mHeadsUpRemoteInput.setRemoved();
1460 }
1461 }
Adrian Roos599be342016-06-13 14:54:39 -07001462
1463 public void setContentHeightAnimating(boolean animating) {
1464 if (!animating) {
1465 mContentHeightAtAnimationStart = UNDEFINED;
1466 }
1467 }
Selim Cineke9bad242016-06-15 11:46:37 -07001468
Adrian Roose18033c2017-01-17 15:22:49 -08001469 @VisibleForTesting
1470 boolean isAnimatingVisibleType() {
1471 return mAnimationStartVisibleType != UNDEFINED;
1472 }
1473
Selim Cinekcafa87f2016-10-26 17:00:17 -07001474 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
1475 mHeadsUpAnimatingAway = headsUpAnimatingAway;
Selim Cinek73cf02a2016-06-17 13:08:00 -07001476 selectLayout(false /* animate */, true /* force */);
1477 }
1478
Selim Cineke9bad242016-06-15 11:46:37 -07001479 public void setFocusOnVisibilityChange() {
1480 mFocusOnVisibilityChange = true;
1481 }
Selim Cinek0242fbb2016-10-19 13:38:32 -07001482
1483 public void setIconsVisible(boolean iconsVisible) {
1484 mIconsVisible = iconsVisible;
1485 updateIconVisibilities();
1486 }
1487
1488 private void updateIconVisibilities() {
1489 if (mContractedWrapper != null) {
1490 NotificationHeaderView header = mContractedWrapper.getNotificationHeader();
1491 if (header != null) {
1492 header.getIcon().setForceHidden(!mIconsVisible);
1493 }
1494 }
1495 if (mHeadsUpWrapper != null) {
1496 NotificationHeaderView header = mHeadsUpWrapper.getNotificationHeader();
1497 if (header != null) {
1498 header.getIcon().setForceHidden(!mIconsVisible);
1499 }
1500 }
1501 if (mExpandedWrapper != null) {
1502 NotificationHeaderView header = mExpandedWrapper.getNotificationHeader();
1503 if (header != null) {
1504 header.getIcon().setForceHidden(!mIconsVisible);
1505 }
1506 }
1507 }
Selim Cinek6743c0b2017-01-18 18:24:01 -08001508
Adrian Roos4320e892017-01-24 12:50:34 -08001509 @Override
1510 public void onVisibilityAggregated(boolean isVisible) {
1511 super.onVisibilityAggregated(isVisible);
1512 if (isVisible) {
1513 fireExpandedVisibleListenerIfVisible();
1514 }
1515 }
1516
1517 /**
1518 * Sets a one-shot listener for when the expanded view becomes visible.
1519 *
1520 * This will fire the listener immediately if the expanded view is already visible.
1521 */
1522 public void setOnExpandedVisibleListener(Runnable r) {
1523 mExpandedVisibleListener = r;
1524 fireExpandedVisibleListenerIfVisible();
1525 }
1526
Selim Cinek6743c0b2017-01-18 18:24:01 -08001527 public void setIsLowPriority(boolean isLowPriority) {
1528 mIsLowPriority = isLowPriority;
1529 }
Selim Cinek63edaf22017-04-24 22:18:48 -07001530
1531 public boolean isDimmable() {
1532 if (!mContractedWrapper.isDimmable()) {
1533 return false;
1534 }
1535 return true;
1536 }
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07001537
1538 /**
1539 * Should a single click be disallowed on this view when on the keyguard?
1540 */
1541 public boolean disallowSingleClick(float x, float y) {
1542 NotificationViewWrapper visibleWrapper = getVisibleWrapper(getVisibleType());
1543 if (visibleWrapper != null) {
1544 return visibleWrapper.disallowSingleClick(x, y);
1545 }
1546 return false;
1547 }
Selim Cinek515b2032017-11-15 10:20:19 -08001548
Selim Cinek86bfcee2018-01-17 11:00:47 -08001549 public boolean shouldClipToRounding(boolean topRounded, boolean bottomRounded) {
1550 boolean needsPaddings = shouldClipToRounding(getVisibleType(), topRounded, bottomRounded);
Selim Cinek515b2032017-11-15 10:20:19 -08001551 if (mUserExpanding) {
Selim Cinek86bfcee2018-01-17 11:00:47 -08001552 needsPaddings |= shouldClipToRounding(mTransformationStartVisibleType, topRounded,
1553 bottomRounded);
Selim Cinek515b2032017-11-15 10:20:19 -08001554 }
1555 return needsPaddings;
1556 }
1557
Selim Cinek86bfcee2018-01-17 11:00:47 -08001558 private boolean shouldClipToRounding(int visibleType, boolean topRounded,
1559 boolean bottomRounded) {
Selim Cinek515b2032017-11-15 10:20:19 -08001560 NotificationViewWrapper visibleWrapper = getVisibleWrapper(visibleType);
1561 if (visibleWrapper == null) {
1562 return false;
1563 }
Selim Cinek86bfcee2018-01-17 11:00:47 -08001564 return visibleWrapper.shouldClipToRounding(topRounded, bottomRounded);
Selim Cinek515b2032017-11-15 10:20:19 -08001565 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001566}