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