1 /* 2 * Copyright (C) 2014 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 androidx.leanback.widget; 15 16 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; 17 18 import android.content.Context; 19 import android.util.AttributeSet; 20 import android.view.View; 21 import android.widget.LinearLayout; 22 23 import androidx.annotation.RestrictTo; 24 25 import java.util.ArrayList; 26 27 /** 28 * @hide 29 */ 30 @RestrictTo(LIBRARY_GROUP) 31 public class NonOverlappingLinearLayout extends LinearLayout { 32 33 boolean mFocusableViewAvailableFixEnabled = false; 34 boolean mDeferFocusableViewAvailableInLayout; 35 final ArrayList<ArrayList<View>> mSortedAvailableViews = new ArrayList(); 36 37 NonOverlappingLinearLayout(Context context)38 public NonOverlappingLinearLayout(Context context) { 39 this(context, null); 40 } 41 NonOverlappingLinearLayout(Context context, AttributeSet attrs)42 public NonOverlappingLinearLayout(Context context, AttributeSet attrs) { 43 this(context, attrs, 0); 44 } 45 NonOverlappingLinearLayout(Context context, AttributeSet attrs, int defStyle)46 public NonOverlappingLinearLayout(Context context, AttributeSet attrs, int defStyle) { 47 super(context, attrs, defStyle); 48 } 49 50 /** 51 * Avoids creating a hardware layer when animating alpha. 52 */ 53 @Override hasOverlappingRendering()54 public boolean hasOverlappingRendering() { 55 return false; 56 } 57 setFocusableViewAvailableFixEnabled(boolean enabled)58 public void setFocusableViewAvailableFixEnabled(boolean enabled) { 59 mFocusableViewAvailableFixEnabled = enabled; 60 } 61 62 @Override onLayout(boolean changed, int l, int t, int r, int b)63 protected void onLayout(boolean changed, int l, int t, int r, int b) { 64 try { 65 mDeferFocusableViewAvailableInLayout = mFocusableViewAvailableFixEnabled 66 && getOrientation() == HORIZONTAL 67 && getLayoutDirection() == LAYOUT_DIRECTION_RTL; 68 if (mDeferFocusableViewAvailableInLayout) { 69 while (mSortedAvailableViews.size() > getChildCount()) { 70 mSortedAvailableViews.remove(mSortedAvailableViews.size() - 1); 71 } 72 while (mSortedAvailableViews.size() < getChildCount()) { 73 mSortedAvailableViews.add(new ArrayList()); 74 } 75 } 76 super.onLayout(changed, l, t, r, b); 77 if (mDeferFocusableViewAvailableInLayout) { 78 for (int i = 0; i < mSortedAvailableViews.size(); i++) { 79 for (int j = 0; j < mSortedAvailableViews.get(i).size(); j++) { 80 super.focusableViewAvailable(mSortedAvailableViews.get(i).get(j)); 81 } 82 } 83 } 84 } finally { 85 if (mDeferFocusableViewAvailableInLayout) { 86 mDeferFocusableViewAvailableInLayout = false; 87 for (int i = 0; i < mSortedAvailableViews.size(); i++) { 88 mSortedAvailableViews.get(i).clear(); 89 } 90 } 91 } 92 } 93 94 @Override focusableViewAvailable(View v)95 public void focusableViewAvailable(View v) { 96 if (mDeferFocusableViewAvailableInLayout) { 97 View i = v; 98 int index = -1; 99 while (i != this && i != null) { 100 if (i.getParent() == this) { 101 index = indexOfChild(i); 102 break; 103 } 104 i = (View) i.getParent(); 105 } 106 if (index != -1) { 107 mSortedAvailableViews.get(index).add(v); 108 } 109 } else { 110 super.focusableViewAvailable(v); 111 } 112 } 113 }