HeadersFragment.java revision 4cf79b1c4d38a190317961891f9fd052836710fd
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
174cf79b1c4d38a190317961891f9fd052836710fdCraig Stoutimport android.graphics.Color;
183c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Guimport android.os.Bundle;
1955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.support.v17.leanback.R;
2055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.support.v17.leanback.widget.FocusHighlightHelper;
2155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.support.v17.leanback.widget.ItemBridgeAdapter;
2255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.support.v17.leanback.widget.Presenter;
2355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.support.v17.leanback.widget.PresenterSelector;
2455c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.support.v17.leanback.widget.OnItemSelectedListener;
2555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.support.v17.leanback.widget.Row;
263c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Guimport android.support.v17.leanback.widget.RowHeaderPresenter;
27bd80644186ff8622c565f067dc3a4136a4dc0586Dake Guimport android.support.v17.leanback.widget.SinglePresenterSelector;
283c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Guimport android.support.v17.leanback.widget.VerticalGridView;
293c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Guimport android.support.v7.widget.RecyclerView;
304cf79b1c4d38a190317961891f9fd052836710fdCraig Stoutimport android.util.TypedValue;
313c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Guimport android.view.LayoutInflater;
3255c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.view.View;
3355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stoutimport android.view.ViewGroup;
342f97594742886d045ca1ce409ebc6e6e780452f6Dake Guimport android.view.View.OnLayoutChangeListener;
3555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
362f97594742886d045ca1ce409ebc6e6e780452f6Dake Guimport java.util.ArrayList;
373c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Guimport java.util.List;
383c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
3955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout/**
4055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout * An internal fragment containing a list of row headers.
4155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout */
42a8a3b898da49324e83ea32c3f08776a481312166Tim Kilbournpublic class HeadersFragment extends BaseRowFragment {
433c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
443c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    interface OnHeaderClickedListener {
453c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        void onHeaderClicked();
463c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    }
473c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
4855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    private OnItemSelectedListener mOnItemSelectedListener;
493c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    private OnHeaderClickedListener mOnHeaderClickedListener;
503c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    private boolean mShow = true;
514cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    private int mBackgroundColor;
524cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    private boolean mBackgroundColorSet;
533c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
54bd80644186ff8622c565f067dc3a4136a4dc0586Dake Gu    private static final PresenterSelector sHeaderPresenter = new SinglePresenterSelector(
55bd80644186ff8622c565f067dc3a4136a4dc0586Dake Gu            new RowHeaderPresenter());
5655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
57a8a3b898da49324e83ea32c3f08776a481312166Tim Kilbourn    public HeadersFragment() {
58bd80644186ff8622c565f067dc3a4136a4dc0586Dake Gu        setPresenterSelector(sHeaderPresenter);
5955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    }
6055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
613c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    public void setOnHeaderClickedListener(OnHeaderClickedListener listener) {
623c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        mOnHeaderClickedListener = listener;
6355c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    }
6455c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
6555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
6655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        mOnItemSelectedListener = listener;
6755c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    }
6855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
6955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    @Override
7055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    protected void onRowSelected(ViewGroup parent, View view, int position, long id) {
7155c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        if (mOnItemSelectedListener != null) {
722f5fbc79d656fc4966119141aaef48161f08376fAndrew Wilson            if (position >= 0) {
732f5fbc79d656fc4966119141aaef48161f08376fAndrew Wilson                Row row = (Row) getAdapter().get(position);
742f5fbc79d656fc4966119141aaef48161f08376fAndrew Wilson                mOnItemSelectedListener.onItemSelected(null, row);
752f5fbc79d656fc4966119141aaef48161f08376fAndrew Wilson            }
7655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        }
7755c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    }
7855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout
793c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    private final ItemBridgeAdapter.AdapterListener mAdapterListener =
803c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            new ItemBridgeAdapter.AdapterListener() {
813c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        @Override
823c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        public void onCreate(ItemBridgeAdapter.ViewHolder viewHolder) {
833c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            View headerView = viewHolder.getViewHolder().view;
843c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            headerView.setOnClickListener(new View.OnClickListener() {
853c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu                @Override
863c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu                public void onClick(View v) {
873c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu                    if (mOnHeaderClickedListener != null) {
883c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu                        mOnHeaderClickedListener.onHeaderClicked();
893c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu                    }
903c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu                }
913c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            });
923c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            headerView.setFocusable(true);
933c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            headerView.setFocusableInTouchMode(true);
942f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            headerView.addOnLayoutChangeListener(sLayoutChangeListener);
953c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        }
963c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
973c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        @Override
983c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
993c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            View headerView = viewHolder.getViewHolder().view;
1002f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            if (mInTransition) {
1012f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu                updateHeaderViewForTransition(headerView, viewHolder.getPosition());
1022f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            }
1033c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        }
1043c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    };
1053c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
1062f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    /**
1072f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu     * Preparing headerView for transition.
1082f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu     */
1092f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private void updateHeaderViewForTransition(View headerView, Integer position) {
1102f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        final VerticalGridView listView = getVerticalGridView();
1112f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        if (position == listView.getSelectedPosition()) {
1122f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            headerView.setId(mReparentHeaderId);
1132f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        } else {
1142f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            headerView.setId(View.NO_ID);
1153c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        }
1162f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        headerView.setTag(R.id.lb_header_transition_position, position);
1173c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    }
1183c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
1192f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    /**
1202f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu     * Preparing all headerViews for transition.
1212f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu     */
1222f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private void updateHeaderViewsForTransition() {
1233c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        final VerticalGridView listView = getVerticalGridView();
1243c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        if (listView == null) {
1253c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            return;
1263c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        }
1273c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        final int count = listView.getChildCount();
1283c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        for (int i = 0; i < count; i++) {
1293c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            View child = listView.getChildAt(i);
1302f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            updateHeaderViewForTransition(child,
1312f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu                    listView.getChildViewHolder(child).getPosition());
1322f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
1332f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
1342f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
1352f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    @Override
1362f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    void onTransitionStart() {
1372f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        super.onTransitionStart();
1382f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        updateHeaderViewsForTransition();
1392f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
1402f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
1412f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    private static OnLayoutChangeListener sLayoutChangeListener = new OnLayoutChangeListener() {
1422f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        @Override
1432f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        public void onLayoutChange(View v, int left, int top, int right, int bottom,
1442f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            int oldLeft, int oldTop, int oldRight, int oldBottom) {
1452f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            v.setPivotX(0);
1462f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            v.setPivotY(v.getMeasuredHeight() / 2);
1472f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        }
1482f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    };
1492f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
1502f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    @Override
1512f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    protected int getLayoutResourceId() {
1522f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        return R.layout.lb_headers_fragment;
1532f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    }
1542f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu
1552f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    @Override
1562f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu    public void onViewCreated(View view, Bundle savedInstanceState) {
1572f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        super.onViewCreated(view, savedInstanceState);
1584cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        final VerticalGridView listView = getVerticalGridView();
1594cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        if (listView == null) {
1604cf79b1c4d38a190317961891f9fd052836710fdCraig Stout            return;
1613c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        }
1624cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        if (getBridgeAdapter() != null) {
1634cf79b1c4d38a190317961891f9fd052836710fdCraig Stout            FocusHighlightHelper.setupHeaderItemFocusHighlight(listView);
1644cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        }
1654cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        listView.setBackgroundColor(getBackgroundColor());
1663c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    }
1673c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
1683c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    void setHeadersVisiblity(boolean show) {
1693c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        mShow = show;
1703c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        final VerticalGridView listView = getVerticalGridView();
1712f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu        if (listView != null) {
1722f97594742886d045ca1ce409ebc6e6e780452f6Dake Gu            listView.setLayoutEnabled(show);
1733c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        }
1743c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    }
1753c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu
1763c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu    @Override
17755c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    protected void updateAdapter() {
17855c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        super.updateAdapter();
17955c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        ItemBridgeAdapter adapter = getBridgeAdapter();
18055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        if (adapter != null) {
1813c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            adapter.setAdapterListener(mAdapterListener);
1823c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        }
1833c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu        if (adapter != null && getVerticalGridView() != null) {
1843c23ada8bc25a05bbaa8c479a9df72e8172c4349Dake Gu            FocusHighlightHelper.setupHeaderItemFocusHighlight(getVerticalGridView());
18555c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout        }
18655c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout    }
1874cf79b1c4d38a190317961891f9fd052836710fdCraig Stout
1884cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    void setBackgroundColor(int color) {
1894cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        mBackgroundColor = color;
1904cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        mBackgroundColorSet = true;
1914cf79b1c4d38a190317961891f9fd052836710fdCraig Stout
1924cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        if (getVerticalGridView() != null) {
1934cf79b1c4d38a190317961891f9fd052836710fdCraig Stout            getVerticalGridView().setBackgroundColor(mBackgroundColor);
1944cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        }
1954cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    }
1964cf79b1c4d38a190317961891f9fd052836710fdCraig Stout
1974cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    int getBackgroundColor() {
1984cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        if (getActivity() == null) {
1994cf79b1c4d38a190317961891f9fd052836710fdCraig Stout            throw new IllegalStateException("Activity must be attached");
2004cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        }
2014cf79b1c4d38a190317961891f9fd052836710fdCraig Stout
2024cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        if (mBackgroundColorSet) {
2034cf79b1c4d38a190317961891f9fd052836710fdCraig Stout            return mBackgroundColor;
2044cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        }
2054cf79b1c4d38a190317961891f9fd052836710fdCraig Stout
2064cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        TypedValue outValue = new TypedValue();
2074cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        getActivity().getTheme().resolveAttribute(android.R.attr.colorBackground, outValue, true);
2084cf79b1c4d38a190317961891f9fd052836710fdCraig Stout        return getResources().getColor(outValue.resourceId);
2094cf79b1c4d38a190317961891f9fd052836710fdCraig Stout    }
21055c9ee4b612ffc7b4632b1e4b7b7ab4900cd47c7Craig Stout}
211