blob: bfb84b193f270e212c3a416823b30c3fc8804004 [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;
20import android.app.RemoteInput;
Jorim Jaggibe565df2014-04-28 17:51:23 +020021import android.content.Context;
22import android.graphics.Rect;
Selim Cinek860b6da2015-12-16 19:02:19 -080023import android.os.Build;
Selim Cinek83bc7832015-10-22 13:26:54 -070024import android.service.notification.StatusBarNotification;
Jorim Jaggibe565df2014-04-28 17:51:23 +020025import android.util.AttributeSet;
Selim Cinekeaa29ca2015-11-23 13:51:13 -080026import android.view.NotificationHeaderView;
Jorim Jaggibe565df2014-04-28 17:51:23 +020027import android.view.View;
Selim Cinek8d490d42015-04-10 00:05:50 -070028import android.view.ViewGroup;
Selim Cinekbb3d1cf2014-10-31 00:12:56 +010029import android.view.ViewTreeObserver;
Selim Cinekc9c00ae2014-05-20 03:33:40 +020030import android.widget.FrameLayout;
Selim Cinek8d490d42015-04-10 00:05:50 -070031
Adrian Roos4ff3b122016-02-01 12:26:13 -080032import com.android.internal.util.NotificationColorUtil;
Jorim Jaggibe565df2014-04-28 17:51:23 +020033import com.android.systemui.R;
Selim Cinek83bc7832015-10-22 13:26:54 -070034import com.android.systemui.statusbar.notification.HybridNotificationView;
35import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
Selim Cinek0ffbda62016-01-01 20:29:12 +010036import com.android.systemui.statusbar.notification.NotificationCustomViewWrapper;
Selim Cinekc3179332016-03-04 14:44:56 -080037import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cinek0ffbda62016-01-01 20:29:12 +010038import com.android.systemui.statusbar.notification.NotificationViewWrapper;
Selim Cinek83bc7832015-10-22 13:26:54 -070039import com.android.systemui.statusbar.phone.NotificationGroupManager;
Adrian Roosb88b1a12015-12-09 18:51:05 -080040import com.android.systemui.statusbar.policy.RemoteInputView;
Jorim Jaggibe565df2014-04-28 17:51:23 +020041
42/**
Selim Cinek684a4422015-04-15 16:18:39 -070043 * A frame layout containing the actual payload of the notification, including the contracted,
44 * expanded and heads up layout. This class is responsible for clipping the content and and
45 * switching between the expanded, contracted and the heads up view depending on its clipped size.
Jorim Jaggibe565df2014-04-28 17:51:23 +020046 */
Selim Cinekc9c00ae2014-05-20 03:33:40 +020047public class NotificationContentView extends FrameLayout {
Jorim Jaggibe565df2014-04-28 17:51:23 +020048
Selim Cinek684a4422015-04-15 16:18:39 -070049 private static final int VISIBLE_TYPE_CONTRACTED = 0;
50 private static final int VISIBLE_TYPE_EXPANDED = 1;
51 private static final int VISIBLE_TYPE_HEADSUP = 2;
Selim Cinek83bc7832015-10-22 13:26:54 -070052 private static final int VISIBLE_TYPE_SINGLELINE = 3;
Selim Cinekc3179332016-03-04 14:44:56 -080053 public static final int UNDEFINED = -1;
Jorim Jaggi11298832014-05-24 16:18:38 +020054
Jorim Jaggibe565df2014-04-28 17:51:23 +020055 private final Rect mClipBounds = new Rect();
Selim Cinek860b6da2015-12-16 19:02:19 -080056 private final int mMinContractedHeight;
Selim Cinek6ecc8102016-01-26 18:26:19 -080057 private final int mNotificationContentMarginEnd;
Selim Cinek30e387d2016-01-11 18:01:47 -080058 private final OnLayoutChangeListener mLayoutUpdater = new OnLayoutChangeListener() {
59 @Override
60 public void onLayoutChange(View v, int left, int top, int right, int bottom,
61 int oldLeft,
62 int oldTop, int oldRight, int oldBottom) {
63 selectLayout(false /* animate */, false /* force */);
64 }
65 };
Selim Cinek860b6da2015-12-16 19:02:19 -080066
Jorim Jaggibe565df2014-04-28 17:51:23 +020067
68 private View mContractedChild;
69 private View mExpandedChild;
Selim Cinek8d490d42015-04-10 00:05:50 -070070 private View mHeadsUpChild;
Selim Cinek83bc7832015-10-22 13:26:54 -070071 private HybridNotificationView mSingleLineView;
Jorim Jaggibe565df2014-04-28 17:51:23 +020072
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070073 private RemoteInputView mExpandedRemoteInput;
74 private RemoteInputView mHeadsUpRemoteInput;
75
Jorim Jaggi4e857f42014-11-17 19:14:04 +010076 private NotificationViewWrapper mContractedWrapper;
Jorim Jaggibe4116a2015-05-20 20:04:08 -070077 private NotificationViewWrapper mExpandedWrapper;
78 private NotificationViewWrapper mHeadsUpWrapper;
Selim Cinek83bc7832015-10-22 13:26:54 -070079 private HybridNotificationViewManager mHybridViewManager;
Selim Cinekc9c00ae2014-05-20 03:33:40 +020080 private int mClipTopAmount;
Selim Cinekb5605e52015-02-20 18:21:41 +010081 private int mContentHeight;
Jorim Jaggibe4116a2015-05-20 20:04:08 -070082 private int mUnrestrictedContentHeight;
Selim Cinek684a4422015-04-15 16:18:39 -070083 private int mVisibleType = VISIBLE_TYPE_CONTRACTED;
John Spurlocke15452b2014-08-21 09:44:39 -040084 private boolean mDark;
Selim Cinekbb3d1cf2014-10-31 00:12:56 +010085 private boolean mAnimate;
Selim Cinek684a4422015-04-15 16:18:39 -070086 private boolean mIsHeadsUp;
Jorim Jaggi59ec3042015-06-05 15:18:43 -070087 private boolean mShowingLegacyBackground;
Selim Cinek83bc7832015-10-22 13:26:54 -070088 private boolean mIsChildInGroup;
Selim Cinek816c8e42015-11-19 12:00:45 -080089 private int mSmallHeight;
Selim Cinek77019c72015-12-09 10:18:02 -080090 private int mHeadsUpHeight;
Selim Cinekd84a5932015-12-15 11:45:36 -080091 private int mNotificationMaxHeight;
Selim Cinek83bc7832015-10-22 13:26:54 -070092 private StatusBarNotification mStatusBarNotification;
Selim Cinek65b2e7c2015-10-26 14:11:31 -070093 private NotificationGroupManager mGroupManager;
Adrian Roosb88b1a12015-12-09 18:51:05 -080094 private RemoteInputController mRemoteInputController;
Jorim Jaggi59ec3042015-06-05 15:18:43 -070095
Jorim Jaggibe4116a2015-05-20 20:04:08 -070096 private final ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
Selim Cinekbb3d1cf2014-10-31 00:12:56 +010097 = new ViewTreeObserver.OnPreDrawListener() {
98 @Override
99 public boolean onPreDraw() {
Selim Cinekd1ad9ab2016-03-01 17:52:20 -0800100 // We need to post since we don't want the notification to animate on the very first
101 // frame
102 post(new Runnable() {
103 @Override
104 public void run() {
105 mAnimate = true;
106 }
107 });
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100108 getViewTreeObserver().removeOnPreDrawListener(this);
109 return true;
110 }
111 };
Jorim Jaggi11298832014-05-24 16:18:38 +0200112
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800113 private OnClickListener mExpandClickListener;
Selim Cinek860b6da2015-12-16 19:02:19 -0800114 private boolean mBeforeN;
Selim Cinek98be3f32015-12-17 16:39:06 -0800115 private boolean mExpandable;
Selim Cinek4ffd6362015-12-29 15:12:23 +0100116 private boolean mClipToActualHeight = true;
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800117 private ExpandableNotificationRow mContainingNotification;
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800118 private int mTransformationStartVisibleType;
119 private boolean mUserExpanding;
Selim Cinek98be3f32015-12-17 16:39:06 -0800120
Jorim Jaggibe565df2014-04-28 17:51:23 +0200121 public NotificationContentView(Context context, AttributeSet attrs) {
122 super(context, attrs);
Selim Cinek83bc7832015-10-22 13:26:54 -0700123 mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
Selim Cinek860b6da2015-12-16 19:02:19 -0800124 mMinContractedHeight = getResources().getDimensionPixelSize(
125 R.dimen.min_notification_layout_height);
Selim Cinek6ecc8102016-01-26 18:26:19 -0800126 mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
127 com.android.internal.R.dimen.notification_content_margin_end);
Selim Cinek51d94912016-03-02 15:34:28 -0800128 reset();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200129 }
130
Selim Cinekd84a5932015-12-15 11:45:36 -0800131 public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
Selim Cinek816c8e42015-11-19 12:00:45 -0800132 mSmallHeight = smallHeight;
Selim Cinek77019c72015-12-09 10:18:02 -0800133 mHeadsUpHeight = headsUpMaxHeight;
Selim Cinekd84a5932015-12-15 11:45:36 -0800134 mNotificationMaxHeight = maxHeight;
Selim Cinek816c8e42015-11-19 12:00:45 -0800135 }
136
Jorim Jaggibe565df2014-04-28 17:51:23 +0200137 @Override
Selim Cinek8d490d42015-04-10 00:05:50 -0700138 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
139 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
140 boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
141 boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
142 int maxSize = Integer.MAX_VALUE;
143 if (hasFixedHeight || isHeightLimited) {
144 maxSize = MeasureSpec.getSize(heightMeasureSpec);
145 }
146 int maxChildHeight = 0;
Selim Cinek6ecc8102016-01-26 18:26:19 -0800147 if (mExpandedChild != null) {
148 int size = Math.min(maxSize, mNotificationMaxHeight);
149 ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
150 if (layoutParams.height >= 0) {
151 // An actual height is set
152 size = Math.min(maxSize, layoutParams.height);
153 }
154 int spec = size == Integer.MAX_VALUE
155 ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
156 : MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
157 mExpandedChild.measure(widthMeasureSpec, spec);
158 maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
159 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700160 if (mContractedChild != null) {
Selim Cinek860b6da2015-12-16 19:02:19 -0800161 int heightSpec;
Selim Cinekf619ffc2016-02-17 14:53:05 -0800162 int size = Math.min(maxSize, mSmallHeight);
Selim Cinek860b6da2015-12-16 19:02:19 -0800163 if (shouldContractedBeFixedSize()) {
Selim Cinek860b6da2015-12-16 19:02:19 -0800164 heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
165 } else {
Selim Cinekf619ffc2016-02-17 14:53:05 -0800166 heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
Selim Cinek860b6da2015-12-16 19:02:19 -0800167 }
168 mContractedChild.measure(widthMeasureSpec, heightSpec);
169 int measuredHeight = mContractedChild.getMeasuredHeight();
170 if (measuredHeight < mMinContractedHeight) {
171 heightSpec = MeasureSpec.makeMeasureSpec(mMinContractedHeight, MeasureSpec.EXACTLY);
172 mContractedChild.measure(widthMeasureSpec, heightSpec);
173 }
174 maxChildHeight = Math.max(maxChildHeight, measuredHeight);
Selim Cinek6ecc8102016-01-26 18:26:19 -0800175 if (updateContractedHeaderWidth()) {
176 mContractedChild.measure(widthMeasureSpec, heightSpec);
Selim Cinek8d490d42015-04-10 00:05:50 -0700177 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700178 }
179 if (mHeadsUpChild != null) {
180 int size = Math.min(maxSize, mHeadsUpHeight);
181 ViewGroup.LayoutParams layoutParams = mHeadsUpChild.getLayoutParams();
182 if (layoutParams.height >= 0) {
183 // An actual height is set
Selim Cinek77019c72015-12-09 10:18:02 -0800184 size = Math.min(size, layoutParams.height);
Selim Cinek8d490d42015-04-10 00:05:50 -0700185 }
186 mHeadsUpChild.measure(widthMeasureSpec,
187 MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST));
188 maxChildHeight = Math.max(maxChildHeight, mHeadsUpChild.getMeasuredHeight());
189 }
Selim Cinek83bc7832015-10-22 13:26:54 -0700190 if (mSingleLineView != null) {
Selim Cinek83bc7832015-10-22 13:26:54 -0700191 mSingleLineView.measure(widthMeasureSpec,
Selim Cinek7b836392015-12-04 20:02:59 -0800192 MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST));
Selim Cinek83bc7832015-10-22 13:26:54 -0700193 maxChildHeight = Math.max(maxChildHeight, mSingleLineView.getMeasuredHeight());
194 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700195 int ownHeight = Math.min(maxChildHeight, maxSize);
196 int width = MeasureSpec.getSize(widthMeasureSpec);
197 setMeasuredDimension(width, ownHeight);
198 }
199
Selim Cinek6ecc8102016-01-26 18:26:19 -0800200 private boolean updateContractedHeaderWidth() {
201 // We need to update the expanded and the collapsed header to have exactly the same with to
202 // have the expand buttons laid out at the same location.
203 NotificationHeaderView contractedHeader = mContractedWrapper.getNotificationHeader();
204 if (contractedHeader != null) {
205 if (mExpandedChild != null
206 && mExpandedWrapper.getNotificationHeader() != null) {
207 NotificationHeaderView expandedHeader = mExpandedWrapper.getNotificationHeader();
208 int expandedSize = expandedHeader.getMeasuredWidth()
209 - expandedHeader.getPaddingEnd();
210 int collapsedSize = contractedHeader.getMeasuredWidth()
211 - expandedHeader.getPaddingEnd();
212 if (expandedSize != collapsedSize) {
213 int paddingEnd = contractedHeader.getMeasuredWidth() - expandedSize;
214 contractedHeader.setPadding(
Selim Cinekcb445682016-01-29 16:13:12 -0800215 contractedHeader.isLayoutRtl()
216 ? paddingEnd
217 : contractedHeader.getPaddingLeft(),
Selim Cinek6ecc8102016-01-26 18:26:19 -0800218 contractedHeader.getPaddingTop(),
Selim Cinekcb445682016-01-29 16:13:12 -0800219 contractedHeader.isLayoutRtl()
220 ? contractedHeader.getPaddingLeft()
221 : paddingEnd,
Selim Cinek6ecc8102016-01-26 18:26:19 -0800222 contractedHeader.getPaddingBottom());
223 contractedHeader.setShowWorkBadgeAtEnd(true);
224 return true;
225 }
226 } else {
227 int paddingEnd = mNotificationContentMarginEnd;
228 if (contractedHeader.getPaddingEnd() != paddingEnd) {
229 contractedHeader.setPadding(
Selim Cinekcb445682016-01-29 16:13:12 -0800230 contractedHeader.isLayoutRtl()
231 ? paddingEnd
232 : contractedHeader.getPaddingLeft(),
Selim Cinek6ecc8102016-01-26 18:26:19 -0800233 contractedHeader.getPaddingTop(),
Selim Cinekcb445682016-01-29 16:13:12 -0800234 contractedHeader.isLayoutRtl()
235 ? contractedHeader.getPaddingLeft()
236 : paddingEnd,
Selim Cinek6ecc8102016-01-26 18:26:19 -0800237 contractedHeader.getPaddingBottom());
238 contractedHeader.setShowWorkBadgeAtEnd(false);
239 return true;
240 }
241 }
242 }
243 return false;
244 }
245
Selim Cinek860b6da2015-12-16 19:02:19 -0800246 private boolean shouldContractedBeFixedSize() {
247 return mBeforeN && mContractedWrapper instanceof NotificationCustomViewWrapper;
248 }
249
Selim Cinek8d490d42015-04-10 00:05:50 -0700250 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +0200251 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
252 super.onLayout(changed, left, top, right, bottom);
253 updateClipping();
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700254 invalidateOutline();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200255 }
256
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100257 @Override
Selim Cinek7b8157e2014-11-20 16:00:32 +0100258 protected void onAttachedToWindow() {
259 super.onAttachedToWindow();
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100260 updateVisibility();
261 }
262
Selim Cinek51d94912016-03-02 15:34:28 -0800263 public void reset() {
Jorim Jaggi0d9f35d2014-08-20 17:06:55 +0200264 if (mContractedChild != null) {
265 mContractedChild.animate().cancel();
Selim Cinekde33a4a2016-02-11 16:43:41 -0800266 removeView(mContractedChild);
Jorim Jaggi0d9f35d2014-08-20 17:06:55 +0200267 }
268 if (mExpandedChild != null) {
269 mExpandedChild.animate().cancel();
Selim Cinekde33a4a2016-02-11 16:43:41 -0800270 removeView(mExpandedChild);
Jorim Jaggi0d9f35d2014-08-20 17:06:55 +0200271 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700272 if (mHeadsUpChild != null) {
273 mHeadsUpChild.animate().cancel();
Selim Cinekde33a4a2016-02-11 16:43:41 -0800274 removeView(mHeadsUpChild);
Selim Cinek8d490d42015-04-10 00:05:50 -0700275 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200276 mContractedChild = null;
277 mExpandedChild = null;
Selim Cinek1f3f5442015-04-10 17:54:46 -0700278 mHeadsUpChild = null;
Christoph Studera7fe6312014-06-27 19:32:44 +0200279 }
280
Selim Cinekcab4a602014-09-03 14:47:57 +0200281 public View getContractedChild() {
282 return mContractedChild;
283 }
284
285 public View getExpandedChild() {
286 return mExpandedChild;
287 }
288
Selim Cinek8d490d42015-04-10 00:05:50 -0700289 public View getHeadsUpChild() {
290 return mHeadsUpChild;
291 }
292
Jorim Jaggibe565df2014-04-28 17:51:23 +0200293 public void setContractedChild(View child) {
294 if (mContractedChild != null) {
Jorim Jaggi0d9f35d2014-08-20 17:06:55 +0200295 mContractedChild.animate().cancel();
Selim Cinek30e387d2016-01-11 18:01:47 -0800296 mContractedChild.removeOnLayoutChangeListener(mLayoutUpdater);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200297 removeView(mContractedChild);
298 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200299 addView(child);
300 mContractedChild = child;
Selim Cinek30e387d2016-01-11 18:01:47 -0800301 mContractedChild.addOnLayoutChangeListener(mLayoutUpdater);
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100302 mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child);
Jorim Jaggi11298832014-05-24 16:18:38 +0200303 selectLayout(false /* animate */, true /* force */);
Jorim Jaggi10ad7612014-12-08 18:41:11 +0100304 mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200305 }
306
307 public void setExpandedChild(View child) {
308 if (mExpandedChild != null) {
Jorim Jaggi0d9f35d2014-08-20 17:06:55 +0200309 mExpandedChild.animate().cancel();
Selim Cinek30e387d2016-01-11 18:01:47 -0800310 mExpandedChild.removeOnLayoutChangeListener(mLayoutUpdater);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200311 removeView(mExpandedChild);
312 }
313 addView(child);
314 mExpandedChild = child;
Selim Cinek30e387d2016-01-11 18:01:47 -0800315 mExpandedChild.addOnLayoutChangeListener(mLayoutUpdater);
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700316 mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child);
Jorim Jaggi11298832014-05-24 16:18:38 +0200317 selectLayout(false /* animate */, true /* force */);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200318 }
319
Selim Cinek8d490d42015-04-10 00:05:50 -0700320 public void setHeadsUpChild(View child) {
321 if (mHeadsUpChild != null) {
322 mHeadsUpChild.animate().cancel();
Selim Cinek30e387d2016-01-11 18:01:47 -0800323 mHeadsUpChild.removeOnLayoutChangeListener(mLayoutUpdater);
Selim Cinek8d490d42015-04-10 00:05:50 -0700324 removeView(mHeadsUpChild);
325 }
326 addView(child);
327 mHeadsUpChild = child;
Selim Cinek30e387d2016-01-11 18:01:47 -0800328 mHeadsUpChild.addOnLayoutChangeListener(mLayoutUpdater);
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700329 mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child);
Selim Cinek8d490d42015-04-10 00:05:50 -0700330 selectLayout(false /* animate */, true /* force */);
331 }
332
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100333 @Override
334 protected void onVisibilityChanged(View changedView, int visibility) {
335 super.onVisibilityChanged(changedView, visibility);
336 updateVisibility();
337 }
338
339 private void updateVisibility() {
340 setVisible(isShown());
341 }
342
343 private void setVisible(final boolean isVisible) {
344 if (isVisible) {
345
346 // We only animate if we are drawn at least once, otherwise the view might animate when
347 // it's shown the first time
348 getViewTreeObserver().addOnPreDrawListener(mEnableAnimationPredrawListener);
349 } else {
350 getViewTreeObserver().removeOnPreDrawListener(mEnableAnimationPredrawListener);
351 mAnimate = false;
352 }
353 }
354
Selim Cinekb5605e52015-02-20 18:21:41 +0100355 public void setContentHeight(int contentHeight) {
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700356 mContentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight());;
357 mUnrestrictedContentHeight = Math.max(contentHeight, getMinHeight());
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100358 selectLayout(mAnimate /* animate */, false /* force */);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200359 updateClipping();
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700360 invalidateOutline();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200361 }
362
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800363 private void updateContentTransformation() {
364 int visibleType = calculateVisibleType();
365 if (visibleType != mVisibleType) {
366 // A new transformation starts
367 mTransformationStartVisibleType = mVisibleType;
368 final TransformableView shownView = getTransformableViewForVisibleType(visibleType);
369 final TransformableView hiddenView = getTransformableViewForVisibleType(
370 mTransformationStartVisibleType);
371 shownView.transformFrom(hiddenView, 0.0f);
372 getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
373 hiddenView.transformTo(shownView, 0.0f);
374 mVisibleType = visibleType;
Selim Cinekc3179332016-03-04 14:44:56 -0800375 updateBackgroundColor(true /* animate */);
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800376 }
377 if (mTransformationStartVisibleType != UNDEFINED
378 && mVisibleType != mTransformationStartVisibleType) {
379 final TransformableView shownView = getTransformableViewForVisibleType(mVisibleType);
380 final TransformableView hiddenView = getTransformableViewForVisibleType(
381 mTransformationStartVisibleType);
382 float transformationAmount = calculateTransformationAmount();
383 shownView.transformFrom(hiddenView, transformationAmount);
384 hiddenView.transformTo(shownView, transformationAmount);
Selim Cinekc3179332016-03-04 14:44:56 -0800385 updateBackgroundTransformation(transformationAmount);
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800386 } else {
387 updateViewVisibilities(visibleType);
Selim Cinekc3179332016-03-04 14:44:56 -0800388 updateBackgroundColor(false);
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800389 }
390 }
391
Selim Cinekc3179332016-03-04 14:44:56 -0800392 private void updateBackgroundTransformation(float transformationAmount) {
393 int endColor = getBackgroundColor(mVisibleType);
394 int startColor = getBackgroundColor(mTransformationStartVisibleType);
395 if (endColor != startColor) {
396 if (startColor == 0) {
397 startColor = mContainingNotification.getBackgroundColorWithoutTint();
398 }
399 if (endColor == 0) {
400 endColor = mContainingNotification.getBackgroundColorWithoutTint();
401 }
402 endColor = NotificationUtils.interpolateColors(startColor, endColor,
403 transformationAmount);
404 }
405 mContainingNotification.setContentBackground(endColor, false, this);
406 }
407
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800408 private float calculateTransformationAmount() {
409 int startHeight = getViewForVisibleType(mTransformationStartVisibleType).getHeight();
410 int endHeight = getViewForVisibleType(mVisibleType).getHeight();
411 int progress = Math.abs(mContentHeight - startHeight);
412 int totalDistance = Math.abs(endHeight - startHeight);
413 float amount = (float) progress / (float) totalDistance;
414 return Math.min(1.0f, amount);
415 }
416
Selim Cinekb5605e52015-02-20 18:21:41 +0100417 public int getContentHeight() {
418 return mContentHeight;
419 }
420
Jorim Jaggibe565df2014-04-28 17:51:23 +0200421 public int getMaxHeight() {
Selim Cinek77019c72015-12-09 10:18:02 -0800422 if (mExpandedChild != null) {
Selim Cinek8d490d42015-04-10 00:05:50 -0700423 return mExpandedChild.getHeight();
Selim Cinek77019c72015-12-09 10:18:02 -0800424 } else if (mIsHeadsUp && mHeadsUpChild != null) {
425 return mHeadsUpChild.getHeight();
Selim Cinek8d490d42015-04-10 00:05:50 -0700426 }
Selim Cinek860b6da2015-12-16 19:02:19 -0800427 return mContractedChild.getHeight();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200428 }
429
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200430 public int getMinHeight() {
Selim Cinek42357e02016-02-24 18:48:01 -0800431 return getMinHeight(false /* likeGroupExpanded */);
432 }
433
434 public int getMinHeight(boolean likeGroupExpanded) {
435 if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
Selim Cinek860b6da2015-12-16 19:02:19 -0800436 return mContractedChild.getHeight();
Selim Cinek42357e02016-02-24 18:48:01 -0800437 } else {
438 return mSingleLineView.getHeight();
Selim Cinek83bc7832015-10-22 13:26:54 -0700439 }
440 }
441
442 private boolean isGroupExpanded() {
443 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200444 }
445
Jorim Jaggibe565df2014-04-28 17:51:23 +0200446 public void setClipTopAmount(int clipTopAmount) {
Selim Cinekc9c00ae2014-05-20 03:33:40 +0200447 mClipTopAmount = clipTopAmount;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200448 updateClipping();
449 }
450
Jorim Jaggibe565df2014-04-28 17:51:23 +0200451 private void updateClipping() {
Selim Cinek4ffd6362015-12-29 15:12:23 +0100452 if (mClipToActualHeight) {
453 mClipBounds.set(0, mClipTopAmount, getWidth(), mContentHeight);
454 setClipBounds(mClipBounds);
455 } else {
456 setClipBounds(null);
457 }
458 }
459
460 public void setClipToActualHeight(boolean clipToActualHeight) {
461 mClipToActualHeight = clipToActualHeight;
462 updateClipping();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200463 }
464
Jorim Jaggi11298832014-05-24 16:18:38 +0200465 private void selectLayout(boolean animate, boolean force) {
466 if (mContractedChild == null) {
467 return;
468 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800469 if (mUserExpanding) {
470 updateContentTransformation();
471 return;
472 }
Selim Cinek684a4422015-04-15 16:18:39 -0700473 int visibleType = calculateVisibleType();
474 if (visibleType != mVisibleType || force) {
Jorim Jaggi021eee52015-06-11 17:07:18 -0700475 if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
Selim Cinek684a4422015-04-15 16:18:39 -0700476 || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
Selim Cinek83bc7832015-10-22 13:26:54 -0700477 || (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null)
Jorim Jaggi021eee52015-06-11 17:07:18 -0700478 || visibleType == VISIBLE_TYPE_CONTRACTED)) {
Selim Cinek4ffd6362015-12-29 15:12:23 +0100479 animateToVisibleType(visibleType);
Selim Cinek8d490d42015-04-10 00:05:50 -0700480 } else {
Selim Cinek684a4422015-04-15 16:18:39 -0700481 updateViewVisibilities(visibleType);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200482 }
Selim Cinek684a4422015-04-15 16:18:39 -0700483 mVisibleType = visibleType;
Selim Cinekc3179332016-03-04 14:44:56 -0800484 updateBackgroundColor(animate);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200485 }
Jorim Jaggi11298832014-05-24 16:18:38 +0200486 }
487
Selim Cinekc3179332016-03-04 14:44:56 -0800488 public void updateBackgroundColor(boolean animate) {
489 int customBackgroundColor = getBackgroundColor(mVisibleType);
490 mContainingNotification.setContentBackground(customBackgroundColor, animate, this);
491 }
492
493 private int getBackgroundColor(int visibleType) {
494 NotificationViewWrapper currentVisibleWrapper = getVisibleWrapper(visibleType);
495 int customBackgroundColor = 0;
496 if (currentVisibleWrapper != null) {
497 customBackgroundColor = currentVisibleWrapper.getCustomBackgroundColor();
498 }
499 return customBackgroundColor;
500 }
501
Selim Cinek684a4422015-04-15 16:18:39 -0700502 private void updateViewVisibilities(int visibleType) {
503 boolean contractedVisible = visibleType == VISIBLE_TYPE_CONTRACTED;
Selim Cinek4ffd6362015-12-29 15:12:23 +0100504 mContractedWrapper.setVisible(contractedVisible);
Selim Cinek8d490d42015-04-10 00:05:50 -0700505 if (mExpandedChild != null) {
Selim Cinek684a4422015-04-15 16:18:39 -0700506 boolean expandedVisible = visibleType == VISIBLE_TYPE_EXPANDED;
Selim Cinek4ffd6362015-12-29 15:12:23 +0100507 mExpandedWrapper.setVisible(expandedVisible);
Selim Cinek8d490d42015-04-10 00:05:50 -0700508 }
509 if (mHeadsUpChild != null) {
Selim Cinek684a4422015-04-15 16:18:39 -0700510 boolean headsUpVisible = visibleType == VISIBLE_TYPE_HEADSUP;
Selim Cinek4ffd6362015-12-29 15:12:23 +0100511 mHeadsUpWrapper.setVisible(headsUpVisible);
Selim Cinek8d490d42015-04-10 00:05:50 -0700512 }
Selim Cinek83bc7832015-10-22 13:26:54 -0700513 if (mSingleLineView != null) {
514 boolean singleLineVisible = visibleType == VISIBLE_TYPE_SINGLELINE;
Selim Cinek4ffd6362015-12-29 15:12:23 +0100515 mSingleLineView.setVisible(singleLineVisible);
Selim Cinek83bc7832015-10-22 13:26:54 -0700516 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700517 }
518
Selim Cinek4ffd6362015-12-29 15:12:23 +0100519 private void animateToVisibleType(int visibleType) {
520 final TransformableView shownView = getTransformableViewForVisibleType(visibleType);
521 final TransformableView hiddenView = getTransformableViewForVisibleType(mVisibleType);
Selim Cinek51d94912016-03-02 15:34:28 -0800522 if (shownView == hiddenView) {
523 shownView.setVisible(true);
524 return;
525 }
Selim Cinek4ffd6362015-12-29 15:12:23 +0100526 shownView.transformFrom(hiddenView);
527 getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
528 hiddenView.transformTo(shownView, new Runnable() {
529 @Override
530 public void run() {
Selim Cinek51d94912016-03-02 15:34:28 -0800531 if (hiddenView != getTransformableViewForVisibleType(mVisibleType)) {
532 hiddenView.setVisible(false);
533 }
Selim Cinek4ffd6362015-12-29 15:12:23 +0100534 }
535 });
Jorim Jaggi11298832014-05-24 16:18:38 +0200536 }
537
Selim Cinek684a4422015-04-15 16:18:39 -0700538 /**
539 * @param visibleType one of the static enum types in this view
Selim Cinek4ffd6362015-12-29 15:12:23 +0100540 * @return the corresponding transformable view according to the given visible type
541 */
542 private TransformableView getTransformableViewForVisibleType(int visibleType) {
543 switch (visibleType) {
544 case VISIBLE_TYPE_EXPANDED:
545 return mExpandedWrapper;
546 case VISIBLE_TYPE_HEADSUP:
547 return mHeadsUpWrapper;
548 case VISIBLE_TYPE_SINGLELINE:
549 return mSingleLineView;
550 default:
551 return mContractedWrapper;
552 }
553 }
554
555 /**
556 * @param visibleType one of the static enum types in this view
Selim Cinek684a4422015-04-15 16:18:39 -0700557 * @return the corresponding view according to the given visible type
558 */
559 private View getViewForVisibleType(int visibleType) {
560 switch (visibleType) {
561 case VISIBLE_TYPE_EXPANDED:
Selim Cinek8d490d42015-04-10 00:05:50 -0700562 return mExpandedChild;
Selim Cinek684a4422015-04-15 16:18:39 -0700563 case VISIBLE_TYPE_HEADSUP:
Selim Cinek8d490d42015-04-10 00:05:50 -0700564 return mHeadsUpChild;
Selim Cinek83bc7832015-10-22 13:26:54 -0700565 case VISIBLE_TYPE_SINGLELINE:
566 return mSingleLineView;
Selim Cinek684a4422015-04-15 16:18:39 -0700567 default:
568 return mContractedChild;
Selim Cinek8d490d42015-04-10 00:05:50 -0700569 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700570 }
571
Selim Cinekc3179332016-03-04 14:44:56 -0800572 private NotificationViewWrapper getVisibleWrapper(int visibleType) {
573 switch (visibleType) {
Selim Cinek34eda5e2016-02-18 17:10:43 -0800574 case VISIBLE_TYPE_EXPANDED:
575 return mExpandedWrapper;
576 case VISIBLE_TYPE_HEADSUP:
577 return mHeadsUpWrapper;
578 case VISIBLE_TYPE_CONTRACTED:
579 return mContractedWrapper;
580 default:
581 return null;
582 }
583 }
584
Selim Cinek684a4422015-04-15 16:18:39 -0700585 /**
586 * @return one of the static enum types in this view, calculated form the current state
587 */
588 private int calculateVisibleType() {
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800589 if (mUserExpanding) {
Selim Cinek42357e02016-02-24 18:48:01 -0800590 int height = !mIsChildInGroup || isGroupExpanded()
Selim Cineke81b82b2016-03-04 11:22:28 -0800591 || mContainingNotification.isExpanded(true /* allowOnKeyguard */)
Selim Cinek42357e02016-02-24 18:48:01 -0800592 ? mContainingNotification.getMaxContentHeight()
593 : mContainingNotification.getShowingLayout().getMinHeight();
Selim Cinek51d94912016-03-02 15:34:28 -0800594 if (height == 0) {
595 height = mContentHeight;
596 }
Selim Cinek42357e02016-02-24 18:48:01 -0800597 int expandedVisualType = getVisualTypeForHeight(height);
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800598 int collapsedVisualType = getVisualTypeForHeight(
599 mContainingNotification.getMinExpandHeight());
600 return mTransformationStartVisibleType == collapsedVisualType
601 ? expandedVisualType
602 : collapsedVisualType;
603 }
Selim Cinek51d94912016-03-02 15:34:28 -0800604 int intrinsicHeight = mContainingNotification.getIntrinsicHeight();
605 int viewHeight = mContentHeight;
606 if (intrinsicHeight != 0) {
607 // the intrinsicHeight might be 0 because it was just reset.
608 viewHeight = Math.min(mContentHeight, intrinsicHeight);
609 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800610 return getVisualTypeForHeight(viewHeight);
611 }
612
613 private int getVisualTypeForHeight(float viewHeight) {
614 boolean noExpandedChild = mExpandedChild == null;
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800615 if (!noExpandedChild && viewHeight == mExpandedChild.getHeight()) {
Adrian Roos777ef562015-12-01 17:37:14 -0800616 return VISIBLE_TYPE_EXPANDED;
617 }
Selim Cinek42357e02016-02-24 18:48:01 -0800618 if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) {
Selim Cinekd84a5932015-12-15 11:45:36 -0800619 return VISIBLE_TYPE_SINGLELINE;
620 }
Adrian Roos777ef562015-12-01 17:37:14 -0800621
Selim Cinek1f3f5442015-04-10 17:54:46 -0700622 if (mIsHeadsUp && mHeadsUpChild != null) {
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800623 if (viewHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
Selim Cinek684a4422015-04-15 16:18:39 -0700624 return VISIBLE_TYPE_HEADSUP;
Selim Cinek8d490d42015-04-10 00:05:50 -0700625 } else {
Selim Cinek684a4422015-04-15 16:18:39 -0700626 return VISIBLE_TYPE_EXPANDED;
Selim Cinek8d490d42015-04-10 00:05:50 -0700627 }
628 } else {
Selim Cineka4091502016-02-11 17:21:16 -0800629 if (noExpandedChild || (viewHeight <= mContractedChild.getHeight()
Selim Cineke81b82b2016-03-04 11:22:28 -0800630 && (!mIsChildInGroup
631 || !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) {
Selim Cinek684a4422015-04-15 16:18:39 -0700632 return VISIBLE_TYPE_CONTRACTED;
Selim Cinek8d490d42015-04-10 00:05:50 -0700633 } else {
Selim Cinek684a4422015-04-15 16:18:39 -0700634 return VISIBLE_TYPE_EXPANDED;
Selim Cinek8d490d42015-04-10 00:05:50 -0700635 }
636 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200637 }
638
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200639 public boolean isContentExpandable() {
640 return mExpandedChild != null;
641 }
John Spurlocke15452b2014-08-21 09:44:39 -0400642
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100643 public void setDark(boolean dark, boolean fade, long delay) {
Selim Cinekb88b9842016-02-26 09:25:33 -0800644 if (mContractedChild == null) {
Selim Cinek0934bd92016-02-19 12:22:33 -0800645 return;
646 }
John Spurlocke15452b2014-08-21 09:44:39 -0400647 mDark = dark;
Selim Cinek19ba7052016-01-27 20:04:27 -0800648 if (mVisibleType == VISIBLE_TYPE_CONTRACTED || !dark) {
Selim Cinek30e387d2016-01-11 18:01:47 -0800649 mContractedWrapper.setDark(dark, fade, delay);
650 }
Selim Cinek19ba7052016-01-27 20:04:27 -0800651 if (mVisibleType == VISIBLE_TYPE_EXPANDED || (mExpandedChild != null && !dark)) {
Selim Cinek30e387d2016-01-11 18:01:47 -0800652 mExpandedWrapper.setDark(dark, fade, delay);
653 }
Selim Cinek19ba7052016-01-27 20:04:27 -0800654 if (mVisibleType == VISIBLE_TYPE_HEADSUP || (mHeadsUpChild != null && !dark)) {
Selim Cinek30e387d2016-01-11 18:01:47 -0800655 mHeadsUpWrapper.setDark(dark, fade, delay);
656 }
Selim Cinek19ba7052016-01-27 20:04:27 -0800657 if (mSingleLineView != null && (mVisibleType == VISIBLE_TYPE_SINGLELINE || !dark)) {
Selim Cinek9c7712d2015-12-08 19:19:48 -0800658 mSingleLineView.setDark(dark, fade, delay);
659 }
John Spurlocke15452b2014-08-21 09:44:39 -0400660 }
661
Selim Cinek8d490d42015-04-10 00:05:50 -0700662 public void setHeadsUp(boolean headsUp) {
663 mIsHeadsUp = headsUp;
664 selectLayout(false /* animate */, true /* force */);
Selim Cinek98be3f32015-12-17 16:39:06 -0800665 updateExpandButtons(mExpandable);
Selim Cinek8d490d42015-04-10 00:05:50 -0700666 }
667
Jorim Jaggiaa92ffb2014-09-10 23:29:28 +0200668 @Override
669 public boolean hasOverlappingRendering() {
670
671 // This is not really true, but good enough when fading from the contracted to the expanded
672 // layout, and saves us some layers.
673 return false;
674 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -0700675
676 public void setShowingLegacyBackground(boolean showing) {
677 mShowingLegacyBackground = showing;
Selim Cinekc3179332016-03-04 14:44:56 -0800678 updateShowingLegacyBackground();
679 }
680
681 private void updateShowingLegacyBackground() {
682 if (mContractedChild != null) {
683 mContractedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
684 }
685 if (mExpandedChild != null) {
686 mExpandedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
687 }
688 if (mHeadsUpChild != null) {
689 mHeadsUpWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
690 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -0700691 }
Selim Cinek8d6440d2015-10-22 13:00:05 -0700692
Selim Cinek83bc7832015-10-22 13:26:54 -0700693 public void setIsChildInGroup(boolean isChildInGroup) {
694 mIsChildInGroup = isChildInGroup;
695 updateSingleLineView();
696 }
697
Adrian Roosb88b1a12015-12-09 18:51:05 -0800698 public void onNotificationUpdated(NotificationData.Entry entry) {
699 mStatusBarNotification = entry.notification;
Selim Cinek860b6da2015-12-16 19:02:19 -0800700 mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
Selim Cinek83bc7832015-10-22 13:26:54 -0700701 updateSingleLineView();
Adrian Roosb88b1a12015-12-09 18:51:05 -0800702 applyRemoteInput(entry);
Selim Cinek8fc93c92015-11-23 17:48:07 -0800703 if (mContractedChild != null) {
Selim Cinek4ffd6362015-12-29 15:12:23 +0100704 mContractedWrapper.notifyContentUpdated(entry.notification);
Selim Cinek8fc93c92015-11-23 17:48:07 -0800705 }
706 if (mExpandedChild != null) {
Selim Cinek4ffd6362015-12-29 15:12:23 +0100707 mExpandedWrapper.notifyContentUpdated(entry.notification);
Selim Cinek8fc93c92015-11-23 17:48:07 -0800708 }
709 if (mHeadsUpChild != null) {
Selim Cinek4ffd6362015-12-29 15:12:23 +0100710 mHeadsUpWrapper.notifyContentUpdated(entry.notification);
Selim Cinek8fc93c92015-11-23 17:48:07 -0800711 }
Selim Cinekc3179332016-03-04 14:44:56 -0800712 updateShowingLegacyBackground();
Selim Cinek51d94912016-03-02 15:34:28 -0800713 selectLayout(false /* animate */, true /* force */);
Selim Cinekb88b9842016-02-26 09:25:33 -0800714 setDark(mDark, false /* animate */, 0 /* delay */);
Selim Cinek83bc7832015-10-22 13:26:54 -0700715 }
716
717 private void updateSingleLineView() {
718 if (mIsChildInGroup) {
719 mSingleLineView = mHybridViewManager.bindFromNotification(
720 mSingleLineView, mStatusBarNotification.getNotification());
Selim Cinekde33a4a2016-02-11 16:43:41 -0800721 } else if (mSingleLineView != null) {
722 removeView(mSingleLineView);
723 mSingleLineView = null;
Selim Cinek83bc7832015-10-22 13:26:54 -0700724 }
725 }
726
Adrian Roosb88b1a12015-12-09 18:51:05 -0800727 private void applyRemoteInput(final NotificationData.Entry entry) {
728 if (mRemoteInputController == null) {
729 return;
730 }
731
732 boolean hasRemoteInput = false;
733
734 Notification.Action[] actions = entry.notification.getNotification().actions;
735 if (actions != null) {
736 for (Notification.Action a : actions) {
737 if (a.getRemoteInputs() != null) {
738 for (RemoteInput ri : a.getRemoteInputs()) {
739 if (ri.getAllowFreeFormInput()) {
740 hasRemoteInput = true;
741 break;
742 }
743 }
744 }
745 }
746 }
747
748 View bigContentView = mExpandedChild;
749 if (bigContentView != null) {
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700750 mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput);
751 } else {
752 mExpandedRemoteInput = null;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800753 }
754 View headsUpContentView = mHeadsUpChild;
755 if (headsUpContentView != null) {
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700756 mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput);
757 } else {
758 mHeadsUpRemoteInput = null;
Adrian Roosb88b1a12015-12-09 18:51:05 -0800759 }
760 }
761
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700762 private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry, boolean hasRemoteInput) {
Adrian Roosb88b1a12015-12-09 18:51:05 -0800763 View actionContainerCandidate = view.findViewById(
764 com.android.internal.R.id.actions_container);
765 if (actionContainerCandidate instanceof FrameLayout) {
766 RemoteInputView existing = (RemoteInputView)
767 view.findViewWithTag(RemoteInputView.VIEW_TAG);
768
769 if (existing != null) {
770 existing.onNotificationUpdate();
771 }
772
773 if (existing == null && hasRemoteInput) {
774 ViewGroup actionContainer = (FrameLayout) actionContainerCandidate;
775 RemoteInputView riv = RemoteInputView.inflate(
776 mContext, actionContainer, entry, mRemoteInputController);
777
778 riv.setVisibility(View.INVISIBLE);
779 actionContainer.addView(riv, new LayoutParams(
780 ViewGroup.LayoutParams.MATCH_PARENT,
781 ViewGroup.LayoutParams.MATCH_PARENT)
782 );
Adrian Roos4ff3b122016-02-01 12:26:13 -0800783 existing = riv;
784 }
785 if (hasRemoteInput) {
Adrian Roosb88b1a12015-12-09 18:51:05 -0800786 int color = entry.notification.getNotification().color;
787 if (color == Notification.COLOR_DEFAULT) {
788 color = mContext.getColor(R.color.default_remote_input_background);
789 }
Adrian Roos4ff3b122016-02-01 12:26:13 -0800790 existing.setBackgroundColor(NotificationColorUtil.ensureTextBackgroundColor(color,
791 mContext.getColor(R.color.remote_input_text),
792 mContext.getColor(R.color.remote_input_hint)));
Adrian Roosb88b1a12015-12-09 18:51:05 -0800793 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700794 return existing;
795 }
796 return null;
797 }
798
799 public void closeRemoteInput() {
800 if (mHeadsUpRemoteInput != null) {
801 mHeadsUpRemoteInput.close();
802 }
803 if (mExpandedRemoteInput != null) {
804 mExpandedRemoteInput.close();
Adrian Roosb88b1a12015-12-09 18:51:05 -0800805 }
806 }
807
Selim Cinek83bc7832015-10-22 13:26:54 -0700808 public void setGroupManager(NotificationGroupManager groupManager) {
809 mGroupManager = groupManager;
810 }
Selim Cinek65b2e7c2015-10-26 14:11:31 -0700811
Adrian Roosb88b1a12015-12-09 18:51:05 -0800812 public void setRemoteInputController(RemoteInputController r) {
813 mRemoteInputController = r;
814 }
815
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800816 public void setExpandClickListener(OnClickListener expandClickListener) {
817 mExpandClickListener = expandClickListener;
818 }
819
820 public void updateExpandButtons(boolean expandable) {
Selim Cinek98be3f32015-12-17 16:39:06 -0800821 mExpandable = expandable;
822 // if the expanded child has the same height as the collapsed one we hide it.
823 if (mExpandedChild != null && mExpandedChild.getHeight() != 0 &&
824 ((mIsHeadsUp && mExpandedChild.getHeight() == mHeadsUpChild.getHeight()) ||
825 (!mIsHeadsUp && mExpandedChild.getHeight() == mContractedChild.getHeight()))) {
826 expandable = false;
827 }
Selim Cinek65b2e7c2015-10-26 14:11:31 -0700828 if (mExpandedChild != null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800829 mExpandedWrapper.updateExpandability(expandable, mExpandClickListener);
Selim Cinek65b2e7c2015-10-26 14:11:31 -0700830 }
831 if (mContractedChild != null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800832 mContractedWrapper.updateExpandability(expandable, mExpandClickListener);
Selim Cinek65b2e7c2015-10-26 14:11:31 -0700833 }
834 if (mHeadsUpChild != null) {
Selim Cinekeaa29ca2015-11-23 13:51:13 -0800835 mHeadsUpWrapper.updateExpandability(expandable, mExpandClickListener);
Selim Cinek65b2e7c2015-10-26 14:11:31 -0700836 }
837 }
Selim Cinekea4bef72015-12-02 15:51:10 -0800838
839 public NotificationHeaderView getNotificationHeader() {
840 NotificationHeaderView header = null;
841 if (mContractedChild != null) {
842 header = mContractedWrapper.getNotificationHeader();
843 }
844 if (header == null && mExpandedChild != null) {
845 header = mExpandedWrapper.getNotificationHeader();
846 }
847 if (header == null && mHeadsUpChild != null) {
848 header = mHeadsUpWrapper.getNotificationHeader();
849 }
850 return header;
851 }
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800852
Selim Cinek34eda5e2016-02-18 17:10:43 -0800853 public NotificationHeaderView getVisibleNotificationHeader() {
Selim Cinekc3179332016-03-04 14:44:56 -0800854 NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
Selim Cinek34eda5e2016-02-18 17:10:43 -0800855 return wrapper == null ? null : wrapper.getNotificationHeader();
856 }
857
Selim Cinekfa0a2d32016-01-14 13:02:21 -0800858 public void setContainingNotification(ExpandableNotificationRow containingNotification) {
859 mContainingNotification = containingNotification;
860 }
861
862 public void requestSelectLayout(boolean needsAnimation) {
863 selectLayout(needsAnimation, false);
864 }
Selim Cinekde33a4a2016-02-11 16:43:41 -0800865
866 public void reInflateViews() {
867 if (mIsChildInGroup && mSingleLineView != null) {
868 removeView(mSingleLineView);
869 mSingleLineView = null;
870 updateSingleLineView();
871 }
872 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800873
874 public void setUserExpanding(boolean userExpanding) {
875 mUserExpanding = userExpanding;
876 if (userExpanding) {
877 mTransformationStartVisibleType = mVisibleType;
878 } else {
879 mTransformationStartVisibleType = UNDEFINED;
880 mVisibleType = calculateVisibleType();
881 updateViewVisibilities(mVisibleType);
Selim Cinekc3179332016-03-04 14:44:56 -0800882 updateBackgroundColor(false);
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800883 }
884 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200885}