blob: 17d9856a8f0836f051b3628aea3aa290e7bc4c15 [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
19import android.content.Context;
Jorim Jaggibe4116a2015-05-20 20:04:08 -070020import android.graphics.Outline;
Jorim Jaggi11298832014-05-24 16:18:38 +020021import android.graphics.Paint;
22import android.graphics.PorterDuff;
23import android.graphics.PorterDuffXfermode;
Jorim Jaggibe565df2014-04-28 17:51:23 +020024import android.graphics.Rect;
Selim Cinek83bc7832015-10-22 13:26:54 -070025import android.service.notification.StatusBarNotification;
Jorim Jaggibe565df2014-04-28 17:51:23 +020026import android.util.AttributeSet;
Jorim Jaggibe565df2014-04-28 17:51:23 +020027import android.view.View;
Selim Cinek8d490d42015-04-10 00:05:50 -070028import android.view.ViewGroup;
Jorim Jaggibe4116a2015-05-20 20:04:08 -070029import android.view.ViewOutlineProvider;
Selim Cinekbb3d1cf2014-10-31 00:12:56 +010030import android.view.ViewTreeObserver;
Jorim Jaggi11298832014-05-24 16:18:38 +020031import android.view.animation.Interpolator;
32import android.view.animation.LinearInterpolator;
Selim Cinekc9c00ae2014-05-20 03:33:40 +020033import android.widget.FrameLayout;
Selim Cinek8d490d42015-04-10 00:05:50 -070034
Jorim Jaggibe565df2014-04-28 17:51:23 +020035import com.android.systemui.R;
Selim Cinek83bc7832015-10-22 13:26:54 -070036import com.android.systemui.statusbar.notification.HybridNotificationView;
37import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
38import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jorim Jaggibe565df2014-04-28 17:51:23 +020039
40/**
Selim Cinek684a4422015-04-15 16:18:39 -070041 * A frame layout containing the actual payload of the notification, including the contracted,
42 * expanded and heads up layout. This class is responsible for clipping the content and and
43 * switching between the expanded, contracted and the heads up view depending on its clipped size.
Jorim Jaggibe565df2014-04-28 17:51:23 +020044 */
Selim Cinekc9c00ae2014-05-20 03:33:40 +020045public class NotificationContentView extends FrameLayout {
Jorim Jaggibe565df2014-04-28 17:51:23 +020046
Jorim Jaggi11298832014-05-24 16:18:38 +020047 private static final long ANIMATION_DURATION_LENGTH = 170;
Selim Cinek684a4422015-04-15 16:18:39 -070048 private static final int VISIBLE_TYPE_CONTRACTED = 0;
49 private static final int VISIBLE_TYPE_EXPANDED = 1;
50 private static final int VISIBLE_TYPE_HEADSUP = 2;
Selim Cinek83bc7832015-10-22 13:26:54 -070051 private static final int VISIBLE_TYPE_SINGLELINE = 3;
Jorim Jaggi11298832014-05-24 16:18:38 +020052
Jorim Jaggibe565df2014-04-28 17:51:23 +020053 private final Rect mClipBounds = new Rect();
Selim Cinek83bc7832015-10-22 13:26:54 -070054 private final int mSingleLineHeight;
Selim Cinek684a4422015-04-15 16:18:39 -070055 private final int mSmallHeight;
56 private final int mHeadsUpHeight;
Jorim Jaggibe4116a2015-05-20 20:04:08 -070057 private final int mRoundRectRadius;
Selim Cinek684a4422015-04-15 16:18:39 -070058 private final Interpolator mLinearInterpolator = new LinearInterpolator();
Jorim Jaggibe4116a2015-05-20 20:04:08 -070059 private final boolean mRoundRectClippingEnabled;
Jorim Jaggibe565df2014-04-28 17:51:23 +020060
61 private View mContractedChild;
62 private View mExpandedChild;
Selim Cinek8d490d42015-04-10 00:05:50 -070063 private View mHeadsUpChild;
Selim Cinek83bc7832015-10-22 13:26:54 -070064 private HybridNotificationView mSingleLineView;
Jorim Jaggibe565df2014-04-28 17:51:23 +020065
Jorim Jaggi4e857f42014-11-17 19:14:04 +010066 private NotificationViewWrapper mContractedWrapper;
Jorim Jaggibe4116a2015-05-20 20:04:08 -070067 private NotificationViewWrapper mExpandedWrapper;
68 private NotificationViewWrapper mHeadsUpWrapper;
Selim Cinek83bc7832015-10-22 13:26:54 -070069 private HybridNotificationViewManager mHybridViewManager;
Selim Cinekc9c00ae2014-05-20 03:33:40 +020070 private int mClipTopAmount;
Selim Cinekb5605e52015-02-20 18:21:41 +010071 private int mContentHeight;
Jorim Jaggibe4116a2015-05-20 20:04:08 -070072 private int mUnrestrictedContentHeight;
Selim Cinek684a4422015-04-15 16:18:39 -070073 private int mVisibleType = VISIBLE_TYPE_CONTRACTED;
John Spurlocke15452b2014-08-21 09:44:39 -040074 private boolean mDark;
Christoph Studera7fe6312014-06-27 19:32:44 +020075 private final Paint mFadePaint = new Paint();
Selim Cinekbb3d1cf2014-10-31 00:12:56 +010076 private boolean mAnimate;
Selim Cinek684a4422015-04-15 16:18:39 -070077 private boolean mIsHeadsUp;
Jorim Jaggi59ec3042015-06-05 15:18:43 -070078 private boolean mShowingLegacyBackground;
Selim Cinek83bc7832015-10-22 13:26:54 -070079 private boolean mIsChildInGroup;
Selim Cinek65b2e7c2015-10-26 14:11:31 -070080 private ExpandableNotificationRow mContainingNotification;
Selim Cinek83bc7832015-10-22 13:26:54 -070081 private StatusBarNotification mStatusBarNotification;
Selim Cinek65b2e7c2015-10-26 14:11:31 -070082 private NotificationGroupManager mGroupManager;
Jorim Jaggi59ec3042015-06-05 15:18:43 -070083
Jorim Jaggibe4116a2015-05-20 20:04:08 -070084 private final ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
Selim Cinekbb3d1cf2014-10-31 00:12:56 +010085 = new ViewTreeObserver.OnPreDrawListener() {
86 @Override
87 public boolean onPreDraw() {
88 mAnimate = true;
89 getViewTreeObserver().removeOnPreDrawListener(this);
90 return true;
91 }
92 };
Jorim Jaggi11298832014-05-24 16:18:38 +020093
Jorim Jaggibe4116a2015-05-20 20:04:08 -070094 private final ViewOutlineProvider mOutlineProvider = new ViewOutlineProvider() {
95 @Override
96 public void getOutline(View view, Outline outline) {
97 outline.setRoundRect(0, 0, view.getWidth(), mUnrestrictedContentHeight,
98 mRoundRectRadius);
99 }
100 };
Selim Cinek65b2e7c2015-10-26 14:11:31 -0700101 private OnClickListener mExpandClickListener = new OnClickListener() {
102 @Override
103 public void onClick(View v) {
104 if (mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
105 mGroupManager.toggleGroupExpansion(mStatusBarNotification);
106 } else {
107 mContainingNotification.setUserExpanded(!mContainingNotification.isExpanded());
108 mContainingNotification.notifyHeightChanged(true);
109 }
110 }
111 };
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700112
Jorim Jaggibe565df2014-04-28 17:51:23 +0200113 public NotificationContentView(Context context, AttributeSet attrs) {
114 super(context, attrs);
Selim Cinek83bc7832015-10-22 13:26:54 -0700115 mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
Jorim Jaggi11298832014-05-24 16:18:38 +0200116 mFadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
Selim Cinek83bc7832015-10-22 13:26:54 -0700117 mSingleLineHeight = getResources().getDimensionPixelSize(
118 R.dimen.notification_single_line_height);
Selim Cinek1f3f5442015-04-10 17:54:46 -0700119 mSmallHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
120 mHeadsUpHeight = getResources().getDimensionPixelSize(R.dimen.notification_mid_height);
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700121 mRoundRectRadius = getResources().getDimensionPixelSize(
122 R.dimen.notification_material_rounded_rect_radius);
123 mRoundRectClippingEnabled = getResources().getBoolean(
124 R.bool.config_notifications_round_rect_clipping);
Selim Cinek1a521f32014-11-03 17:39:29 +0100125 reset(true);
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700126 setOutlineProvider(mOutlineProvider);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200127 }
128
129 @Override
Selim Cinek8d490d42015-04-10 00:05:50 -0700130 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
131 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
132 boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
133 boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
134 int maxSize = Integer.MAX_VALUE;
135 if (hasFixedHeight || isHeightLimited) {
136 maxSize = MeasureSpec.getSize(heightMeasureSpec);
137 }
138 int maxChildHeight = 0;
139 if (mContractedChild != null) {
140 int size = Math.min(maxSize, mSmallHeight);
141 mContractedChild.measure(widthMeasureSpec,
Selim Cinek06a24ebd2015-04-22 14:22:05 -0700142 MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY));
Selim Cinek8d490d42015-04-10 00:05:50 -0700143 maxChildHeight = Math.max(maxChildHeight, mContractedChild.getMeasuredHeight());
144 }
145 if (mExpandedChild != null) {
146 int size = maxSize;
147 ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
148 if (layoutParams.height >= 0) {
149 // An actual height is set
150 size = Math.min(maxSize, layoutParams.height);
151 }
Selim Cinek684a4422015-04-15 16:18:39 -0700152 int spec = size == Integer.MAX_VALUE
153 ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
154 : MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
Selim Cinek8d490d42015-04-10 00:05:50 -0700155 mExpandedChild.measure(widthMeasureSpec, spec);
156 maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
157 }
158 if (mHeadsUpChild != null) {
159 int size = Math.min(maxSize, mHeadsUpHeight);
160 ViewGroup.LayoutParams layoutParams = mHeadsUpChild.getLayoutParams();
161 if (layoutParams.height >= 0) {
162 // An actual height is set
163 size = Math.min(maxSize, layoutParams.height);
164 }
165 mHeadsUpChild.measure(widthMeasureSpec,
166 MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST));
167 maxChildHeight = Math.max(maxChildHeight, mHeadsUpChild.getMeasuredHeight());
168 }
Selim Cinek83bc7832015-10-22 13:26:54 -0700169 if (mSingleLineView != null) {
170 int size = Math.min(maxSize, mSingleLineHeight);
171 mSingleLineView.measure(widthMeasureSpec,
172 MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY));
173 maxChildHeight = Math.max(maxChildHeight, mSingleLineView.getMeasuredHeight());
174 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700175 int ownHeight = Math.min(maxChildHeight, maxSize);
176 int width = MeasureSpec.getSize(widthMeasureSpec);
177 setMeasuredDimension(width, ownHeight);
178 }
179
180 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +0200181 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
182 super.onLayout(changed, left, top, right, bottom);
183 updateClipping();
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700184 invalidateOutline();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200185 }
186
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100187 @Override
Selim Cinek7b8157e2014-11-20 16:00:32 +0100188 protected void onAttachedToWindow() {
189 super.onAttachedToWindow();
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100190 updateVisibility();
191 }
192
Selim Cinek1a521f32014-11-03 17:39:29 +0100193 public void reset(boolean resetActualHeight) {
Jorim Jaggi0d9f35d2014-08-20 17:06:55 +0200194 if (mContractedChild != null) {
195 mContractedChild.animate().cancel();
196 }
197 if (mExpandedChild != null) {
198 mExpandedChild.animate().cancel();
199 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700200 if (mHeadsUpChild != null) {
201 mHeadsUpChild.animate().cancel();
202 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200203 removeAllViews();
204 mContractedChild = null;
205 mExpandedChild = null;
Selim Cinek1f3f5442015-04-10 17:54:46 -0700206 mHeadsUpChild = null;
Selim Cinek684a4422015-04-15 16:18:39 -0700207 mVisibleType = VISIBLE_TYPE_CONTRACTED;
Selim Cinek1a521f32014-11-03 17:39:29 +0100208 if (resetActualHeight) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100209 mContentHeight = mSmallHeight;
Selim Cinek1a521f32014-11-03 17:39:29 +0100210 }
Christoph Studera7fe6312014-06-27 19:32:44 +0200211 }
212
Selim Cinekcab4a602014-09-03 14:47:57 +0200213 public View getContractedChild() {
214 return mContractedChild;
215 }
216
217 public View getExpandedChild() {
218 return mExpandedChild;
219 }
220
Selim Cinek8d490d42015-04-10 00:05:50 -0700221 public View getHeadsUpChild() {
222 return mHeadsUpChild;
223 }
224
Jorim Jaggibe565df2014-04-28 17:51:23 +0200225 public void setContractedChild(View child) {
226 if (mContractedChild != null) {
Jorim Jaggi0d9f35d2014-08-20 17:06:55 +0200227 mContractedChild.animate().cancel();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200228 removeView(mContractedChild);
229 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200230 addView(child);
231 mContractedChild = child;
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100232 mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child);
Jorim Jaggi11298832014-05-24 16:18:38 +0200233 selectLayout(false /* animate */, true /* force */);
Jorim Jaggi10ad7612014-12-08 18:41:11 +0100234 mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700235 updateRoundRectClipping();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200236 }
237
238 public void setExpandedChild(View child) {
239 if (mExpandedChild != null) {
Jorim Jaggi0d9f35d2014-08-20 17:06:55 +0200240 mExpandedChild.animate().cancel();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200241 removeView(mExpandedChild);
242 }
243 addView(child);
244 mExpandedChild = child;
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700245 mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child);
Jorim Jaggi11298832014-05-24 16:18:38 +0200246 selectLayout(false /* animate */, true /* force */);
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700247 updateRoundRectClipping();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200248 }
249
Selim Cinek8d490d42015-04-10 00:05:50 -0700250 public void setHeadsUpChild(View child) {
251 if (mHeadsUpChild != null) {
252 mHeadsUpChild.animate().cancel();
253 removeView(mHeadsUpChild);
254 }
255 addView(child);
256 mHeadsUpChild = child;
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700257 mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child);
Selim Cinek8d490d42015-04-10 00:05:50 -0700258 selectLayout(false /* animate */, true /* force */);
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700259 updateRoundRectClipping();
Selim Cinek8d490d42015-04-10 00:05:50 -0700260 }
261
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100262 @Override
263 protected void onVisibilityChanged(View changedView, int visibility) {
264 super.onVisibilityChanged(changedView, visibility);
265 updateVisibility();
266 }
267
268 private void updateVisibility() {
269 setVisible(isShown());
270 }
271
272 private void setVisible(final boolean isVisible) {
273 if (isVisible) {
274
275 // We only animate if we are drawn at least once, otherwise the view might animate when
276 // it's shown the first time
277 getViewTreeObserver().addOnPreDrawListener(mEnableAnimationPredrawListener);
278 } else {
279 getViewTreeObserver().removeOnPreDrawListener(mEnableAnimationPredrawListener);
280 mAnimate = false;
281 }
282 }
283
Selim Cinekb5605e52015-02-20 18:21:41 +0100284 public void setContentHeight(int contentHeight) {
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700285 mContentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight());;
286 mUnrestrictedContentHeight = Math.max(contentHeight, getMinHeight());
Selim Cinekbb3d1cf2014-10-31 00:12:56 +0100287 selectLayout(mAnimate /* animate */, false /* force */);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200288 updateClipping();
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700289 invalidateOutline();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200290 }
291
Selim Cinekb5605e52015-02-20 18:21:41 +0100292 public int getContentHeight() {
293 return mContentHeight;
294 }
295
Jorim Jaggibe565df2014-04-28 17:51:23 +0200296 public int getMaxHeight() {
Selim Cinek8d490d42015-04-10 00:05:50 -0700297 if (mIsHeadsUp && mHeadsUpChild != null) {
298 return mHeadsUpChild.getHeight();
299 } else if (mExpandedChild != null) {
300 return mExpandedChild.getHeight();
301 }
302 return mSmallHeight;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200303 }
304
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200305 public int getMinHeight() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700306 if (mIsChildInGroup && !isGroupExpanded()) {
307 return mSingleLineHeight;
308 } else {
309 return mSmallHeight;
310 }
311 }
312
313 private boolean isGroupExpanded() {
314 return mGroupManager.isGroupExpanded(mStatusBarNotification);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200315 }
316
Jorim Jaggibe565df2014-04-28 17:51:23 +0200317 public void setClipTopAmount(int clipTopAmount) {
Selim Cinekc9c00ae2014-05-20 03:33:40 +0200318 mClipTopAmount = clipTopAmount;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200319 updateClipping();
320 }
321
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700322 private void updateRoundRectClipping() {
323 boolean enabled = needsRoundRectClipping();
324 setClipToOutline(enabled);
325 }
326
327 private boolean needsRoundRectClipping() {
328 if (!mRoundRectClippingEnabled) {
329 return false;
330 }
331 boolean needsForContracted = mContractedChild != null
332 && mContractedChild.getVisibility() == View.VISIBLE
333 && mContractedWrapper.needsRoundRectClipping();
334 boolean needsForExpanded = mExpandedChild != null
335 && mExpandedChild.getVisibility() == View.VISIBLE
336 && mExpandedWrapper.needsRoundRectClipping();
337 boolean needsForHeadsUp = mExpandedChild != null
338 && mExpandedChild.getVisibility() == View.VISIBLE
339 && mExpandedWrapper.needsRoundRectClipping();
340 return needsForContracted || needsForExpanded || needsForHeadsUp;
341 }
342
Jorim Jaggibe565df2014-04-28 17:51:23 +0200343 private void updateClipping() {
Selim Cinekb5605e52015-02-20 18:21:41 +0100344 mClipBounds.set(0, mClipTopAmount, getWidth(), mContentHeight);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200345 setClipBounds(mClipBounds);
346 }
347
Jorim Jaggi11298832014-05-24 16:18:38 +0200348 private void selectLayout(boolean animate, boolean force) {
349 if (mContractedChild == null) {
350 return;
351 }
Selim Cinek684a4422015-04-15 16:18:39 -0700352 int visibleType = calculateVisibleType();
353 if (visibleType != mVisibleType || force) {
Jorim Jaggi021eee52015-06-11 17:07:18 -0700354 if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
Selim Cinek684a4422015-04-15 16:18:39 -0700355 || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
Selim Cinek83bc7832015-10-22 13:26:54 -0700356 || (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null)
Jorim Jaggi021eee52015-06-11 17:07:18 -0700357 || visibleType == VISIBLE_TYPE_CONTRACTED)) {
Selim Cinek684a4422015-04-15 16:18:39 -0700358 runSwitchAnimation(visibleType);
Selim Cinek8d490d42015-04-10 00:05:50 -0700359 } else {
Selim Cinek684a4422015-04-15 16:18:39 -0700360 updateViewVisibilities(visibleType);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200361 }
Selim Cinek684a4422015-04-15 16:18:39 -0700362 mVisibleType = visibleType;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200363 }
Jorim Jaggi11298832014-05-24 16:18:38 +0200364 }
365
Selim Cinek684a4422015-04-15 16:18:39 -0700366 private void updateViewVisibilities(int visibleType) {
367 boolean contractedVisible = visibleType == VISIBLE_TYPE_CONTRACTED;
Selim Cinek8d490d42015-04-10 00:05:50 -0700368 mContractedChild.setVisibility(contractedVisible ? View.VISIBLE : View.INVISIBLE);
369 mContractedChild.setAlpha(contractedVisible ? 1f : 0f);
370 mContractedChild.setLayerType(LAYER_TYPE_NONE, null);
371 if (mExpandedChild != null) {
Selim Cinek684a4422015-04-15 16:18:39 -0700372 boolean expandedVisible = visibleType == VISIBLE_TYPE_EXPANDED;
Selim Cinek8d490d42015-04-10 00:05:50 -0700373 mExpandedChild.setVisibility(expandedVisible ? View.VISIBLE : View.INVISIBLE);
374 mExpandedChild.setAlpha(expandedVisible ? 1f : 0f);
375 mExpandedChild.setLayerType(LAYER_TYPE_NONE, null);
376 }
377 if (mHeadsUpChild != null) {
Selim Cinek684a4422015-04-15 16:18:39 -0700378 boolean headsUpVisible = visibleType == VISIBLE_TYPE_HEADSUP;
Selim Cinek8d490d42015-04-10 00:05:50 -0700379 mHeadsUpChild.setVisibility(headsUpVisible ? View.VISIBLE : View.INVISIBLE);
380 mHeadsUpChild.setAlpha(headsUpVisible ? 1f : 0f);
381 mHeadsUpChild.setLayerType(LAYER_TYPE_NONE, null);
382 }
Selim Cinek83bc7832015-10-22 13:26:54 -0700383 if (mSingleLineView != null) {
384 boolean singleLineVisible = visibleType == VISIBLE_TYPE_SINGLELINE;
385 mSingleLineView.setVisibility(singleLineVisible ? View.VISIBLE : View.INVISIBLE);
386 mSingleLineView.setAlpha(singleLineVisible ? 1f : 0f);
387 mSingleLineView.setLayerType(LAYER_TYPE_NONE, null);
388 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700389 setLayerType(LAYER_TYPE_NONE, null);
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700390 updateRoundRectClipping();
Selim Cinek8d490d42015-04-10 00:05:50 -0700391 }
392
Selim Cinek684a4422015-04-15 16:18:39 -0700393 private void runSwitchAnimation(int visibleType) {
394 View shownView = getViewForVisibleType(visibleType);
395 View hiddenView = getViewForVisibleType(mVisibleType);
Selim Cinek8d490d42015-04-10 00:05:50 -0700396 shownView.setVisibility(View.VISIBLE);
397 hiddenView.setVisibility(View.VISIBLE);
398 shownView.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint);
399 hiddenView.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint);
Jorim Jaggi11298832014-05-24 16:18:38 +0200400 setLayerType(LAYER_TYPE_HARDWARE, null);
Selim Cinek8d490d42015-04-10 00:05:50 -0700401 hiddenView.animate()
402 .alpha(0f)
Jorim Jaggi11298832014-05-24 16:18:38 +0200403 .setDuration(ANIMATION_DURATION_LENGTH)
Selim Cinek8d490d42015-04-10 00:05:50 -0700404 .setInterpolator(mLinearInterpolator)
405 .withEndAction(null); // In case we have multiple changes in one frame.
406 shownView.animate()
407 .alpha(1f)
Jorim Jaggi11298832014-05-24 16:18:38 +0200408 .setDuration(ANIMATION_DURATION_LENGTH)
409 .setInterpolator(mLinearInterpolator)
410 .withEndAction(new Runnable() {
411 @Override
412 public void run() {
Selim Cinek684a4422015-04-15 16:18:39 -0700413 updateViewVisibilities(mVisibleType);
Jorim Jaggi11298832014-05-24 16:18:38 +0200414 }
415 });
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700416 updateRoundRectClipping();
Jorim Jaggi11298832014-05-24 16:18:38 +0200417 }
418
Selim Cinek684a4422015-04-15 16:18:39 -0700419 /**
420 * @param visibleType one of the static enum types in this view
421 * @return the corresponding view according to the given visible type
422 */
423 private View getViewForVisibleType(int visibleType) {
424 switch (visibleType) {
425 case VISIBLE_TYPE_EXPANDED:
Selim Cinek8d490d42015-04-10 00:05:50 -0700426 return mExpandedChild;
Selim Cinek684a4422015-04-15 16:18:39 -0700427 case VISIBLE_TYPE_HEADSUP:
Selim Cinek8d490d42015-04-10 00:05:50 -0700428 return mHeadsUpChild;
Selim Cinek83bc7832015-10-22 13:26:54 -0700429 case VISIBLE_TYPE_SINGLELINE:
430 return mSingleLineView;
Selim Cinek684a4422015-04-15 16:18:39 -0700431 default:
432 return mContractedChild;
Selim Cinek8d490d42015-04-10 00:05:50 -0700433 }
Selim Cinek8d490d42015-04-10 00:05:50 -0700434 }
435
Selim Cinek684a4422015-04-15 16:18:39 -0700436 /**
437 * @return one of the static enum types in this view, calculated form the current state
438 */
439 private int calculateVisibleType() {
Selim Cinek8d490d42015-04-10 00:05:50 -0700440 boolean noExpandedChild = mExpandedChild == null;
Selim Cinek1f3f5442015-04-10 17:54:46 -0700441 if (mIsHeadsUp && mHeadsUpChild != null) {
442 if (mContentHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
Selim Cinek684a4422015-04-15 16:18:39 -0700443 return VISIBLE_TYPE_HEADSUP;
Selim Cinek8d490d42015-04-10 00:05:50 -0700444 } else {
Selim Cinek684a4422015-04-15 16:18:39 -0700445 return VISIBLE_TYPE_EXPANDED;
Selim Cinek8d490d42015-04-10 00:05:50 -0700446 }
447 } else {
Selim Cinek83bc7832015-10-22 13:26:54 -0700448 if (mIsChildInGroup && !isGroupExpanded()) {
449 return VISIBLE_TYPE_SINGLELINE;
450 } else if (mContentHeight <= mSmallHeight || noExpandedChild) {
Selim Cinek684a4422015-04-15 16:18:39 -0700451 return VISIBLE_TYPE_CONTRACTED;
Selim Cinek8d490d42015-04-10 00:05:50 -0700452 } else {
Selim Cinek684a4422015-04-15 16:18:39 -0700453 return VISIBLE_TYPE_EXPANDED;
Selim Cinek8d490d42015-04-10 00:05:50 -0700454 }
455 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200456 }
457
458 public void notifyContentUpdated() {
Selim Cinek83bc7832015-10-22 13:26:54 -0700459 updateSingleLineView();
Jorim Jaggi11298832014-05-24 16:18:38 +0200460 selectLayout(false /* animate */, true /* force */);
Jorim Jaggi394a5d62014-11-26 23:07:13 +0100461 if (mContractedChild != null) {
Jorim Jaggidacc9242014-12-08 19:21:26 +0100462 mContractedWrapper.notifyContentUpdated();
Jorim Jaggi394a5d62014-11-26 23:07:13 +0100463 mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
464 }
Jorim Jaggibe4116a2015-05-20 20:04:08 -0700465 if (mExpandedChild != null) {
466 mExpandedWrapper.notifyContentUpdated();
467 }
468 updateRoundRectClipping();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200469 }
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200470
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200471 public boolean isContentExpandable() {
472 return mExpandedChild != null;
473 }
John Spurlocke15452b2014-08-21 09:44:39 -0400474
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100475 public void setDark(boolean dark, boolean fade, long delay) {
John Spurlockc3dfd322014-08-27 14:55:54 -0400476 if (mDark == dark || mContractedChild == null) return;
John Spurlocke15452b2014-08-21 09:44:39 -0400477 mDark = dark;
Jorim Jaggi59ec3042015-06-05 15:18:43 -0700478 mContractedWrapper.setDark(dark && !mShowingLegacyBackground, fade, delay);
John Spurlocke15452b2014-08-21 09:44:39 -0400479 }
480
Selim Cinek8d490d42015-04-10 00:05:50 -0700481 public void setHeadsUp(boolean headsUp) {
482 mIsHeadsUp = headsUp;
483 selectLayout(false /* animate */, true /* force */);
484 }
485
Jorim Jaggiaa92ffb2014-09-10 23:29:28 +0200486 @Override
487 public boolean hasOverlappingRendering() {
488
489 // This is not really true, but good enough when fading from the contracted to the expanded
490 // layout, and saves us some layers.
491 return false;
492 }
Jorim Jaggi59ec3042015-06-05 15:18:43 -0700493
494 public void setShowingLegacyBackground(boolean showing) {
495 mShowingLegacyBackground = showing;
496 }
Selim Cinek8d6440d2015-10-22 13:00:05 -0700497
Selim Cinek83bc7832015-10-22 13:26:54 -0700498 public void setIsChildInGroup(boolean isChildInGroup) {
499 mIsChildInGroup = isChildInGroup;
500 updateSingleLineView();
501 }
502
Selim Cinek65b2e7c2015-10-26 14:11:31 -0700503 public void setContainingNotification(ExpandableNotificationRow notification) {
504 mContainingNotification = notification;
505 }
506
Selim Cinek83bc7832015-10-22 13:26:54 -0700507 public void setStatusBarNotification(StatusBarNotification statusBarNotification) {
508 mStatusBarNotification = statusBarNotification;
509 updateSingleLineView();
510 }
511
512 private void updateSingleLineView() {
513 if (mIsChildInGroup) {
514 mSingleLineView = mHybridViewManager.bindFromNotification(
515 mSingleLineView, mStatusBarNotification.getNotification());
516 }
517 }
518
Selim Cinek8d6440d2015-10-22 13:00:05 -0700519 public void setSubTextVisible(boolean visible) {
520 if (mExpandedChild != null) {
521 mExpandedWrapper.setSubTextVisible(visible);
522 }
523 if (mContractedChild != null) {
524 mContractedWrapper.setSubTextVisible(visible);
525 }
526 if (mHeadsUpChild != null) {
527 mHeadsUpWrapper.setSubTextVisible(visible);
528 }
529 }
Selim Cinek83bc7832015-10-22 13:26:54 -0700530
531 public void setGroupManager(NotificationGroupManager groupManager) {
532 mGroupManager = groupManager;
533 }
Selim Cinek65b2e7c2015-10-26 14:11:31 -0700534
535 public void updateExpandButtons() {
536 if (mExpandedChild != null) {
537 mExpandedWrapper.updateExpandability(mContainingNotification.isExpandable(),
538 mExpandClickListener);
539 }
540 if (mContractedChild != null) {
541 mContractedWrapper.updateExpandability(mContainingNotification.isExpandable(),
542 mExpandClickListener);
543 }
544 if (mHeadsUpChild != null) {
545 mHeadsUpWrapper.updateExpandability(mContainingNotification.isExpandable(),
546 mExpandClickListener);
547 }
548 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200549}