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 android.content.Context;
17 import android.graphics.Rect;
18 import android.util.AttributeSet;
19 import android.view.View;
20 import android.view.ViewGroup;
21 import android.widget.LinearLayout;
22 
23 import java.util.ArrayList;
24 
25 class ControlBar extends LinearLayout {
26 
27     public interface OnChildFocusedListener {
onChildFocusedListener(View child, View focused)28         public void onChildFocusedListener(View child, View focused);
29     }
30 
31     private int mChildMarginFromCenter;
32     private OnChildFocusedListener mOnChildFocusedListener;
33     int mLastFocusIndex = -1;
34     boolean mDefaultFocusToMiddle = true;
35 
ControlBar(Context context, AttributeSet attrs)36     public ControlBar(Context context, AttributeSet attrs) {
37         super(context, attrs);
38     }
39 
ControlBar(Context context, AttributeSet attrs, int defStyle)40     public ControlBar(Context context, AttributeSet attrs, int defStyle) {
41         super(context, attrs, defStyle);
42     }
43 
setDefaultFocusToMiddle(boolean defaultFocusToMiddle)44     void setDefaultFocusToMiddle(boolean defaultFocusToMiddle) {
45         mDefaultFocusToMiddle = defaultFocusToMiddle;
46     }
47 
getDefaultFocusIndex()48     int getDefaultFocusIndex() {
49         return mDefaultFocusToMiddle ? getChildCount() / 2 : 0;
50     }
51 
52     @Override
onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect)53     protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
54         if (getChildCount() > 0) {
55             int index = mLastFocusIndex >= 0 && mLastFocusIndex < getChildCount()
56                     ? mLastFocusIndex : getDefaultFocusIndex();
57             if (getChildAt(index).requestFocus(direction, previouslyFocusedRect)) {
58                 return true;
59             }
60         }
61         return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
62     }
63 
64     @Override
65     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
66         if ((direction == ViewGroup.FOCUS_UP || direction == ViewGroup.FOCUS_DOWN)) {
67             if (mLastFocusIndex >= 0 && mLastFocusIndex < getChildCount()) {
68                 views.add(getChildAt(mLastFocusIndex));
69             } else if (getChildCount() > 0) {
70                 views.add(getChildAt(getDefaultFocusIndex()));
71             }
72         } else {
73             super.addFocusables(views, direction, focusableMode);
74         }
75     }
76 
77     public void setOnChildFocusedListener(OnChildFocusedListener listener) {
78         mOnChildFocusedListener = listener;
79     }
80 
81     public void setChildMarginFromCenter(int marginFromCenter) {
82         mChildMarginFromCenter = marginFromCenter;
83     }
84 
85     @Override
86     public void requestChildFocus (View child, View focused) {
87         super.requestChildFocus(child, focused);
88         mLastFocusIndex = indexOfChild(child);
89         if (mOnChildFocusedListener != null) {
90             mOnChildFocusedListener.onChildFocusedListener(child, focused);
91         }
92     }
93 
94     @Override
95     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
96         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
97         if (mChildMarginFromCenter <= 0) {
98             return;
99         }
100 
101         int totalExtraMargin = 0;
102         for (int i = 0; i < getChildCount() - 1; i++) {
103             View first = getChildAt(i);
104             View second = getChildAt(i+1);
105             int measuredWidth = first.getMeasuredWidth() + second.getMeasuredWidth();
106             int marginStart = mChildMarginFromCenter - measuredWidth / 2;
107             LayoutParams lp = (LayoutParams) second.getLayoutParams();
108             int extraMargin = marginStart - lp.getMarginStart();
109             lp.setMarginStart(marginStart);
110             second.setLayoutParams(lp);
111             totalExtraMargin += extraMargin;
112         }
113         setMeasuredDimension(getMeasuredWidth() + totalExtraMargin, getMeasuredHeight());
114     }
115 }
116