blob: 0a5d1389b336046f832faa59a86f50404d11a029 [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 Jaggibe565df2014-04-28 17:51:23 +020020import android.util.AttributeSet;
Jorim Jaggi00ebdfe2014-05-02 17:29:56 +020021import android.view.MotionEvent;
Jorim Jaggibe565df2014-04-28 17:51:23 +020022import android.view.View;
Selim Cinekc9c00ae2014-05-20 03:33:40 +020023import android.view.ViewGroup;
Selim Cinek24d7cfa2014-05-20 13:50:57 +020024import android.widget.FrameLayout;
25import com.android.systemui.R;
26
27import java.util.ArrayList;
Jorim Jaggibe565df2014-04-28 17:51:23 +020028
29/**
30 * An abstract view for expandable views.
31 */
Selim Cinek24d7cfa2014-05-20 13:50:57 +020032public abstract class ExpandableView extends FrameLayout {
33
34 private final int mMaxNotificationHeight;
Jorim Jaggibe565df2014-04-28 17:51:23 +020035
36 private OnHeightChangedListener mOnHeightChangedListener;
37 protected int mActualHeight;
38 protected int mClipTopAmount;
Jorim Jaggibe565df2014-04-28 17:51:23 +020039 private boolean mActualHeightInitialized;
Selim Cinek24d7cfa2014-05-20 13:50:57 +020040 private ArrayList<View> mMatchParentViews = new ArrayList<View>();
Jorim Jaggibe565df2014-04-28 17:51:23 +020041
42 public ExpandableView(Context context, AttributeSet attrs) {
43 super(context, attrs);
Selim Cinek24d7cfa2014-05-20 13:50:57 +020044 mMaxNotificationHeight = getResources().getDimensionPixelSize(
45 R.dimen.notification_max_height);
46 }
47
48 @Override
49 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
50 int ownMaxHeight = mMaxNotificationHeight;
51 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
52 boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
53 boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
54 if (hasFixedHeight || isHeightLimited) {
55 int size = MeasureSpec.getSize(heightMeasureSpec);
56 ownMaxHeight = Math.min(ownMaxHeight, size);
57 }
58 int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
59 int maxChildHeight = 0;
60 int childCount = getChildCount();
61 for (int i = 0; i < childCount; i++) {
62 View child = getChildAt(i);
63 int childHeightSpec = newHeightSpec;
64 ViewGroup.LayoutParams layoutParams = child.getLayoutParams();
65 if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) {
66 if (layoutParams.height >= 0) {
67 // An actual height is set
68 childHeightSpec = layoutParams.height > ownMaxHeight
69 ? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY)
70 : MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
71 }
Jorim Jaggib741f052014-06-03 19:57:26 +020072 child.measure(
73 getChildMeasureSpec(widthMeasureSpec, 0 /* padding */, layoutParams.width),
74 childHeightSpec);
Selim Cinek24d7cfa2014-05-20 13:50:57 +020075 int childHeight = child.getMeasuredHeight();
76 maxChildHeight = Math.max(maxChildHeight, childHeight);
77 } else {
78 mMatchParentViews.add(child);
79 }
80 }
81 int ownHeight = hasFixedHeight ? ownMaxHeight : maxChildHeight;
82 newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
83 for (View child : mMatchParentViews) {
Jorim Jaggib741f052014-06-03 19:57:26 +020084 child.measure(getChildMeasureSpec(
85 widthMeasureSpec, 0 /* padding */, child.getLayoutParams().width),
86 newHeightSpec);
Selim Cinek24d7cfa2014-05-20 13:50:57 +020087 }
88 mMatchParentViews.clear();
89 int width = MeasureSpec.getSize(widthMeasureSpec);
90 setMeasuredDimension(width, ownHeight);
Jorim Jaggibe565df2014-04-28 17:51:23 +020091 }
92
93 @Override
Jorim Jaggibe565df2014-04-28 17:51:23 +020094 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Selim Cinek24d7cfa2014-05-20 13:50:57 +020095 super.onLayout(changed, left, top, right, bottom);
Jorim Jaggibe565df2014-04-28 17:51:23 +020096 if (!mActualHeightInitialized && mActualHeight == 0) {
Jorim Jaggi3c3c3fc2014-05-20 23:16:42 +020097 setActualHeight(getInitialHeight());
Jorim Jaggibe565df2014-04-28 17:51:23 +020098 }
Jorim Jaggibe565df2014-04-28 17:51:23 +020099 }
100
Selim Cinekc27437b2014-05-14 10:23:33 +0200101 protected int getInitialHeight() {
102 return getHeight();
103 }
104
Jorim Jaggi00ebdfe2014-05-02 17:29:56 +0200105 @Override
106 public boolean dispatchTouchEvent(MotionEvent ev) {
107 if (filterMotionEvent(ev)) {
108 return super.dispatchTouchEvent(ev);
109 }
110 return false;
111 }
112
113 private boolean filterMotionEvent(MotionEvent event) {
114 return event.getActionMasked() != MotionEvent.ACTION_DOWN
115 || event.getY() > mClipTopAmount && event.getY() < mActualHeight;
116 }
117
Jorim Jaggibe565df2014-04-28 17:51:23 +0200118 /**
119 * Sets the actual height of this notification. This is different than the laid out
120 * {@link View#getHeight()}, as we want to avoid layouting during scrolling and expanding.
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200121 *
122 * @param actualHeight The height of this notification.
123 * @param notifyListeners Whether the listener should be informed about the change.
Jorim Jaggibe565df2014-04-28 17:51:23 +0200124 */
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200125 public void setActualHeight(int actualHeight, boolean notifyListeners) {
Jorim Jaggi2580a9762014-06-25 03:08:25 +0200126 mActualHeightInitialized = true;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200127 mActualHeight = actualHeight;
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200128 if (notifyListeners) {
129 notifyHeightChanged();
130 }
131 }
132
133 public void setActualHeight(int actualHeight) {
134 setActualHeight(actualHeight, true);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200135 }
136
137 /**
138 * See {@link #setActualHeight}.
139 *
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200140 * @return The current actual height of this notification.
Jorim Jaggibe565df2014-04-28 17:51:23 +0200141 */
142 public int getActualHeight() {
143 return mActualHeight;
144 }
145
146 /**
147 * @return The maximum height of this notification.
148 */
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200149 public int getMaxHeight() {
150 return getHeight();
151 }
152
153 /**
154 * @return The minimum height of this notification.
155 */
156 public int getMinHeight() {
157 return getHeight();
158 }
Jorim Jaggibe565df2014-04-28 17:51:23 +0200159
160 /**
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200161 * Sets the notification as dimmed. The default implementation does nothing.
162 *
163 * @param dimmed Whether the notification should be dimmed.
164 * @param fade Whether an animation should be played to change the state.
165 */
166 public void setDimmed(boolean dimmed, boolean fade) {
167 }
168
169 /**
John Spurlockbf370992014-06-17 13:58:31 -0400170 * Sets the notification as dark. The default implementation does nothing.
171 *
172 * @param dark Whether the notification should be dark.
173 * @param fade Whether an animation should be played to change the state.
174 */
175 public void setDark(boolean dark, boolean fade) {
176 }
177
178 /**
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200179 * @return The desired notification height.
180 */
181 public int getIntrinsicHeight() {
Selim Cineka5eaa602014-05-12 21:27:47 +0200182 return getHeight();
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200183 }
184
185 /**
Jorim Jaggibe565df2014-04-28 17:51:23 +0200186 * Sets the amount this view should be clipped from the top. This is used when an expanded
187 * notification is scrolling in the top or bottom stack.
188 *
189 * @param clipTopAmount The amount of pixels this view should be clipped from top.
190 */
191 public void setClipTopAmount(int clipTopAmount) {
192 mClipTopAmount = clipTopAmount;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200193 }
194
Selim Cinekeb973562014-05-02 17:07:49 +0200195 public int getClipTopAmount() {
196 return mClipTopAmount;
197 }
198
Jorim Jaggibe565df2014-04-28 17:51:23 +0200199 public void setOnHeightChangedListener(OnHeightChangedListener listener) {
200 mOnHeightChangedListener = listener;
201 }
202
203 /**
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200204 * @return Whether we can expand this views content.
Jorim Jaggibe565df2014-04-28 17:51:23 +0200205 */
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200206 public boolean isContentExpandable() {
207 return false;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200208 }
209
Jorim Jaggi9cbadd32014-05-01 20:18:31 +0200210 public void notifyHeightChanged() {
211 if (mOnHeightChangedListener != null) {
212 mOnHeightChangedListener.onHeightChanged(this);
213 }
214 }
215
Selim Cinekc27437b2014-05-14 10:23:33 +0200216 public boolean isTransparent() {
217 return false;
218 }
219
Jorim Jaggibe565df2014-04-28 17:51:23 +0200220 /**
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200221 * Perform a remove animation on this view.
222 *
223 * @param translationDirection The direction value from [-1 ... 1] indicating in which the
224 * animation should be performed. A value of -1 means that The
225 * remove animation should be performed upwards,
226 * such that the child appears to be going away to the top. 1
227 * Should mean the opposite.
228 * @param onFinishedRunnable A runnable which should be run when the animation is finished.
229 */
230 public abstract void performRemoveAnimation(float translationDirection,
231 Runnable onFinishedRunnable);
232
233 public abstract void performAddAnimation(long delay);
234
Selim Cinekf54090e2014-06-17 17:24:51 -0700235 public abstract void setScrimAmount(float scrimAmount);
236
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200237 /**
Jorim Jaggibe565df2014-04-28 17:51:23 +0200238 * A listener notifying when {@link #getActualHeight} changes.
239 */
240 public interface OnHeightChangedListener {
241 void onHeightChanged(ExpandableView view);
242 }
243}