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