blob: df6a9778142f7a008af0f302891d46719757dfb0 [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
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
Selim Cinekbbcebde2016-11-09 18:28:20 -080028import com.android.systemui.statusbar.stack.ExpandableViewState;
Anthony Chen04d1ea72017-04-21 14:30:11 -070029import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekbbcebde2016-11-09 18:28:20 -080030import com.android.systemui.statusbar.stack.StackScrollState;
Selim Cinek24d7cfa2014-05-20 13:50:57 +020031
32import java.util.ArrayList;
Jorim Jaggibe565df2014-04-28 17:51:23 +020033
34/**
35 * An abstract view for expandable views.
36 */
Selim Cinek24d7cfa2014-05-20 13:50:57 +020037public abstract class ExpandableView extends FrameLayout {
38
Selim Cinekb5605e52015-02-20 18:21:41 +010039 protected OnHeightChangedListener mOnHeightChangedListener;
Chris Wren310df312014-10-31 14:29:46 -040040 private int mActualHeight;
Jorim Jaggibe565df2014-04-28 17:51:23 +020041 protected int mClipTopAmount;
Selim Cinekb3dadcc2016-11-21 17:21:13 -080042 protected int mClipBottomAmount;
Jorim Jaggi4e857f42014-11-17 19:14:04 +010043 private boolean mDark;
Selim Cinek24d7cfa2014-05-20 13:50:57 +020044 private ArrayList<View> mMatchParentViews = new ArrayList<View>();
Selim Cineka272dfe2015-02-20 18:12:28 +010045 private static Rect mClipRect = new Rect();
Selim Cinek2cd45df2015-06-09 18:00:07 -070046 private boolean mWillBeGone;
Selim Cinek9c17b772015-07-07 20:37:09 -070047 private int mMinClipTopAmount = 0;
Selim Cinek4ffd6362015-12-29 15:12:23 +010048 private boolean mClipToActualHeight = true;
Adrian Roos14503e22016-03-09 14:01:24 -080049 private boolean mChangingPosition = false;
Selim Cinekd1395642016-04-28 12:22:42 -070050 private ViewGroup mTransientContainer;
Selim Cinekeccb5de2016-10-28 15:04:05 -070051 private boolean mInShelf;
52 private boolean mTransformingInShelf;
Jorim Jaggibe565df2014-04-28 17:51:23 +020053
54 public ExpandableView(Context context, AttributeSet attrs) {
55 super(context, attrs);
Selim Cinek24d7cfa2014-05-20 13:50:57 +020056 }
57
58 @Override
59 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Selim Cinek471e31a2015-12-11 13:39:48 -080060 final int givenSize = MeasureSpec.getSize(heightMeasureSpec);
Selim Cinekd84a5932015-12-15 11:45:36 -080061 int ownMaxHeight = Integer.MAX_VALUE;
Selim Cinek6f145cf2015-05-18 15:16:08 -070062 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
Selim Cineka69f2a62015-12-11 17:28:12 -080063 if (heightMode != MeasureSpec.UNSPECIFIED && givenSize != 0) {
Selim Cinek471e31a2015-12-11 13:39:48 -080064 ownMaxHeight = Math.min(givenSize, ownMaxHeight);
Selim Cinek6f145cf2015-05-18 15:16:08 -070065 }
Selim Cinek24d7cfa2014-05-20 13:50:57 +020066 int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
67 int maxChildHeight = 0;
68 int childCount = getChildCount();
69 for (int i = 0; i < childCount; i++) {
70 View child = getChildAt(i);
Selim Cinek263398f2015-10-21 17:40:23 -070071 if (child.getVisibility() == GONE) {
Selim Cinekb5605e52015-02-20 18:21:41 +010072 continue;
73 }
Selim Cinek24d7cfa2014-05-20 13:50:57 +020074 int childHeightSpec = newHeightSpec;
75 ViewGroup.LayoutParams layoutParams = child.getLayoutParams();
76 if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) {
77 if (layoutParams.height >= 0) {
78 // An actual height is set
Selim Cineka69f2a62015-12-11 17:28:12 -080079 childHeightSpec = layoutParams.height > ownMaxHeight
Selim Cinek24d7cfa2014-05-20 13:50:57 +020080 ? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY)
81 : MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
82 }
Jorim Jaggib741f052014-06-03 19:57:26 +020083 child.measure(
84 getChildMeasureSpec(widthMeasureSpec, 0 /* padding */, layoutParams.width),
85 childHeightSpec);
Selim Cinek24d7cfa2014-05-20 13:50:57 +020086 int childHeight = child.getMeasuredHeight();
87 maxChildHeight = Math.max(maxChildHeight, childHeight);
88 } else {
89 mMatchParentViews.add(child);
90 }
91 }
Selim Cineka69f2a62015-12-11 17:28:12 -080092 int ownHeight = heightMode == MeasureSpec.EXACTLY
93 ? givenSize : Math.min(ownMaxHeight, maxChildHeight);
Selim Cinek24d7cfa2014-05-20 13:50:57 +020094 newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
95 for (View child : mMatchParentViews) {
Jorim Jaggib741f052014-06-03 19:57:26 +020096 child.measure(getChildMeasureSpec(
97 widthMeasureSpec, 0 /* padding */, child.getLayoutParams().width),
98 newHeightSpec);
Selim Cinek24d7cfa2014-05-20 13:50:57 +020099 }
100 mMatchParentViews.clear();
101 int width = MeasureSpec.getSize(widthMeasureSpec);
102 setMeasuredDimension(width, ownHeight);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200103 }
104
105 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +0200106 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Selim Cinek24d7cfa2014-05-20 13:50:57 +0200107 super.onLayout(changed, left, top, right, bottom);
Selim Cinekba67acf2015-04-10 17:00:42 -0700108 updateClipping();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200109 }
110
Jorim Jaggi00ebdfe2014-05-02 17:29:56 +0200111 @Override
Selim Cineka69f2a62015-12-11 17:28:12 -0800112 public boolean pointInView(float localX, float localY, float slop) {
113 float top = mClipTopAmount;
114 float bottom = mActualHeight;
115 return localX >= -slop && localY >= top - slop && localX < ((mRight - mLeft) + slop) &&
116 localY < (bottom + slop);
Jorim Jaggi00ebdfe2014-05-02 17:29:56 +0200117 }
118
Jorim Jaggibe565df2014-04-28 17:51:23 +0200119 /**
120 * Sets the actual height of this notification. This is different than the laid out
121 * {@link View#getHeight()}, as we want to avoid layouting during scrolling and expanding.
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200122 *
123 * @param actualHeight The height of this notification.
124 * @param notifyListeners Whether the listener should be informed about the change.
Jorim Jaggibe565df2014-04-28 17:51:23 +0200125 */
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200126 public void setActualHeight(int actualHeight, boolean notifyListeners) {
Jorim Jaggibe565df2014-04-28 17:51:23 +0200127 mActualHeight = actualHeight;
Selim Cineka272dfe2015-02-20 18:12:28 +0100128 updateClipping();
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200129 if (notifyListeners) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100130 notifyHeightChanged(false /* needsAnimation */);
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200131 }
132 }
133
Selim Cinekb0ee18f2017-12-21 16:15:53 -0800134 /**
135 * Set the distance to the top roundness, from where we should start clipping a value above
136 * or equal to 0 is the effective distance, and if a value below 0 is received, there should
137 * be no clipping.
138 */
139 public void setDistanceToTopRoundness(float distanceToTopRoundness) {
140 }
141
Selim Cinekeef84282015-10-30 16:28:00 -0700142 public void setActualHeight(int actualHeight) {
143 setActualHeight(actualHeight, true /* notifyListeners */);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200144 }
145
146 /**
147 * See {@link #setActualHeight}.
148 *
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200149 * @return The current actual height of this notification.
Jorim Jaggibe565df2014-04-28 17:51:23 +0200150 */
151 public int getActualHeight() {
152 return mActualHeight;
153 }
154
Selim Cinek2627d722018-01-19 12:16:49 -0800155 public boolean isExpandAnimationRunning() {
156 return false;
157 }
158
Jorim Jaggibe565df2014-04-28 17:51:23 +0200159 /**
160 * @return The maximum height of this notification.
161 */
Selim Cinekb5605e52015-02-20 18:21:41 +0100162 public int getMaxContentHeight() {
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200163 return getHeight();
164 }
165
166 /**
Selim Cinekeb3fc3d2017-09-15 13:37:14 -0700167 * @return The minimum content height of this notification. This also respects the temporary
168 * states of the view.
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200169 */
170 public int getMinHeight() {
Selim Cinekeb3fc3d2017-09-15 13:37:14 -0700171 return getMinHeight(false /* ignoreTemporaryStates */);
172 }
173
174 /**
175 * Get the minimum height of this view.
176 *
177 * @param ignoreTemporaryStates should temporary states be ignored like the guts or heads-up.
178 *
179 * @return The minimum height that this view needs.
180 */
181 public int getMinHeight(boolean ignoreTemporaryStates) {
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200182 return getHeight();
183 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200184
185 /**
Selim Cinek567e8452016-03-24 10:54:56 -0700186 * @return The collapsed height of this view. Note that this might be different
187 * than {@link #getMinHeight()} because some elements like groups may have different sizes when
188 * they are system expanded.
Selim Cinek816c8e42015-11-19 12:00:45 -0800189 */
Selim Cinek567e8452016-03-24 10:54:56 -0700190 public int getCollapsedHeight() {
Selim Cinek816c8e42015-11-19 12:00:45 -0800191 return getHeight();
192 }
193
194 /**
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200195 * Sets the notification as dimmed. The default implementation does nothing.
196 *
197 * @param dimmed Whether the notification should be dimmed.
198 * @param fade Whether an animation should be played to change the state.
199 */
200 public void setDimmed(boolean dimmed, boolean fade) {
201 }
202
203 /**
John Spurlockbf370992014-06-17 13:58:31 -0400204 * Sets the notification as dark. The default implementation does nothing.
205 *
206 * @param dark Whether the notification should be dark.
207 * @param fade Whether an animation should be played to change the state.
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100208 * @param delay If fading, the delay of the animation.
John Spurlockbf370992014-06-17 13:58:31 -0400209 */
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100210 public void setDark(boolean dark, boolean fade, long delay) {
211 mDark = dark;
212 }
213
214 public boolean isDark() {
215 return mDark;
John Spurlockbf370992014-06-17 13:58:31 -0400216 }
217
Selim Cinekd9b7dd42017-11-10 17:53:47 -0800218 public boolean isRemoved() {
219 return false;
220 }
221
John Spurlockbf370992014-06-17 13:58:31 -0400222 /**
Jorim Jaggiae441282014-08-01 02:45:18 +0200223 * See {@link #setHideSensitive}. This is a variant which notifies this view in advance about
224 * the upcoming state of hiding sensitive notifications. It gets called at the very beginning
225 * of a stack scroller update such that the updated intrinsic height (which is dependent on
226 * whether private or public layout is showing) gets taken into account into all layout
227 * calculations.
228 */
229 public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
230 }
231
232 /**
233 * Sets whether the notification should hide its private contents if it is sensitive.
234 */
235 public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
236 long duration) {
237 }
238
239 /**
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200240 * @return The desired notification height.
241 */
242 public int getIntrinsicHeight() {
Selim Cineka5eaa602014-05-12 21:27:47 +0200243 return getHeight();
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200244 }
245
246 /**
Jorim Jaggibe565df2014-04-28 17:51:23 +0200247 * Sets the amount this view should be clipped from the top. This is used when an expanded
248 * notification is scrolling in the top or bottom stack.
249 *
250 * @param clipTopAmount The amount of pixels this view should be clipped from top.
251 */
252 public void setClipTopAmount(int clipTopAmount) {
253 mClipTopAmount = clipTopAmount;
Mady Mellorc128f222016-04-26 11:42:46 -0700254 updateClipping();
Jorim Jaggibe565df2014-04-28 17:51:23 +0200255 }
256
Selim Cineka686b2c2016-10-26 13:58:27 -0700257 /**
258 * Set the amount the the notification is clipped on the bottom in addition to the regular
259 * clipping. This is mainly used to clip something in a non-animated way without changing the
260 * actual height of the notification and is purely visual.
261 *
262 * @param clipBottomAmount the amount to clip.
263 */
264 public void setClipBottomAmount(int clipBottomAmount) {
265 mClipBottomAmount = clipBottomAmount;
266 updateClipping();
267 }
268
Selim Cinekeb973562014-05-02 17:07:49 +0200269 public int getClipTopAmount() {
270 return mClipTopAmount;
271 }
272
Selim Cinekb3dadcc2016-11-21 17:21:13 -0800273 public int getClipBottomAmount() {
Selim Cineka686b2c2016-10-26 13:58:27 -0700274 return mClipBottomAmount;
275 }
276
Jorim Jaggibe565df2014-04-28 17:51:23 +0200277 public void setOnHeightChangedListener(OnHeightChangedListener listener) {
278 mOnHeightChangedListener = listener;
279 }
280
281 /**
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200282 * @return Whether we can expand this views content.
Jorim Jaggibe565df2014-04-28 17:51:23 +0200283 */
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200284 public boolean isContentExpandable() {
285 return false;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200286 }
287
Selim Cinekb5605e52015-02-20 18:21:41 +0100288 public void notifyHeightChanged(boolean needsAnimation) {
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200289 if (mOnHeightChangedListener != null) {
Selim Cinekb5605e52015-02-20 18:21:41 +0100290 mOnHeightChangedListener.onHeightChanged(this, needsAnimation);
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200291 }
292 }
293
Selim Cinekc27437b2014-05-14 10:23:33 +0200294 public boolean isTransparent() {
295 return false;
296 }
297
Jorim Jaggibe565df2014-04-28 17:51:23 +0200298 /**
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200299 * Perform a remove animation on this view.
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200300 * @param duration The duration of the remove animation.
Selim Cinek332c23f2018-03-16 17:37:50 -0700301 * @param delay The delay of the animation
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200302 * @param translationDirection The direction value from [-1 ... 1] indicating in which the
Selim Cinek332c23f2018-03-16 17:37:50 -0700303 * animation should be performed. A value of -1 means that The
304 * remove animation should be performed upwards,
305 * such that the child appears to be going away to the top. 1
306 * Should mean the opposite.
307 * @param isHeadsUpAnimation Is this a headsUp animation.
308 * @param endLocation The location where the horizonal heads up disappear animation should end.
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200309 * @param onFinishedRunnable A runnable which should be run when the animation is finished.
Selim Cinek332c23f2018-03-16 17:37:50 -0700310 * @param animationListener An animation listener to add to the animation.
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200311 */
Selim Cinek332c23f2018-03-16 17:37:50 -0700312 public abstract void performRemoveAnimation(long duration,
313 long delay, float translationDirection, boolean isHeadsUpAnimation, float endLocation,
314 Runnable onFinishedRunnable,
315 AnimatorListenerAdapter animationListener);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200316
Selim Cinek332c23f2018-03-16 17:37:50 -0700317 public abstract void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200318
Selim Cinek281c2022016-10-13 19:14:43 -0700319 /**
Selim Cinekdb167372016-11-17 15:41:17 -0800320 * Set the notification appearance to be below the speed bump.
Selim Cinek281c2022016-10-13 19:14:43 -0700321 * @param below true if it is below.
322 */
Selim Cinekdb167372016-11-17 15:41:17 -0800323 public void setBelowSpeedBump(boolean below) {
Selim Cinek3d2b94bf2014-07-02 22:12:47 +0200324 }
325
Selim Cinekd127d792016-11-01 19:11:41 -0700326 public int getPinnedHeadsUpHeight() {
327 return getIntrinsicHeight();
328 }
329
330
Mady Mellor34958fa2016-02-23 09:52:17 -0800331 /**
332 * Sets the translation of the view.
333 */
334 public void setTranslation(float translation) {
335 setTranslationX(translation);
336 }
337
338 /**
339 * Gets the translation of the view.
340 */
341 public float getTranslation() {
342 return getTranslationX();
343 }
344
Selim Cinek31094df2014-08-14 19:28:15 +0200345 public void onHeightReset() {
Selim Cineke34c6512014-08-14 11:19:41 +0200346 if (mOnHeightChangedListener != null) {
347 mOnHeightChangedListener.onReset(this);
348 }
Selim Cineka5e211b2014-08-11 17:35:48 +0200349 }
350
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200351 /**
Selim Cineke32010a2014-08-20 23:50:41 +0200352 * This method returns the drawing rect for the view which is different from the regular
353 * drawing rect, since we layout all children in the {@link NotificationStackScrollLayout} at
354 * position 0 and usually the translation is neglected. Since we are manually clipping this
355 * view,we also need to subtract the clipTopAmount from the top. This is needed in order to
356 * ensure that accessibility and focusing work correctly.
357 *
358 * @param outRect The (scrolled) drawing bounds of the view.
359 */
360 @Override
361 public void getDrawingRect(Rect outRect) {
362 super.getDrawingRect(outRect);
363 outRect.left += getTranslationX();
364 outRect.right += getTranslationX();
365 outRect.bottom = (int) (outRect.top + getTranslationY() + getActualHeight());
366 outRect.top += getTranslationY() + getClipTopAmount();
367 }
368
Adrian Rooscd55f432015-06-10 16:42:53 -0700369 @Override
370 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
371 super.getBoundsOnScreen(outRect, clipToParent);
Adrian Roos98dd7f12016-06-14 15:51:40 -0700372 if (getTop() + getTranslationY() < 0) {
373 // We got clipped to the parent here - make sure we undo that.
374 outRect.top += getTop() + getTranslationY();
375 }
Adrian Roosb44f5482015-06-11 12:19:16 -0700376 outRect.bottom = outRect.top + getActualHeight();
Mady Mellorc128f222016-04-26 11:42:46 -0700377 outRect.top += getClipTopAmount();
Adrian Rooscd55f432015-06-10 16:42:53 -0700378 }
379
Selim Cinek263398f2015-10-21 17:40:23 -0700380 public boolean isSummaryWithChildren() {
Selim Cinekb5605e52015-02-20 18:21:41 +0100381 return false;
382 }
383
384 public boolean areChildrenExpanded() {
385 return false;
386 }
387
Selim Cinek2627d722018-01-19 12:16:49 -0800388 protected void updateClipping() {
389 if (mClipToActualHeight && shouldClipToActualHeight()) {
Mady Mellorc128f222016-04-26 11:42:46 -0700390 int top = getClipTopAmount();
Selim Cinekb3dadcc2016-11-21 17:21:13 -0800391 mClipRect.set(0, top, getWidth(), Math.max(getActualHeight() + getExtraBottomPadding()
Anthony Chen04d1ea72017-04-21 14:30:11 -0700392 - mClipBottomAmount, top));
Selim Cinek4ffd6362015-12-29 15:12:23 +0100393 setClipBounds(mClipRect);
394 } else {
395 setClipBounds(null);
Selim Cinekf92a1fd2015-07-31 16:10:32 -0700396 }
Selim Cinek4ffd6362015-12-29 15:12:23 +0100397 }
398
Selim Cinek99e9adf2018-03-15 09:17:47 -0700399 public float getHeaderVisibleAmount() {
400 return 1.0f;
401 }
402
Selim Cinek2627d722018-01-19 12:16:49 -0800403 protected boolean shouldClipToActualHeight() {
404 return true;
405 }
406
Selim Cinek4ffd6362015-12-29 15:12:23 +0100407 public void setClipToActualHeight(boolean clipToActualHeight) {
408 mClipToActualHeight = clipToActualHeight;
409 updateClipping();
Selim Cineka272dfe2015-02-20 18:12:28 +0100410 }
411
Selim Cinek2cd45df2015-06-09 18:00:07 -0700412 public boolean willBeGone() {
413 return mWillBeGone;
414 }
415
416 public void setWillBeGone(boolean willBeGone) {
417 mWillBeGone = willBeGone;
418 }
419
Selim Cinek9c17b772015-07-07 20:37:09 -0700420 public int getMinClipTopAmount() {
421 return mMinClipTopAmount;
422 }
423
424 public void setMinClipTopAmount(int minClipTopAmount) {
425 mMinClipTopAmount = minClipTopAmount;
426 }
427
Selim Cinek471e31a2015-12-11 13:39:48 -0800428 @Override
429 public void setLayerType(int layerType, Paint paint) {
430 if (hasOverlappingRendering()) {
431 super.setLayerType(layerType, paint);
432 }
433 }
434
435 @Override
436 public boolean hasOverlappingRendering() {
Selim Cineka69f2a62015-12-11 17:28:12 -0800437 // Otherwise it will be clipped
438 return super.hasOverlappingRendering() && getActualHeight() <= getHeight();
Selim Cinek471e31a2015-12-11 13:39:48 -0800439 }
440
Selim Cinek277a8aa2016-01-22 12:12:37 -0800441 public float getShadowAlpha() {
442 return 0.0f;
443 }
444
445 public void setShadowAlpha(float shadowAlpha) {
446 }
447
Selim Cinek42357e02016-02-24 18:48:01 -0800448 /**
Selim Cineka7ed2c12017-01-23 20:47:24 -0800449 * @return an amount between -1 and 1 of increased padding that this child needs. 1 means it
450 * needs a full increased padding while -1 means it needs no padding at all. For 0.0f the normal
451 * padding is applied.
Selim Cinek42357e02016-02-24 18:48:01 -0800452 */
453 public float getIncreasedPaddingAmount() {
454 return 0.0f;
Selim Cinek61633a82016-01-25 15:54:10 -0800455 }
456
Selim Cinek3776fe02016-02-04 13:32:43 -0800457 public boolean mustStayOnScreen() {
458 return false;
459 }
460
Selim Cinek33223572016-02-19 19:32:22 -0800461 public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
462 int outlineTranslation) {
463 }
464
465 public float getOutlineAlpha() {
466 return 0.0f;
467 }
468
469 public int getOutlineTranslation() {
470 return 0;
471 }
472
Adrian Roos14503e22016-03-09 14:01:24 -0800473 public void setChangingPosition(boolean changingPosition) {
474 mChangingPosition = changingPosition;
475 }
476
477 public boolean isChangingPosition() {
478 return mChangingPosition;
479 }
480
Selim Cinekd1395642016-04-28 12:22:42 -0700481 public void setTransientContainer(ViewGroup transientContainer) {
482 mTransientContainer = transientContainer;
483 }
484
485 public ViewGroup getTransientContainer() {
486 return mTransientContainer;
487 }
488
Selim Cineke32010a2014-08-20 23:50:41 +0200489 /**
Mady Mellorb0a82462016-04-30 17:31:02 -0700490 * @return padding used to alter how much of the view is clipped.
491 */
492 public int getExtraBottomPadding() {
493 return 0;
494 }
495
496 /**
497 * @return true if the group's expansion state is changing, false otherwise.
498 */
499 public boolean isGroupExpansionChanging() {
500 return false;
501 }
502
503 public boolean isGroupExpanded() {
504 return false;
505 }
506
Selim Cinek9b9d6e12017-11-30 12:29:47 +0100507 public void setHeadsUpIsVisible() {
508 }
509
Mady Mellorb0a82462016-04-30 17:31:02 -0700510 public boolean isChildInGroup() {
511 return false;
512 }
513
Adrian Roos599be342016-06-13 14:54:39 -0700514 public void setActualHeightAnimating(boolean animating) {}
515
Selim Cinekbbcebde2016-11-09 18:28:20 -0800516 public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
517 return new ExpandableViewState();
518 }
519
Mady Mellorb0a82462016-04-30 17:31:02 -0700520 /**
Selim Cinek281c2022016-10-13 19:14:43 -0700521 * @return whether the current view doesn't add height to the overall content. This means that
522 * if it is added to a list of items, it's content will still have the same height.
523 * An example is the notification shelf, that is always placed on top of another view.
524 */
525 public boolean hasNoContentHeight() {
526 return false;
527 }
528
529 /**
Selim Cinekeccb5de2016-10-28 15:04:05 -0700530 * @param inShelf whether the view is currently fully in the notification shelf.
531 */
532 public void setInShelf(boolean inShelf) {
533 mInShelf = inShelf;
534 }
535
536 public boolean isInShelf() {
537 return mInShelf;
538 }
539
540 /**
541 * @param transformingInShelf whether the view is currently transforming into the shelf in an
542 * animated way
543 */
544 public void setTransformingInShelf(boolean transformingInShelf) {
545 mTransformingInShelf = transformingInShelf;
546 }
547
548 public boolean isTransformingIntoShelf() {
549 return mTransformingInShelf;
550 }
551
Selim Cinekd127d792016-11-01 19:11:41 -0700552 public boolean isAboveShelf() {
553 return false;
554 }
555
Selim Cinekc25989e2018-02-16 16:42:14 -0800556 public boolean hasExpandingChild() {
557 return false;
558 }
559
Selim Cinekeccb5de2016-10-28 15:04:05 -0700560 /**
Jorim Jaggibe565df2014-04-28 17:51:23 +0200561 * A listener notifying when {@link #getActualHeight} changes.
562 */
563 public interface OnHeightChangedListener {
Jorim Jaggi30c305c2014-07-01 23:34:41 +0200564
565 /**
566 * @param view the view for which the height changed, or {@code null} if just the top
567 * padding or the padding between the elements changed
Selim Cinekb5605e52015-02-20 18:21:41 +0100568 * @param needsAnimation whether the view height needs to be animated
Jorim Jaggi30c305c2014-07-01 23:34:41 +0200569 */
Selim Cinekb5605e52015-02-20 18:21:41 +0100570 void onHeightChanged(ExpandableView view, boolean needsAnimation);
Selim Cineka5e211b2014-08-11 17:35:48 +0200571
572 /**
573 * Called when the view is reset and therefore the height will change abruptly
574 *
575 * @param view The view which was reset.
576 */
577 void onReset(ExpandableView view);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200578 }
579}