ExpandableView.java revision be565dfc1c17b7ddafa9753851b8f82849fd3f42
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.graphics.Canvas;
21be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggiimport android.graphics.Outline;
22be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggiimport android.graphics.Rect;
23be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggiimport android.graphics.drawable.Drawable;
24be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggiimport android.graphics.drawable.InsetDrawable;
25be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggiimport android.util.AttributeSet;
26be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggiimport android.view.View;
27be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggiimport android.widget.FrameLayout;
28be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
29be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi/**
30be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi * An abstract view for expandable views.
31be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi */
32be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggipublic abstract class ExpandableView extends FrameLayout {
33be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
34be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    private OnHeightChangedListener mOnHeightChangedListener;
35be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    protected int mActualHeight;
36be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    protected int mClipTopAmount;
37be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    protected Drawable mCustomBackground;
38be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    private boolean mActualHeightInitialized;
39be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
40be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public ExpandableView(Context context, AttributeSet attrs) {
41be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        super(context, attrs);
42be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
43be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
44be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    @Override
45be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    protected void onDraw(Canvas canvas) {
46be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        if (mCustomBackground != null) {
47be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi            mCustomBackground.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
48be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi            mCustomBackground.draw(canvas);
49be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        }
50be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
51be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
52be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    @Override
53be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    protected boolean verifyDrawable(Drawable who) {
54be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        return super.verifyDrawable(who) || who == mCustomBackground;
55be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
56be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
57be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    @Override
58be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    protected void drawableStateChanged() {
59be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        final Drawable d = mCustomBackground;
60be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        if (d != null && d.isStateful()) {
61be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi            d.setState(getDrawableState());
62be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        }
63be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
64be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
65be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    @Override
66be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
67be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        super.onLayout(changed, left, top, right, bottom);
68be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        if (!mActualHeightInitialized && mActualHeight == 0) {
69be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi            mActualHeight = getHeight();
70be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        }
71be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mActualHeightInitialized = true;
72be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
73be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
74be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    /**
75be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * Sets the actual height of this notification. This is different than the laid out
76be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * {@link View#getHeight()}, as we want to avoid layouting during scrolling and expanding.
77be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     */
78be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public void setActualHeight(int actualHeight) {
79be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mActualHeight = actualHeight;
80be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        invalidate();
81be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        if (mOnHeightChangedListener != null) {
82be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi            mOnHeightChangedListener.onHeightChanged(this);
83be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        }
84be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
85be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
86be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    /**
87be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * See {@link #setActualHeight}.
88be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     *
89be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * @return The actual height of this notification.
90be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     */
91be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public int getActualHeight() {
92be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        return mActualHeight;
93be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
94be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
95be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    /**
96be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * @return The maximum height of this notification.
97be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     */
98be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public abstract int getMaxHeight();
99be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
100be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    /**
101be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * Sets the amount this view should be clipped from the top. This is used when an expanded
102be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * notification is scrolling in the top or bottom stack.
103be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     *
104be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * @param clipTopAmount The amount of pixels this view should be clipped from top.
105be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     */
106be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public void setClipTopAmount(int clipTopAmount) {
107be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mClipTopAmount = clipTopAmount;
108be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        invalidate();
109be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
110be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
111be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public void setOnHeightChangedListener(OnHeightChangedListener listener) {
112be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mOnHeightChangedListener = listener;
113be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
114be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
115be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    /**
116be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * Sets a custom background drawable. As we need to change our bounds independently of layout,
117be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * we need the notition of a custom background.
118be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     */
119be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public void setCustomBackground(Drawable customBackground) {
120be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        if (mCustomBackground != null) {
121be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi            mCustomBackground.setCallback(null);
122be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi            unscheduleDrawable(mCustomBackground);
123be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        }
124be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mCustomBackground = customBackground;
125be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mCustomBackground.setCallback(this);
126be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        setWillNotDraw(customBackground == null);
127be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        invalidate();
128be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
129be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
130be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public void setCustomBackgroundResource(int drawableResId) {
131be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        setCustomBackground(getResources().getDrawable(drawableResId));
132be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
133be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
134be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    /**
135be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     * A listener notifying when {@link #getActualHeight} changes.
136be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi     */
137be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public interface OnHeightChangedListener {
138be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        void onHeightChanged(ExpandableView view);
139be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
140be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi}
141