Home | History | Annotate | Download | only in widget
      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  */
     14 package android.support.v17.leanback.widget;
     15 
     16 import android.content.Context;
     17 import android.content.res.TypedArray;
     18 import android.graphics.Canvas;
     19 import android.graphics.Rect;
     20 import android.graphics.drawable.Drawable;
     21 import android.os.Build.VERSION;
     22 import android.util.AttributeSet;
     23 import android.widget.LinearLayout;
     24 
     25 /**
     26  * Implements foreground drawable before M and falls back to M's foreground implementation.
     27  * @hide
     28  */
     29 class 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 }