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 }