blob: 91960df9b01d016e8a114cec6f0787dc0d851878 [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;
Selim Cinek83bc7832015-10-22 13:26:54 -070025import android.service.notification.StatusBarNotification;
Jorim Jaggibe565df2014-04-28 17:51:23 +020026import android.util.AttributeSet;
Selim Cinek011bde92017-11-22 05:53:38 -080027import android.util.Log;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080028import android.view.NotificationHeaderView;
Jorim Jaggibe565df2014-04-28 17:51:23 +020029import android.view.View;
Selim Cinek8d490d42015-04-10 00:05:50 -070030import android.view.ViewGroup;
Selim Cinekbb3d1cf2014-10-31 00:12:56 +010031import android.view.ViewTreeObserver;
Selim Cinekc9c00ae2014-05-20 03:33:40 +020032import android.widget.FrameLayout;
Selim Cineke9bad242016-06-15 11:46:37 -070033import android.widget.ImageView;
Petr Cermak7997d7a2018-01-18 15:52:10 +000034import android.widget.LinearLayout;
Selim Cinek8d490d42015-04-10 00:05:50 -070035
Adrian Roose18033c2017-01-17 15:22:49 -080036import com.android.internal.annotations.VisibleForTesting;
Adrian Roos4ff3b122016-02-01 12:26:13 -080037import com.android.internal.util.NotificationColorUtil;
Petr Cermak10011fa2018-02-05 19:00:54 +000038import com.android.systemui.Dependency;
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 Cermak10011fa2018-02-05 19:00:54 +000047import com.android.systemui.statusbar.policy.SmartReplyConstants;
Petr Cermak7997d7a2018-01-18 15:52:10 +000048import com.android.systemui.statusbar.policy.SmartReplyView;
Jorim Jaggibe565df2014-04-28 17:51:23 +020049
50/**
Selim Cinek684a4422015-04-15 16:18:39 -070051 * A frame layout containing the actual payload of the notification, including the contracted,
52 * expanded and heads up layout. This class is responsible for clipping the content and and
53 * switching between the expanded, contracted and the heads up view depending on its clipped size.
Jorim Jaggibe565df2014-04-28 17:51:23 +020054 */
Selim Cinekc9c00ae2014-05-20 03:33:40 +020055public class NotificationContentView extends FrameLayout {
Jorim Jaggibe565df2014-04-28 17:51:23 +020056
Selim Cinek011bde92017-11-22 05:53:38 -080057 private static final String TAG = "NotificationContentView";
Selim Cinek131f1a42017-06-05 17:50:19 -070058 public static final int VISIBLE_TYPE_CONTRACTED = 0;
59 public static final int VISIBLE_TYPE_EXPANDED = 1;
60 public static final int VISIBLE_TYPE_HEADSUP = 2;
Selim Cinek83bc7832015-10-22 13:26:54 -070061 private static final int VISIBLE_TYPE_SINGLELINE = 3;
Selim Cinek131f1a42017-06-05 17:50:19 -070062 public static final int VISIBLE_TYPE_AMBIENT = 4;
Adrian Roos6f6e1592017-05-02 16:22:53 -070063 private static final int VISIBLE_TYPE_AMBIENT_SINGLELINE = 5;
Selim Cinekc3179332016-03-04 14:44:56 -080064 public static final int UNDEFINED = -1;
Jorim Jaggi11298832014-05-24 16:18:38 +020065
Jorim Jaggibe565df2014-04-28 17:51:23 +020066 private final Rect mClipBounds = new Rect();
67
Selim Cinek9b49f6d2017-11-13 18:19:35 -080068 private int mMinContractedHeight;
69 private int mNotificationContentMarginEnd;
Jorim Jaggibe565df2014-04-28 17:51:23 +020070 private View mContractedChild;
71 private View mExpandedChild;
Selim Cinek8d490d42015-04-10 00:05:50 -070072 private View mHeadsUpChild;
Selim Cinek83bc7832015-10-22 13:26:54 -070073 private HybridNotificationView mSingleLineView;
Adrian Roos0aac04f2016-12-08 15:59:29 -080074 private View mAmbientChild;
Adrian Roos6f6e1592017-05-02 16:22:53 -070075 private HybridNotificationView mAmbientSingleLineChild;
Jorim Jaggibe565df2014-04-28 17:51:23 +020076
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070077 private RemoteInputView mExpandedRemoteInput;
78 private RemoteInputView mHeadsUpRemoteInput;
Petr Cermak10011fa2018-02-05 19:00:54 +000079
80 private SmartReplyConstants mSmartReplyConstants;
Petr Cermak7997d7a2018-01-18 15:52:10 +000081 private SmartReplyView mExpandedSmartReplyView;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070082
Jorim Jaggi4e857f42014-11-17 19:14:04 +010083 private NotificationViewWrapper mContractedWrapper;
Jorim Jaggibe4116a2015-05-20 20:04:08 -070084 private NotificationViewWrapper mExpandedWrapper;
85 private NotificationViewWrapper mHeadsUpWrapper;
Adrian Roos0aac04f2016-12-08 15:59:29 -080086 private NotificationViewWrapper mAmbientWrapper;
Selim Cinekc897bd32016-03-18 17:32:31 -070087 private HybridGroupManager mHybridGroupManager;
Selim Cinekc9c00ae2014-05-20 03:33:40 +020088 private int mClipTopAmount;
Selim Cinekb5605e52015-02-20 18:21:41 +010089 private int mContentHeight;
Selim Cinek684a4422015-04-15 16:18:39 -070090 private int mVisibleType = VISIBLE_TYPE_CONTRACTED;
John Spurlocke15452b2014-08-21 09:44:39 -040091 private boolean mDark;
Selim Cinekbb3d1cf2014-10-31 00:12:56 +010092 private boolean mAnimate;
Selim Cinek684a4422015-04-15 16:18:39 -070093 private boolean mIsHeadsUp;
Selim Cinek1a48bab2017-02-17 19:38:40 -080094 private boolean mLegacy;
Selim Cinek83bc7832015-10-22 13:26:54 -070095 private boolean mIsChildInGroup;
Selim Cinek816c8e42015-11-19 12:00:45 -080096 private int mSmallHeight;
Selim Cinek77019c72015-12-09 10:18:02 -080097 private int mHeadsUpHeight;
Selim Cinekd84a5932015-12-15 11:45:36 -080098 private int mNotificationMaxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -080099 private int mNotificationAmbientHeight;
Selim Cinek83bc7832015-10-22 13:26:54 -0700100 private StatusBarNotification mStatusBarNotification;
Selim Cinek65b2e7c2015-10-26 14:11:31 -0700101 private NotificationGroupManager mGroupManager;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800102 private RemoteInputController mRemoteInputController;
Adrian Roos4320e892017-01-24 12:50:34 -0800103 private Runnable mExpandedVisibleListener;
Jorim Jaggi59ec3042015-06-05 15:18:43 -0700104
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700105 private final ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100106 = new ViewTreeObserver.OnPreDrawListener() {
107 @Override
108 public boolean onPreDraw() {
Selim Cinekd1ad9ab2016-03-01 17:52:20 -0800109 // We need to post since we don't want the notification to animate on the very first
110 // frame
111 post(new Runnable() {
112 @Override
113 public void run() {
114 mAnimate = true;
115 }
116 });
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100117 getViewTreeObserver().removeOnPreDrawListener(this);
118 return true;
119 }
120 };
Jorim Jaggi11298832014-05-24 16:18:38 +0200121
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800122 private OnClickListener mExpandClickListener;
Selim Cinek860b6da2015-12-16 19:02:19 -0800123 private boolean mBeforeN;
Selim Cinek98be3f32015-12-17 16:39:06 -0800124 private boolean mExpandable;
Selim Cinek4ffd6362015-12-29 15:12:23 +0100125 private boolean mClipToActualHeight = true;
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800126 private ExpandableNotificationRow mContainingNotification;
Adrian Roos599be342016-06-13 14:54:39 -0700127 /** The visible type at the start of a touch driven transformation */
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800128 private int mTransformationStartVisibleType;
Adrian Roos599be342016-06-13 14:54:39 -0700129 /** The visible type at the start of an animation driven transformation */
130 private int mAnimationStartVisibleType = UNDEFINED;
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800131 private boolean mUserExpanding;
Selim Cinekc897bd32016-03-18 17:32:31 -0700132 private int mSingleLineWidthIndention;
Selim Cinek589fd3e2016-04-26 18:17:57 -0700133 private boolean mForceSelectNextLayout = true;
Adrian Roos4c1fcc82016-03-31 14:39:39 -0700134 private PendingIntent mPreviousExpandedRemoteInputIntent;
135 private PendingIntent mPreviousHeadsUpRemoteInputIntent;
Adrian Roos7813dd72016-09-23 17:12:17 -0700136 private RemoteInputView mCachedExpandedRemoteInput;
137 private RemoteInputView mCachedHeadsUpRemoteInput;
Selim Cinek98be3f32015-12-17 16:39:06 -0800138
Adrian Roos599be342016-06-13 14:54:39 -0700139 private int mContentHeightAtAnimationStart = UNDEFINED;
Selim Cineke9bad242016-06-15 11:46:37 -0700140 private boolean mFocusOnVisibilityChange;
Selim Cinekcafa87f2016-10-26 17:00:17 -0700141 private boolean mHeadsUpAnimatingAway;
Selim Cinek0242fbb2016-10-19 13:38:32 -0700142 private boolean mIconsVisible;
Selim Cineka686b2c2016-10-26 13:58:27 -0700143 private int mClipBottomAmount;
Selim Cinek6743c0b2017-01-18 18:24:01 -0800144 private boolean mIsLowPriority;
Selim Cinekc0ac4af2017-03-03 15:13:48 -0800145 private boolean mIsContentExpandable;
Selim Cineked64a142018-02-06 18:06:01 -0800146 private boolean mRemoteInputVisible;
147 private int mUnrestrictedContentHeight;
Adrian Roos599be342016-06-13 14:54:39 -0700148
149
Jorim Jaggibe565df2014-04-28 17:51:23 +0200150 public NotificationContentView(Context context, AttributeSet attrs) {
151 super(context, attrs);
Selim Cinekc897bd32016-03-18 17:32:31 -0700152 mHybridGroupManager = new HybridGroupManager(getContext(), this);
Petr Cermak10011fa2018-02-05 19:00:54 +0000153 mSmartReplyConstants = Dependency.get(SmartReplyConstants.class);
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800154 initView();
155 }
156
157 public void initView() {
Selim Cinek860b6da2015-12-16 19:02:19 -0800158 mMinContractedHeight = getResources().getDimensionPixelSize(
159 R.dimen.min_notification_layout_height);
Selim Cinek6ecc8102016-01-26 18:26:19 -0800160 mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
161 com.android.internal.R.dimen.notification_content_margin_end);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200162 }
163
Adrian Roos0aac04f2016-12-08 15:59:29 -0800164 public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight,
165 int ambientHeight) {
Selim Cinek816c8e42015-11-19 12:00:45 -0800166 mSmallHeight = smallHeight;
Selim Cinek77019c72015-12-09 10:18:02 -0800167 mHeadsUpHeight = headsUpMaxHeight;
Selim Cinekd84a5932015-12-15 11:45:36 -0800168 mNotificationMaxHeight = maxHeight;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800169 mNotificationAmbientHeight = ambientHeight;
Selim Cinek816c8e42015-11-19 12:00:45 -0800170 }
171
Jorim Jaggibe565df2014-04-28 17:51:23 +0200172 @Override
Selim Cinek8d490d42015-04-10 00:05:50 -0700173 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
174 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
175 boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
176 boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
177 int maxSize = Integer.MAX_VALUE;
Selim Cinekc897bd32016-03-18 17:32:31 -0700178 int width = MeasureSpec.getSize(widthMeasureSpec);
Selim Cinek8d490d42015-04-10 00:05:50 -0700179 if (hasFixedHeight || isHeightLimited) {
180 maxSize = MeasureSpec.getSize(heightMeasureSpec);
181 }
182 int maxChildHeight = 0;
Selim Cinek6ecc8102016-01-26 18:26:19 -0800183 if (mExpandedChild != null) {
184 int size = Math.min(maxSize, mNotificationMaxHeight);
185 ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800186 boolean useExactly = false;
Selim Cinek6ecc8102016-01-26 18:26:19 -0800187 if (layoutParams.height >= 0) {
188 // An actual height is set
189 size = Math.min(maxSize, layoutParams.height);
Selim Cinek6743c0b2017-01-18 18:24:01 -0800190 useExactly = true;
Selim Cinek6ecc8102016-01-26 18:26:19 -0800191 }
192 int spec = size == Integer.MAX_VALUE
193 ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
Selim Cinek6743c0b2017-01-18 18:24:01 -0800194 : MeasureSpec.makeMeasureSpec(size, useExactly
195 ? MeasureSpec.EXACTLY
196 : MeasureSpec.AT_MOST);
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800197 measureChildWithMargins(mExpandedChild, widthMeasureSpec, 0, spec, 0);
Selim Cinek6ecc8102016-01-26 18:26:19 -0800198 maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
199 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700200 if (mContractedChild != null) {
Selim Cinek860b6da2015-12-16 19:02:19 -0800201 int heightSpec;
Selim Cinekf619ffc2016-02-17 14:53:05 -0800202 int size = Math.min(maxSize, mSmallHeight);
Selim Cinek6743c0b2017-01-18 18:24:01 -0800203 ViewGroup.LayoutParams layoutParams = mContractedChild.getLayoutParams();
204 boolean useExactly = false;
205 if (layoutParams.height >= 0) {
206 // An actual height is set
207 size = Math.min(size, layoutParams.height);
208 useExactly = true;
209 }
210 if (shouldContractedBeFixedSize() || useExactly) {
Selim Cinek860b6da2015-12-16 19:02:19 -0800211 heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
212 } else {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800213 heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
Selim Cinek860b6da2015-12-16 19:02:19 -0800214 }
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800215 measureChildWithMargins(mContractedChild, widthMeasureSpec, 0, heightSpec, 0);
Selim Cinek860b6da2015-12-16 19:02:19 -0800216 int measuredHeight = mContractedChild.getMeasuredHeight();
217 if (measuredHeight < mMinContractedHeight) {
218 heightSpec = MeasureSpec.makeMeasureSpec(mMinContractedHeight, MeasureSpec.EXACTLY);
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800219 measureChildWithMargins(mContractedChild, widthMeasureSpec, 0, heightSpec, 0);
Selim Cinek860b6da2015-12-16 19:02:19 -0800220 }
221 maxChildHeight = Math.max(maxChildHeight, measuredHeight);
Selim Cinek6ecc8102016-01-26 18:26:19 -0800222 if (updateContractedHeaderWidth()) {
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800223 measureChildWithMargins(mContractedChild, widthMeasureSpec, 0, heightSpec, 0);
Selim Cinek8d490d42015-04-10 00:05:50 -0700224 }
Selim Cinek1ba41d12016-04-21 16:14:46 -0700225 if (mExpandedChild != null
226 && mContractedChild.getMeasuredHeight() > mExpandedChild.getMeasuredHeight()) {
227 // the Expanded child is smaller then the collapsed. Let's remeasure it.
228 heightSpec = MeasureSpec.makeMeasureSpec(mContractedChild.getMeasuredHeight(),
229 MeasureSpec.EXACTLY);
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800230 measureChildWithMargins(mExpandedChild, widthMeasureSpec, 0, heightSpec, 0);
Selim Cinek1ba41d12016-04-21 16:14:46 -0700231 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700232 }
233 if (mHeadsUpChild != null) {
234 int size = Math.min(maxSize, mHeadsUpHeight);
235 ViewGroup.LayoutParams layoutParams = mHeadsUpChild.getLayoutParams();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800236 boolean useExactly = false;
Selim Cinek8d490d42015-04-10 00:05:50 -0700237 if (layoutParams.height >= 0) {
238 // An actual height is set
Selim Cinek77019c72015-12-09 10:18:02 -0800239 size = Math.min(size, layoutParams.height);
Selim Cinek6743c0b2017-01-18 18:24:01 -0800240 useExactly = true;
Selim Cinek8d490d42015-04-10 00:05:50 -0700241 }
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800242 measureChildWithMargins(mHeadsUpChild, widthMeasureSpec, 0,
Selim Cinek6743c0b2017-01-18 18:24:01 -0800243 MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800244 : MeasureSpec.AT_MOST), 0);
Selim Cinek8d490d42015-04-10 00:05:50 -0700245 maxChildHeight = Math.max(maxChildHeight, mHeadsUpChild.getMeasuredHeight());
246 }
Selim Cinek83bc7832015-10-22 13:26:54 -0700247 if (mSingleLineView != null) {
Selim Cinekc897bd32016-03-18 17:32:31 -0700248 int singleLineWidthSpec = widthMeasureSpec;
249 if (mSingleLineWidthIndention != 0
250 && MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
251 singleLineWidthSpec = MeasureSpec.makeMeasureSpec(
252 width - mSingleLineWidthIndention + mSingleLineView.getPaddingEnd(),
Selim Cinek09b7dea2016-08-30 11:28:19 -0700253 MeasureSpec.EXACTLY);
Selim Cinekc897bd32016-03-18 17:32:31 -0700254 }
255 mSingleLineView.measure(singleLineWidthSpec,
Selim Cinek7b836392015-12-04 20:02:59 -0800256 MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST));
Selim Cinek83bc7832015-10-22 13:26:54 -0700257 maxChildHeight = Math.max(maxChildHeight, mSingleLineView.getMeasuredHeight());
258 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800259 if (mAmbientChild != null) {
260 int size = Math.min(maxSize, mNotificationAmbientHeight);
261 ViewGroup.LayoutParams layoutParams = mAmbientChild.getLayoutParams();
Selim Cinek6743c0b2017-01-18 18:24:01 -0800262 boolean useExactly = false;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800263 if (layoutParams.height >= 0) {
264 // An actual height is set
265 size = Math.min(size, layoutParams.height);
Selim Cinek6743c0b2017-01-18 18:24:01 -0800266 useExactly = true;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800267 }
268 mAmbientChild.measure(widthMeasureSpec,
Selim Cinek6743c0b2017-01-18 18:24:01 -0800269 MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
270 : MeasureSpec.AT_MOST));
Adrian Roos0aac04f2016-12-08 15:59:29 -0800271 maxChildHeight = Math.max(maxChildHeight, mAmbientChild.getMeasuredHeight());
272 }
Adrian Roos6f6e1592017-05-02 16:22:53 -0700273 if (mAmbientSingleLineChild != null) {
274 int size = Math.min(maxSize, mNotificationAmbientHeight);
275 ViewGroup.LayoutParams layoutParams = mAmbientSingleLineChild.getLayoutParams();
276 boolean useExactly = false;
277 if (layoutParams.height >= 0) {
278 // An actual height is set
279 size = Math.min(size, layoutParams.height);
280 useExactly = true;
281 }
282 int ambientSingleLineWidthSpec = widthMeasureSpec;
283 if (mSingleLineWidthIndention != 0
284 && MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
285 ambientSingleLineWidthSpec = MeasureSpec.makeMeasureSpec(
286 width - mSingleLineWidthIndention + mAmbientSingleLineChild.getPaddingEnd(),
287 MeasureSpec.EXACTLY);
288 }
289 mAmbientSingleLineChild.measure(ambientSingleLineWidthSpec,
290 MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
291 : MeasureSpec.AT_MOST));
292 maxChildHeight = Math.max(maxChildHeight, mAmbientSingleLineChild.getMeasuredHeight());
293 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700294 int ownHeight = Math.min(maxChildHeight, maxSize);
Selim Cinek8d490d42015-04-10 00:05:50 -0700295 setMeasuredDimension(width, ownHeight);
296 }
297
Selim Cineked64a142018-02-06 18:06:01 -0800298 /**
299 * Get the extra height that needs to be added to the notification height for a given
300 * {@link RemoteInputView}.
301 * This is needed when the user is inline replying in order to ensure that the reply bar has
302 * enough padding.
303 *
304 * @param remoteInput The remote input to check.
305 * @return The extra height needed.
306 */
307 private int getExtraRemoteInputHeight(RemoteInputView remoteInput) {
308 if (remoteInput != null && remoteInput.getVisibility() == VISIBLE
309 && remoteInput.isActive()) {
310 return getResources().getDimensionPixelSize(
311 com.android.internal.R.dimen.notification_content_margin);
312 }
313 return 0;
314 }
315
Selim Cinek6ecc8102016-01-26 18:26:19 -0800316 private boolean updateContractedHeaderWidth() {
317 // We need to update the expanded and the collapsed header to have exactly the same with to
318 // have the expand buttons laid out at the same location.
319 NotificationHeaderView contractedHeader = mContractedWrapper.getNotificationHeader();
320 if (contractedHeader != null) {
321 if (mExpandedChild != null
322 && mExpandedWrapper.getNotificationHeader() != null) {
323 NotificationHeaderView expandedHeader = mExpandedWrapper.getNotificationHeader();
324 int expandedSize = expandedHeader.getMeasuredWidth()
325 - expandedHeader.getPaddingEnd();
326 int collapsedSize = contractedHeader.getMeasuredWidth()
327 - expandedHeader.getPaddingEnd();
328 if (expandedSize != collapsedSize) {
329 int paddingEnd = contractedHeader.getMeasuredWidth() - expandedSize;
330 contractedHeader.setPadding(
Selim Cinekcb445682016-01-29 16:13:12 -0800331 contractedHeader.isLayoutRtl()
332 ? paddingEnd
333 : contractedHeader.getPaddingLeft(),
Selim Cinek6ecc8102016-01-26 18:26:19 -0800334 contractedHeader.getPaddingTop(),
Selim Cinekcb445682016-01-29 16:13:12 -0800335 contractedHeader.isLayoutRtl()
336 ? contractedHeader.getPaddingLeft()
337 : paddingEnd,
Selim Cinek6ecc8102016-01-26 18:26:19 -0800338 contractedHeader.getPaddingBottom());
339 contractedHeader.setShowWorkBadgeAtEnd(true);
340 return true;
341 }
342 } else {
343 int paddingEnd = mNotificationContentMarginEnd;
344 if (contractedHeader.getPaddingEnd() != paddingEnd) {
345 contractedHeader.setPadding(
Selim Cinekcb445682016-01-29 16:13:12 -0800346 contractedHeader.isLayoutRtl()
347 ? paddingEnd
348 : contractedHeader.getPaddingLeft(),
Selim Cinek6ecc8102016-01-26 18:26:19 -0800349 contractedHeader.getPaddingTop(),
Selim Cinekcb445682016-01-29 16:13:12 -0800350 contractedHeader.isLayoutRtl()
351 ? contractedHeader.getPaddingLeft()
352 : paddingEnd,
Selim Cinek6ecc8102016-01-26 18:26:19 -0800353 contractedHeader.getPaddingBottom());
354 contractedHeader.setShowWorkBadgeAtEnd(false);
355 return true;
356 }
357 }
358 }
359 return false;
360 }
361
Selim Cinek860b6da2015-12-16 19:02:19 -0800362 private boolean shouldContractedBeFixedSize() {
363 return mBeforeN && mContractedWrapper instanceof NotificationCustomViewWrapper;
364 }
365
Selim Cinek8d490d42015-04-10 00:05:50 -0700366 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +0200367 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Adrian Roos599be342016-06-13 14:54:39 -0700368 int previousHeight = 0;
369 if (mExpandedChild != null) {
370 previousHeight = mExpandedChild.getHeight();
371 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200372 super.onLayout(changed, left, top, right, bottom);
Adrian Roos599be342016-06-13 14:54:39 -0700373 if (previousHeight != 0 && mExpandedChild.getHeight() != previousHeight) {
374 mContentHeightAtAnimationStart = previousHeight;
375 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200376 updateClipping();
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700377 invalidateOutline();
Selim Cinek589fd3e2016-04-26 18:17:57 -0700378 selectLayout(false /* animate */, mForceSelectNextLayout /* force */);
379 mForceSelectNextLayout = false;
Selim Cinek5f56d852016-05-24 16:55:13 -0700380 updateExpandButtons(mExpandable);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200381 }
382
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100383 @Override
Selim Cinek7b8157e2014-11-20 16:00:32 +0100384 protected void onAttachedToWindow() {
385 super.onAttachedToWindow();
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100386 updateVisibility();
387 }
388
Selim Cinekcab4a602014-09-03 14:47:57 +0200389 public View getContractedChild() {
390 return mContractedChild;
391 }
392
393 public View getExpandedChild() {
394 return mExpandedChild;
395 }
396
Selim Cinek8d490d42015-04-10 00:05:50 -0700397 public View getHeadsUpChild() {
398 return mHeadsUpChild;
399 }
400
Adrian Roos0aac04f2016-12-08 15:59:29 -0800401 public View getAmbientChild() {
402 return mAmbientChild;
403 }
404
Adrian Roos6f6e1592017-05-02 16:22:53 -0700405 public HybridNotificationView getAmbientSingleLineChild() {
406 return mAmbientSingleLineChild;
407 }
408
Jorim Jaggibe565df2014-04-28 17:51:23 +0200409 public void setContractedChild(View child) {
410 if (mContractedChild != null) {
Jorim Jaggi0d9f35d2014-08-20 17:06:55 +0200411 mContractedChild.animate().cancel();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200412 removeView(mContractedChild);
413 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200414 addView(child);
415 mContractedChild = child;
Selim Cinek7d1c63e2016-04-21 15:26:10 -0700416 mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child,
417 mContainingNotification);
Jorim Jaggi10ad7612014-12-08 18:41:11 +0100418 mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
Selim Cinek9b49f6d2017-11-13 18:19:35 -0800419 }
420
421 private NotificationViewWrapper getWrapperForView(View child) {
422 if (child == mContractedChild) {
423 return mContractedWrapper;
424 }
425 if (child == mExpandedChild) {
426 return mExpandedWrapper;
427 }
428 if (child == mHeadsUpChild) {
429 return mHeadsUpWrapper;
430 }
431 if (child == mAmbientChild) {
432 return mAmbientWrapper;
433 }
434 return null;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200435 }
436
437 public void setExpandedChild(View child) {
438 if (mExpandedChild != null) {
Selim Cinek1a48bab2017-02-17 19:38:40 -0800439 mPreviousExpandedRemoteInputIntent = null;
440 if (mExpandedRemoteInput != null) {
441 mExpandedRemoteInput.onNotificationUpdateOrReset();
442 if (mExpandedRemoteInput.isActive()) {
443 mPreviousExpandedRemoteInputIntent = mExpandedRemoteInput.getPendingIntent();
444 mCachedExpandedRemoteInput = mExpandedRemoteInput;
445 mExpandedRemoteInput.dispatchStartTemporaryDetach();
446 ((ViewGroup)mExpandedRemoteInput.getParent()).removeView(mExpandedRemoteInput);
447 }
448 }
Jorim Jaggi0d9f35d2014-08-20 17:06:55 +0200449 mExpandedChild.animate().cancel();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200450 removeView(mExpandedChild);
Selim Cinek1a48bab2017-02-17 19:38:40 -0800451 mExpandedRemoteInput = null;
452 }
453 if (child == null) {
454 mExpandedChild = null;
455 mExpandedWrapper = null;
456 if (mVisibleType == VISIBLE_TYPE_EXPANDED) {
457 mVisibleType = VISIBLE_TYPE_CONTRACTED;
458 }
459 if (mTransformationStartVisibleType == VISIBLE_TYPE_EXPANDED) {
460 mTransformationStartVisibleType = UNDEFINED;
461 }
462 return;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200463 }
464 addView(child);
465 mExpandedChild = child;
Selim Cinek7d1c63e2016-04-21 15:26:10 -0700466 mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child,
467 mContainingNotification);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200468 }
469
Selim Cinek8d490d42015-04-10 00:05:50 -0700470 public void setHeadsUpChild(View child) {
471 if (mHeadsUpChild != null) {
Selim Cinek1a48bab2017-02-17 19:38:40 -0800472 mPreviousHeadsUpRemoteInputIntent = null;
473 if (mHeadsUpRemoteInput != null) {
474 mHeadsUpRemoteInput.onNotificationUpdateOrReset();
475 if (mHeadsUpRemoteInput.isActive()) {
476 mPreviousHeadsUpRemoteInputIntent = mHeadsUpRemoteInput.getPendingIntent();
477 mCachedHeadsUpRemoteInput = mHeadsUpRemoteInput;
478 mHeadsUpRemoteInput.dispatchStartTemporaryDetach();
479 ((ViewGroup)mHeadsUpRemoteInput.getParent()).removeView(mHeadsUpRemoteInput);
480 }
481 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700482 mHeadsUpChild.animate().cancel();
483 removeView(mHeadsUpChild);
Selim Cinek1a48bab2017-02-17 19:38:40 -0800484 mHeadsUpRemoteInput = null;
485 }
486 if (child == null) {
487 mHeadsUpChild = null;
488 mHeadsUpWrapper = null;
489 if (mVisibleType == VISIBLE_TYPE_HEADSUP) {
490 mVisibleType = VISIBLE_TYPE_CONTRACTED;
491 }
492 if (mTransformationStartVisibleType == VISIBLE_TYPE_HEADSUP) {
493 mTransformationStartVisibleType = UNDEFINED;
494 }
495 return;
Selim Cinek8d490d42015-04-10 00:05:50 -0700496 }
497 addView(child);
498 mHeadsUpChild = child;
Selim Cinek7d1c63e2016-04-21 15:26:10 -0700499 mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child,
500 mContainingNotification);
Selim Cinek8d490d42015-04-10 00:05:50 -0700501 }
502
Adrian Roos0aac04f2016-12-08 15:59:29 -0800503 public void setAmbientChild(View child) {
504 if (mAmbientChild != null) {
505 mAmbientChild.animate().cancel();
506 removeView(mAmbientChild);
507 }
Adrian Roos1a1ecfc2017-04-17 11:17:59 -0700508 if (child == null) {
509 return;
510 }
Adrian Roos0aac04f2016-12-08 15:59:29 -0800511 addView(child);
512 mAmbientChild = child;
513 mAmbientWrapper = NotificationViewWrapper.wrap(getContext(), child,
514 mContainingNotification);
515 }
516
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100517 @Override
518 protected void onVisibilityChanged(View changedView, int visibility) {
519 super.onVisibilityChanged(changedView, visibility);
520 updateVisibility();
521 }
522
523 private void updateVisibility() {
524 setVisible(isShown());
525 }
526
Jorim Jaggi38b5ec92016-04-12 01:39:49 -0700527 @Override
528 protected void onDetachedFromWindow() {
529 super.onDetachedFromWindow();
530 getViewTreeObserver().removeOnPreDrawListener(mEnableAnimationPredrawListener);
531 }
532
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100533 private void setVisible(final boolean isVisible) {
534 if (isVisible) {
Selim Cinekf1614a62016-05-26 16:57:20 -0700535 // This call can happen multiple times, but removing only removes a single one.
536 // We therefore need to remove the old one.
537 getViewTreeObserver().removeOnPreDrawListener(mEnableAnimationPredrawListener);
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100538 // We only animate if we are drawn at least once, otherwise the view might animate when
539 // it's shown the first time
540 getViewTreeObserver().addOnPreDrawListener(mEnableAnimationPredrawListener);
541 } else {
542 getViewTreeObserver().removeOnPreDrawListener(mEnableAnimationPredrawListener);
543 mAnimate = false;
544 }
545 }
546
Selim Cineke9bad242016-06-15 11:46:37 -0700547 private void focusExpandButtonIfNecessary() {
548 if (mFocusOnVisibilityChange) {
549 NotificationHeaderView header = getVisibleNotificationHeader();
550 if (header != null) {
551 ImageView expandButton = header.getExpandButton();
552 if (expandButton != null) {
553 expandButton.requestAccessibilityFocus();
554 }
555 }
556 mFocusOnVisibilityChange = false;
557 }
558 }
559
Selim Cinekb5605e52015-02-20 18:21:41 +0100560 public void setContentHeight(int contentHeight) {
Selim Cineked64a142018-02-06 18:06:01 -0800561 mUnrestrictedContentHeight = Math.max(contentHeight, getMinHeight());
562 int maxContentHeight = mContainingNotification.getIntrinsicHeight()
563 - getExtraRemoteInputHeight(mExpandedRemoteInput)
564 - getExtraRemoteInputHeight(mHeadsUpRemoteInput);
565 mContentHeight = Math.min(mUnrestrictedContentHeight, maxContentHeight);
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100566 selectLayout(mAnimate /* animate */, false /* force */);
Adrian Roos181385c2016-05-05 17:45:44 -0400567
568 int minHeightHint = getMinContentHeightHint();
569
570 NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
571 if (wrapper != null) {
Selim Cineked64a142018-02-06 18:06:01 -0800572 wrapper.setContentHeight(mUnrestrictedContentHeight, minHeightHint);
Adrian Roos181385c2016-05-05 17:45:44 -0400573 }
574
575 wrapper = getVisibleWrapper(mTransformationStartVisibleType);
576 if (wrapper != null) {
Selim Cineked64a142018-02-06 18:06:01 -0800577 wrapper.setContentHeight(mUnrestrictedContentHeight, minHeightHint);
Adrian Roos181385c2016-05-05 17:45:44 -0400578 }
579
Jorim Jaggibe565df2014-04-28 17:51:23 +0200580 updateClipping();
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700581 invalidateOutline();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200582 }
583
Adrian Roos181385c2016-05-05 17:45:44 -0400584 /**
585 * @return the minimum apparent height that the wrapper should allow for the purpose
586 * of aligning elements at the bottom edge. If this is larger than the content
587 * height, the notification is clipped instead of being further shrunk.
588 */
589 private int getMinContentHeightHint() {
Adrian Roos599be342016-06-13 14:54:39 -0700590 if (mIsChildInGroup && isVisibleOrTransitioning(VISIBLE_TYPE_SINGLELINE)) {
Adrian Roos181385c2016-05-05 17:45:44 -0400591 return mContext.getResources().getDimensionPixelSize(
592 com.android.internal.R.dimen.notification_action_list_height);
593 }
Adrian Roos599be342016-06-13 14:54:39 -0700594
595 // Transition between heads-up & expanded, or pinned.
596 if (mHeadsUpChild != null && mExpandedChild != null) {
597 boolean transitioningBetweenHunAndExpanded =
598 isTransitioningFromTo(VISIBLE_TYPE_HEADSUP, VISIBLE_TYPE_EXPANDED) ||
599 isTransitioningFromTo(VISIBLE_TYPE_EXPANDED, VISIBLE_TYPE_HEADSUP);
Selim Cinek73cf02a2016-06-17 13:08:00 -0700600 boolean pinned = !isVisibleOrTransitioning(VISIBLE_TYPE_CONTRACTED)
Selim Cinekc494e382017-01-31 16:09:23 -0800601 && (mIsHeadsUp || mHeadsUpAnimatingAway)
602 && !mContainingNotification.isOnKeyguard();
Adrian Roos599be342016-06-13 14:54:39 -0700603 if (transitioningBetweenHunAndExpanded || pinned) {
604 return Math.min(mHeadsUpChild.getHeight(), mExpandedChild.getHeight());
605 }
606 }
607
608 // Size change of the expanded version
609 if ((mVisibleType == VISIBLE_TYPE_EXPANDED) && mContentHeightAtAnimationStart >= 0
610 && mExpandedChild != null) {
611 return Math.min(mContentHeightAtAnimationStart, mExpandedChild.getHeight());
612 }
613
Adrian Roosbb73e9c62016-05-26 12:06:40 -0700614 int hint;
Adrian Roos05d3d002017-01-26 15:28:07 -0800615 if (mAmbientChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_AMBIENT)) {
616 hint = mAmbientChild.getHeight();
Adrian Roos6f6e1592017-05-02 16:22:53 -0700617 } else if (mAmbientSingleLineChild != null && isVisibleOrTransitioning(
618 VISIBLE_TYPE_AMBIENT_SINGLELINE)) {
619 hint = mAmbientSingleLineChild.getHeight();
Adrian Roos05d3d002017-01-26 15:28:07 -0800620 } else if (mHeadsUpChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_HEADSUP)) {
Adrian Roosbb73e9c62016-05-26 12:06:40 -0700621 hint = mHeadsUpChild.getHeight();
Adrian Roos599be342016-06-13 14:54:39 -0700622 } else if (mExpandedChild != null) {
623 hint = mExpandedChild.getHeight();
Adrian Roos181385c2016-05-05 17:45:44 -0400624 } else {
Adrian Roosbb73e9c62016-05-26 12:06:40 -0700625 hint = mContractedChild.getHeight() + mContext.getResources().getDimensionPixelSize(
626 com.android.internal.R.dimen.notification_action_list_height);
Adrian Roos181385c2016-05-05 17:45:44 -0400627 }
Adrian Roos599be342016-06-13 14:54:39 -0700628
629 if (mExpandedChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_EXPANDED)) {
Adrian Roosbb73e9c62016-05-26 12:06:40 -0700630 hint = Math.min(hint, mExpandedChild.getHeight());
631 }
632 return hint;
Adrian Roos181385c2016-05-05 17:45:44 -0400633 }
634
Adrian Roos599be342016-06-13 14:54:39 -0700635 private boolean isTransitioningFromTo(int from, int to) {
636 return (mTransformationStartVisibleType == from || mAnimationStartVisibleType == from)
637 && mVisibleType == to;
638 }
639
640 private boolean isVisibleOrTransitioning(int type) {
641 return mVisibleType == type || mTransformationStartVisibleType == type
642 || mAnimationStartVisibleType == type;
643 }
644
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800645 private void updateContentTransformation() {
646 int visibleType = calculateVisibleType();
647 if (visibleType != mVisibleType) {
648 // A new transformation starts
649 mTransformationStartVisibleType = mVisibleType;
650 final TransformableView shownView = getTransformableViewForVisibleType(visibleType);
651 final TransformableView hiddenView = getTransformableViewForVisibleType(
652 mTransformationStartVisibleType);
653 shownView.transformFrom(hiddenView, 0.0f);
654 getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
655 hiddenView.transformTo(shownView, 0.0f);
656 mVisibleType = visibleType;
Selim Cinekc3179332016-03-04 14:44:56 -0800657 updateBackgroundColor(true /* animate */);
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800658 }
Selim Cineke8578872016-05-03 16:42:50 -0700659 if (mForceSelectNextLayout) {
660 forceUpdateVisibilities();
661 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800662 if (mTransformationStartVisibleType != UNDEFINED
Selim Cinek589fd3e2016-04-26 18:17:57 -0700663 && mVisibleType != mTransformationStartVisibleType
664 && getViewForVisibleType(mTransformationStartVisibleType) != null) {
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800665 final TransformableView shownView = getTransformableViewForVisibleType(mVisibleType);
666 final TransformableView hiddenView = getTransformableViewForVisibleType(
667 mTransformationStartVisibleType);
668 float transformationAmount = calculateTransformationAmount();
669 shownView.transformFrom(hiddenView, transformationAmount);
670 hiddenView.transformTo(shownView, transformationAmount);
Selim Cinekc3179332016-03-04 14:44:56 -0800671 updateBackgroundTransformation(transformationAmount);
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800672 } else {
673 updateViewVisibilities(visibleType);
Selim Cinekc3179332016-03-04 14:44:56 -0800674 updateBackgroundColor(false);
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800675 }
676 }
677
Selim Cinekc3179332016-03-04 14:44:56 -0800678 private void updateBackgroundTransformation(float transformationAmount) {
679 int endColor = getBackgroundColor(mVisibleType);
680 int startColor = getBackgroundColor(mTransformationStartVisibleType);
681 if (endColor != startColor) {
682 if (startColor == 0) {
683 startColor = mContainingNotification.getBackgroundColorWithoutTint();
684 }
685 if (endColor == 0) {
686 endColor = mContainingNotification.getBackgroundColorWithoutTint();
687 }
688 endColor = NotificationUtils.interpolateColors(startColor, endColor,
689 transformationAmount);
690 }
Mady Mellorc7d65b42016-05-04 11:44:57 -0400691 mContainingNotification.updateBackgroundAlpha(transformationAmount);
Selim Cinekc3179332016-03-04 14:44:56 -0800692 mContainingNotification.setContentBackground(endColor, false, this);
693 }
694
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800695 private float calculateTransformationAmount() {
696 int startHeight = getViewForVisibleType(mTransformationStartVisibleType).getHeight();
697 int endHeight = getViewForVisibleType(mVisibleType).getHeight();
698 int progress = Math.abs(mContentHeight - startHeight);
699 int totalDistance = Math.abs(endHeight - startHeight);
Selim Cinek011bde92017-11-22 05:53:38 -0800700 if (totalDistance == 0) {
701 Log.wtf(TAG, "the total transformation distance is 0"
702 + "\n StartType: " + mTransformationStartVisibleType + " height: " + startHeight
703 + "\n VisibleType: " + mVisibleType + " height: " + endHeight
704 + "\n mContentHeight: " + mContentHeight);
705 return 1.0f;
706 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800707 float amount = (float) progress / (float) totalDistance;
708 return Math.min(1.0f, amount);
709 }
710
Selim Cinekb5605e52015-02-20 18:21:41 +0100711 public int getContentHeight() {
712 return mContentHeight;
713 }
714
Jorim Jaggibe565df2014-04-28 17:51:23 +0200715 public int getMaxHeight() {
Adrian Roos6f6e1592017-05-02 16:22:53 -0700716 if (mContainingNotification.isShowingAmbient()) {
717 return getShowingAmbientView().getHeight();
718 } else if (mExpandedChild != null) {
Selim Cineked64a142018-02-06 18:06:01 -0800719 return mExpandedChild.getHeight() + getExtraRemoteInputHeight(mExpandedRemoteInput);
Selim Cinekc494e382017-01-31 16:09:23 -0800720 } else if (mIsHeadsUp && mHeadsUpChild != null && !mContainingNotification.isOnKeyguard()) {
Selim Cineked64a142018-02-06 18:06:01 -0800721 return mHeadsUpChild.getHeight() + getExtraRemoteInputHeight(mHeadsUpRemoteInput);
Selim Cinek8d490d42015-04-10 00:05:50 -0700722 }
Selim Cinek860b6da2015-12-16 19:02:19 -0800723 return mContractedChild.getHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200724 }
725
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200726 public int getMinHeight() {
Selim Cinek42357e02016-02-24 18:48:01 -0800727 return getMinHeight(false /* likeGroupExpanded */);
728 }
729
730 public int getMinHeight(boolean likeGroupExpanded) {
Adrian Roos6f6e1592017-05-02 16:22:53 -0700731 if (mContainingNotification.isShowingAmbient()) {
732 return getShowingAmbientView().getHeight();
733 } else if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
Selim Cinek860b6da2015-12-16 19:02:19 -0800734 return mContractedChild.getHeight();
Selim Cinek42357e02016-02-24 18:48:01 -0800735 } else {
736 return mSingleLineView.getHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700737 }
738 }
739
Adrian Roos6f6e1592017-05-02 16:22:53 -0700740 public View getShowingAmbientView() {
741 View v = mIsChildInGroup ? mAmbientSingleLineChild : mAmbientChild;
742 if (v != null) {
743 return v;
744 } else {
745 return mContractedChild;
746 }
747 }
748
Selim Cinek83bc7832015-10-22 13:26:54 -0700749 private boolean isGroupExpanded() {
750 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200751 }
752
Jorim Jaggibe565df2014-04-28 17:51:23 +0200753 public void setClipTopAmount(int clipTopAmount) {
Selim Cinekc9c00ae2014-05-20 03:33:40 +0200754 mClipTopAmount = clipTopAmount;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200755 updateClipping();
756 }
757
Selim Cineka686b2c2016-10-26 13:58:27 -0700758
759 public void setClipBottomAmount(int clipBottomAmount) {
760 mClipBottomAmount = clipBottomAmount;
761 updateClipping();
762 }
763
Selim Cinek875a3a12016-11-18 17:52:16 -0800764 @Override
765 public void setTranslationY(float translationY) {
766 super.setTranslationY(translationY);
767 updateClipping();
768 }
769
Jorim Jaggibe565df2014-04-28 17:51:23 +0200770 private void updateClipping() {
Selim Cinek4ffd6362015-12-29 15:12:23 +0100771 if (mClipToActualHeight) {
Selim Cinek875a3a12016-11-18 17:52:16 -0800772 int top = (int) (mClipTopAmount - getTranslationY());
Selim Cineked64a142018-02-06 18:06:01 -0800773 int bottom = (int) (mUnrestrictedContentHeight - mClipBottomAmount - getTranslationY());
Selim Cineka686b2c2016-10-26 13:58:27 -0700774 bottom = Math.max(top, bottom);
775 mClipBounds.set(0, top, getWidth(), bottom);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100776 setClipBounds(mClipBounds);
777 } else {
778 setClipBounds(null);
779 }
780 }
781
782 public void setClipToActualHeight(boolean clipToActualHeight) {
783 mClipToActualHeight = clipToActualHeight;
784 updateClipping();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200785 }
786
Jorim Jaggi11298832014-05-24 16:18:38 +0200787 private void selectLayout(boolean animate, boolean force) {
788 if (mContractedChild == null) {
789 return;
790 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800791 if (mUserExpanding) {
792 updateContentTransformation();
Selim Cinek589fd3e2016-04-26 18:17:57 -0700793 } else {
794 int visibleType = calculateVisibleType();
Selim Cineke9bad242016-06-15 11:46:37 -0700795 boolean changedType = visibleType != mVisibleType;
796 if (changedType || force) {
Adrian Roos181385c2016-05-05 17:45:44 -0400797 View visibleView = getViewForVisibleType(visibleType);
798 if (visibleView != null) {
799 visibleView.setVisibility(VISIBLE);
800 transferRemoteInputFocus(visibleType);
801 }
Adrian Roos4c1fcc82016-03-31 14:39:39 -0700802
Selim Cinek589fd3e2016-04-26 18:17:57 -0700803 if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
804 || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
805 || (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null)
806 || visibleType == VISIBLE_TYPE_CONTRACTED)) {
807 animateToVisibleType(visibleType);
808 } else {
809 updateViewVisibilities(visibleType);
810 }
811 mVisibleType = visibleType;
Selim Cineke9bad242016-06-15 11:46:37 -0700812 if (changedType) {
813 focusExpandButtonIfNecessary();
814 }
Adrian Roos05d3d002017-01-26 15:28:07 -0800815 NotificationViewWrapper visibleWrapper = getVisibleWrapper(visibleType);
816 if (visibleWrapper != null) {
Selim Cineked64a142018-02-06 18:06:01 -0800817 visibleWrapper.setContentHeight(mUnrestrictedContentHeight,
818 getMinContentHeightHint());
Adrian Roos05d3d002017-01-26 15:28:07 -0800819 }
Selim Cinek589fd3e2016-04-26 18:17:57 -0700820 updateBackgroundColor(animate);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200821 }
Selim Cinek589fd3e2016-04-26 18:17:57 -0700822 }
Selim Cinek589fd3e2016-04-26 18:17:57 -0700823 }
824
825 private void forceUpdateVisibilities() {
Adrian Roos0aac04f2016-12-08 15:59:29 -0800826 forceUpdateVisibility(VISIBLE_TYPE_CONTRACTED, mContractedChild, mContractedWrapper);
827 forceUpdateVisibility(VISIBLE_TYPE_EXPANDED, mExpandedChild, mExpandedWrapper);
828 forceUpdateVisibility(VISIBLE_TYPE_HEADSUP, mHeadsUpChild, mHeadsUpWrapper);
829 forceUpdateVisibility(VISIBLE_TYPE_SINGLELINE, mSingleLineView, mSingleLineView);
830 forceUpdateVisibility(VISIBLE_TYPE_AMBIENT, mAmbientChild, mAmbientWrapper);
Adrian Roos6f6e1592017-05-02 16:22:53 -0700831 forceUpdateVisibility(VISIBLE_TYPE_AMBIENT_SINGLELINE, mAmbientSingleLineChild,
832 mAmbientSingleLineChild);
Adrian Roos4320e892017-01-24 12:50:34 -0800833 fireExpandedVisibleListenerIfVisible();
Adrian Roose18033c2017-01-17 15:22:49 -0800834 // forceUpdateVisibilities cancels outstanding animations without updating the
835 // mAnimationStartVisibleType. Do so here instead.
836 mAnimationStartVisibleType = UNDEFINED;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800837 }
838
Adrian Roos4320e892017-01-24 12:50:34 -0800839 private void fireExpandedVisibleListenerIfVisible() {
840 if (mExpandedVisibleListener != null && mExpandedChild != null && isShown()
841 && mExpandedChild.getVisibility() == VISIBLE) {
842 Runnable listener = mExpandedVisibleListener;
843 mExpandedVisibleListener = null;
844 listener.run();
845 }
846 }
847
Adrian Roos0aac04f2016-12-08 15:59:29 -0800848 private void forceUpdateVisibility(int type, View view, TransformableView wrapper) {
849 if (view == null) {
850 return;
851 }
852 boolean visible = mVisibleType == type
853 || mTransformationStartVisibleType == type;
854 if (!visible) {
855 view.setVisibility(INVISIBLE);
Selim Cinek589fd3e2016-04-26 18:17:57 -0700856 } else {
Adrian Roos0aac04f2016-12-08 15:59:29 -0800857 wrapper.setVisible(true);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200858 }
Jorim Jaggi11298832014-05-24 16:18:38 +0200859 }
860
Selim Cinekc3179332016-03-04 14:44:56 -0800861 public void updateBackgroundColor(boolean animate) {
862 int customBackgroundColor = getBackgroundColor(mVisibleType);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400863 mContainingNotification.resetBackgroundAlpha();
Selim Cinekc3179332016-03-04 14:44:56 -0800864 mContainingNotification.setContentBackground(customBackgroundColor, animate, this);
865 }
866
Mady Mellorb0a82462016-04-30 17:31:02 -0700867 public int getVisibleType() {
868 return mVisibleType;
869 }
870
871 public int getBackgroundColorForExpansionState() {
872 // When expanding or user locked we want the new type, when collapsing we want
873 // the original type
874 final int visibleType = (mContainingNotification.isGroupExpanded()
875 || mContainingNotification.isUserLocked())
876 ? calculateVisibleType()
877 : getVisibleType();
878 return getBackgroundColor(visibleType);
879 }
880
881 public int getBackgroundColor(int visibleType) {
Selim Cinekc3179332016-03-04 14:44:56 -0800882 NotificationViewWrapper currentVisibleWrapper = getVisibleWrapper(visibleType);
883 int customBackgroundColor = 0;
884 if (currentVisibleWrapper != null) {
885 customBackgroundColor = currentVisibleWrapper.getCustomBackgroundColor();
886 }
887 return customBackgroundColor;
888 }
889
Selim Cinek684a4422015-04-15 16:18:39 -0700890 private void updateViewVisibilities(int visibleType) {
Adrian Roos0aac04f2016-12-08 15:59:29 -0800891 updateViewVisibility(visibleType, VISIBLE_TYPE_CONTRACTED,
892 mContractedChild, mContractedWrapper);
893 updateViewVisibility(visibleType, VISIBLE_TYPE_EXPANDED,
894 mExpandedChild, mExpandedWrapper);
895 updateViewVisibility(visibleType, VISIBLE_TYPE_HEADSUP,
896 mHeadsUpChild, mHeadsUpWrapper);
897 updateViewVisibility(visibleType, VISIBLE_TYPE_SINGLELINE,
898 mSingleLineView, mSingleLineView);
899 updateViewVisibility(visibleType, VISIBLE_TYPE_AMBIENT,
900 mAmbientChild, mAmbientWrapper);
Adrian Roos6f6e1592017-05-02 16:22:53 -0700901 updateViewVisibility(visibleType, VISIBLE_TYPE_AMBIENT_SINGLELINE,
902 mAmbientSingleLineChild, mAmbientSingleLineChild);
Adrian Roos4320e892017-01-24 12:50:34 -0800903 fireExpandedVisibleListenerIfVisible();
Adrian Roose18033c2017-01-17 15:22:49 -0800904 // updateViewVisibilities cancels outstanding animations without updating the
905 // mAnimationStartVisibleType. Do so here instead.
906 mAnimationStartVisibleType = UNDEFINED;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800907 }
908
909 private void updateViewVisibility(int visibleType, int type, View view,
910 TransformableView wrapper) {
911 if (view != null) {
912 wrapper.setVisible(visibleType == type);
Selim Cinek83bc7832015-10-22 13:26:54 -0700913 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700914 }
915
Selim Cinek4ffd6362015-12-29 15:12:23 +0100916 private void animateToVisibleType(int visibleType) {
917 final TransformableView shownView = getTransformableViewForVisibleType(visibleType);
918 final TransformableView hiddenView = getTransformableViewForVisibleType(mVisibleType);
Selim Cinek589fd3e2016-04-26 18:17:57 -0700919 if (shownView == hiddenView || hiddenView == null) {
Selim Cinek51d94912016-03-02 15:34:28 -0800920 shownView.setVisible(true);
921 return;
922 }
Adrian Roos599be342016-06-13 14:54:39 -0700923 mAnimationStartVisibleType = mVisibleType;
Selim Cinek4ffd6362015-12-29 15:12:23 +0100924 shownView.transformFrom(hiddenView);
925 getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
926 hiddenView.transformTo(shownView, new Runnable() {
927 @Override
928 public void run() {
Selim Cinek51d94912016-03-02 15:34:28 -0800929 if (hiddenView != getTransformableViewForVisibleType(mVisibleType)) {
930 hiddenView.setVisible(false);
931 }
Adrian Roos599be342016-06-13 14:54:39 -0700932 mAnimationStartVisibleType = UNDEFINED;
Selim Cinek4ffd6362015-12-29 15:12:23 +0100933 }
934 });
Adrian Roos4320e892017-01-24 12:50:34 -0800935 fireExpandedVisibleListenerIfVisible();
Jorim Jaggi11298832014-05-24 16:18:38 +0200936 }
937
Adrian Roos4c1fcc82016-03-31 14:39:39 -0700938 private void transferRemoteInputFocus(int visibleType) {
939 if (visibleType == VISIBLE_TYPE_HEADSUP
940 && mHeadsUpRemoteInput != null
941 && (mExpandedRemoteInput != null && mExpandedRemoteInput.isActive())) {
942 mHeadsUpRemoteInput.stealFocusFrom(mExpandedRemoteInput);
943 }
944 if (visibleType == VISIBLE_TYPE_EXPANDED
945 && mExpandedRemoteInput != null
946 && (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isActive())) {
947 mExpandedRemoteInput.stealFocusFrom(mHeadsUpRemoteInput);
948 }
949 }
950
Selim Cinek684a4422015-04-15 16:18:39 -0700951 /**
952 * @param visibleType one of the static enum types in this view
Selim Cinek4ffd6362015-12-29 15:12:23 +0100953 * @return the corresponding transformable view according to the given visible type
954 */
955 private TransformableView getTransformableViewForVisibleType(int visibleType) {
956 switch (visibleType) {
957 case VISIBLE_TYPE_EXPANDED:
958 return mExpandedWrapper;
959 case VISIBLE_TYPE_HEADSUP:
960 return mHeadsUpWrapper;
961 case VISIBLE_TYPE_SINGLELINE:
962 return mSingleLineView;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800963 case VISIBLE_TYPE_AMBIENT:
964 return mAmbientWrapper;
Adrian Roos6f6e1592017-05-02 16:22:53 -0700965 case VISIBLE_TYPE_AMBIENT_SINGLELINE:
966 return mAmbientSingleLineChild;
Selim Cinek4ffd6362015-12-29 15:12:23 +0100967 default:
968 return mContractedWrapper;
969 }
970 }
971
972 /**
973 * @param visibleType one of the static enum types in this view
Selim Cinek684a4422015-04-15 16:18:39 -0700974 * @return the corresponding view according to the given visible type
975 */
976 private View getViewForVisibleType(int visibleType) {
977 switch (visibleType) {
978 case VISIBLE_TYPE_EXPANDED:
Selim Cinek8d490d42015-04-10 00:05:50 -0700979 return mExpandedChild;
Selim Cinek684a4422015-04-15 16:18:39 -0700980 case VISIBLE_TYPE_HEADSUP:
Selim Cinek8d490d42015-04-10 00:05:50 -0700981 return mHeadsUpChild;
Selim Cinek83bc7832015-10-22 13:26:54 -0700982 case VISIBLE_TYPE_SINGLELINE:
983 return mSingleLineView;
Adrian Roos0aac04f2016-12-08 15:59:29 -0800984 case VISIBLE_TYPE_AMBIENT:
985 return mAmbientChild;
Adrian Roos6f6e1592017-05-02 16:22:53 -0700986 case VISIBLE_TYPE_AMBIENT_SINGLELINE:
987 return mAmbientSingleLineChild;
Selim Cinek684a4422015-04-15 16:18:39 -0700988 default:
989 return mContractedChild;
Selim Cinek8d490d42015-04-10 00:05:50 -0700990 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700991 }
992
Selim Cinek131f1a42017-06-05 17:50:19 -0700993 public NotificationViewWrapper getVisibleWrapper(int visibleType) {
Selim Cinekc3179332016-03-04 14:44:56 -0800994 switch (visibleType) {
Selim Cinek34eda5e2016-02-18 17:10:43 -0800995 case VISIBLE_TYPE_EXPANDED:
996 return mExpandedWrapper;
997 case VISIBLE_TYPE_HEADSUP:
998 return mHeadsUpWrapper;
999 case VISIBLE_TYPE_CONTRACTED:
1000 return mContractedWrapper;
Adrian Roos0aac04f2016-12-08 15:59:29 -08001001 case VISIBLE_TYPE_AMBIENT:
1002 return mAmbientWrapper;
Selim Cinek34eda5e2016-02-18 17:10:43 -08001003 default:
1004 return null;
1005 }
1006 }
1007
Selim Cinek684a4422015-04-15 16:18:39 -07001008 /**
1009 * @return one of the static enum types in this view, calculated form the current state
1010 */
Mady Mellorb0a82462016-04-30 17:31:02 -07001011 public int calculateVisibleType() {
Adrian Roos6f6e1592017-05-02 16:22:53 -07001012 if (mContainingNotification.isShowingAmbient()) {
1013 if (mIsChildInGroup && mAmbientSingleLineChild != null) {
1014 return VISIBLE_TYPE_AMBIENT_SINGLELINE;
1015 } else if (mAmbientChild != null) {
1016 return VISIBLE_TYPE_AMBIENT;
1017 } else {
1018 return VISIBLE_TYPE_CONTRACTED;
1019 }
Adrian Roos0aac04f2016-12-08 15:59:29 -08001020 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001021 if (mUserExpanding) {
Selim Cinek42357e02016-02-24 18:48:01 -08001022 int height = !mIsChildInGroup || isGroupExpanded()
Selim Cineke81b82b2016-03-04 11:22:28 -08001023 || mContainingNotification.isExpanded(true /* allowOnKeyguard */)
Selim Cinek42357e02016-02-24 18:48:01 -08001024 ? mContainingNotification.getMaxContentHeight()
1025 : mContainingNotification.getShowingLayout().getMinHeight();
Selim Cinek51d94912016-03-02 15:34:28 -08001026 if (height == 0) {
1027 height = mContentHeight;
1028 }
Selim Cinek42357e02016-02-24 18:48:01 -08001029 int expandedVisualType = getVisualTypeForHeight(height);
Selim Cinek414ad332017-02-24 19:06:12 -08001030 int collapsedVisualType = mIsChildInGroup && !isGroupExpanded()
Selim Cinek589fd3e2016-04-26 18:17:57 -07001031 ? VISIBLE_TYPE_SINGLELINE
1032 : getVisualTypeForHeight(mContainingNotification.getCollapsedHeight());
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001033 return mTransformationStartVisibleType == collapsedVisualType
1034 ? expandedVisualType
1035 : collapsedVisualType;
1036 }
Selim Cinek51d94912016-03-02 15:34:28 -08001037 int intrinsicHeight = mContainingNotification.getIntrinsicHeight();
1038 int viewHeight = mContentHeight;
1039 if (intrinsicHeight != 0) {
1040 // the intrinsicHeight might be 0 because it was just reset.
1041 viewHeight = Math.min(mContentHeight, intrinsicHeight);
1042 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001043 return getVisualTypeForHeight(viewHeight);
1044 }
1045
1046 private int getVisualTypeForHeight(float viewHeight) {
1047 boolean noExpandedChild = mExpandedChild == null;
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001048 if (!noExpandedChild && viewHeight == mExpandedChild.getHeight()) {
Adrian Roos777ef562015-12-01 17:37:14 -08001049 return VISIBLE_TYPE_EXPANDED;
1050 }
Selim Cinek414ad332017-02-24 19:06:12 -08001051 if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -08001052 return VISIBLE_TYPE_SINGLELINE;
1053 }
Adrian Roos777ef562015-12-01 17:37:14 -08001054
Selim Cinekc494e382017-01-31 16:09:23 -08001055 if ((mIsHeadsUp || mHeadsUpAnimatingAway) && mHeadsUpChild != null
1056 && !mContainingNotification.isOnKeyguard()) {
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001057 if (viewHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
Selim Cinek684a4422015-04-15 16:18:39 -07001058 return VISIBLE_TYPE_HEADSUP;
Selim Cinek8d490d42015-04-10 00:05:50 -07001059 } else {
Selim Cinek684a4422015-04-15 16:18:39 -07001060 return VISIBLE_TYPE_EXPANDED;
Selim Cinek8d490d42015-04-10 00:05:50 -07001061 }
1062 } else {
Selim Cineka4091502016-02-11 17:21:16 -08001063 if (noExpandedChild || (viewHeight <= mContractedChild.getHeight()
Selim Cinek6ac3fa82016-05-10 17:11:54 -04001064 && (!mIsChildInGroup || isGroupExpanded()
Selim Cineke81b82b2016-03-04 11:22:28 -08001065 || !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) {
Selim Cinek684a4422015-04-15 16:18:39 -07001066 return VISIBLE_TYPE_CONTRACTED;
Selim Cinek8d490d42015-04-10 00:05:50 -07001067 } else {
Selim Cinek684a4422015-04-15 16:18:39 -07001068 return VISIBLE_TYPE_EXPANDED;
Selim Cinek8d490d42015-04-10 00:05:50 -07001069 }
1070 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001071 }
1072
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001073 public boolean isContentExpandable() {
Selim Cinekc0ac4af2017-03-03 15:13:48 -08001074 return mIsContentExpandable;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +02001075 }
John Spurlocke15452b2014-08-21 09:44:39 -04001076
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001077 public void setDark(boolean dark, boolean fade, long delay) {
Selim Cinekb88b9842016-02-26 09:25:33 -08001078 if (mContractedChild == null) {
Selim Cinek0934bd92016-02-19 12:22:33 -08001079 return;
1080 }
John Spurlocke15452b2014-08-21 09:44:39 -04001081 mDark = dark;
Selim Cinek19ba7052016-01-27 20:04:27 -08001082 if (mVisibleType == VISIBLE_TYPE_CONTRACTED || !dark) {
Selim Cinek30e387d2016-01-11 18:01:47 -08001083 mContractedWrapper.setDark(dark, fade, delay);
1084 }
Selim Cinek19ba7052016-01-27 20:04:27 -08001085 if (mVisibleType == VISIBLE_TYPE_EXPANDED || (mExpandedChild != null && !dark)) {
Selim Cinek30e387d2016-01-11 18:01:47 -08001086 mExpandedWrapper.setDark(dark, fade, delay);
1087 }
Selim Cinek19ba7052016-01-27 20:04:27 -08001088 if (mVisibleType == VISIBLE_TYPE_HEADSUP || (mHeadsUpChild != null && !dark)) {
Selim Cinek30e387d2016-01-11 18:01:47 -08001089 mHeadsUpWrapper.setDark(dark, fade, delay);
1090 }
Selim Cinek19ba7052016-01-27 20:04:27 -08001091 if (mSingleLineView != null && (mVisibleType == VISIBLE_TYPE_SINGLELINE || !dark)) {
Selim Cinek9c7712d2015-12-08 19:19:48 -08001092 mSingleLineView.setDark(dark, fade, delay);
1093 }
Adrian Roos0aac04f2016-12-08 15:59:29 -08001094 selectLayout(!dark && fade /* animate */, false /* force */);
John Spurlocke15452b2014-08-21 09:44:39 -04001095 }
1096
Selim Cinek8d490d42015-04-10 00:05:50 -07001097 public void setHeadsUp(boolean headsUp) {
1098 mIsHeadsUp = headsUp;
1099 selectLayout(false /* animate */, true /* force */);
Selim Cinek98be3f32015-12-17 16:39:06 -08001100 updateExpandButtons(mExpandable);
Selim Cinek8d490d42015-04-10 00:05:50 -07001101 }
1102
Jorim Jaggiaa92ffb2014-09-10 23:29:28 +02001103 @Override
1104 public boolean hasOverlappingRendering() {
1105
1106 // This is not really true, but good enough when fading from the contracted to the expanded
1107 // layout, and saves us some layers.
1108 return false;
1109 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001110
Selim Cinek1a48bab2017-02-17 19:38:40 -08001111 public void setLegacy(boolean legacy) {
1112 mLegacy = legacy;
1113 updateLegacy();
Selim Cinekc3179332016-03-04 14:44:56 -08001114 }
1115
Selim Cinek1a48bab2017-02-17 19:38:40 -08001116 private void updateLegacy() {
Selim Cinekc3179332016-03-04 14:44:56 -08001117 if (mContractedChild != null) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08001118 mContractedWrapper.setLegacy(mLegacy);
Selim Cinekc3179332016-03-04 14:44:56 -08001119 }
1120 if (mExpandedChild != null) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08001121 mExpandedWrapper.setLegacy(mLegacy);
Selim Cinekc3179332016-03-04 14:44:56 -08001122 }
1123 if (mHeadsUpChild != null) {
Selim Cinek1a48bab2017-02-17 19:38:40 -08001124 mHeadsUpWrapper.setLegacy(mLegacy);
Selim Cinekc3179332016-03-04 14:44:56 -08001125 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -07001126 }
Selim Cinek8d6440d2015-10-22 13:00:05 -07001127
Selim Cinek83bc7832015-10-22 13:26:54 -07001128 public void setIsChildInGroup(boolean isChildInGroup) {
1129 mIsChildInGroup = isChildInGroup;
Selim Cinek414ad332017-02-24 19:06:12 -08001130 if (mContractedChild != null) {
1131 mContractedWrapper.setIsChildInGroup(mIsChildInGroup);
1132 }
1133 if (mExpandedChild != null) {
1134 mExpandedWrapper.setIsChildInGroup(mIsChildInGroup);
1135 }
1136 if (mHeadsUpChild != null) {
1137 mHeadsUpWrapper.setIsChildInGroup(mIsChildInGroup);
1138 }
1139 if (mAmbientChild != null) {
1140 mAmbientWrapper.setIsChildInGroup(mIsChildInGroup);
1141 }
Adrian Roos6f6e1592017-05-02 16:22:53 -07001142 updateAllSingleLineViews();
Selim Cinek83bc7832015-10-22 13:26:54 -07001143 }
1144
Adrian Roosb88b1a12015-12-09 18:51:05 -08001145 public void onNotificationUpdated(NotificationData.Entry entry) {
1146 mStatusBarNotification = entry.notification;
Selim Cinek860b6da2015-12-16 19:02:19 -08001147 mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
Adrian Roos6f6e1592017-05-02 16:22:53 -07001148 updateAllSingleLineViews();
Selim Cinek8fc93c92015-11-23 17:48:07 -08001149 if (mContractedChild != null) {
Selim Cinek131f1a42017-06-05 17:50:19 -07001150 mContractedWrapper.onContentUpdated(entry.row);
Selim Cinek8fc93c92015-11-23 17:48:07 -08001151 }
1152 if (mExpandedChild != null) {
Selim Cinek131f1a42017-06-05 17:50:19 -07001153 mExpandedWrapper.onContentUpdated(entry.row);
Selim Cinek8fc93c92015-11-23 17:48:07 -08001154 }
1155 if (mHeadsUpChild != null) {
Selim Cinek131f1a42017-06-05 17:50:19 -07001156 mHeadsUpWrapper.onContentUpdated(entry.row);
Selim Cinek8fc93c92015-11-23 17:48:07 -08001157 }
Adrian Roos0aac04f2016-12-08 15:59:29 -08001158 if (mAmbientChild != null) {
Selim Cinek131f1a42017-06-05 17:50:19 -07001159 mAmbientWrapper.onContentUpdated(entry.row);
Adrian Roos0aac04f2016-12-08 15:59:29 -08001160 }
Petr Cermak7997d7a2018-01-18 15:52:10 +00001161 applyRemoteInputAndSmartReply(entry);
Selim Cinek1a48bab2017-02-17 19:38:40 -08001162 updateLegacy();
Selim Cinek589fd3e2016-04-26 18:17:57 -07001163 mForceSelectNextLayout = true;
Selim Cinekb88b9842016-02-26 09:25:33 -08001164 setDark(mDark, false /* animate */, 0 /* delay */);
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001165 mPreviousExpandedRemoteInputIntent = null;
1166 mPreviousHeadsUpRemoteInputIntent = null;
Selim Cinek83bc7832015-10-22 13:26:54 -07001167 }
1168
Adrian Roos6f6e1592017-05-02 16:22:53 -07001169 private void updateAllSingleLineViews() {
1170 updateSingleLineView();
1171 updateAmbientSingleLineView();
1172 }
Selim Cinek83bc7832015-10-22 13:26:54 -07001173 private void updateSingleLineView() {
1174 if (mIsChildInGroup) {
Selim Cinekc897bd32016-03-18 17:32:31 -07001175 mSingleLineView = mHybridGroupManager.bindFromNotification(
Selim Cinek83bc7832015-10-22 13:26:54 -07001176 mSingleLineView, mStatusBarNotification.getNotification());
Selim Cinekde33a4a2016-02-11 16:43:41 -08001177 } else if (mSingleLineView != null) {
1178 removeView(mSingleLineView);
1179 mSingleLineView = null;
Selim Cinek83bc7832015-10-22 13:26:54 -07001180 }
1181 }
1182
Adrian Roos6f6e1592017-05-02 16:22:53 -07001183 private void updateAmbientSingleLineView() {
1184 if (mIsChildInGroup) {
1185 mAmbientSingleLineChild = mHybridGroupManager.bindAmbientFromNotification(
1186 mAmbientSingleLineChild, mStatusBarNotification.getNotification());
1187 } else if (mAmbientSingleLineChild != null) {
1188 removeView(mAmbientSingleLineChild);
1189 mAmbientSingleLineChild = null;
1190 }
1191 }
1192
Petr Cermak7997d7a2018-01-18 15:52:10 +00001193 private void applyRemoteInputAndSmartReply(final NotificationData.Entry entry) {
Adrian Roosb88b1a12015-12-09 18:51:05 -08001194 if (mRemoteInputController == null) {
1195 return;
1196 }
1197
Petr Cermak10011fa2018-02-05 19:00:54 +00001198 boolean enableSmartReplies = mSmartReplyConstants.isEnabled();
Petr Cermak7997d7a2018-01-18 15:52:10 +00001199
Adrian Roosb88b1a12015-12-09 18:51:05 -08001200 boolean hasRemoteInput = false;
Petr Cermak7997d7a2018-01-18 15:52:10 +00001201 RemoteInput remoteInputWithChoices = null;
1202 PendingIntent pendingIntentWithChoices = null;
Adrian Roosb88b1a12015-12-09 18:51:05 -08001203
1204 Notification.Action[] actions = entry.notification.getNotification().actions;
1205 if (actions != null) {
1206 for (Notification.Action a : actions) {
1207 if (a.getRemoteInputs() != null) {
1208 for (RemoteInput ri : a.getRemoteInputs()) {
Petr Cermak7997d7a2018-01-18 15:52:10 +00001209 boolean showRemoteInputView = ri.getAllowFreeFormInput();
1210 boolean showSmartReplyView = enableSmartReplies && ri.getChoices() != null
1211 && ri.getChoices().length > 0;
1212 if (showRemoteInputView) {
Adrian Roosb88b1a12015-12-09 18:51:05 -08001213 hasRemoteInput = true;
Petr Cermak7997d7a2018-01-18 15:52:10 +00001214 }
1215 if (showSmartReplyView) {
1216 remoteInputWithChoices = ri;
1217 pendingIntentWithChoices = a.actionIntent;
1218 }
1219 if (showRemoteInputView || showSmartReplyView) {
Adrian Roosb88b1a12015-12-09 18:51:05 -08001220 break;
1221 }
1222 }
1223 }
1224 }
1225 }
1226
Petr Cermak7997d7a2018-01-18 15:52:10 +00001227 applyRemoteInput(entry, hasRemoteInput);
1228 applySmartReplyView(remoteInputWithChoices, pendingIntentWithChoices);
1229 }
1230
1231 private void applyRemoteInput(NotificationData.Entry entry, boolean hasRemoteInput) {
Adrian Roosb88b1a12015-12-09 18:51:05 -08001232 View bigContentView = mExpandedChild;
1233 if (bigContentView != null) {
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001234 mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput,
Adrian Roos7b9ed0d2017-01-24 15:55:18 -08001235 mPreviousExpandedRemoteInputIntent, mCachedExpandedRemoteInput,
1236 mExpandedWrapper);
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001237 } else {
1238 mExpandedRemoteInput = null;
Adrian Roosb88b1a12015-12-09 18:51:05 -08001239 }
Adrian Roos7813dd72016-09-23 17:12:17 -07001240 if (mCachedExpandedRemoteInput != null
1241 && mCachedExpandedRemoteInput != mExpandedRemoteInput) {
1242 // We had a cached remote input but didn't reuse it. Clean up required.
1243 mCachedExpandedRemoteInput.dispatchFinishTemporaryDetach();
1244 }
1245 mCachedExpandedRemoteInput = null;
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001246
Adrian Roosb88b1a12015-12-09 18:51:05 -08001247 View headsUpContentView = mHeadsUpChild;
1248 if (headsUpContentView != null) {
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001249 mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput,
Adrian Roos7b9ed0d2017-01-24 15:55:18 -08001250 mPreviousHeadsUpRemoteInputIntent, mCachedHeadsUpRemoteInput, mHeadsUpWrapper);
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001251 } else {
1252 mHeadsUpRemoteInput = null;
Adrian Roosb88b1a12015-12-09 18:51:05 -08001253 }
Adrian Roos7813dd72016-09-23 17:12:17 -07001254 if (mCachedHeadsUpRemoteInput != null
1255 && mCachedHeadsUpRemoteInput != mHeadsUpRemoteInput) {
1256 // We had a cached remote input but didn't reuse it. Clean up required.
1257 mCachedHeadsUpRemoteInput.dispatchFinishTemporaryDetach();
1258 }
1259 mCachedHeadsUpRemoteInput = null;
Adrian Roosb88b1a12015-12-09 18:51:05 -08001260 }
1261
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001262 private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry,
Adrian Roos7813dd72016-09-23 17:12:17 -07001263 boolean hasRemoteInput, PendingIntent existingPendingIntent,
Adrian Roos7b9ed0d2017-01-24 15:55:18 -08001264 RemoteInputView cachedView, NotificationViewWrapper wrapper) {
Adrian Roosb88b1a12015-12-09 18:51:05 -08001265 View actionContainerCandidate = view.findViewById(
1266 com.android.internal.R.id.actions_container);
1267 if (actionContainerCandidate instanceof FrameLayout) {
1268 RemoteInputView existing = (RemoteInputView)
1269 view.findViewWithTag(RemoteInputView.VIEW_TAG);
1270
1271 if (existing != null) {
Adrian Roos0789ee02016-06-01 11:34:58 -07001272 existing.onNotificationUpdateOrReset();
Adrian Roosb88b1a12015-12-09 18:51:05 -08001273 }
1274
1275 if (existing == null && hasRemoteInput) {
1276 ViewGroup actionContainer = (FrameLayout) actionContainerCandidate;
Adrian Roos7813dd72016-09-23 17:12:17 -07001277 if (cachedView == null) {
1278 RemoteInputView riv = RemoteInputView.inflate(
1279 mContext, actionContainer, entry, mRemoteInputController);
Adrian Roosb88b1a12015-12-09 18:51:05 -08001280
Adrian Roos7813dd72016-09-23 17:12:17 -07001281 riv.setVisibility(View.INVISIBLE);
1282 actionContainer.addView(riv, new LayoutParams(
1283 ViewGroup.LayoutParams.MATCH_PARENT,
1284 ViewGroup.LayoutParams.MATCH_PARENT)
1285 );
1286 existing = riv;
1287 } else {
1288 actionContainer.addView(cachedView);
1289 cachedView.dispatchFinishTemporaryDetach();
1290 cachedView.requestFocus();
1291 existing = cachedView;
1292 }
Adrian Roos4ff3b122016-02-01 12:26:13 -08001293 }
1294 if (hasRemoteInput) {
Adrian Roosb88b1a12015-12-09 18:51:05 -08001295 int color = entry.notification.getNotification().color;
1296 if (color == Notification.COLOR_DEFAULT) {
1297 color = mContext.getColor(R.color.default_remote_input_background);
1298 }
Adrian Roos4ff3b122016-02-01 12:26:13 -08001299 existing.setBackgroundColor(NotificationColorUtil.ensureTextBackgroundColor(color,
Adrian Roos25ea5b82016-04-27 16:34:35 -07001300 mContext.getColor(R.color.remote_input_text_enabled),
Adrian Roos4ff3b122016-02-01 12:26:13 -08001301 mContext.getColor(R.color.remote_input_hint)));
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001302
Adrian Roos7b9ed0d2017-01-24 15:55:18 -08001303 existing.setWrapper(wrapper);
Selim Cineked64a142018-02-06 18:06:01 -08001304 existing.setOnVisibilityChangedListener(this::setRemoteInputVisible);
Adrian Roos7b9ed0d2017-01-24 15:55:18 -08001305
Adrian Roos4c1fcc82016-03-31 14:39:39 -07001306 if (existingPendingIntent != null || existing.isActive()) {
1307 // The current action could be gone, or the pending intent no longer valid.
1308 // If we find a matching action in the new notification, focus, otherwise close.
1309 Notification.Action[] actions = entry.notification.getNotification().actions;
1310 if (existingPendingIntent != null) {
1311 existing.setPendingIntent(existingPendingIntent);
1312 }
1313 if (existing.updatePendingIntentFromActions(actions)) {
1314 if (!existing.isActive()) {
1315 existing.focus();
1316 }
1317 } else {
1318 if (existing.isActive()) {
1319 existing.close();
1320 }
1321 }
1322 }
Adrian Roosb88b1a12015-12-09 18:51:05 -08001323 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001324 return existing;
1325 }
1326 return null;
1327 }
1328
Petr Cermak7997d7a2018-01-18 15:52:10 +00001329 private void applySmartReplyView(RemoteInput remoteInput, PendingIntent pendingIntent) {
1330 mExpandedSmartReplyView = mExpandedChild == null ?
1331 null : applySmartReplyView(mExpandedChild, remoteInput, pendingIntent);
1332 }
1333
1334 private SmartReplyView applySmartReplyView(
1335 View view, RemoteInput remoteInput, PendingIntent pendingIntent) {
1336 View smartReplyContainerCandidate = view.findViewById(
1337 com.android.internal.R.id.smart_reply_container);
1338 if (!(smartReplyContainerCandidate instanceof LinearLayout)) {
1339 return null;
1340 }
1341 LinearLayout smartReplyContainer = (LinearLayout) smartReplyContainerCandidate;
1342 if (remoteInput == null || pendingIntent == null) {
1343 smartReplyContainer.setVisibility(View.GONE);
1344 return null;
1345 }
1346 SmartReplyView smartReplyView = null;
1347 if (smartReplyContainer.getChildCount() == 0) {
1348 smartReplyView = SmartReplyView.inflate(mContext, smartReplyContainer);
1349 smartReplyContainer.addView(smartReplyView);
1350 } else if (smartReplyContainer.getChildCount() == 1) {
1351 View child = smartReplyContainer.getChildAt(0);
1352 if (child instanceof SmartReplyView) {
1353 smartReplyView = (SmartReplyView) child;
1354 }
1355 }
1356 if (smartReplyView != null) {
1357 smartReplyView.setRepliesFromRemoteInput(remoteInput, pendingIntent);
1358 smartReplyContainer.setVisibility(View.VISIBLE);
1359 }
1360 return smartReplyView;
1361 }
1362
Adrian Roos0bd8a4b2016-03-14 16:21:44 -07001363 public void closeRemoteInput() {
1364 if (mHeadsUpRemoteInput != null) {
1365 mHeadsUpRemoteInput.close();
1366 }
1367 if (mExpandedRemoteInput != null) {
1368 mExpandedRemoteInput.close();
Adrian Roosb88b1a12015-12-09 18:51:05 -08001369 }
1370 }
1371
Selim Cinek83bc7832015-10-22 13:26:54 -07001372 public void setGroupManager(NotificationGroupManager groupManager) {
1373 mGroupManager = groupManager;
1374 }
Selim Cinek65b2e7c2015-10-26 14:11:31 -07001375
Adrian Roosb88b1a12015-12-09 18:51:05 -08001376 public void setRemoteInputController(RemoteInputController r) {
1377 mRemoteInputController = r;
1378 }
1379
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001380 public void setExpandClickListener(OnClickListener expandClickListener) {
1381 mExpandClickListener = expandClickListener;
1382 }
1383
1384 public void updateExpandButtons(boolean expandable) {
Selim Cinek98be3f32015-12-17 16:39:06 -08001385 mExpandable = expandable;
1386 // if the expanded child has the same height as the collapsed one we hide it.
Selim Cinek8ea2d5f2016-04-20 17:10:40 -07001387 if (mExpandedChild != null && mExpandedChild.getHeight() != 0) {
Selim Cinek4ca6c632017-02-23 18:03:37 -08001388 if ((!mIsHeadsUp && !mHeadsUpAnimatingAway)
1389 || mHeadsUpChild == null || mContainingNotification.isOnKeyguard()) {
Selim Cinek9635cf32017-03-03 16:59:03 -08001390 if (mExpandedChild.getHeight() <= mContractedChild.getHeight()) {
Selim Cinek8ea2d5f2016-04-20 17:10:40 -07001391 expandable = false;
1392 }
Selim Cinek9635cf32017-03-03 16:59:03 -08001393 } else if (mExpandedChild.getHeight() <= mHeadsUpChild.getHeight()) {
Selim Cinek8ea2d5f2016-04-20 17:10:40 -07001394 expandable = false;
1395 }
Selim Cinek98be3f32015-12-17 16:39:06 -08001396 }
Selim Cinek65b2e7c2015-10-26 14:11:31 -07001397 if (mExpandedChild != null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001398 mExpandedWrapper.updateExpandability(expandable, mExpandClickListener);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07001399 }
1400 if (mContractedChild != null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001401 mContractedWrapper.updateExpandability(expandable, mExpandClickListener);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07001402 }
1403 if (mHeadsUpChild != null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -08001404 mHeadsUpWrapper.updateExpandability(expandable, mExpandClickListener);
Selim Cinek65b2e7c2015-10-26 14:11:31 -07001405 }
Selim Cinekc0ac4af2017-03-03 15:13:48 -08001406 mIsContentExpandable = expandable;
Selim Cinek65b2e7c2015-10-26 14:11:31 -07001407 }
Selim Cinekea4bef72015-12-02 15:51:10 -08001408
1409 public NotificationHeaderView getNotificationHeader() {
1410 NotificationHeaderView header = null;
1411 if (mContractedChild != null) {
1412 header = mContractedWrapper.getNotificationHeader();
1413 }
1414 if (header == null && mExpandedChild != null) {
1415 header = mExpandedWrapper.getNotificationHeader();
1416 }
1417 if (header == null && mHeadsUpChild != null) {
1418 header = mHeadsUpWrapper.getNotificationHeader();
1419 }
Adrian Roos0aac04f2016-12-08 15:59:29 -08001420 if (header == null && mAmbientChild != null) {
1421 header = mAmbientWrapper.getNotificationHeader();
1422 }
Selim Cinekea4bef72015-12-02 15:51:10 -08001423 return header;
1424 }
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001425
Selim Cinekb26afa32017-06-29 10:28:17 +02001426
1427 public NotificationHeaderView getContractedNotificationHeader() {
1428 if (mContractedChild != null) {
1429 return mContractedWrapper.getNotificationHeader();
1430 }
1431 return null;
1432 }
1433
Selim Cinek34eda5e2016-02-18 17:10:43 -08001434 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekc3179332016-03-04 14:44:56 -08001435 NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
Selim Cinek34eda5e2016-02-18 17:10:43 -08001436 return wrapper == null ? null : wrapper.getNotificationHeader();
1437 }
1438
Selim Cinekfa0a2d32016-01-14 13:02:21 -08001439 public void setContainingNotification(ExpandableNotificationRow containingNotification) {
1440 mContainingNotification = containingNotification;
1441 }
1442
1443 public void requestSelectLayout(boolean needsAnimation) {
1444 selectLayout(needsAnimation, false);
1445 }
Selim Cinekde33a4a2016-02-11 16:43:41 -08001446
1447 public void reInflateViews() {
1448 if (mIsChildInGroup && mSingleLineView != null) {
1449 removeView(mSingleLineView);
1450 mSingleLineView = null;
Adrian Roos6f6e1592017-05-02 16:22:53 -07001451 updateAllSingleLineViews();
Selim Cinekde33a4a2016-02-11 16:43:41 -08001452 }
1453 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001454
1455 public void setUserExpanding(boolean userExpanding) {
1456 mUserExpanding = userExpanding;
1457 if (userExpanding) {
1458 mTransformationStartVisibleType = mVisibleType;
1459 } else {
1460 mTransformationStartVisibleType = UNDEFINED;
1461 mVisibleType = calculateVisibleType();
1462 updateViewVisibilities(mVisibleType);
Selim Cinekc3179332016-03-04 14:44:56 -08001463 updateBackgroundColor(false);
Selim Cinek8f2f6a62016-02-23 19:56:31 -08001464 }
1465 }
Selim Cinekc897bd32016-03-18 17:32:31 -07001466
1467 /**
1468 * Set by how much the single line view should be indented. Used when a overflow indicator is
1469 * present and only during measuring
1470 */
1471 public void setSingleLineWidthIndention(int singleLineWidthIndention) {
1472 if (singleLineWidthIndention != mSingleLineWidthIndention) {
1473 mSingleLineWidthIndention = singleLineWidthIndention;
1474 mContainingNotification.forceLayout();
1475 forceLayout();
1476 }
1477 }
1478
1479 public HybridNotificationView getSingleLineView() {
1480 return mSingleLineView;
1481 }
Adrian Roosd009ab12016-05-20 17:58:53 -07001482
1483 public void setRemoved() {
1484 if (mExpandedRemoteInput != null) {
1485 mExpandedRemoteInput.setRemoved();
1486 }
1487 if (mHeadsUpRemoteInput != null) {
1488 mHeadsUpRemoteInput.setRemoved();
1489 }
1490 }
Adrian Roos599be342016-06-13 14:54:39 -07001491
1492 public void setContentHeightAnimating(boolean animating) {
1493 if (!animating) {
1494 mContentHeightAtAnimationStart = UNDEFINED;
1495 }
1496 }
Selim Cineke9bad242016-06-15 11:46:37 -07001497
Adrian Roose18033c2017-01-17 15:22:49 -08001498 @VisibleForTesting
1499 boolean isAnimatingVisibleType() {
1500 return mAnimationStartVisibleType != UNDEFINED;
1501 }
1502
Selim Cinekcafa87f2016-10-26 17:00:17 -07001503 public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
1504 mHeadsUpAnimatingAway = headsUpAnimatingAway;
Selim Cinek73cf02a2016-06-17 13:08:00 -07001505 selectLayout(false /* animate */, true /* force */);
1506 }
1507
Selim Cineke9bad242016-06-15 11:46:37 -07001508 public void setFocusOnVisibilityChange() {
1509 mFocusOnVisibilityChange = true;
1510 }
Selim Cinek0242fbb2016-10-19 13:38:32 -07001511
1512 public void setIconsVisible(boolean iconsVisible) {
1513 mIconsVisible = iconsVisible;
1514 updateIconVisibilities();
1515 }
1516
1517 private void updateIconVisibilities() {
1518 if (mContractedWrapper != null) {
1519 NotificationHeaderView header = mContractedWrapper.getNotificationHeader();
1520 if (header != null) {
1521 header.getIcon().setForceHidden(!mIconsVisible);
1522 }
1523 }
1524 if (mHeadsUpWrapper != null) {
1525 NotificationHeaderView header = mHeadsUpWrapper.getNotificationHeader();
1526 if (header != null) {
1527 header.getIcon().setForceHidden(!mIconsVisible);
1528 }
1529 }
1530 if (mExpandedWrapper != null) {
1531 NotificationHeaderView header = mExpandedWrapper.getNotificationHeader();
1532 if (header != null) {
1533 header.getIcon().setForceHidden(!mIconsVisible);
1534 }
1535 }
1536 }
Selim Cinek6743c0b2017-01-18 18:24:01 -08001537
Adrian Roos4320e892017-01-24 12:50:34 -08001538 @Override
1539 public void onVisibilityAggregated(boolean isVisible) {
1540 super.onVisibilityAggregated(isVisible);
1541 if (isVisible) {
1542 fireExpandedVisibleListenerIfVisible();
1543 }
1544 }
1545
1546 /**
1547 * Sets a one-shot listener for when the expanded view becomes visible.
1548 *
1549 * This will fire the listener immediately if the expanded view is already visible.
1550 */
1551 public void setOnExpandedVisibleListener(Runnable r) {
1552 mExpandedVisibleListener = r;
1553 fireExpandedVisibleListenerIfVisible();
1554 }
1555
Selim Cinek6743c0b2017-01-18 18:24:01 -08001556 public void setIsLowPriority(boolean isLowPriority) {
1557 mIsLowPriority = isLowPriority;
1558 }
Selim Cinek63edaf22017-04-24 22:18:48 -07001559
1560 public boolean isDimmable() {
1561 if (!mContractedWrapper.isDimmable()) {
1562 return false;
1563 }
1564 return true;
1565 }
Selim Cinek5d6ef8d2017-05-18 22:16:00 -07001566
1567 /**
1568 * Should a single click be disallowed on this view when on the keyguard?
1569 */
1570 public boolean disallowSingleClick(float x, float y) {
1571 NotificationViewWrapper visibleWrapper = getVisibleWrapper(getVisibleType());
1572 if (visibleWrapper != null) {
1573 return visibleWrapper.disallowSingleClick(x, y);
1574 }
1575 return false;
1576 }
Selim Cinek515b2032017-11-15 10:20:19 -08001577
Selim Cinek86bfcee2018-01-17 11:00:47 -08001578 public boolean shouldClipToRounding(boolean topRounded, boolean bottomRounded) {
1579 boolean needsPaddings = shouldClipToRounding(getVisibleType(), topRounded, bottomRounded);
Selim Cinek515b2032017-11-15 10:20:19 -08001580 if (mUserExpanding) {
Selim Cinek86bfcee2018-01-17 11:00:47 -08001581 needsPaddings |= shouldClipToRounding(mTransformationStartVisibleType, topRounded,
1582 bottomRounded);
Selim Cinek515b2032017-11-15 10:20:19 -08001583 }
1584 return needsPaddings;
1585 }
1586
Selim Cinek86bfcee2018-01-17 11:00:47 -08001587 private boolean shouldClipToRounding(int visibleType, boolean topRounded,
1588 boolean bottomRounded) {
Selim Cinek515b2032017-11-15 10:20:19 -08001589 NotificationViewWrapper visibleWrapper = getVisibleWrapper(visibleType);
1590 if (visibleWrapper == null) {
1591 return false;
1592 }
Selim Cinek86bfcee2018-01-17 11:00:47 -08001593 return visibleWrapper.shouldClipToRounding(topRounded, bottomRounded);
Selim Cinek515b2032017-11-15 10:20:19 -08001594 }
Selim Cinekde4de0e2018-01-24 16:21:07 -08001595
1596 public CharSequence getActiveRemoteInputText() {
1597 if (mExpandedRemoteInput != null && mExpandedRemoteInput.isActive()) {
1598 return mExpandedRemoteInput.getText();
1599 }
1600 if (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isActive()) {
1601 return mHeadsUpRemoteInput.getText();
1602 }
1603 return null;
1604 }
Selim Cineked64a142018-02-06 18:06:01 -08001605
1606 public int getExpandHeight() {
1607 View expandedChild = mExpandedChild;
1608 if (expandedChild == null) {
1609 expandedChild = mContractedChild;
1610 }
1611 return expandedChild.getHeight() + getExtraRemoteInputHeight(mExpandedRemoteInput);
1612 }
1613
1614 public int getHeadsUpHeight() {
1615 View headsUpChild = mHeadsUpChild;
1616 if (headsUpChild == null) {
1617 headsUpChild = mContractedChild;
1618 }
1619 return headsUpChild.getHeight()+ getExtraRemoteInputHeight(mHeadsUpRemoteInput);
1620 }
1621
1622 public void setRemoteInputVisible(boolean remoteInputVisible) {
1623 mRemoteInputVisible = remoteInputVisible;
1624 setClipChildren(!remoteInputVisible);
1625 }
1626
1627 @Override
1628 public void setClipChildren(boolean clipChildren) {
1629 clipChildren = clipChildren && !mRemoteInputVisible;
1630 super.setClipChildren(clipChildren);
1631 }
Jorim Jaggibe565df2014-04-28 17:51:23 +02001632}