blob: a0fef0068b05123bfe990fa277b9abc7ac64d062 [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
Rohan Shah20790b82018-07-02 17:21:04 -070017package com.android.systemui.statusbar.notification.row;
Jorim Jaggibe565df2014-04-28 17:51:23 +020018
Selim Cinek332c23f2018-03-16 17:37:50 -070019import android.animation.AnimatorListenerAdapter;
Jorim Jaggibe565df2014-04-28 17:51:23 +020020import android.content.Context;
Selim Cinek471e31a2015-12-11 13:39:48 -080021import android.graphics.Paint;
Selim Cineke32010a2014-08-20 23:50:41 +020022import android.graphics.Rect;
Jorim Jaggibe565df2014-04-28 17:51:23 +020023import android.util.AttributeSet;
24import android.view.View;
Selim Cinekc9c00ae2014-05-20 03:33:40 +020025import android.view.ViewGroup;
Selim Cinek24d7cfa2014-05-20 13:50:57 +020026import android.widget.FrameLayout;
Selim Cinekd84a5932015-12-15 11:45:36 -080027
Dave Mankoffa4d195d2018-11-16 13:33:27 -050028import androidx.annotation.Nullable;
29
Selim Cinek30887662018-10-15 17:37:21 -070030import com.android.systemui.Dumpable;
Rohan Shah20790b82018-07-02 17:21:04 -070031import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
32import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
Selim Cinek24d7cfa2014-05-20 13:50:57 +020033
Selim Cinek30887662018-10-15 17:37:21 -070034import java.io.FileDescriptor;
35import java.io.PrintWriter;
Selim Cinek24d7cfa2014-05-20 13:50:57 +020036import java.util.ArrayList;
Dave Mankoffa4d195d2018-11-16 13:33:27 -050037import java.util.List;
Jorim Jaggibe565df2014-04-28 17:51:23 +020038
39/**
40 * An abstract view for expandable views.
41 */
Selim Cinek30887662018-10-15 17:37:21 -070042public abstract class ExpandableView extends FrameLayout implements Dumpable {
Dave Mankoffa4d195d2018-11-16 13:33:27 -050043 private static final String TAG = "ExpandableView";
Selim Cinek24d7cfa2014-05-20 13:50:57 +020044
Selim Cinekeccf4942018-05-30 09:55:36 -070045 public static final float NO_ROUNDNESS = -1;
Selim Cinekb5605e52015-02-20 18:21:41 +010046 protected OnHeightChangedListener mOnHeightChangedListener;
Chris Wren310df312014-10-31 14:29:46 -040047 private int mActualHeight;
Jorim Jaggibe565df2014-04-28 17:51:23 +020048 protected int mClipTopAmount;
Selim Cinekb3dadcc2016-11-21 17:21:13 -080049 protected int mClipBottomAmount;
Selim Cinek53328492018-12-05 14:58:44 -080050 protected int mMinimumHeightForClipping = 0;
51 protected float mExtraWidthForClipping = 0;
Selim Cinek24d7cfa2014-05-20 13:50:57 +020052 private ArrayList<View> mMatchParentViews = new ArrayList<View>();
Selim Cineka272dfe2015-02-20 18:12:28 +010053 private static Rect mClipRect = new Rect();
Selim Cinek2cd45df2015-06-09 18:00:07 -070054 private boolean mWillBeGone;
Selim Cinek9c17b772015-07-07 20:37:09 -070055 private int mMinClipTopAmount = 0;
Selim Cinek4ffd6362015-12-29 15:12:23 +010056 private boolean mClipToActualHeight = true;
Adrian Roos14503e22016-03-09 14:01:24 -080057 private boolean mChangingPosition = false;
Selim Cinekd1395642016-04-28 12:22:42 -070058 private ViewGroup mTransientContainer;
Selim Cinekeccb5de2016-10-28 15:04:05 -070059 private boolean mInShelf;
60 private boolean mTransformingInShelf;
Dave Mankoffc56db332018-12-10 11:31:49 -050061 private final ExpandableViewState mViewState;
Jorim Jaggibe565df2014-04-28 17:51:23 +020062
63 public ExpandableView(Context context, AttributeSet attrs) {
64 super(context, attrs);
Dave Mankoffc56db332018-12-10 11:31:49 -050065 mViewState = createExpandableViewState();
Selim Cinek24d7cfa2014-05-20 13:50:57 +020066 }
67
68 @Override
69 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Selim Cinek471e31a2015-12-11 13:39:48 -080070 final int givenSize = MeasureSpec.getSize(heightMeasureSpec);
felkachang79ca96d2018-04-27 16:55:40 +080071 final int viewHorizontalPadding = getPaddingStart() + getPaddingEnd();
Selim Cinekd84a5932015-12-15 11:45:36 -080072 int ownMaxHeight = Integer.MAX_VALUE;
Selim Cinek6f145cf2015-05-18 15:16:08 -070073 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
Selim Cineka69f2a62015-12-11 17:28:12 -080074 if (heightMode != MeasureSpec.UNSPECIFIED && givenSize != 0) {
Selim Cinek471e31a2015-12-11 13:39:48 -080075 ownMaxHeight = Math.min(givenSize, ownMaxHeight);
Selim Cinek6f145cf2015-05-18 15:16:08 -070076 }
Selim Cinek24d7cfa2014-05-20 13:50:57 +020077 int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
78 int maxChildHeight = 0;
79 int childCount = getChildCount();
80 for (int i = 0; i < childCount; i++) {
81 View child = getChildAt(i);
Selim Cinek263398f2015-10-21 17:40:23 -070082 if (child.getVisibility() == GONE) {
Selim Cinekb5605e52015-02-20 18:21:41 +010083 continue;
84 }
Selim Cinek24d7cfa2014-05-20 13:50:57 +020085 int childHeightSpec = newHeightSpec;
86 ViewGroup.LayoutParams layoutParams = child.getLayoutParams();
87 if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) {
88 if (layoutParams.height >= 0) {
89 // An actual height is set
Selim Cineka69f2a62015-12-11 17:28:12 -080090 childHeightSpec = layoutParams.height > ownMaxHeight
Selim Cinek24d7cfa2014-05-20 13:50:57 +020091 ? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY)
92 : MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
93 }
felkachang79ca96d2018-04-27 16:55:40 +080094 child.measure(getChildMeasureSpec(
95 widthMeasureSpec, viewHorizontalPadding, layoutParams.width),
Jorim Jaggib741f052014-06-03 19:57:26 +020096 childHeightSpec);
Selim Cinek24d7cfa2014-05-20 13:50:57 +020097 int childHeight = child.getMeasuredHeight();
98 maxChildHeight = Math.max(maxChildHeight, childHeight);
99 } else {
100 mMatchParentViews.add(child);
101 }
102 }
Selim Cineka69f2a62015-12-11 17:28:12 -0800103 int ownHeight = heightMode == MeasureSpec.EXACTLY
104 ? givenSize : Math.min(ownMaxHeight, maxChildHeight);
Selim Cinek24d7cfa2014-05-20 13:50:57 +0200105 newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
106 for (View child : mMatchParentViews) {
Jorim Jaggib741f052014-06-03 19:57:26 +0200107 child.measure(getChildMeasureSpec(
felkachang79ca96d2018-04-27 16:55:40 +0800108 widthMeasureSpec, viewHorizontalPadding, child.getLayoutParams().width),
Jorim Jaggib741f052014-06-03 19:57:26 +0200109 newHeightSpec);
Selim Cinek24d7cfa2014-05-20 13:50:57 +0200110 }
111 mMatchParentViews.clear();
112 int width = MeasureSpec.getSize(widthMeasureSpec);
113 setMeasuredDimension(width, ownHeight);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200114 }
115
116 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +0200117 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Selim Cinek24d7cfa2014-05-20 13:50:57 +0200118 super.onLayout(changed, left, top, right, bottom);
Selim Cinekba67acf2015-04-10 17:00:42 -0700119 updateClipping();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200120 }
121
Jorim Jaggi00ebdfe2014-05-02 17:29:56 +0200122 @Override
Selim Cineka69f2a62015-12-11 17:28:12 -0800123 public boolean pointInView(float localX, float localY, float slop) {
124 float top = mClipTopAmount;
125 float bottom = mActualHeight;
126 return localX >= -slop && localY >= top - slop && localX < ((mRight - mLeft) + slop) &&
127 localY < (bottom + slop);
Jorim Jaggi00ebdfe2014-05-02 17:29:56 +0200128 }
129
Jorim Jaggibe565df2014-04-28 17:51:23 +0200130 /**
131 * Sets the actual height of this notification. This is different than the laid out
132 * {@link View#getHeight()}, as we want to avoid layouting during scrolling and expanding.
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200133 *
134 * @param actualHeight The height of this notification.
135 * @param notifyListeners Whether the listener should be informed about the change.
Jorim Jaggibe565df2014-04-28 17:51:23 +0200136 */
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200137 public void setActualHeight(int actualHeight, boolean notifyListeners) {
Jorim Jaggibe565df2014-04-28 17:51:23 +0200138 mActualHeight = actualHeight;
Selim Cineka272dfe2015-02-20 18:12:28 +0100139 updateClipping();
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200140 if (notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100141 notifyHeightChanged(false /* needsAnimation */);
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200142 }
143 }
144
Selim Cinekb0ee18f2017-12-21 16:15:53 -0800145 /**
146 * Set the distance to the top roundness, from where we should start clipping a value above
147 * or equal to 0 is the effective distance, and if a value below 0 is received, there should
148 * be no clipping.
149 */
150 public void setDistanceToTopRoundness(float distanceToTopRoundness) {
151 }
152
Selim Cinekeef84282015-10-30 16:28:00 -0700153 public void setActualHeight(int actualHeight) {
154 setActualHeight(actualHeight, true /* notifyListeners */);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200155 }
156
157 /**
158 * See {@link #setActualHeight}.
159 *
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200160 * @return The current actual height of this notification.
Jorim Jaggibe565df2014-04-28 17:51:23 +0200161 */
162 public int getActualHeight() {
163 return mActualHeight;
164 }
165
Selim Cinek2627d722018-01-19 12:16:49 -0800166 public boolean isExpandAnimationRunning() {
167 return false;
168 }
169
Jorim Jaggibe565df2014-04-28 17:51:23 +0200170 /**
171 * @return The maximum height of this notification.
172 */
Selim Cinekb5605e52015-02-20 18:21:41 +0100173 public int getMaxContentHeight() {
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200174 return getHeight();
175 }
176
177 /**
Selim Cinekeb3fc3d2017-09-15 13:37:14 -0700178 * @return The minimum content height of this notification. This also respects the temporary
179 * states of the view.
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200180 */
181 public int getMinHeight() {
Selim Cinekeb3fc3d2017-09-15 13:37:14 -0700182 return getMinHeight(false /* ignoreTemporaryStates */);
183 }
184
185 /**
186 * Get the minimum height of this view.
187 *
188 * @param ignoreTemporaryStates should temporary states be ignored like the guts or heads-up.
189 *
190 * @return The minimum height that this view needs.
191 */
192 public int getMinHeight(boolean ignoreTemporaryStates) {
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200193 return getHeight();
194 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200195
196 /**
Selim Cinek567e8452016-03-24 10:54:56 -0700197 * @return The collapsed height of this view. Note that this might be different
198 * than {@link #getMinHeight()} because some elements like groups may have different sizes when
199 * they are system expanded.
Selim Cinek816c8e42015-11-19 12:00:45 -0800200 */
Selim Cinek567e8452016-03-24 10:54:56 -0700201 public int getCollapsedHeight() {
Selim Cinek816c8e42015-11-19 12:00:45 -0800202 return getHeight();
203 }
204
205 /**
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200206 * Sets the notification as dimmed. The default implementation does nothing.
207 *
208 * @param dimmed Whether the notification should be dimmed.
209 * @param fade Whether an animation should be played to change the state.
210 */
211 public void setDimmed(boolean dimmed, boolean fade) {
212 }
213
Selim Cinekd9b7dd42017-11-10 17:53:47 -0800214 public boolean isRemoved() {
215 return false;
216 }
217
John Spurlockbf370992014-06-17 13:58:31 -0400218 /**
Jorim Jaggiae441282014-08-01 02:45:18 +0200219 * See {@link #setHideSensitive}. This is a variant which notifies this view in advance about
220 * the upcoming state of hiding sensitive notifications. It gets called at the very beginning
221 * of a stack scroller update such that the updated intrinsic height (which is dependent on
222 * whether private or public layout is showing) gets taken into account into all layout
223 * calculations.
224 */
225 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
226 }
227
228 /**
229 * Sets whether the notification should hide its private contents if it is sensitive.
230 */
231 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
232 long duration) {
233 }
234
235 /**
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200236 * @return The desired notification height.
237 */
238 public int getIntrinsicHeight() {
Selim Cineka5eaa602014-05-12 21:27:47 +0200239 return getHeight();
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200240 }
241
242 /**
Jorim Jaggibe565df2014-04-28 17:51:23 +0200243 * Sets the amount this view should be clipped from the top. This is used when an expanded
244 * notification is scrolling in the top or bottom stack.
245 *
246 * @param clipTopAmount The amount of pixels this view should be clipped from top.
247 */
248 public void setClipTopAmount(int clipTopAmount) {
249 mClipTopAmount = clipTopAmount;
Mady Mellorc128f222016-04-26 11:42:46 -0700250 updateClipping();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200251 }
252
Selim Cineka686b2c2016-10-26 13:58:27 -0700253 /**
254 * Set the amount the the notification is clipped on the bottom in addition to the regular
255 * clipping. This is mainly used to clip something in a non-animated way without changing the
256 * actual height of the notification and is purely visual.
257 *
258 * @param clipBottomAmount the amount to clip.
259 */
260 public void setClipBottomAmount(int clipBottomAmount) {
261 mClipBottomAmount = clipBottomAmount;
262 updateClipping();
263 }
264
Selim Cinekeb973562014-05-02 17:07:49 +0200265 public int getClipTopAmount() {
266 return mClipTopAmount;
267 }
268
Selim Cinekb3dadcc2016-11-21 17:21:13 -0800269 public int getClipBottomAmount() {
Selim Cineka686b2c2016-10-26 13:58:27 -0700270 return mClipBottomAmount;
271 }
272
Jorim Jaggibe565df2014-04-28 17:51:23 +0200273 public void setOnHeightChangedListener(OnHeightChangedListener listener) {
274 mOnHeightChangedListener = listener;
275 }
276
277 /**
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200278 * @return Whether we can expand this views content.
Jorim Jaggibe565df2014-04-28 17:51:23 +0200279 */
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200280 public boolean isContentExpandable() {
281 return false;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200282 }
283
Selim Cinekb5605e52015-02-20 18:21:41 +0100284 public void notifyHeightChanged(boolean needsAnimation) {
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200285 if (mOnHeightChangedListener != null) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100286 mOnHeightChangedListener.onHeightChanged(this, needsAnimation);
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200287 }
288 }
289
Selim Cinekc27437b2014-05-14 10:23:33 +0200290 public boolean isTransparent() {
291 return false;
292 }
293
Jorim Jaggibe565df2014-04-28 17:51:23 +0200294 /**
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200295 * Perform a remove animation on this view.
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200296 * @param duration The duration of the remove animation.
Selim Cinek332c23f2018-03-16 17:37:50 -0700297 * @param delay The delay of the animation
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200298 * @param translationDirection The direction value from [-1 ... 1] indicating in which the
Gus Prevas211181532018-12-13 14:49:33 -0500299 * animation should be performed. A value of -1 means that The
300 * remove animation should be performed upwards,
301 * such that the child appears to be going away to the top. 1
302 * Should mean the opposite.
Selim Cinek332c23f2018-03-16 17:37:50 -0700303 * @param isHeadsUpAnimation Is this a headsUp animation.
304 * @param endLocation The location where the horizonal heads up disappear animation should end.
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200305 * @param onFinishedRunnable A runnable which should be run when the animation is finished.
Selim Cinek332c23f2018-03-16 17:37:50 -0700306 * @param animationListener An animation listener to add to the animation.
Gus Prevas211181532018-12-13 14:49:33 -0500307 *
308 * @return The additional delay, in milliseconds, that this view needs to add before the
309 * animation starts.
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200310 */
Gus Prevas211181532018-12-13 14:49:33 -0500311 public abstract long performRemoveAnimation(long duration,
Selim Cinek332c23f2018-03-16 17:37:50 -0700312 long delay, float translationDirection, boolean isHeadsUpAnimation, float endLocation,
313 Runnable onFinishedRunnable,
314 AnimatorListenerAdapter animationListener);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200315
Selim Cinek332c23f2018-03-16 17:37:50 -0700316 public abstract void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200317
Selim Cinek281c2022016-10-13 19:14:43 -0700318 /**
Selim Cinekdb167372016-11-17 15:41:17 -0800319 * Set the notification appearance to be below the speed bump.
Selim Cinek281c2022016-10-13 19:14:43 -0700320 * @param below true if it is below.
321 */
Selim Cinekdb167372016-11-17 15:41:17 -0800322 public void setBelowSpeedBump(boolean below) {
Selim Cinek3d2b94bf2014-07-02 22:12:47 +0200323 }
324
Selim Cinekd127d792016-11-01 19:11:41 -0700325 public int getPinnedHeadsUpHeight() {
326 return getIntrinsicHeight();
327 }
328
329
Mady Mellor34958fa2016-02-23 09:52:17 -0800330 /**
331 * Sets the translation of the view.
332 */
333 public void setTranslation(float translation) {
334 setTranslationX(translation);
335 }
336
337 /**
338 * Gets the translation of the view.
339 */
340 public float getTranslation() {
341 return getTranslationX();
342 }
343
Selim Cinek31094df2014-08-14 19:28:15 +0200344 public void onHeightReset() {
Selim Cineke34c6512014-08-14 11:19:41 +0200345 if (mOnHeightChangedListener != null) {
346 mOnHeightChangedListener.onReset(this);
347 }
Selim Cineka5e211b2014-08-11 17:35:48 +0200348 }
349
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200350 /**
Selim Cineke32010a2014-08-20 23:50:41 +0200351 * This method returns the drawing rect for the view which is different from the regular
352 * drawing rect, since we layout all children in the {@link NotificationStackScrollLayout} at
353 * position 0 and usually the translation is neglected. Since we are manually clipping this
354 * view,we also need to subtract the clipTopAmount from the top. This is needed in order to
355 * ensure that accessibility and focusing work correctly.
356 *
357 * @param outRect The (scrolled) drawing bounds of the view.
358 */
359 @Override
360 public void getDrawingRect(Rect outRect) {
361 super.getDrawingRect(outRect);
362 outRect.left += getTranslationX();
363 outRect.right += getTranslationX();
364 outRect.bottom = (int) (outRect.top + getTranslationY() + getActualHeight());
365 outRect.top += getTranslationY() + getClipTopAmount();
366 }
367
Adrian Rooscd55f432015-06-10 16:42:53 -0700368 @Override
369 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
370 super.getBoundsOnScreen(outRect, clipToParent);
Adrian Roos98dd7f12016-06-14 15:51:40 -0700371 if (getTop() + getTranslationY() < 0) {
372 // We got clipped to the parent here - make sure we undo that.
373 outRect.top += getTop() + getTranslationY();
374 }
Adrian Roosb44f5482015-06-11 12:19:16 -0700375 outRect.bottom = outRect.top + getActualHeight();
Mady Mellorc128f222016-04-26 11:42:46 -0700376 outRect.top += getClipTopAmount();
Adrian Rooscd55f432015-06-10 16:42:53 -0700377 }
378
Selim Cinek263398f2015-10-21 17:40:23 -0700379 public boolean isSummaryWithChildren() {
Selim Cinekb5605e52015-02-20 18:21:41 +0100380 return false;
381 }
382
383 public boolean areChildrenExpanded() {
384 return false;
385 }
386
Selim Cinek2627d722018-01-19 12:16:49 -0800387 protected void updateClipping() {
388 if (mClipToActualHeight && shouldClipToActualHeight()) {
Mady Mellorc128f222016-04-26 11:42:46 -0700389 int top = getClipTopAmount();
Selim Cinek53328492018-12-05 14:58:44 -0800390 int bottom = Math.max(Math.max(getActualHeight() + getExtraBottomPadding()
391 - mClipBottomAmount, top), mMinimumHeightForClipping);
392 int halfExtraWidth = (int) (mExtraWidthForClipping / 2.0f);
393 mClipRect.set(-halfExtraWidth, top, getWidth() + halfExtraWidth, bottom);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100394 setClipBounds(mClipRect);
395 } else {
396 setClipBounds(null);
Selim Cinekf92a1fd2015-07-31 16:10:32 -0700397 }
Selim Cinek4ffd6362015-12-29 15:12:23 +0100398 }
399
Selim Cinek53328492018-12-05 14:58:44 -0800400 public void setMinimumHeightForClipping(int minimumHeightForClipping) {
401 mMinimumHeightForClipping = minimumHeightForClipping;
402 updateClipping();
403 }
404
405 public void setExtraWidthForClipping(float extraWidthForClipping) {
406 mExtraWidthForClipping = extraWidthForClipping;
407 updateClipping();
408 }
409
Selim Cinek99e9adf2018-03-15 09:17:47 -0700410 public float getHeaderVisibleAmount() {
411 return 1.0f;
412 }
413
Selim Cinek2627d722018-01-19 12:16:49 -0800414 protected boolean shouldClipToActualHeight() {
415 return true;
416 }
417
Selim Cinek4ffd6362015-12-29 15:12:23 +0100418 public void setClipToActualHeight(boolean clipToActualHeight) {
419 mClipToActualHeight = clipToActualHeight;
420 updateClipping();
Selim Cineka272dfe2015-02-20 18:12:28 +0100421 }
422
Selim Cinek2cd45df2015-06-09 18:00:07 -0700423 public boolean willBeGone() {
424 return mWillBeGone;
425 }
426
427 public void setWillBeGone(boolean willBeGone) {
428 mWillBeGone = willBeGone;
429 }
430
Selim Cinek9c17b772015-07-07 20:37:09 -0700431 public int getMinClipTopAmount() {
432 return mMinClipTopAmount;
433 }
434
435 public void setMinClipTopAmount(int minClipTopAmount) {
436 mMinClipTopAmount = minClipTopAmount;
437 }
438
Selim Cinek471e31a2015-12-11 13:39:48 -0800439 @Override
440 public void setLayerType(int layerType, Paint paint) {
441 if (hasOverlappingRendering()) {
442 super.setLayerType(layerType, paint);
443 }
444 }
445
446 @Override
447 public boolean hasOverlappingRendering() {
Selim Cineka69f2a62015-12-11 17:28:12 -0800448 // Otherwise it will be clipped
449 return super.hasOverlappingRendering() && getActualHeight() <= getHeight();
Selim Cinek471e31a2015-12-11 13:39:48 -0800450 }
451
Selim Cinek42357e02016-02-24 18:48:01 -0800452 /**
Selim Cineka7ed2c12017-01-23 20:47:24 -0800453 * @return an amount between -1 and 1 of increased padding that this child needs. 1 means it
454 * needs a full increased padding while -1 means it needs no padding at all. For 0.0f the normal
455 * padding is applied.
Selim Cinek42357e02016-02-24 18:48:01 -0800456 */
457 public float getIncreasedPaddingAmount() {
458 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -0800459 }
460
Selim Cinek3776fe02016-02-04 13:32:43 -0800461 public boolean mustStayOnScreen() {
462 return false;
463 }
464
Selim Cinek33223572016-02-19 19:32:22 -0800465 public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
466 int outlineTranslation) {
467 }
468
469 public float getOutlineAlpha() {
470 return 0.0f;
471 }
472
473 public int getOutlineTranslation() {
474 return 0;
475 }
476
Adrian Roos14503e22016-03-09 14:01:24 -0800477 public void setChangingPosition(boolean changingPosition) {
478 mChangingPosition = changingPosition;
479 }
480
481 public boolean isChangingPosition() {
482 return mChangingPosition;
483 }
484
Selim Cinekd1395642016-04-28 12:22:42 -0700485 public void setTransientContainer(ViewGroup transientContainer) {
486 mTransientContainer = transientContainer;
487 }
488
489 public ViewGroup getTransientContainer() {
490 return mTransientContainer;
491 }
492
Selim Cineke32010a2014-08-20 23:50:41 +0200493 /**
Mady Mellorb0a82462016-04-30 17:31:02 -0700494 * @return padding used to alter how much of the view is clipped.
495 */
496 public int getExtraBottomPadding() {
497 return 0;
498 }
499
500 /**
501 * @return true if the group's expansion state is changing, false otherwise.
502 */
503 public boolean isGroupExpansionChanging() {
504 return false;
505 }
506
507 public boolean isGroupExpanded() {
508 return false;
509 }
510
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100511 public void setHeadsUpIsVisible() {
512 }
513
Selim Cinekc3fec682019-06-06 18:11:07 -0700514 public boolean showingPulsing() {
Selim Cinek5040f2e2019-02-14 18:22:42 -0800515 return false;
516 }
517
Mady Mellorb0a82462016-04-30 17:31:02 -0700518 public boolean isChildInGroup() {
519 return false;
520 }
521
Adrian Roos599be342016-06-13 14:54:39 -0700522 public void setActualHeightAnimating(boolean animating) {}
523
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500524 protected ExpandableViewState createExpandableViewState() {
Selim Cinekbbcebde2016-11-09 18:28:20 -0800525 return new ExpandableViewState();
526 }
527
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500528 /** Sets {@link ExpandableViewState} to default state. */
529 public ExpandableViewState resetViewState() {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500530 // initialize with the default values of the view
531 mViewState.height = getIntrinsicHeight();
532 mViewState.gone = getVisibility() == View.GONE;
533 mViewState.alpha = 1f;
534 mViewState.notGoneIndex = -1;
535 mViewState.xTranslation = getTranslationX();
536 mViewState.hidden = false;
537 mViewState.scaleX = getScaleX();
538 mViewState.scaleY = getScaleY();
539 mViewState.inShelf = false;
540 mViewState.headsUpIsVisible = false;
541
542 // handling reset for child notifications
543 if (this instanceof ExpandableNotificationRow) {
544 ExpandableNotificationRow row = (ExpandableNotificationRow) this;
545 List<ExpandableNotificationRow> children = row.getNotificationChildren();
546 if (row.isSummaryWithChildren() && children != null) {
547 for (ExpandableNotificationRow childRow : children) {
548 childRow.resetViewState();
549 }
550 }
551 }
552
553 return mViewState;
554 }
555
556 @Nullable public ExpandableViewState getViewState() {
557 return mViewState;
558 }
559
560 /** Applies internal {@link ExpandableViewState} to this view. */
561 public void applyViewState() {
Dave Mankoffc56db332018-12-10 11:31:49 -0500562 if (!mViewState.gone) {
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500563 mViewState.applyToView(this);
564 }
565 }
566
Mady Mellorb0a82462016-04-30 17:31:02 -0700567 /**
Selim Cinek281c2022016-10-13 19:14:43 -0700568 * @return whether the current view doesn't add height to the overall content. This means that
569 * if it is added to a list of items, it's content will still have the same height.
570 * An example is the notification shelf, that is always placed on top of another view.
571 */
572 public boolean hasNoContentHeight() {
573 return false;
574 }
575
576 /**
Selim Cinekeccb5de2016-10-28 15:04:05 -0700577 * @param inShelf whether the view is currently fully in the notification shelf.
578 */
579 public void setInShelf(boolean inShelf) {
580 mInShelf = inShelf;
581 }
582
583 public boolean isInShelf() {
584 return mInShelf;
585 }
586
587 /**
588 * @param transformingInShelf whether the view is currently transforming into the shelf in an
589 * animated way
590 */
591 public void setTransformingInShelf(boolean transformingInShelf) {
592 mTransformingInShelf = transformingInShelf;
593 }
594
595 public boolean isTransformingIntoShelf() {
596 return mTransformingInShelf;
597 }
598
Selim Cinekd127d792016-11-01 19:11:41 -0700599 public boolean isAboveShelf() {
600 return false;
601 }
602
Selim Cinekc25989e2018-02-16 16:42:14 -0800603 public boolean hasExpandingChild() {
604 return false;
605 }
606
Selim Cinek30887662018-10-15 17:37:21 -0700607 @Override
608 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
609 }
610
Selim Cinekeccb5de2016-10-28 15:04:05 -0700611 /**
Jorim Jaggibe565df2014-04-28 17:51:23 +0200612 * A listener notifying when {@link #getActualHeight} changes.
613 */
614 public interface OnHeightChangedListener {
Jorim Jaggi30c305c2014-07-01 23:34:41 +0200615
616 /**
617 * @param view the view for which the height changed, or {@code null} if just the top
618 * padding or the padding between the elements changed
Selim Cinekb5605e52015-02-20 18:21:41 +0100619 * @param needsAnimation whether the view height needs to be animated
Jorim Jaggi30c305c2014-07-01 23:34:41 +0200620 */
Selim Cinekb5605e52015-02-20 18:21:41 +0100621 void onHeightChanged(ExpandableView view, boolean needsAnimation);
Selim Cineka5e211b2014-08-11 17:35:48 +0200622
623 /**
624 * Called when the view is reset and therefore the height will change abruptly
625 *
626 * @param view The view which was reset.
627 */
628 void onReset(ExpandableView view);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200629 }
630}