HeadersSupportFragment.java revision 729cbf4cd57c87bcd569db5974c8cbd51a942581
1/* This file is auto-generated from HeadersFragment.java.  DO NOT MODIFY. */
2
3/*
4 * Copyright (C) 2014 The Android Open Source Project
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7 * in compliance with the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software distributed under the License
12 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13 * or implied. See the License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17package android.support.v17.leanback.app;
18
19import android.content.Context;
20import android.graphics.Color;
21import android.graphics.drawable.ColorDrawable;
22import android.graphics.drawable.Drawable;
23import android.graphics.drawable.GradientDrawable;
24import android.os.Bundle;
25import android.support.v17.leanback.R;
26import android.support.v17.leanback.widget.FocusHighlightHelper;
27import android.support.v17.leanback.widget.ItemBridgeAdapter;
28import android.support.v17.leanback.widget.PresenterSelector;
29import android.support.v17.leanback.widget.OnItemViewSelectedListener;
30import android.support.v17.leanback.widget.Row;
31import android.support.v17.leanback.widget.RowHeaderPresenter;
32import android.support.v17.leanback.widget.SinglePresenterSelector;
33import android.support.v17.leanback.widget.VerticalGridView;
34import android.support.v7.widget.RecyclerView;
35import android.util.TypedValue;
36import android.view.View;
37import android.view.ViewGroup;
38import android.view.View.OnLayoutChangeListener;
39import android.widget.FrameLayout;
40
41/**
42 * An internal fragment containing a list of row headers.
43 */
44public class HeadersSupportFragment extends BaseRowSupportFragment {
45
46    /**
47     * Interface definition for a callback to be invoked when a header item is clicked.
48     */
49    public interface OnHeaderClickedListener {
50        /**
51         * Called when a header item has been clicked.
52         *
53         * @param viewHolder Row ViewHolder object corresponding to the selected Header.
54         * @param row Row object corresponding to the selected Header.
55         */
56        void onHeaderClicked(RowHeaderPresenter.ViewHolder viewHolder, Row row);
57    }
58
59    /**
60     * Interface definition for a callback to be invoked when a header item is selected.
61     */
62    public interface OnHeaderViewSelectedListener {
63        /**
64         * Called when a header item has been selected.
65         *
66         * @param viewHolder Row ViewHolder object corresponding to the selected Header.
67         * @param row Row object corresponding to the selected Header.
68         */
69        void onHeaderSelected(RowHeaderPresenter.ViewHolder viewHolder, Row row);
70    }
71
72    private OnHeaderViewSelectedListener mOnHeaderViewSelectedListener;
73    private OnHeaderClickedListener mOnHeaderClickedListener;
74    private boolean mHeadersEnabled = true;
75    private boolean mHeadersGone = false;
76    private int mBackgroundColor;
77    private boolean mBackgroundColorSet;
78
79    private static final PresenterSelector sHeaderPresenter = new SinglePresenterSelector(
80            new RowHeaderPresenter(R.layout.lb_header));
81
82    public HeadersSupportFragment() {
83        setPresenterSelector(sHeaderPresenter);
84    }
85
86    public void setOnHeaderClickedListener(OnHeaderClickedListener listener) {
87        mOnHeaderClickedListener = listener;
88    }
89
90    public void setOnHeaderViewSelectedListener(OnHeaderViewSelectedListener listener) {
91        mOnHeaderViewSelectedListener = listener;
92    }
93
94    @Override
95    VerticalGridView findGridViewFromRoot(View view) {
96        return (VerticalGridView) view.findViewById(R.id.browse_headers);
97    }
98
99    @Override
100    void onRowSelected(RecyclerView parent, RecyclerView.ViewHolder viewHolder,
101            int position, int subposition) {
102        if (mOnHeaderViewSelectedListener != null) {
103            if (viewHolder != null && position >= 0) {
104                ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder) viewHolder;
105                mOnHeaderViewSelectedListener.onHeaderSelected(
106                        (RowHeaderPresenter.ViewHolder) vh.getViewHolder(), (Row) vh.getItem());
107            } else {
108                mOnHeaderViewSelectedListener.onHeaderSelected(null, null);
109            }
110        }
111    }
112
113    private final ItemBridgeAdapter.AdapterListener mAdapterListener =
114            new ItemBridgeAdapter.AdapterListener() {
115        @Override
116        public void onCreate(final ItemBridgeAdapter.ViewHolder viewHolder) {
117            View headerView = viewHolder.getViewHolder().view;
118            headerView.setOnClickListener(new View.OnClickListener() {
119                @Override
120                public void onClick(View v) {
121                    if (mOnHeaderClickedListener != null) {
122                        mOnHeaderClickedListener.onHeaderClicked(
123                                (RowHeaderPresenter.ViewHolder) viewHolder.getViewHolder(),
124                                (Row) viewHolder.getItem());
125                    }
126                }
127            });
128            headerView.setFocusable(true);
129            headerView.setFocusableInTouchMode(true);
130            if (mWrapper != null) {
131                viewHolder.itemView.addOnLayoutChangeListener(sLayoutChangeListener);
132            } else {
133                headerView.addOnLayoutChangeListener(sLayoutChangeListener);
134            }
135        }
136
137    };
138
139    private static OnLayoutChangeListener sLayoutChangeListener = new OnLayoutChangeListener() {
140        @Override
141        public void onLayoutChange(View v, int left, int top, int right, int bottom,
142            int oldLeft, int oldTop, int oldRight, int oldBottom) {
143            v.setPivotX(v.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? v.getWidth() : 0);
144            v.setPivotY(v.getMeasuredHeight() / 2);
145        }
146    };
147
148    @Override
149    int getLayoutResourceId() {
150        return R.layout.lb_headers_fragment;
151    }
152
153    @Override
154    public void onViewCreated(View view, Bundle savedInstanceState) {
155        super.onViewCreated(view, savedInstanceState);
156        final VerticalGridView listView = getVerticalGridView();
157        if (listView == null) {
158            return;
159        }
160        if (getBridgeAdapter() != null) {
161            FocusHighlightHelper.setupHeaderItemFocusHighlight(listView);
162        }
163        if (mBackgroundColorSet) {
164            listView.setBackgroundColor(mBackgroundColor);
165            updateFadingEdgeToBrandColor(mBackgroundColor);
166        } else {
167            Drawable d = listView.getBackground();
168            if (d instanceof ColorDrawable) {
169                updateFadingEdgeToBrandColor(((ColorDrawable) d).getColor());
170            }
171        }
172        updateListViewVisibility();
173    }
174
175    private void updateListViewVisibility() {
176        final VerticalGridView listView = getVerticalGridView();
177        if (listView != null) {
178            getView().setVisibility(mHeadersGone ? View.GONE : View.VISIBLE);
179            if (!mHeadersGone) {
180                if (mHeadersEnabled) {
181                    listView.setChildrenVisibility(View.VISIBLE);
182                } else {
183                    listView.setChildrenVisibility(View.INVISIBLE);
184                }
185            }
186        }
187    }
188
189    void setHeadersEnabled(boolean enabled) {
190        mHeadersEnabled = enabled;
191        updateListViewVisibility();
192    }
193
194    void setHeadersGone(boolean gone) {
195        mHeadersGone = gone;
196        updateListViewVisibility();
197    }
198
199    static class NoOverlappingFrameLayout extends FrameLayout {
200
201        public NoOverlappingFrameLayout(Context context) {
202            super(context);
203        }
204
205        /**
206         * Avoid creating hardware layer for header dock.
207         */
208        @Override
209        public boolean hasOverlappingRendering() {
210            return false;
211        }
212    }
213
214    // Wrapper needed because of conflict between RecyclerView's use of alpha
215    // for ADD animations, and RowHeaderPresnter's use of alpha for selected level.
216    private final ItemBridgeAdapter.Wrapper mWrapper = new ItemBridgeAdapter.Wrapper() {
217        @Override
218        public void wrap(View wrapper, View wrapped) {
219            ((FrameLayout) wrapper).addView(wrapped);
220        }
221
222        @Override
223        public View createWrapper(View root) {
224            return new NoOverlappingFrameLayout(root.getContext());
225        }
226    };
227    @Override
228    void updateAdapter() {
229        super.updateAdapter();
230        ItemBridgeAdapter adapter = getBridgeAdapter();
231        if (adapter != null) {
232            adapter.setAdapterListener(mAdapterListener);
233            adapter.setWrapper(mWrapper);
234        }
235        if (adapter != null && getVerticalGridView() != null) {
236            FocusHighlightHelper.setupHeaderItemFocusHighlight(getVerticalGridView());
237        }
238    }
239
240    void setBackgroundColor(int color) {
241        mBackgroundColor = color;
242        mBackgroundColorSet = true;
243
244        if (getVerticalGridView() != null) {
245            getVerticalGridView().setBackgroundColor(mBackgroundColor);
246            updateFadingEdgeToBrandColor(mBackgroundColor);
247        }
248    }
249
250    private void updateFadingEdgeToBrandColor(int backgroundColor) {
251        View fadingView = getView().findViewById(R.id.fade_out_edge);
252        Drawable background = fadingView.getBackground();
253        if (background instanceof GradientDrawable) {
254            background.mutate();
255            ((GradientDrawable) background).setColors(
256                    new int[] {Color.TRANSPARENT, backgroundColor});
257        }
258    }
259
260    @Override
261    void onTransitionStart() {
262        super.onTransitionStart();
263        if (!mHeadersEnabled) {
264            // When enabling headers fragment,  the RowHeaderView gets a focus but
265            // isShown() is still false because its parent is INVSIBILE, accessibility
266            // event is not sent.
267            // Workaround is: prevent focus to a child view during transition and put
268            // focus on it after transition is done.
269            final VerticalGridView listView = getVerticalGridView();
270            if (listView != null) {
271                listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
272                if (listView.hasFocus()) {
273                    listView.requestFocus();
274                }
275            }
276        }
277    }
278
279    @Override
280    void onTransitionEnd() {
281        if (mHeadersEnabled) {
282            final VerticalGridView listView = getVerticalGridView();
283            if (listView != null) {
284                listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
285                if (listView.hasFocus()) {
286                    listView.requestFocus();
287                }
288            }
289        }
290        super.onTransitionEnd();
291    }
292}
293