HeadersFragment.java revision e51474af2c4b5192a75fd283cb737d02fccc58a4
155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout/*
255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout * Copyright (C) 2014 The Android Open Source Project
355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout *
455c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout * in compliance with the License. You may obtain a copy of the License at
655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout *
755c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout * http://www.apache.org/licenses/LICENSE-2.0
855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout *
955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout * Unless required by applicable law or agreed to in writing, software distributed under the License
1055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
1155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout * or implied. See the License for the specific language governing permissions and limitations under
1255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout * the License.
1355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout */
1455c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
1555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutpackage android.support.v17.leanback.app;
1655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
173c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Guimport android.os.Bundle;
1855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.support.v17.leanback.R;
1955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.support.v17.leanback.widget.FocusHighlightHelper;
2055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.support.v17.leanback.widget.ItemBridgeAdapter;
2155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.support.v17.leanback.widget.PresenterSelector;
2255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.support.v17.leanback.widget.OnItemSelectedListener;
2355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.support.v17.leanback.widget.Row;
243c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Guimport android.support.v17.leanback.widget.RowHeaderPresenter;
25bd80644186ff8622c565f067dc3a4136a4dc0586Dake Guimport android.support.v17.leanback.widget.SinglePresenterSelector;
263c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Guimport android.support.v17.leanback.widget.VerticalGridView;
274cf79b1c4d38a190317961891f9fd052836710fdCraig Stoutimport android.util.TypedValue;
2855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.view.View;
2955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.view.ViewGroup;
302f97594742886d045ca1ce409ebc6e6e780452f6Dake Guimport android.view.View.OnLayoutChangeListener;
31e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stoutimport android.widget.FrameLayout;
3255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
3355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout/**
3455c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout * An internal fragment containing a list of row headers.
3555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout */
36a8a3b898da49324e83ea32c3f08776a481312166Tim Kilbournpublic class HeadersFragment extends BaseRowFragment {
373c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
383c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    interface OnHeaderClickedListener {
393c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        void onHeaderClicked();
403c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    }
413c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
4255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    private OnItemSelectedListener mOnItemSelectedListener;
433c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    private OnHeaderClickedListener mOnHeaderClickedListener;
44d559710c8763acb37fd444735da7ee770b84df07Craig Stout    private boolean mHeadersEnabled = true;
45d559710c8763acb37fd444735da7ee770b84df07Craig Stout    private boolean mHeadersGone = false;
464cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    private int mBackgroundColor;
474cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    private boolean mBackgroundColorSet;
483c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
49bd80644186ff8622c565f067dc3a4136a4dc0586Dake Gu    private static final PresenterSelector sHeaderPresenter = new SinglePresenterSelector(
50268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout            new RowHeaderPresenter(R.layout.lb_header));
5155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
52a8a3b898da49324e83ea32c3f08776a481312166Tim Kilbourn    public HeadersFragment() {
53bd80644186ff8622c565f067dc3a4136a4dc0586Dake Gu        setPresenterSelector(sHeaderPresenter);
5455c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    }
5555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
563c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    public void setOnHeaderClickedListener(OnHeaderClickedListener listener) {
573c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        mOnHeaderClickedListener = listener;
5855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    }
5955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
6055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
6155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        mOnItemSelectedListener = listener;
6255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    }
6355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
6455c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    @Override
6555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    protected void onRowSelected(ViewGroup parent, View view, int position, long id) {
6655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        if (mOnItemSelectedListener != null) {
672f5fbc79d656fc4966119141aaef48161f08376fAndrew Wilson            if (position >= 0) {
682f5fbc79d656fc4966119141aaef48161f08376fAndrew Wilson                Row row = (Row) getAdapter().get(position);
692f5fbc79d656fc4966119141aaef48161f08376fAndrew Wilson                mOnItemSelectedListener.onItemSelected(null, row);
70d736653bfee7fc83fc68d57d0e0bee5fa807287fDake Gu            } else {
71d736653bfee7fc83fc68d57d0e0bee5fa807287fDake Gu                mOnItemSelectedListener.onItemSelected(null, null);
722f5fbc79d656fc4966119141aaef48161f08376fAndrew Wilson            }
7355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        }
7455c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    }
7555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
763c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    private final ItemBridgeAdapter.AdapterListener mAdapterListener =
773c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            new ItemBridgeAdapter.AdapterListener() {
783c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        @Override
793c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        public void onCreate(ItemBridgeAdapter.ViewHolder viewHolder) {
803c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            View headerView = viewHolder.getViewHolder().view;
813c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            headerView.setOnClickListener(new View.OnClickListener() {
823c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu                @Override
833c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu                public void onClick(View v) {
843c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu                    if (mOnHeaderClickedListener != null) {
853c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu                        mOnHeaderClickedListener.onHeaderClicked();
863c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu                    }
873c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu                }
883c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            });
893c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            headerView.setFocusable(true);
903c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            headerView.setFocusableInTouchMode(true);
91e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout            if (mWrapper != null) {
92e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout                viewHolder.itemView.addOnLayoutChangeListener(sLayoutChangeListener);
93e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout            } else {
94e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout                headerView.addOnLayoutChangeListener(sLayoutChangeListener);
95e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout            }
963c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        }
973c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
983c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    };
993c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
1002f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private static OnLayoutChangeListener sLayoutChangeListener = new OnLayoutChangeListener() {
1012f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
1022f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        public void onLayoutChange(View v, int left, int top, int right, int bottom,
1032f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            int oldLeft, int oldTop, int oldRight, int oldBottom) {
1042f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            v.setPivotX(0);
1052f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            v.setPivotY(v.getMeasuredHeight() / 2);
1062f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
1072f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    };
1082f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
1092f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    @Override
1102f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    protected int getLayoutResourceId() {
1112f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        return R.layout.lb_headers_fragment;
1122f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
1132f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
1142f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    @Override
1152f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    public void onViewCreated(View view, Bundle savedInstanceState) {
1162f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        super.onViewCreated(view, savedInstanceState);
1174cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        final VerticalGridView listView = getVerticalGridView();
1184cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        if (listView == null) {
1194cf79b1c4d38a190317961891f9fd052836710fdCraig Stout            return;
1203c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        }
1214cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        if (getBridgeAdapter() != null) {
1224cf79b1c4d38a190317961891f9fd052836710fdCraig Stout            FocusHighlightHelper.setupHeaderItemFocusHighlight(listView);
1234cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        }
1244cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        listView.setBackgroundColor(getBackgroundColor());
125d559710c8763acb37fd444735da7ee770b84df07Craig Stout        listView.setVisibility(mHeadersGone ? View.GONE : View.VISIBLE);
126d559710c8763acb37fd444735da7ee770b84df07Craig Stout        listView.setLayoutEnabled(mHeadersEnabled);
1273c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    }
1283c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
129d559710c8763acb37fd444735da7ee770b84df07Craig Stout    void setHeadersEnabled(boolean enabled) {
130d559710c8763acb37fd444735da7ee770b84df07Craig Stout        mHeadersEnabled = enabled;
1313c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        final VerticalGridView listView = getVerticalGridView();
1322f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        if (listView != null) {
133d559710c8763acb37fd444735da7ee770b84df07Craig Stout            listView.setLayoutEnabled(mHeadersEnabled);
134d559710c8763acb37fd444735da7ee770b84df07Craig Stout        }
135d559710c8763acb37fd444735da7ee770b84df07Craig Stout    }
136d559710c8763acb37fd444735da7ee770b84df07Craig Stout
137d559710c8763acb37fd444735da7ee770b84df07Craig Stout    void setHeadersGone(boolean gone) {
138d559710c8763acb37fd444735da7ee770b84df07Craig Stout        mHeadersGone = gone;
139d559710c8763acb37fd444735da7ee770b84df07Craig Stout        final VerticalGridView listView = getVerticalGridView();
140d559710c8763acb37fd444735da7ee770b84df07Craig Stout        if (listView != null) {
141d559710c8763acb37fd444735da7ee770b84df07Craig Stout            listView.setVisibility(mHeadersGone ? View.GONE : View.VISIBLE);
1423c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        }
1433c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    }
1443c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
145e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout    // Wrapper needed because of conflict between RecyclerView's use of alpha
146e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout    // for ADD animations, and RowHeaderPresnter's use of alpha for selected level.
147e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout    private final ItemBridgeAdapter.Wrapper mWrapper = new ItemBridgeAdapter.Wrapper() {
148e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout        @Override
149e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout        public void wrap(View wrapper, View wrapped) {
150e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout            ((FrameLayout) wrapper).addView(wrapped);
151e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout        }
152e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout
153e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout        @Override
154e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout        public View createWrapper(View root) {
155e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout            return new FrameLayout(root.getContext());
156e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout        }
157e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout    };
1583c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    @Override
15955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    protected void updateAdapter() {
16055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        super.updateAdapter();
16155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        ItemBridgeAdapter adapter = getBridgeAdapter();
16255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        if (adapter != null) {
1633c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            adapter.setAdapterListener(mAdapterListener);
164e51474af2c4b5192a75fd283cb737d02fccc58a4Craig Stout            adapter.setWrapper(mWrapper);
1653c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        }
1663c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        if (adapter != null && getVerticalGridView() != null) {
1673c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            FocusHighlightHelper.setupHeaderItemFocusHighlight(getVerticalGridView());
16855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        }
16955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    }
1704cf79b1c4d38a190317961891f9fd052836710fdCraig Stout
1714cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    void setBackgroundColor(int color) {
1724cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        mBackgroundColor = color;
1734cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        mBackgroundColorSet = true;
1744cf79b1c4d38a190317961891f9fd052836710fdCraig Stout
1754cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        if (getVerticalGridView() != null) {
1764cf79b1c4d38a190317961891f9fd052836710fdCraig Stout            getVerticalGridView().setBackgroundColor(mBackgroundColor);
1774cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        }
1784cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    }
1794cf79b1c4d38a190317961891f9fd052836710fdCraig Stout
1804cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    int getBackgroundColor() {
1814cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        if (getActivity() == null) {
1824cf79b1c4d38a190317961891f9fd052836710fdCraig Stout            throw new IllegalStateException("Activity must be attached");
1834cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        }
1844cf79b1c4d38a190317961891f9fd052836710fdCraig Stout
1854cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        if (mBackgroundColorSet) {
1864cf79b1c4d38a190317961891f9fd052836710fdCraig Stout            return mBackgroundColor;
1874cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        }
1884cf79b1c4d38a190317961891f9fd052836710fdCraig Stout
1894cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        TypedValue outValue = new TypedValue();
190056561d81012983d2d27b8665c4aeabb427174cbTim Kilbourn        getActivity().getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true);
1914cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        return getResources().getColor(outValue.resourceId);
1924cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    }
19355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout}
194