1816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko/* 2816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Copyright (C) 2015 The Android Open Source Project 3816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 4816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License"); 5816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * you may not use this file except in compliance with the License. 6816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * You may obtain a copy of the License at 7816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 8816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * http://www.apache.org/licenses/LICENSE-2.0 9816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 10816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Unless required by applicable law or agreed to in writing, software 11816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS, 12816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * See the License for the specific language governing permissions and 14816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * limitations under the License. 15816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 16816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 17ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkerstenpackage com.android.tv.ui.sidepanel; 18ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 19ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkerstenimport android.app.Fragment; 20816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.content.Context; 21816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.graphics.drawable.RippleDrawable; 22ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkerstenimport android.os.Bundle; 23ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkerstenimport android.support.v17.leanback.widget.VerticalGridView; 24ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkerstenimport android.support.v7.widget.RecyclerView; 25816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.KeyEvent; 26ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkerstenimport android.view.LayoutInflater; 27ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkerstenimport android.view.View; 28ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkerstenimport android.view.ViewGroup; 296ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport android.widget.FrameLayout; 30ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkerstenimport android.widget.TextView; 31ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 32816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.MainActivity; 33ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkerstenimport com.android.tv.R; 34816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.TvApplication; 356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.android.tv.util.DurationTimer; 36816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.analytics.HasTrackerLabel; 37816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.analytics.Tracker; 38816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.data.ChannelDataManager; 39816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.data.ProgramDataManager; 40816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.util.SystemProperties; 416ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.android.tv.util.ViewCache; 42ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 43ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkerstenimport java.util.List; 44ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 456ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkopublic abstract class SideFragment<T extends Item> extends Fragment implements HasTrackerLabel { 46816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public static final int INVALID_POSITION = -1; 47816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 486ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private static final int PRELOAD_VIEW_SIZE = 7; 496ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private static final int[] PRELOAD_VIEW_IDS = { 50816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.layout.option_item_radio_button, 51816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.layout.option_item_channel_lock, 52816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko R.layout.option_item_check_box, 536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko R.layout.option_item_channel_check, 546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko R.layout.option_item_action 55816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko }; 56816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 576ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private static RecyclerView.RecycledViewPool sRecycledViewPool = 586ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko new RecyclerView.RecycledViewPool(); 59816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 60816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private VerticalGridView mListView; 61816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private ItemAdapter mAdapter; 62816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private SideFragmentListener mListener; 63816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private ChannelDataManager mChannelDataManager; 64816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private ProgramDataManager mProgramDataManager; 65816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private Tracker mTracker; 66816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final DurationTimer mSidePanelDurationTimer = new DurationTimer(); 67816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 68816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final int mHideKey; 69816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final int mDebugHideKey; 70816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 71816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public SideFragment() { 72816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko this(KeyEvent.KEYCODE_UNKNOWN, KeyEvent.KEYCODE_UNKNOWN); 73816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 74816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 75816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 76816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * @param hideKey the KeyCode used to hide the fragment 77816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * @param debugHideKey the KeyCode used to hide the fragment if 78816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * {@link SystemProperties#USE_DEBUG_KEYS}. 79816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 80816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public SideFragment(int hideKey, int debugHideKey) { 81816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mHideKey = hideKey; 82816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mDebugHideKey = debugHideKey; 83816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 84816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 85816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 8665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public void onAttach(Context context) { 8765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko super.onAttach(context); 88816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelDataManager = getMainActivity().getChannelDataManager(); 89816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramDataManager = getMainActivity().getProgramDataManager(); 9065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mTracker = TvApplication.getSingletons(context).getTracker(); 91816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 92ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 93ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten @Override 94ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten public View onCreateView(LayoutInflater inflater, ViewGroup container, 95ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten Bundle savedInstanceState) { 966ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko View view = ViewCache.getInstance().getOrCreateView( 976ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko inflater, getFragmentLayoutResourceId(), container); 98ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 99ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten TextView textView = (TextView) view.findViewById(R.id.side_panel_title); 100ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten textView.setText(getTitle()); 101ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 102816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListView = (VerticalGridView) view.findViewById(R.id.side_panel_list); 103816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListView.setRecycledViewPool(sRecycledViewPool); 104ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 105816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mAdapter = new ItemAdapter(inflater, getItemList()); 106816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListView.setAdapter(mAdapter); 107816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListView.requestFocus(); 108ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 109ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten return view; 110ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 111ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 112ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten @Override 113816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onResume() { 114816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko super.onResume(); 115816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendShowSidePanel(this); 116816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendScreenView(this.getTrackerLabel()); 117816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSidePanelDurationTimer.start(); 118816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 119816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 120816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 121816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onPause() { 122816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker.sendHideSidePanel(this, mSidePanelDurationTimer.reset()); 123816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko super.onPause(); 124816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 125816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 126816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 127ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten public void onDetach() { 128816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTracker = null; 129ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten super.onDetach(); 130816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 131816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 132816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public final boolean isHideKeyForThisPanel(int keyCode) { 133816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko boolean debugKeysEnabled = SystemProperties.USE_DEBUG_KEYS.getValue(); 134816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return mHideKey != KeyEvent.KEYCODE_UNKNOWN && 135816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko (mHideKey == keyCode || (debugKeysEnabled && mDebugHideKey == keyCode)); 136816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 137ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 138816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 139816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onDestroyView() { 140816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko super.onDestroyView(); 141816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListView.swapAdapter(null, true); 142816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mListener != null) { 143816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListener.onSideFragmentViewDestroyed(); 144ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 145ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 146ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 147816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public final void setListener(SideFragmentListener listener) { 148816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListener = listener; 149816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 150816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 151816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected void setSelectedPosition(int position) { 152816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListView.setSelectedPosition(position); 153816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 154816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 155816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected int getSelectedPosition() { 156816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return mListView.getSelectedPosition(); 157816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 158816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 1596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void setItems(List<T> items) { 160816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mAdapter.reset(items); 161816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 162816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 163816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected void closeFragment() { 164816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko getMainActivity().getOverlayManager().getSideFragmentManager().popSideFragment(); 165816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 166816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 167816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected MainActivity getMainActivity() { 168816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return (MainActivity) getActivity(); 169816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 170816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 171816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected ChannelDataManager getChannelDataManager() { 172816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return mChannelDataManager; 173816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 174816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 175816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected ProgramDataManager getProgramDataManager() { 176816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return mProgramDataManager; 177ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 178ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 179ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten protected void notifyDataSetChanged() { 180816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mAdapter.notifyDataSetChanged(); 181816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 182816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 183816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /* 184816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * HACK: The following methods bypass the updating mechanism of RecyclerView.Adapter and 185816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * directly updates each item. This works around a bug in the base libraries where calling 186816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Adapter.notifyItemsChanged() causes the VerticalGridView to lose track of displayed item 187816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * position. 188816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 189816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 190816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected void notifyItemChanged(int position) { 191816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko notifyItemChanged(mAdapter.getItem(position)); 192816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 193816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 194816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected void notifyItemChanged(Item item) { 195816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko item.notifyUpdated(); 196816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 197816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 198816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 199816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Notifies all items of ItemAdapter has changed without structural changes. 200816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 201816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected void notifyItemsChanged() { 202816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko notifyItemsChanged(0, mAdapter.getItemCount()); 203816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 204816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 205816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 206816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Notifies some items of ItemAdapter has changed starting from position 207816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * <code>positionStart</code> to the end without structural changes. 208816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 209816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected void notifyItemsChanged(int positionStart) { 210816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko notifyItemsChanged(positionStart, mAdapter.getItemCount() - positionStart); 211816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 212816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 213816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected void notifyItemsChanged(int positionStart, int itemCount) { 214816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko while (itemCount-- != 0) { 215816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko notifyItemChanged(positionStart++); 216816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 217816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 218816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 219816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /* 220816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * END HACK 221816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 222816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 223816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected int getFragmentLayoutResourceId() { 224816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return R.layout.option_fragment; 225ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 226ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 227ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten protected abstract String getTitle(); 228816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 229816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public abstract String getTrackerLabel(); 2306ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko protected abstract List<T> getItemList(); 231ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 232816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public interface SideFragmentListener { 233816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko void onSideFragmentViewDestroyed(); 234816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 235816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 236d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko /** 2376ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Preloads the item views. 238d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko */ 2396ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public static void preloadItemViews(Context context) { 2406ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko ViewCache.getInstance().putView( 2416ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko context, R.layout.option_fragment, new FrameLayout(context), 1); 2426ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko VerticalGridView fakeParent = new VerticalGridView(context); 2436ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko for (int id : PRELOAD_VIEW_IDS) { 2446ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko sRecycledViewPool.setMaxRecycledViews(id, PRELOAD_VIEW_SIZE); 2456ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko ViewCache.getInstance().putView(context, id, fakeParent, PRELOAD_VIEW_SIZE); 246816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 247816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 248816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 249d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko /** 2506ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Releases the recycled view pool. 251d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko */ 2526ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public static void releaseRecycledViewPool() { 2536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko sRecycledViewPool.clear(); 254d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko } 255d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko 2566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private static class ItemAdapter<T extends Item> extends RecyclerView.Adapter<ViewHolder> { 257ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten private final LayoutInflater mLayoutInflater; 2586ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private List<T> mItems; 259ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 2606ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private ItemAdapter(LayoutInflater layoutInflater, List<T> items) { 261ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten mLayoutInflater = layoutInflater; 262ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten mItems = items; 263ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 264ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 2656ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private void reset(List<T> items) { 266816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mItems = items; 267816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko notifyDataSetChanged(); 268816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 269816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 270ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten @Override 271ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 2726ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko View view = ViewCache.getInstance().getOrCreateView(mLayoutInflater, viewType, parent); 2736ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko return new ViewHolder(view); 274ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 275ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 276ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten @Override 277ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten public void onBindViewHolder(ViewHolder holder, int position) { 278816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko holder.onBind(this, getItem(position)); 279ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 280ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 281ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten @Override 282ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten public void onViewRecycled(ViewHolder holder) { 283816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko holder.onUnbind(); 284ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 285ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 286ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten @Override 287ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten public int getItemViewType(int position) { 288ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten return getItem(position).getResourceId(); 289ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 290ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 291ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten @Override 292ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten public int getItemCount() { 293ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten return mItems == null ? 0 : mItems.size(); 294ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 295ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 2966ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private T getItem(int position) { 297ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten return mItems.get(position); 298ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 299ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 3006ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private void clearRadioGroup(T item) { 301ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten int position = mItems.indexOf(item); 302ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten for (int i = position - 1; i >= 0; --i) { 303ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten if ((item = mItems.get(i)) instanceof RadioButtonItem) { 304ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten ((RadioButtonItem) item).setChecked(false); 305ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } else { 306ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten break; 307ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 308ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 309ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten for (int i = position + 1; i < mItems.size(); ++i) { 310ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten if ((item = mItems.get(i)) instanceof RadioButtonItem) { 311ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten ((RadioButtonItem) item).setChecked(false); 312ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } else { 313ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten break; 314ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 315ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 316ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 3176ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 318ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 3196ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private static class ViewHolder extends RecyclerView.ViewHolder 3206ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko implements View.OnClickListener, View.OnFocusChangeListener { 3216ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private ItemAdapter mAdapter; 3226ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public Item mItem; 323ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten 3246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private ViewHolder(View view) { 3256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko super(view); 3266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko itemView.setOnClickListener(this); 3276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko itemView.setOnFocusChangeListener(this); 3286ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 329816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 3306ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void onBind(ItemAdapter adapter, Item item) { 3316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mAdapter = adapter; 3326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mItem = item; 3336ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mItem.onBind(itemView); 3346ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mItem.onUpdate(); 3356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 336816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 3376ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void onUnbind() { 3386ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mItem.onUnbind(); 3396ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mItem = null; 3406ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mAdapter = null; 3416ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 342816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 3436ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko @Override 3446ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void onClick(View view) { 3456ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (mItem instanceof RadioButtonItem) { 3466ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mAdapter.clearRadioGroup(mItem); 3476ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 3486ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (view.getBackground() instanceof RippleDrawable) { 3496ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko view.postDelayed( 3506ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko new Runnable() { 3516ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko @Override 3526ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void run() { 3536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (mItem != null) { 3546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mItem.onSelected(); 3556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 356816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 3576ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko }, 3586ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko view.getResources().getInteger(R.integer.side_panel_ripple_anim_duration)); 3596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } else { 3606ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mItem.onSelected(); 361816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 3626ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 363816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 3646ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko @Override 3656ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void onFocusChange(View view, boolean focusGained) { 3666ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (focusGained) { 3676ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mItem.onFocused(); 368ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 369ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 370ad8bb145f00812459b96e54fdaad36f3a7a3612cChristofer Åkersten } 371816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko} 372