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 32 import java.util.Collections; 33 import java.util.List; 34 35 /** 36 * A view that shows a title and list view. 37 */ 38 public class ItemListRowView extends MenuRowView implements OnChildSelectedListener { 39 private static final String TAG = MenuView.TAG; 40 private static final boolean DEBUG = MenuView.DEBUG; 41 42 public interface CardView<T> { 43 void onBind(T row, boolean selected); 44 void onRecycled(); 45 void onSelected(); 46 void onDeselected(); 47 } 48 49 private HorizontalGridView mListView; 50 private CardView<?> mSelectedCard; 51 52 public ItemListRowView(Context context) { 53 this(context, null); 54 } 55 56 public ItemListRowView(Context context, AttributeSet attrs) { 57 this(context, attrs, 0); 58 } 59 60 public ItemListRowView(Context context, AttributeSet attrs, int defStyle) { 61 this(context, attrs, defStyle, 0); 62 } 63 64 public ItemListRowView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 65 super(context, attrs, defStyleAttr, defStyleRes); 66 } 67 68 @Override 69 protected void onFinishInflate() { 70 super.onFinishInflate(); 71 mListView = (HorizontalGridView) getContentsView(); 72 } 73 74 @Override 75 protected int getContentsViewId() { 76 return R.id.list_view; 77 } 78 79 @Override 80 public void onBind(MenuRow row) { 81 super.onBind(row); 82 ItemListAdapter<?> adapter = ((ItemListRow) row).getAdapter(); 83 adapter.mItemListView = this; 84 85 mListView.setOnChildSelectedListener(this); 86 mListView.setAdapter(adapter); 87 } 88 89 @Override 90 public void initialize(int reason) { 91 super.initialize(reason); 92 setInitialFocusView(mListView); 93 mListView.setSelectedPosition(getAdapter().getInitialPosition()); 94 } 95 96 private ItemListAdapter<?> getAdapter() { 97 return (ItemListAdapter<?>) mListView.getAdapter(); 98 } 99 100 @Override 101 public void onChildSelected(ViewGroup parent, View child, int position, long id) { 102 if (DEBUG) Log.d(TAG, "onChildSelected: child=" + child); 103 if (mSelectedCard == child) { 104 return; 105 } 106 if (mSelectedCard != null) { 107 mSelectedCard.onDeselected(); 108 } 109 mSelectedCard = (CardView<?>) child; 110 if (mSelectedCard != null) { 111 mSelectedCard.onSelected(); 112 } 113 } 114 115 public static abstract class ItemListAdapter<T> 116 extends RecyclerView.Adapter<ItemListAdapter.MyViewHolder> { 117 private final MainActivity mMainActivity; 118 private final LayoutInflater mLayoutInflater; 119 private List<T> mItemList = Collections.emptyList(); 120 private ItemListRowView mItemListView; 121 122 public ItemListAdapter(Context context) { 123 // Only MainActivity can use the main menu. 124 mMainActivity = (MainActivity) context; 125 mLayoutInflater = LayoutInflater.from(context); 126 } 127 128 /** 129 * In most cases, implementation should call {@link #setItemList(java.util.List)} with 130 * newly update item list. 131 */ 132 public abstract void update(); 133 134 /** 135 * Gets layout resource ID. It'll be used in {@link #onCreateViewHolder}. 136 */ 137 protected abstract int getLayoutResId(int viewType); 138 139 /** 140 * Releases all the resources which need to be released. 141 */ 142 public void release() { 143 } 144 145 /** 146 * The initial position of list that will be selected when the main menu appears. 147 * By default, the first item is initially selected. 148 */ 149 public int getInitialPosition() { 150 return 0; 151 } 152 153 /** The MainActivity that the corresponding ItemListView belongs to. */ 154 protected MainActivity getMainActivity() { 155 return mMainActivity; 156 } 157 158 /** The item list. */ 159 protected List<T> getItemList() { 160 return mItemList; 161 } 162 163 /** 164 * Sets the item list. 165 * 166 * <p>This sends an item change event, not a structural change event. The items of the same 167 * positions retain the same identity. 168 * 169 * <p>If there's any structural change and relayout and rebind is needed, call 170 * {@link #notifyDataSetChanged} explicitly. 171 */ 172 protected void setItemList(List<T> itemList) { 173 int oldSize = mItemList.size(); 174 int newSize = itemList.size(); 175 mItemList = itemList; 176 if (oldSize > newSize) { 177 notifyItemRangeChanged(0, newSize); 178 notifyItemRangeRemoved(newSize, oldSize - newSize); 179 } else if (oldSize < newSize) { 180 notifyItemRangeChanged(0, oldSize); 181 notifyItemRangeInserted(oldSize, newSize - oldSize); 182 } else { 183 notifyItemRangeChanged(0, oldSize); 184 } 185 } 186 187 @Override 188 public int getItemViewType(int position) { 189 return 0; 190 } 191 192 @Override 193 public int getItemCount() { 194 return mItemList.size(); 195 } 196 197 @Override 198 public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 199 View view = mLayoutInflater.inflate(getLayoutResId(viewType), parent, false); 200 return new MyViewHolder(view); 201 } 202 203 @Override 204 public void onBindViewHolder(MyViewHolder viewHolder, int position) { 205 @SuppressWarnings("unchecked") 206 CardView<T> cardView = (CardView<T>) viewHolder.itemView; 207 cardView.onBind(mItemList.get(position), cardView.equals(mItemListView.mSelectedCard)); 208 } 209 210 @Override 211 public void onViewRecycled(MyViewHolder viewHolder) { 212 super.onViewRecycled(viewHolder); 213 CardView<T> cardView = (CardView<T>) viewHolder.itemView; 214 cardView.onRecycled(); 215 } 216 217 public static class MyViewHolder extends RecyclerView.ViewHolder { 218 public MyViewHolder(View view) { 219 super(view); 220 } 221 } 222 } 223 } 224