• 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 import java.util.List;
23 
24 /**
25  * Bridge from {@link Presenter} to {@link RecyclerView.Adapter}. Public to allow use by third
26  * party Presenters.
27  */
28 public class ItemBridgeAdapter extends RecyclerView.Adapter implements FacetProviderAdapter {
29     static final String TAG = "ItemBridgeAdapter";
30     static final boolean DEBUG = false;
31 
32     /**
33      * Interface for listening to ViewHolder operations.
34      */
35     public static class AdapterListener {
onAddPresenter(Presenter presenter, int type)36         public void onAddPresenter(Presenter presenter, int type) {
37         }
38 
onCreate(ViewHolder viewHolder)39         public void onCreate(ViewHolder viewHolder) {
40         }
41 
onBind(ViewHolder viewHolder)42         public void onBind(ViewHolder viewHolder) {
43         }
44 
onBind(ViewHolder viewHolder, List payloads)45         public void onBind(ViewHolder viewHolder, List payloads) {
46             onBind(viewHolder);
47         }
48 
onUnbind(ViewHolder viewHolder)49         public void onUnbind(ViewHolder viewHolder) {
50         }
51 
onAttachedToWindow(ViewHolder viewHolder)52         public void onAttachedToWindow(ViewHolder viewHolder) {
53         }
54 
onDetachedFromWindow(ViewHolder viewHolder)55         public void onDetachedFromWindow(ViewHolder viewHolder) {
56         }
57     }
58 
59     /**
60      * Interface for wrapping a view created by a Presenter into another view.
61      * The wrapper must be the immediate parent of the wrapped view.
62      */
63     public static abstract class Wrapper {
createWrapper(View root)64         public abstract View createWrapper(View root);
65 
wrap(View wrapper, View wrapped)66         public abstract void wrap(View wrapper, View wrapped);
67     }
68 
69     private ObjectAdapter mAdapter;
70     Wrapper mWrapper;
71     private PresenterSelector mPresenterSelector;
72     FocusHighlightHandler mFocusHighlight;
73     private AdapterListener mAdapterListener;
74     private ArrayList<Presenter> mPresenters = new ArrayList<Presenter>();
75 
76     final class OnFocusChangeListener implements View.OnFocusChangeListener {
77         View.OnFocusChangeListener mChainedListener;
78 
79         @Override
onFocusChange(View view, boolean hasFocus)80         public void onFocusChange(View view, boolean hasFocus) {
81             if (DEBUG) {
82                 Log.v(TAG, "onFocusChange " + hasFocus + " " + view
83                         + " mFocusHighlight" + mFocusHighlight);
84             }
85             if (mWrapper != null) {
86                 view = (View) view.getParent();
87             }
88             if (mFocusHighlight != null) {
89                 mFocusHighlight.onItemFocused(view, hasFocus);
90             }
91             if (mChainedListener != null) {
92                 mChainedListener.onFocusChange(view, hasFocus);
93             }
94         }
95     }
96 
97     /**
98      * ViewHolder for the ItemBridgeAdapter.
99      */
100     public class ViewHolder extends RecyclerView.ViewHolder implements FacetProvider {
101         final Presenter mPresenter;
102         final Presenter.ViewHolder mHolder;
103         final OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener();
104         Object mItem;
105         Object mExtraObject;
106 
107         /**
108          * Get {@link Presenter}.
109          */
getPresenter()110         public final Presenter getPresenter() {
111             return mPresenter;
112         }
113 
114         /**
115          * Get {@link Presenter.ViewHolder}.
116          */
getViewHolder()117         public final Presenter.ViewHolder getViewHolder() {
118             return mHolder;
119         }
120 
121         /**
122          * Get currently bound object.
123          */
getItem()124         public final Object getItem() {
125             return mItem;
126         }
127 
128         /**
129          * Get extra object associated with the view.  Developer can attach
130          * any customized UI object in addition to {@link Presenter.ViewHolder}.
131          * A typical use case is attaching an animator object.
132          */
getExtraObject()133         public final Object getExtraObject() {
134             return mExtraObject;
135         }
136 
137         /**
138          * Set extra object associated with the view.  Developer can attach
139          * any customized UI object in addition to {@link Presenter.ViewHolder}.
140          * A typical use case is attaching an animator object.
141          */
setExtraObject(Object object)142         public void setExtraObject(Object object) {
143             mExtraObject = object;
144         }
145 
146         @Override
getFacet(Class<?> facetClass)147         public Object getFacet(Class<?> facetClass) {
148             return mHolder.getFacet(facetClass);
149         }
150 
ViewHolder(Presenter presenter, View view, Presenter.ViewHolder holder)151         ViewHolder(Presenter presenter, View view, Presenter.ViewHolder holder) {
152             super(view);
153             mPresenter = presenter;
154             mHolder = holder;
155         }
156     }
157 
158     private ObjectAdapter.DataObserver mDataObserver = new ObjectAdapter.DataObserver() {
159         @Override
160         public void onChanged() {
161             ItemBridgeAdapter.this.notifyDataSetChanged();
162         }
163 
164         @Override
165         public void onItemRangeChanged(int positionStart, int itemCount) {
166             ItemBridgeAdapter.this.notifyItemRangeChanged(positionStart, itemCount);
167         }
168 
169         @Override
170         public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
171             ItemBridgeAdapter.this.notifyItemRangeChanged(positionStart, itemCount, payload);
172         }
173 
174         @Override
175         public void onItemRangeInserted(int positionStart, int itemCount) {
176             ItemBridgeAdapter.this.notifyItemRangeInserted(positionStart, itemCount);
177         }
178 
179         @Override
180         public void onItemRangeRemoved(int positionStart, int itemCount) {
181             ItemBridgeAdapter.this.notifyItemRangeRemoved(positionStart, itemCount);
182         }
183 
184         @Override
185         public void onItemMoved(int fromPosition, int toPosition) {
186             ItemBridgeAdapter.this.notifyItemMoved(fromPosition, toPosition);
187         }
188     };
189 
ItemBridgeAdapter(ObjectAdapter adapter, PresenterSelector presenterSelector)190     public ItemBridgeAdapter(ObjectAdapter adapter, PresenterSelector presenterSelector) {
191         setAdapter(adapter);
192         mPresenterSelector = presenterSelector;
193     }
194 
ItemBridgeAdapter(ObjectAdapter adapter)195     public ItemBridgeAdapter(ObjectAdapter adapter) {
196         this(adapter, null);
197     }
198 
ItemBridgeAdapter()199     public ItemBridgeAdapter() {
200     }
201 
202     /**
203      * Sets the {@link ObjectAdapter}.
204      */
setAdapter(ObjectAdapter adapter)205     public void setAdapter(ObjectAdapter adapter) {
206         if (adapter == mAdapter) {
207             return;
208         }
209         if (mAdapter != null) {
210             mAdapter.unregisterObserver(mDataObserver);
211         }
212         mAdapter = adapter;
213         if (mAdapter == null) {
214             notifyDataSetChanged();
215             return;
216         }
217 
218         mAdapter.registerObserver(mDataObserver);
219         if (hasStableIds() != mAdapter.hasStableIds()) {
220             setHasStableIds(mAdapter.hasStableIds());
221         }
222         notifyDataSetChanged();
223     }
224 
225     /**
226      * Changes Presenter that creates and binds the view.
227      *
228      * @param presenterSelector Presenter that creates and binds the view.
229      */
setPresenter(PresenterSelector presenterSelector)230     public void setPresenter(PresenterSelector presenterSelector) {
231         mPresenterSelector = presenterSelector;
232         notifyDataSetChanged();
233     }
234 
235     /**
236      * Sets the {@link Wrapper}.
237      */
setWrapper(Wrapper wrapper)238     public void setWrapper(Wrapper wrapper) {
239         mWrapper = wrapper;
240     }
241 
242     /**
243      * Returns the {@link Wrapper}.
244      */
getWrapper()245     public Wrapper getWrapper() {
246         return mWrapper;
247     }
248 
setFocusHighlight(FocusHighlightHandler listener)249     void setFocusHighlight(FocusHighlightHandler listener) {
250         mFocusHighlight = listener;
251         if (DEBUG) Log.v(TAG, "setFocusHighlight " + mFocusHighlight);
252     }
253 
254     /**
255      * Clears the adapter.
256      */
clear()257     public void clear() {
258         setAdapter(null);
259     }
260 
261     /**
262      * Sets the presenter mapper array.
263      */
setPresenterMapper(ArrayList<Presenter> presenters)264     public void setPresenterMapper(ArrayList<Presenter> presenters) {
265         mPresenters = presenters;
266     }
267 
268     /**
269      * Returns the presenter mapper array.
270      */
getPresenterMapper()271     public ArrayList<Presenter> getPresenterMapper() {
272         return mPresenters;
273     }
274 
275     @Override
getItemCount()276     public int getItemCount() {
277         return mAdapter != null ? mAdapter.size() : 0;
278     }
279 
280     @Override
getItemViewType(int position)281     public int getItemViewType(int position) {
282         PresenterSelector presenterSelector = mPresenterSelector != null
283                 ? mPresenterSelector : mAdapter.getPresenterSelector();
284         Object item = mAdapter.get(position);
285         Presenter presenter = presenterSelector.getPresenter(item);
286         int type = mPresenters.indexOf(presenter);
287         if (type < 0) {
288             mPresenters.add(presenter);
289             type = mPresenters.indexOf(presenter);
290             if (DEBUG) Log.v(TAG, "getItemViewType added presenter " + presenter + " type " + type);
291             onAddPresenter(presenter, type);
292             if (mAdapterListener != null) {
293                 mAdapterListener.onAddPresenter(presenter, type);
294             }
295         }
296         return type;
297     }
298 
299     /**
300      * Called when presenter is added to Adapter.
301      */
onAddPresenter(Presenter presenter, int type)302     protected void onAddPresenter(Presenter presenter, int type) {
303     }
304 
305     /**
306      * Called when ViewHolder is created.
307      */
onCreate(ViewHolder viewHolder)308     protected void onCreate(ViewHolder viewHolder) {
309     }
310 
311     /**
312      * Called when ViewHolder has been bound to data.
313      */
onBind(ViewHolder viewHolder)314     protected void onBind(ViewHolder viewHolder) {
315     }
316 
317     /**
318      * Called when ViewHolder has been unbound from data.
319      */
onUnbind(ViewHolder viewHolder)320     protected void onUnbind(ViewHolder viewHolder) {
321     }
322 
323     /**
324      * Called when ViewHolder has been attached to window.
325      */
onAttachedToWindow(ViewHolder viewHolder)326     protected void onAttachedToWindow(ViewHolder viewHolder) {
327     }
328 
329     /**
330      * Called when ViewHolder has been detached from window.
331      */
onDetachedFromWindow(ViewHolder viewHolder)332     protected void onDetachedFromWindow(ViewHolder viewHolder) {
333     }
334 
335     /**
336      * {@link View.OnFocusChangeListener} that assigned in
337      * {@link Presenter#onCreateViewHolder(ViewGroup)} may be chained, user should never change
338      * {@link View.OnFocusChangeListener} after that.
339      */
340     @Override
onCreateViewHolder(ViewGroup parent, int viewType)341     public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
342         if (DEBUG) Log.v(TAG, "onCreateViewHolder viewType " + viewType);
343         Presenter presenter = mPresenters.get(viewType);
344         Presenter.ViewHolder presenterVh;
345         View view;
346         if (mWrapper != null) {
347             view = mWrapper.createWrapper(parent);
348             presenterVh = presenter.onCreateViewHolder(parent);
349             mWrapper.wrap(view, presenterVh.view);
350         } else {
351             presenterVh = presenter.onCreateViewHolder(parent);
352             view = presenterVh.view;
353         }
354         ViewHolder viewHolder = new ViewHolder(presenter, view, presenterVh);
355         onCreate(viewHolder);
356         if (mAdapterListener != null) {
357             mAdapterListener.onCreate(viewHolder);
358         }
359         View presenterView = viewHolder.mHolder.view;
360         if (presenterView != null) {
361             viewHolder.mFocusChangeListener.mChainedListener =
362                     presenterView.getOnFocusChangeListener();
363             presenterView.setOnFocusChangeListener(viewHolder.mFocusChangeListener);
364         }
365         if (mFocusHighlight != null) {
366             mFocusHighlight.onInitializeView(view);
367         }
368         return viewHolder;
369     }
370 
371     /**
372      * Sets the AdapterListener.
373      */
setAdapterListener(AdapterListener listener)374     public void setAdapterListener(AdapterListener listener) {
375         mAdapterListener = listener;
376     }
377 
378     @Override
onBindViewHolder(RecyclerView.ViewHolder holder, int position)379     public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
380         if (DEBUG) Log.v(TAG, "onBindViewHolder position " + position);
381         ViewHolder viewHolder = (ViewHolder) holder;
382         viewHolder.mItem = mAdapter.get(position);
383 
384         viewHolder.mPresenter.onBindViewHolder(viewHolder.mHolder, viewHolder.mItem);
385 
386         onBind(viewHolder);
387         if (mAdapterListener != null) {
388             mAdapterListener.onBind(viewHolder);
389         }
390     }
391 
392     @Override
onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads)393     public final  void onBindViewHolder(RecyclerView.ViewHolder holder, int position,
394             List payloads) {
395         if (DEBUG) Log.v(TAG, "onBindViewHolder position " + position);
396         ViewHolder viewHolder = (ViewHolder) holder;
397         viewHolder.mItem = mAdapter.get(position);
398 
399         viewHolder.mPresenter.onBindViewHolder(viewHolder.mHolder, viewHolder.mItem, payloads);
400 
401         onBind(viewHolder);
402         if (mAdapterListener != null) {
403             mAdapterListener.onBind(viewHolder, payloads);
404         }
405     }
406 
407     @Override
onViewRecycled(RecyclerView.ViewHolder holder)408     public final void onViewRecycled(RecyclerView.ViewHolder holder) {
409         ViewHolder viewHolder = (ViewHolder) holder;
410         viewHolder.mPresenter.onUnbindViewHolder(viewHolder.mHolder);
411         onUnbind(viewHolder);
412         if (mAdapterListener != null) {
413             mAdapterListener.onUnbind(viewHolder);
414         }
415         viewHolder.mItem = null;
416     }
417 
418     @Override
onViewAttachedToWindow(RecyclerView.ViewHolder holder)419     public final void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
420         ViewHolder viewHolder = (ViewHolder) holder;
421         onAttachedToWindow(viewHolder);
422         if (mAdapterListener != null) {
423             mAdapterListener.onAttachedToWindow(viewHolder);
424         }
425         viewHolder.mPresenter.onViewAttachedToWindow(viewHolder.mHolder);
426     }
427 
428     @Override
onViewDetachedFromWindow(RecyclerView.ViewHolder holder)429     public final void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
430         ViewHolder viewHolder = (ViewHolder) holder;
431         viewHolder.mPresenter.onViewDetachedFromWindow(viewHolder.mHolder);
432         onDetachedFromWindow(viewHolder);
433         if (mAdapterListener != null) {
434             mAdapterListener.onDetachedFromWindow(viewHolder);
435         }
436     }
437 
438     @Override
getItemId(int position)439     public long getItemId(int position) {
440         return mAdapter.getId(position);
441     }
442 
443     @Override
getFacetProvider(int type)444     public FacetProvider getFacetProvider(int type) {
445         return mPresenters.get(type);
446     }
447 }
448