ExpandableView.java revision c9c00ae2fa5fb787e9f12705f8cd8de445ecde4b
1be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi/*
2be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * Copyright (C) 2014 The Android Open Source Project
3be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi *
4be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License");
5be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * you may not use this file except in compliance with the License.
6be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * You may obtain a copy of the License at
7be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi *
8be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi *      http://www.apache.org/licenses/LICENSE-2.0
9be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi *
10be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * Unless required by applicable law or agreed to in writing, software
11be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS,
12be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * See the License for the specific language governing permissions and
14be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * limitations under the License
15be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi */
16be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
17be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggipackage com.android.systemui.statusbar;
18be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
19be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggiimport android.content.Context;
20be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggiimport android.util.AttributeSet;
2100ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggiimport android.view.MotionEvent;
22be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggiimport android.view.View;
23c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinekimport android.view.ViewGroup;
24be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
25be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi/**
26be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * An abstract view for expandable views.
27be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi */
28c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinekpublic abstract class ExpandableView extends ViewGroup {
29be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
30be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    private OnHeightChangedListener mOnHeightChangedListener;
31be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    protected int mActualHeight;
32be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    protected int mClipTopAmount;
33be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    private boolean mActualHeightInitialized;
34be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
35be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public ExpandableView(Context context, AttributeSet attrs) {
36be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        super(context, attrs);
37be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
38be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
39be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    @Override
40be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
41c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinek        for (int i = 0; i < getChildCount(); i++) {
42c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinek            View child = getChildAt(i);
43c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinek            int height = child.getMeasuredHeight();
44c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinek            int width = child.getMeasuredWidth();
45c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinek            int center = getWidth() / 2;
46c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinek            int childLeft = center - width / 2;
47c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinek            child.layout(childLeft,
48c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinek                    0,
49c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinek                    childLeft + width,
50c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinek                    height);
51c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinek        }
52be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        if (!mActualHeightInitialized && mActualHeight == 0) {
53c27437b7fd04e682ae2abdf0727a99bf5c6e409dSelim Cinek            mActualHeight = getInitialHeight();
54be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        }
55be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mActualHeightInitialized = true;
56be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
57be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
58c27437b7fd04e682ae2abdf0727a99bf5c6e409dSelim Cinek    protected int getInitialHeight() {
59c27437b7fd04e682ae2abdf0727a99bf5c6e409dSelim Cinek        return getHeight();
60c27437b7fd04e682ae2abdf0727a99bf5c6e409dSelim Cinek    }
61c27437b7fd04e682ae2abdf0727a99bf5c6e409dSelim Cinek
6200ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggi    @Override
6300ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggi    public boolean dispatchTouchEvent(MotionEvent ev) {
6400ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggi        if (filterMotionEvent(ev)) {
6500ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggi            return super.dispatchTouchEvent(ev);
6600ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggi        }
6700ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggi        return false;
6800ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggi    }
6900ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggi
7000ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggi    private boolean filterMotionEvent(MotionEvent event) {
7100ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggi        return event.getActionMasked() != MotionEvent.ACTION_DOWN
7200ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggi                || event.getY() > mClipTopAmount && event.getY() < mActualHeight;
7300ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggi    }
7400ebdfe8ba98c05a767660de2ed7c9a19fb49d74Jorim Jaggi
75be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    /**
76be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * Sets the actual height of this notification. This is different than the laid out
77be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * {@link View#getHeight()}, as we want to avoid layouting during scrolling and expanding.
78d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi     *
79d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi     * @param actualHeight The height of this notification.
80d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi     * @param notifyListeners Whether the listener should be informed about the change.
81be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     */
82d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi    public void setActualHeight(int actualHeight, boolean notifyListeners) {
83be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mActualHeight = actualHeight;
84d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi        if (notifyListeners) {
85d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi            notifyHeightChanged();
86d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi        }
87d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi    }
88d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi
89d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi    public void setActualHeight(int actualHeight) {
90d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi        setActualHeight(actualHeight, true);
91be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
92be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
93be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    /**
94be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * See {@link #setActualHeight}.
95be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     *
969cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi     * @return The current actual height of this notification.
97be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     */
98be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public int getActualHeight() {
99be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        return mActualHeight;
100be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
101be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
102be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    /**
103be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * @return The maximum height of this notification.
104be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     */
1054222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi    public int getMaxHeight() {
1064222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi        return getHeight();
1074222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi    }
1084222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi
1094222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi    /**
1104222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi     * @return The minimum height of this notification.
1114222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi     */
1124222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi    public int getMinHeight() {
1134222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi        return getHeight();
1144222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi    }
115be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
116be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    /**
117d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi     * Sets the notification as dimmed. The default implementation does nothing.
118d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi     *
119d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi     * @param dimmed Whether the notification should be dimmed.
120d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi     * @param fade Whether an animation should be played to change the state.
121d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi     */
122d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi    public void setDimmed(boolean dimmed, boolean fade) {
123d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi    }
124d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi
125d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi    /**
1269cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi     * @return The desired notification height.
1279cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi     */
1289cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi    public int getIntrinsicHeight() {
129a5eaa6034dd48fab0f5a232c09ebed35f359963eSelim Cinek        return getHeight();
1309cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi    }
1319cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi
1329cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi    /**
133be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * Sets the amount this view should be clipped from the top. This is used when an expanded
134be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * notification is scrolling in the top or bottom stack.
135be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     *
136be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * @param clipTopAmount The amount of pixels this view should be clipped from top.
137be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     */
138be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public void setClipTopAmount(int clipTopAmount) {
139be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mClipTopAmount = clipTopAmount;
140be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
141be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
142eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek    public int getClipTopAmount() {
143eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek        return mClipTopAmount;
144eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek    }
145eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek
146be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public void setOnHeightChangedListener(OnHeightChangedListener listener) {
147be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mOnHeightChangedListener = listener;
148be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
149be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
150be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    /**
1514222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi     * @return Whether we can expand this views content.
152be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     */
1534222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi    public boolean isContentExpandable() {
1544222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi        return false;
155be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
156be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
1579cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi    public void notifyHeightChanged() {
1589cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi        if (mOnHeightChangedListener != null) {
1599cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi            mOnHeightChangedListener.onHeightChanged(this);
1609cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi        }
1619cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi    }
1629cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi
163c27437b7fd04e682ae2abdf0727a99bf5c6e409dSelim Cinek    public boolean isTransparent() {
164c27437b7fd04e682ae2abdf0727a99bf5c6e409dSelim Cinek        return false;
165c27437b7fd04e682ae2abdf0727a99bf5c6e409dSelim Cinek    }
166c27437b7fd04e682ae2abdf0727a99bf5c6e409dSelim Cinek
167be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    /**
168be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * A listener notifying when {@link #getActualHeight} changes.
169be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     */
170be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public interface OnHeightChangedListener {
171be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        void onHeightChanged(ExpandableView view);
172be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
173be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi}
174