11db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu/*
21db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu * Copyright (C) 2015 The Android Open Source Project
31db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu *
41db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
51db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu * in compliance with the License. You may obtain a copy of the License at
61db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu *
71db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu * http://www.apache.org/licenses/LICENSE-2.0
81db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu *
91db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu * Unless required by applicable law or agreed to in writing, software distributed under the License
101db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
111db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu * or implied. See the License for the specific language governing permissions and limitations under
121db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu * the License.
131db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu */
14ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.leanback.widget;
151db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
161db5382081756ee276c1fb88f5ebdbc138b70249Dake Guimport android.content.Context;
171db5382081756ee276c1fb88f5ebdbc138b70249Dake Guimport android.content.res.TypedArray;
181db5382081756ee276c1fb88f5ebdbc138b70249Dake Guimport android.graphics.Canvas;
191db5382081756ee276c1fb88f5ebdbc138b70249Dake Guimport android.graphics.Rect;
201db5382081756ee276c1fb88f5ebdbc138b70249Dake Guimport android.graphics.drawable.Drawable;
211db5382081756ee276c1fb88f5ebdbc138b70249Dake Guimport android.os.Build.VERSION;
221db5382081756ee276c1fb88f5ebdbc138b70249Dake Guimport android.util.AttributeSet;
231db5382081756ee276c1fb88f5ebdbc138b70249Dake Guimport android.widget.LinearLayout;
241db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
251db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu/**
261db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu * Implements foreground drawable before M and falls back to M's foreground implementation.
271db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu */
281db5382081756ee276c1fb88f5ebdbc138b70249Dake Guclass NonOverlappingLinearLayoutWithForeground extends LinearLayout {
291db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
301db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    private static final int VERSION_M = 23;
311db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
321db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    private Drawable mForeground;
331db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    private boolean mForegroundBoundsChanged;
341db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    private final Rect mSelfBounds = new Rect();
351db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
361db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    public NonOverlappingLinearLayoutWithForeground(Context context) {
371db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        this(context, null);
381db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    }
391db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
401db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    public NonOverlappingLinearLayoutWithForeground(Context context, AttributeSet attrs) {
411db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        this(context, attrs, 0);
421db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    }
431db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
441db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    public NonOverlappingLinearLayoutWithForeground(Context context, AttributeSet attrs,
451db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            int defStyle) {
461db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        super(context, attrs, defStyle);
471db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        if (context.getApplicationInfo().targetSdkVersion >= VERSION_M
481db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                && VERSION.SDK_INT >= VERSION_M) {
49c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas            // don't need do anything, base View constructor >=M already reads the foreground if
501db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            // targetSDK is >= M.
511db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        } else {
521db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            // in other cases, including M but targetSDK is less than M, we need setForeground in
531db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            // code.
541db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            TypedArray a = context.obtainStyledAttributes(attrs,
551db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                    new int[] { android.R.attr.foreground });
561db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            Drawable d = a.getDrawable(0);
571db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            if (d != null) {
581db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                setForegroundCompat(d);
591db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            }
60b655650666d7bd317c41c7a5be229e3a80dd2692Dake Gu            a.recycle();
611db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        }
621db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    }
631db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
641db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    public void setForegroundCompat(Drawable d) {
651db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        if (VERSION.SDK_INT >= VERSION_M) {
661db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            // From M,  foreground is naturally supported.
67e32ee755efe98500d56ed3edf0ac91d262a48f1bAurimas Liutikas            ForegroundHelper.setForeground(this, d);
681db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        } else {
691db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            // before M, do our own customized foreground draw.
701db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            if (mForeground != d) {
711db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                mForeground = d;
721db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                mForegroundBoundsChanged = true;
731db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                setWillNotDraw(false);
741db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                mForeground.setCallback(this);
751db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                if (mForeground.isStateful()) {
761db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                    mForeground.setState(getDrawableState());
771db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                }
781db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            }
791db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        }
801db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    }
811db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
821db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    public Drawable getForegroundCompat() {
831db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        if (VERSION.SDK_INT >= VERSION_M) {
84e32ee755efe98500d56ed3edf0ac91d262a48f1bAurimas Liutikas            return ForegroundHelper.getForeground(this);
851db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        } else {
861db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            return mForeground;
871db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        }
881db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    }
891db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
901db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    @Override
911db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    public void draw(Canvas canvas) {
921db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        super.draw(canvas);
931db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        if (mForeground != null) {
941db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            final Drawable foreground = mForeground;
951db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            if (mForegroundBoundsChanged) {
961db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                mForegroundBoundsChanged = false;
971db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                final Rect selfBounds = mSelfBounds;
981db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                final int w = getRight() - getLeft();
991db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                final int h = getBottom() - getTop();
1001db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                selfBounds.set(0, 0, w, h);
1011db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu                foreground.setBounds(selfBounds);
1021db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            }
1031db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            foreground.draw(canvas);
1041db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        }
1051db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    }
1061db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
1071db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    @Override
1081db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1091db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        super.onLayout(changed, left, top, right, bottom);
1101db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        mForegroundBoundsChanged |= changed;
1111db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    }
1121db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
1131db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    @Override
1141db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    protected boolean verifyDrawable(Drawable who) {
1151db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        return super.verifyDrawable(who) || (who == mForeground);
1161db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    }
1171db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
1181db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    @Override
1191db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    public void jumpDrawablesToCurrentState() {
1201db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        super.jumpDrawablesToCurrentState();
1211db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        if (mForeground != null) {
1221db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            mForeground.jumpToCurrentState();
1231db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        }
1241db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    }
1251db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
1261db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    @Override
1271db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    protected void drawableStateChanged() {
1281db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        super.drawableStateChanged();
1291db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        if (mForeground != null && mForeground.isStateful()) {
1301db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu            mForeground.setState(getDrawableState());
1311db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        }
1321db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    }
1331db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu
1341db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    /**
1351db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu     * Avoids creating a hardware layer when animating alpha.
1361db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu     */
1371db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    @Override
1381db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    public boolean hasOverlappingRendering() {
1391db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu        return false;
1401db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu    }
1411db5382081756ee276c1fb88f5ebdbc138b70249Dake Gu}