• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 package android.support.v17.leanback.widget;
15 
16 import android.support.v7.widget.RecyclerView;
17 import android.util.Log;
18 import android.view.View;
19 import android.view.ViewGroup;
20 
21 import java.util.ArrayList;
22 
23 /**
24  * Bridge from Presenter to RecyclerView.Adapter. Public to allow use by third
25  * party presenters.
26  */
27 public class ItemBridgeAdapter extends RecyclerView.Adapter {
28     private static final String TAG = "ItemBridgeAdapter";
29     private static final boolean DEBUG = false;
30 
31     /**
32      * Interface for listening to view holder operations.
33      */
34     public static class AdapterListener {
onAddPresenter(Presenter presenter, int type)35         public void onAddPresenter(Presenter presenter, int type) {
36         }
onCreate(ViewHolder viewHolder)37         public void onCreate(ViewHolder viewHolder) {
38         }
onBind(ViewHolder viewHolder)39         public void onBind(ViewHolder viewHolder) {
40         }
onUnbind(ViewHolder viewHolder)41         public void onUnbind(ViewHolder viewHolder) {
42         }
onAttachedToWindow(ViewHolder viewHolder)43         public void onAttachedToWindow(ViewHolder viewHolder) {
44         }
onDetachedFromWindow(ViewHolder viewHolder)45         public void onDetachedFromWindow(ViewHolder viewHolder) {
46         }
47     }
48 
49     /**
50      * Interface for wrapping a view created by presenter into another view.
51      * The wrapper must be immediate parent of the wrapped view.
52      */
53     public static abstract class Wrapper {
createWrapper(View root)54         public abstract View createWrapper(View root);
wrap(View wrapper, View wrapped)55         public abstract void wrap(View wrapper, View wrapped);
56     }
57 
58     private ObjectAdapter mAdapter;
59     private Wrapper mWrapper;
60     private PresenterSelector mPresenterSelector;
61     private FocusHighlightHandler mFocusHighlight;
62     private AdapterListener mAdapterListener;
63     private ArrayList<Presenter> mPresenters = new ArrayList<Presenter>();
64 
65     final class OnFocusChangeListener implements View.OnFocusChangeListener {
66         View.OnFocusChangeListener mChainedListener;
67 
68         @Override
onFocusChange(View view, boolean hasFocus)69         public void onFocusChange(View view, boolean hasFocus) {
70             if (DEBUG) Log.v(TAG, "onFocusChange " + hasFocus + " " + view
71                     + " mFocusHighlight" + mFocusHighlight);
72             if (mWrapper != null) {
73                 view = (View) view.getParent();
74             }
75             if (mFocusHighlight != null) {
76                 mFocusHighlight.onItemFocused(view, hasFocus);
77             }
78             if (mChainedListener != null) {
79                 mChainedListener.onFocusChange(view, hasFocus);
80             }
81         }
82     }
83 
84     public class ViewHolder extends RecyclerView.ViewHolder {
85         final Presenter mPresenter;
86         final Presenter.ViewHolder mHolder;
87         final OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener();
88         Object mItem;
89         Object mExtraObject;
90 
91         /**
92          * Get {@link Presenter}.
93          */
getPresenter()94         public final Presenter getPresenter() {
95             return mPresenter;
96         }
97 
98         /**
99          * Get {@link Presenter.ViewHolder}.
100          */
getViewHolder()101         public final Presenter.ViewHolder getViewHolder() {
102             return mHolder;
103         }
104 
105         /**
106          * Get currently bound object.
107          */
getItem()108         public final Object getItem() {
109             return mItem;
110         }
111 
112         /**
113          * Get extra object associated with the view.  Developer can attach
114          * any customized UI object in addition to {@link Presenter.ViewHolder}.
115          * A typical use case is attaching an animator object.
116          */
getExtraObject()117         public final Object getExtraObject() {
118             return mExtraObject;
119         }
120 
121         /**
122          * Set extra object associated with the view.  Developer can attach
123          * any customized UI object in addition to {@link Presenter.ViewHolder}.
124          * A typical use case is attaching an animator object.
125          */
setExtraObject(Object object)126         public void setExtraObject(Object object) {
127             mExtraObject = object;
128         }
129 
ViewHolder(Presenter presenter, View view, Presenter.ViewHolder holder)130         ViewHolder(Presenter presenter, View view, Presenter.ViewHolder holder) {
131             super(view);
132             mPresenter = presenter;
133             mHolder = holder;
134         }
135     }
136 
137     private ObjectAdapter.DataObserver mDataObserver = new ObjectAdapter.DataObserver() {
138         @Override
139         public void onChanged() {
140             ItemBridgeAdapter.this.notifyDataSetChanged();
141         }
142         @Override
143         public void onItemRangeChanged(int positionStart, int itemCount) {
144             ItemBridgeAdapter.this.notifyItemRangeChanged(positionStart, itemCount);
145         }
146         @Override
147         public void onItemRangeInserted(int positionStart, int itemCount) {
148             ItemBridgeAdapter.this.notifyItemRangeInserted(positionStart, itemCount);
149         }
150         @Override
151         public void onItemRangeRemoved(int positionStart, int itemCount) {
152             ItemBridgeAdapter.this.notifyItemRangeRemoved(positionStart, itemCount);
153         }
154     };
155 
ItemBridgeAdapter(ObjectAdapter adapter, PresenterSelector presenterSelector)156     public ItemBridgeAdapter(ObjectAdapter adapter, PresenterSelector presenterSelector) {
157         setAdapter(adapter);
158         mPresenterSelector = presenterSelector;
159     }
160 
ItemBridgeAdapter(ObjectAdapter adapter)161     public ItemBridgeAdapter(ObjectAdapter adapter) {
162         this(adapter, null);
163     }
164 
ItemBridgeAdapter()165     public ItemBridgeAdapter() {
166     }
167 
setAdapter(ObjectAdapter adapter)168     public void setAdapter(ObjectAdapter adapter) {
169         if (mAdapter != null) {
170             mAdapter.unregisterObserver(mDataObserver);
171         }
172         mAdapter = adapter;
173         if (mAdapter == null) {
174             return;
175         }
176 
177         mAdapter.registerObserver(mDataObserver);
178         if (hasStableIds() != mAdapter.hasStableIds()) {
179             setHasStableIds(mAdapter.hasStableIds());
180         }
181     }
182 
setWrapper(Wrapper wrapper)183     public void setWrapper(Wrapper wrapper) {
184         mWrapper = wrapper;
185     }
186 
getWrapper()187     public Wrapper getWrapper() {
188         return mWrapper;
189     }
190 
setFocusHighlight(FocusHighlightHandler listener)191     void setFocusHighlight(FocusHighlightHandler listener) {
192         mFocusHighlight = listener;
193         if (DEBUG) Log.v(TAG, "setFocusHighlight " + mFocusHighlight);
194     }
195 
clear()196     public void clear() {
197         setAdapter(null);
198     }
199 
setPresenterMapper(ArrayList<Presenter> presenters)200     public void setPresenterMapper(ArrayList<Presenter> presenters) {
201         mPresenters = presenters;
202     }
203 
getPresenterMapper()204     public ArrayList<Presenter> getPresenterMapper() {
205         return mPresenters;
206     }
207 
208     @Override
getItemCount()209     public int getItemCount() {
210         return mAdapter.size();
211     }
212 
213     @Override
getItemViewType(int position)214     public int getItemViewType(int position) {
215         PresenterSelector presenterSelector = mPresenterSelector != null ?
216                 mPresenterSelector : mAdapter.getPresenterSelector();
217         Object item = mAdapter.get(position);
218         Presenter presenter = presenterSelector.getPresenter(item);
219         int type = mPresenters.indexOf(presenter);
220         if (type < 0) {
221             mPresenters.add(presenter);
222             type = mPresenters.indexOf(presenter);
223             if (DEBUG) Log.v(TAG, "getItemViewType added presenter " + presenter + " type " + type);
224             if (mAdapterListener != null) {
225                 mAdapterListener.onAddPresenter(presenter, type);
226             }
227         }
228         return type;
229     }
230 
231     /**
232      * {@link View.OnFocusChangeListener} that assigned in
233      * {@link Presenter#onCreateViewHolder(ViewGroup)} may be chained, user should never change
234      * {@link View.OnFocusChangeListener} after that.
235      */
236     @Override
onCreateViewHolder(ViewGroup parent, int viewType)237     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
238         if (DEBUG) Log.v(TAG, "onCreateViewHolder viewType " + viewType);
239         Presenter presenter = mPresenters.get(viewType);
240         Presenter.ViewHolder presenterVh;
241         View view;
242         if (mWrapper != null) {
243             view = mWrapper.createWrapper(parent);
244             presenterVh = presenter.onCreateViewHolder(parent);
245             mWrapper.wrap(view, presenterVh.view);
246         } else {
247             presenterVh = presenter.onCreateViewHolder(parent);
248             view = presenterVh.view;
249         }
250         ViewHolder viewHolder = new ViewHolder(presenter, view, presenterVh);
251         if (mAdapterListener != null) {
252             mAdapterListener.onCreate(viewHolder);
253         }
254         View presenterView = viewHolder.mHolder.view;
255         if (presenterView != null) {
256             viewHolder.mFocusChangeListener.mChainedListener = presenterView.getOnFocusChangeListener();
257             presenterView.setOnFocusChangeListener(viewHolder.mFocusChangeListener);
258         }
259         if (mFocusHighlight != null) {
260             mFocusHighlight.onInitializeView(view);
261         }
262         return viewHolder;
263     }
264 
setAdapterListener(AdapterListener listener)265     public void setAdapterListener(AdapterListener listener) {
266         mAdapterListener = listener;
267     }
268 
269     @Override
onBindViewHolder(RecyclerView.ViewHolder holder, int position)270     public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
271         if (DEBUG) Log.v(TAG, "onBindViewHolder position " + position);
272         ViewHolder viewHolder = (ViewHolder) holder;
273         viewHolder.mItem = mAdapter.get(position);
274 
275         viewHolder.mPresenter.onBindViewHolder(viewHolder.mHolder, viewHolder.mItem);
276 
277         if (mAdapterListener != null) {
278             mAdapterListener.onBind(viewHolder);
279         }
280     }
281 
282     @Override
onViewRecycled(RecyclerView.ViewHolder holder)283     public void onViewRecycled(RecyclerView.ViewHolder holder) {
284         ViewHolder viewHolder = (ViewHolder) holder;
285         viewHolder.mPresenter.onUnbindViewHolder(viewHolder.mHolder);
286 
287         viewHolder.mItem = null;
288 
289         if (mAdapterListener != null) {
290             mAdapterListener.onUnbind(viewHolder);
291         }
292     }
293 
294     @Override
onViewAttachedToWindow(RecyclerView.ViewHolder holder)295     public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
296         ViewHolder viewHolder = (ViewHolder) holder;
297         if (mAdapterListener != null) {
298             mAdapterListener.onAttachedToWindow(viewHolder);
299         }
300         viewHolder.mPresenter.onViewAttachedToWindow(viewHolder.mHolder);
301     }
302 
303     @Override
onViewDetachedFromWindow(RecyclerView.ViewHolder holder)304     public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
305         ViewHolder viewHolder = (ViewHolder) holder;
306         viewHolder.mPresenter.onViewDetachedFromWindow(viewHolder.mHolder);
307         if (mAdapterListener != null) {
308             mAdapterListener.onDetachedFromWindow(viewHolder);
309         }
310     }
311 
312     @Override
getItemId(int position)313     public long getItemId(int position) {
314         return mAdapter.getId(position);
315     }
316 
317 }
318