1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14package android.support.v17.leanback.widget;
15
16import android.content.Context;
17import android.content.res.TypedArray;
18import android.graphics.Canvas;
19import android.graphics.Rect;
20import android.graphics.drawable.Drawable;
21import android.os.Build.VERSION;
22import android.util.AttributeSet;
23import android.widget.LinearLayout;
24
25/**
26 * Implements foreground drawable before M and falls back to M's foreground implementation.
27 * @hide
28 */
29class NonOverlappingLinearLayoutWithForeground extends LinearLayout {
30
31    private static final int VERSION_M = 23;
32
33    private Drawable mForeground;
34    private boolean mForegroundBoundsChanged;
35    private final Rect mSelfBounds = new Rect();
36
37    public NonOverlappingLinearLayoutWithForeground(Context context) {
38        this(context, null);
39    }
40
41    public NonOverlappingLinearLayoutWithForeground(Context context, AttributeSet attrs) {
42        this(context, attrs, 0);
43    }
44
45    public NonOverlappingLinearLayoutWithForeground(Context context, AttributeSet attrs,
46            int defStyle) {
47        super(context, attrs, defStyle);
48        if (context.getApplicationInfo().targetSdkVersion >= VERSION_M
49                && VERSION.SDK_INT >= VERSION_M) {
50            // dont need do anything, base View constructor >=M already reads the foreground if
51            // targetSDK is >= M.
52        } else {
53            // in other cases, including M but targetSDK is less than M, we need setForeground in
54            // code.
55            TypedArray a = context.obtainStyledAttributes(attrs,
56                    new int[] { android.R.attr.foreground });
57            Drawable d = a.getDrawable(0);
58            if (d != null) {
59                setForegroundCompat(d);
60            }
61        }
62    }
63
64    public void setForegroundCompat(Drawable d) {
65        if (VERSION.SDK_INT >= VERSION_M) {
66            // From M,  foreground is naturally supported.
67            ForegroundHelper.getInstance().setForeground(this, d);
68        } else {
69            // before M, do our own customized foreground draw.
70            if (mForeground != d) {
71                mForeground = d;
72                mForegroundBoundsChanged = true;
73                setWillNotDraw(false);
74                mForeground.setCallback(this);
75                if (mForeground.isStateful()) {
76                    mForeground.setState(getDrawableState());
77                }
78            }
79        }
80    }
81
82    public Drawable getForegroundCompat() {
83        if (VERSION.SDK_INT >= VERSION_M) {
84            return ForegroundHelper.getInstance().getForeground(this);
85        } else {
86            return mForeground;
87        }
88    }
89
90    @Override
91    public void draw(Canvas canvas) {
92        super.draw(canvas);
93        if (mForeground != null) {
94            final Drawable foreground = mForeground;
95            if (mForegroundBoundsChanged) {
96                mForegroundBoundsChanged = false;
97                final Rect selfBounds = mSelfBounds;
98                final int w = getRight() - getLeft();
99                final int h = getBottom() - getTop();
100                selfBounds.set(0, 0, w, h);
101                foreground.setBounds(selfBounds);
102            }
103            foreground.draw(canvas);
104        }
105    }
106
107    @Override
108    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
109        super.onLayout(changed, left, top, right, bottom);
110        mForegroundBoundsChanged |= changed;
111    }
112
113    @Override
114    protected boolean verifyDrawable(Drawable who) {
115        return super.verifyDrawable(who) || (who == mForeground);
116    }
117
118    @Override
119    public void jumpDrawablesToCurrentState() {
120        super.jumpDrawablesToCurrentState();
121        if (mForeground != null) {
122            mForeground.jumpToCurrentState();
123        }
124    }
125
126    @Override
127    protected void drawableStateChanged() {
128        super.drawableStateChanged();
129        if (mForeground != null && mForeground.isStateful()) {
130            mForeground.setState(getDrawableState());
131        }
132    }
133
134    /**
135     * Avoids creating a hardware layer when animating alpha.
136     */
137    @Override
138    public boolean hasOverlappingRendering() {
139        return false;
140    }
141}