NonOverlappingLinearLayoutWithForeground.java revision c39d9c75590eca86a5e7e32a8824ba04a0d42e9b
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.support.annotation.RestrictTo; 23import android.util.AttributeSet; 24import android.widget.LinearLayout; 25 26import static android.support.annotation.RestrictTo.Scope.GROUP_ID; 27 28/** 29 * Implements foreground drawable before M and falls back to M's foreground implementation. 30 */ 31class NonOverlappingLinearLayoutWithForeground extends LinearLayout { 32 33 private static final int VERSION_M = 23; 34 35 private Drawable mForeground; 36 private boolean mForegroundBoundsChanged; 37 private final Rect mSelfBounds = new Rect(); 38 39 public NonOverlappingLinearLayoutWithForeground(Context context) { 40 this(context, null); 41 } 42 43 public NonOverlappingLinearLayoutWithForeground(Context context, AttributeSet attrs) { 44 this(context, attrs, 0); 45 } 46 47 public NonOverlappingLinearLayoutWithForeground(Context context, AttributeSet attrs, 48 int defStyle) { 49 super(context, attrs, defStyle); 50 if (context.getApplicationInfo().targetSdkVersion >= VERSION_M 51 && VERSION.SDK_INT >= VERSION_M) { 52 // don't need do anything, base View constructor >=M already reads the foreground if 53 // targetSDK is >= M. 54 } else { 55 // in other cases, including M but targetSDK is less than M, we need setForeground in 56 // code. 57 TypedArray a = context.obtainStyledAttributes(attrs, 58 new int[] { android.R.attr.foreground }); 59 Drawable d = a.getDrawable(0); 60 if (d != null) { 61 setForegroundCompat(d); 62 } 63 } 64 } 65 66 public void setForegroundCompat(Drawable d) { 67 if (VERSION.SDK_INT >= VERSION_M) { 68 // From M, foreground is naturally supported. 69 ForegroundHelper.getInstance().setForeground(this, d); 70 } else { 71 // before M, do our own customized foreground draw. 72 if (mForeground != d) { 73 mForeground = d; 74 mForegroundBoundsChanged = true; 75 setWillNotDraw(false); 76 mForeground.setCallback(this); 77 if (mForeground.isStateful()) { 78 mForeground.setState(getDrawableState()); 79 } 80 } 81 } 82 } 83 84 public Drawable getForegroundCompat() { 85 if (VERSION.SDK_INT >= VERSION_M) { 86 return ForegroundHelper.getInstance().getForeground(this); 87 } else { 88 return mForeground; 89 } 90 } 91 92 @Override 93 public void draw(Canvas canvas) { 94 super.draw(canvas); 95 if (mForeground != null) { 96 final Drawable foreground = mForeground; 97 if (mForegroundBoundsChanged) { 98 mForegroundBoundsChanged = false; 99 final Rect selfBounds = mSelfBounds; 100 final int w = getRight() - getLeft(); 101 final int h = getBottom() - getTop(); 102 selfBounds.set(0, 0, w, h); 103 foreground.setBounds(selfBounds); 104 } 105 foreground.draw(canvas); 106 } 107 } 108 109 @Override 110 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 111 super.onLayout(changed, left, top, right, bottom); 112 mForegroundBoundsChanged |= changed; 113 } 114 115 @Override 116 protected boolean verifyDrawable(Drawable who) { 117 return super.verifyDrawable(who) || (who == mForeground); 118 } 119 120 @Override 121 public void jumpDrawablesToCurrentState() { 122 super.jumpDrawablesToCurrentState(); 123 if (mForeground != null) { 124 mForeground.jumpToCurrentState(); 125 } 126 } 127 128 @Override 129 protected void drawableStateChanged() { 130 super.drawableStateChanged(); 131 if (mForeground != null && mForeground.isStateful()) { 132 mForeground.setState(getDrawableState()); 133 } 134 } 135 136 /** 137 * Avoids creating a hardware layer when animating alpha. 138 */ 139 @Override 140 public boolean hasOverlappingRendering() { 141 return false; 142 } 143}