ItemBridgeAdapter.java revision 8b068ddbbf22a246eab49ec25a2f7c3abfbdca51
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 */
14package android.support.v17.leanback.widget;
15
16import android.support.v7.widget.RecyclerView;
17import android.support.v17.leanback.R;
18import android.util.Log;
19import android.view.View;
20import android.view.ViewGroup;
21
22import java.util.ArrayList;
23
24/**
25 * Bridge from Presenter to RecyclerView.Adapter. Public to allow use by third
26 * party presenters.
27 */
28public class ItemBridgeAdapter extends RecyclerView.Adapter {
29    private static final String TAG = "ItemBridgeAdapter";
30    private static final boolean DEBUG = false;
31
32    /**
33     * Interface for listening to view holder operations.
34     */
35    public static class AdapterListener {
36        public void onAddPresenter(Presenter presenter) {
37        }
38        public void onCreate(ViewHolder viewHolder) {
39        }
40        public void onBind(ViewHolder viewHolder) {
41        }
42        public void onUnbind(ViewHolder viewHolder) {
43        }
44        public void onAttachedToWindow(ViewHolder viewHolder) {
45        }
46        public void onDetachedFromWindow(ViewHolder viewHolder) {
47        }
48    }
49
50    private ObjectAdapter mAdapter;
51    private PresenterSelector mPresenterSelector;
52    private FocusHighlight mFocusHighlight;
53    private AdapterListener mAdapterListener;
54    private ArrayList<Presenter> mPresenters = new ArrayList<Presenter>();
55
56    class OnFocusChangeListener implements View.OnFocusChangeListener {
57        View.OnFocusChangeListener mChainedListener;
58
59        @Override
60        public void onFocusChange(View view, boolean hasFocus) {
61            if (DEBUG) Log.v(TAG, "onFocusChange " + hasFocus + " " + view + " mFocusHighlight" + mFocusHighlight);
62            ViewHolder viewHolder = getChildViewHolder(view);
63            if (mFocusHighlight != null) {
64                mFocusHighlight.onItemFocused(view, viewHolder.mItem, hasFocus);
65            }
66            if (mChainedListener != null) {
67                mChainedListener.onFocusChange(view, hasFocus);
68            }
69        }
70    }
71
72    public class ViewHolder extends RecyclerView.ViewHolder {
73        Presenter mPresenter;
74        Presenter.ViewHolder mHolder;
75        Object mItem;
76        OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener();
77
78        public final Presenter getPresenter() {
79            return mPresenter;
80        }
81        public final Presenter.ViewHolder getViewHolder() {
82            return mHolder;
83        }
84
85        ViewHolder(Presenter presenter, Presenter.ViewHolder holder) {
86            super(holder.view);
87            mPresenter = presenter;
88            mHolder = holder;
89        }
90    }
91
92    private ObjectAdapter.DataObserver mDataObserver = new ObjectAdapter.DataObserver() {
93        @Override
94        public void onChanged() {
95            ItemBridgeAdapter.this.notifyDataSetChanged();
96        }
97        @Override
98        public void onItemRangeChanged(int positionStart, int itemCount) {
99            ItemBridgeAdapter.this.notifyItemRangeChanged(positionStart, itemCount);
100        }
101        @Override
102        public void onItemRangeInserted(int positionStart, int itemCount) {
103            ItemBridgeAdapter.this.notifyItemRangeInserted(positionStart, itemCount);
104        }
105        @Override
106        public void onItemRangeRemoved(int positionStart, int itemCount) {
107            ItemBridgeAdapter.this.notifyItemRangeRemoved(positionStart, itemCount);
108        }
109    };
110
111    public ItemBridgeAdapter(ObjectAdapter adapter, PresenterSelector presenterSelector) {
112        setAdapter(adapter);
113        mPresenterSelector = presenterSelector;
114    }
115
116    public ItemBridgeAdapter() {
117    }
118
119    private ViewHolder getChildViewHolder(View view) {
120        RecyclerView recyclerView = (RecyclerView) view.getParent();
121        return (ViewHolder) recyclerView.getChildViewHolder(view);
122    }
123
124    public void setAdapter(ObjectAdapter adapter) {
125        if (mAdapter != null) {
126            mAdapter.unregisterObserver(mDataObserver);
127        }
128        mAdapter = adapter;
129        if (mAdapter == null) {
130            return;
131        }
132
133        mAdapter.registerObserver(mDataObserver);
134        setHasStableIds(mAdapter.hasStableIds());
135    }
136
137    void setFocusHighlight(FocusHighlight listener) {
138        mFocusHighlight = listener;
139        if (DEBUG) Log.v(TAG, "setFocusHighlight " + mFocusHighlight);
140    }
141
142    public void clear() {
143        setAdapter(null);
144    }
145
146    @Override
147    public int getItemCount() {
148        return mAdapter.size();
149    }
150
151    @Override
152    public int getItemViewType(int position) {
153        PresenterSelector presenterSelector = mPresenterSelector != null ?
154                mPresenterSelector : mAdapter.getPresenterSelector();
155        Object item = mAdapter.get(position);
156        Presenter presenter = presenterSelector.getPresenter(item);
157        int type = mPresenters.indexOf(presenter);
158        if (type < 0) {
159            mPresenters.add(presenter);
160            type = mPresenters.indexOf(presenter);
161            if (mAdapterListener != null) {
162                mAdapterListener.onAddPresenter(presenter);
163            }
164        }
165        return type;
166    }
167
168    /**
169     * {@link View.OnFocusChangeListener} that assigned in
170     * {@link Presenter#onCreateViewHolder(ViewGroup)} may be chained, user should never change
171     * {@link View.OnFocusChangeListener} after that.
172     */
173    @Override
174    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
175        if (DEBUG) Log.v(TAG, "onCreateViewHolder viewType " + viewType);
176        Presenter presenter = mPresenters.get(viewType);
177        ViewHolder viewHolder = new ViewHolder(presenter, presenter.onCreateViewHolder(parent));
178        if (mAdapterListener != null) {
179            mAdapterListener.onCreate(viewHolder);
180        }
181        View view = viewHolder.mHolder.view;
182        if (view != null) {
183            viewHolder.mFocusChangeListener.mChainedListener = view.getOnFocusChangeListener();
184            view.setOnFocusChangeListener(viewHolder.mFocusChangeListener);
185        }
186        return viewHolder;
187    }
188
189    public void setAdapterListener(AdapterListener listener) {
190        mAdapterListener = listener;
191    }
192
193    @Override
194    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
195        if (DEBUG) Log.v(TAG, "onBindViewHolder position " + position);
196        ViewHolder viewHolder = (ViewHolder) holder;
197        viewHolder.mItem = mAdapter.get(position);
198
199        viewHolder.mPresenter.onBindViewHolder(viewHolder.mHolder, viewHolder.mItem);
200
201        if (mAdapterListener != null) {
202            mAdapterListener.onBind(viewHolder);
203        }
204    }
205
206    @Override
207    public void onViewRecycled(RecyclerView.ViewHolder holder) {
208        ViewHolder viewHolder = (ViewHolder) holder;
209        viewHolder.mPresenter.onUnbindViewHolder(viewHolder.mHolder);
210
211        viewHolder.mItem = null;
212
213        if (mAdapterListener != null) {
214            mAdapterListener.onUnbind(viewHolder);
215        }
216    }
217
218    @Override
219    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
220        ViewHolder viewHolder = (ViewHolder) holder;
221        if (mAdapterListener != null) {
222            mAdapterListener.onAttachedToWindow(viewHolder);
223        }
224        viewHolder.mPresenter.onViewAttachedToWindow(viewHolder.mHolder);
225    }
226
227    @Override
228    public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
229        ViewHolder viewHolder = (ViewHolder) holder;
230        viewHolder.mPresenter.onViewDetachedFromWindow(viewHolder.mHolder);
231        if (mAdapterListener != null) {
232            mAdapterListener.onDetachedFromWindow(viewHolder);
233        }
234    }
235
236    @Override
237    public long getItemId(int position) {
238        return mAdapter.getId(position);
239    }
240
241}
242