• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tv.menu;
18 
19 import android.content.Context;
20 import android.support.v17.leanback.widget.HorizontalGridView;
21 import android.support.v17.leanback.widget.OnChildSelectedListener;
22 import android.support.v7.widget.RecyclerView;
23 import android.util.AttributeSet;
24 import android.util.Log;
25 import android.view.LayoutInflater;
26 import android.view.View;
27 import android.view.ViewGroup;
28 
29 import com.android.tv.MainActivity;
30 import com.android.tv.R;
31 import com.android.tv.util.ViewCache;
32 
33 import java.util.Collections;
34 import java.util.List;
35 
36 /**
37  * A view that shows a title and list view.
38  */
39 public class ItemListRowView extends MenuRowView implements OnChildSelectedListener {
40     private static final String TAG = MenuView.TAG;
41     private static final boolean DEBUG = MenuView.DEBUG;
42 
43     public interface CardView<T> {
onBind(T row, boolean selected)44         void onBind(T row, boolean selected);
onRecycled()45         void onRecycled();
onSelected()46         void onSelected();
onDeselected()47         void onDeselected();
48     }
49 
50     private HorizontalGridView mListView;
51     private CardView<?> mSelectedCard;
52 
ItemListRowView(Context context)53     public ItemListRowView(Context context) {
54         this(context, null);
55     }
56 
ItemListRowView(Context context, AttributeSet attrs)57     public ItemListRowView(Context context, AttributeSet attrs) {
58         this(context, attrs, 0);
59     }
60 
ItemListRowView(Context context, AttributeSet attrs, int defStyle)61     public ItemListRowView(Context context, AttributeSet attrs, int defStyle) {
62         this(context, attrs, defStyle, 0);
63     }
64 
ItemListRowView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)65     public ItemListRowView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
66         super(context, attrs, defStyleAttr, defStyleRes);
67     }
68 
69     @Override
onFinishInflate()70     protected void onFinishInflate() {
71         super.onFinishInflate();
72         mListView = (HorizontalGridView) getContentsView();
73         // Disable the position change animation of the cards.
74         mListView.setItemAnimator(null);
75     }
76 
77     @Override
getContentsViewId()78     protected int getContentsViewId() {
79         return R.id.list_view;
80     }
81 
82     @Override
onBind(MenuRow row)83     public void onBind(MenuRow row) {
84         super.onBind(row);
85         ItemListAdapter<?> adapter = ((ItemListRow) row).getAdapter();
86         adapter.mItemListView = this;
87 
88         mListView.setOnChildSelectedListener(this);
89         mListView.setAdapter(adapter);
90     }
91 
92     @Override
initialize(int reason)93     public void initialize(int reason) {
94         super.initialize(reason);
95         setInitialFocusView(mListView);
96         mListView.setSelectedPosition(getAdapter().getInitialPosition());
97     }
98 
getAdapter()99     private ItemListAdapter<?> getAdapter() {
100         return (ItemListAdapter<?>) mListView.getAdapter();
101     }
102 
103     @Override
onChildSelected(ViewGroup parent, View child, int position, long id)104     public void onChildSelected(ViewGroup parent, View child, int position, long id) {
105         if (DEBUG) Log.d(TAG, "onChildSelected: child=" + child);
106         if (mSelectedCard == child) {
107             return;
108         }
109         if (mSelectedCard != null) {
110             mSelectedCard.onDeselected();
111         }
112         mSelectedCard = (CardView<?>) child;
113         if (mSelectedCard != null) {
114             mSelectedCard.onSelected();
115         }
116     }
117 
118     public static abstract class ItemListAdapter<T>
119             extends RecyclerView.Adapter<ItemListAdapter.MyViewHolder> {
120         private final MainActivity mMainActivity;
121         private final LayoutInflater mLayoutInflater;
122         private List<T> mItemList = Collections.emptyList();
123         private ItemListRowView mItemListView;
124 
ItemListAdapter(Context context)125         public ItemListAdapter(Context context) {
126             // Only MainActivity can use the main menu.
127             mMainActivity = (MainActivity) context;
128             mLayoutInflater = LayoutInflater.from(context);
129         }
130 
131         /**
132          * In most cases, implementation should call {@link #setItemList(java.util.List)} with
133          * newly update item list.
134          */
update()135         public abstract void update();
136 
137         /**
138          * Gets layout resource ID. It'll be used in {@link #onCreateViewHolder}.
139          */
getLayoutResId(int viewType)140         protected abstract int getLayoutResId(int viewType);
141 
142         /**
143          * Releases all the resources which need to be released.
144         */
release()145         public void release() {
146         }
147 
148         /**
149          * The initial position of list that will be selected when the main menu appears.
150          * By default, the first item is initially selected.
151          */
getInitialPosition()152         public int getInitialPosition() {
153             return 0;
154         }
155 
156         /** The MainActivity that the corresponding ItemListView belongs to. */
getMainActivity()157         protected MainActivity getMainActivity() {
158             return mMainActivity;
159         }
160 
161         /** The item list. */
getItemList()162         protected List<T> getItemList() {
163             return mItemList;
164         }
165 
166         /**
167          * Sets the item list.
168          *
169          * <p>This sends an item change event, not a structural change event. The items of the same
170          * positions retain the same identity.
171          *
172          * <p>If there's any structural change and relayout and rebind is needed, call
173          * {@link #notifyDataSetChanged} explicitly.
174          */
setItemList(List<T> itemList)175         protected void setItemList(List<T> itemList) {
176             int oldSize = mItemList.size();
177             int newSize = itemList.size();
178             mItemList = itemList;
179             if (oldSize > newSize) {
180                 notifyItemRangeChanged(0, newSize);
181                 notifyItemRangeRemoved(newSize, oldSize - newSize);
182             } else if (oldSize < newSize) {
183                 notifyItemRangeChanged(0, oldSize);
184                 notifyItemRangeInserted(oldSize, newSize - oldSize);
185             } else {
186                 notifyItemRangeChanged(0, oldSize);
187             }
188         }
189 
190         @Override
getItemViewType(int position)191         public int getItemViewType(int position) {
192             return 0;
193         }
194 
195         @Override
getItemCount()196         public int getItemCount() {
197             return mItemList.size();
198         }
199 
200         /**
201          * Returns the position of the item.
202          */
getItemPosition(T item)203         protected int getItemPosition(T item) {
204             return mItemList.indexOf(item);
205         }
206 
207         /**
208          * Returns {@code true} if the item list contains the item, otherwise {@code false}.
209          */
containsItem(T item)210         protected boolean containsItem(T item) {
211             return mItemList.contains(item);
212         }
213 
214         @Override
onCreateViewHolder(ViewGroup parent, int viewType)215         public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
216             View view = ViewCache.getInstance().getOrCreateView(
217                     mLayoutInflater, getLayoutResId(viewType), parent);
218             return new MyViewHolder(view);
219         }
220 
221         @Override
onBindViewHolder(MyViewHolder viewHolder, int position)222         public void onBindViewHolder(MyViewHolder viewHolder, int position) {
223             @SuppressWarnings("unchecked")
224             CardView<T> cardView = (CardView<T>) viewHolder.itemView;
225             cardView.onBind(mItemList.get(position), cardView.equals(mItemListView.mSelectedCard));
226         }
227 
228         @Override
onViewRecycled(MyViewHolder viewHolder)229         public void onViewRecycled(MyViewHolder viewHolder) {
230             super.onViewRecycled(viewHolder);
231             CardView<T> cardView = (CardView<T>) viewHolder.itemView;
232             cardView.onRecycled();
233         }
234 
235         public static class MyViewHolder extends RecyclerView.ViewHolder {
MyViewHolder(View view)236             public MyViewHolder(View view) {
237                 super(view);
238             }
239         }
240     }
241 }
242