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