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}