NonOverlappingLinearLayoutWithForeground.java revision ac5fe7c617c66850fff75a9fce9979c6e5674b0f
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 androidx.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 */ 28class NonOverlappingLinearLayoutWithForeground extends LinearLayout { 29 30 private static final int VERSION_M = 23; 31 32 private Drawable mForeground; 33 private boolean mForegroundBoundsChanged; 34 private final Rect mSelfBounds = new Rect(); 35 36 public NonOverlappingLinearLayoutWithForeground(Context context) { 37 this(context, null); 38 } 39 40 public NonOverlappingLinearLayoutWithForeground(Context context, AttributeSet attrs) { 41 this(context, attrs, 0); 42 } 43 44 public NonOverlappingLinearLayoutWithForeground(Context context, AttributeSet attrs, 45 int defStyle) { 46 super(context, attrs, defStyle); 47 if (context.getApplicationInfo().targetSdkVersion >= VERSION_M 48 && VERSION.SDK_INT >= VERSION_M) { 49 // don't need do anything, base View constructor >=M already reads the foreground if 50 // targetSDK is >= M. 51 } else { 52 // in other cases, including M but targetSDK is less than M, we need setForeground in 53 // code. 54 TypedArray a = context.obtainStyledAttributes(attrs, 55 new int[] { android.R.attr.foreground }); 56 Drawable d = a.getDrawable(0); 57 if (d != null) { 58 setForegroundCompat(d); 59 } 60 a.recycle(); 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.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.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}