ControlBarPresenter.java revision aa93f6777233b789feb14d95d900b158d0ac4841
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.content.Context;
17import android.support.v17.leanback.R;
18import android.util.SparseArray;
19import android.view.LayoutInflater;
20import android.view.View;
21import android.view.ViewGroup;
22import android.widget.LinearLayout;
23
24/**
25 * A presenter that assumes a LinearLayout container for a series
26 * of control buttons backed by objects of type {@link Action}.
27 *
28 * Different layouts may be passed to the presenter constructor.
29 * The layout must contain a view with id control_bar.
30 */
31class ControlBarPresenter extends Presenter {
32
33    private static final int MAX_CONTROLS = 7;
34
35    /**
36     * The data type expected by this presenter.
37     */
38    static class BoundData {
39        /**
40         * Adapter containing objects of type {@link Action}.
41         */
42        ObjectAdapter adapter;
43
44        /**
45         * The presenter to be used for the adapter objects.
46         */
47        Presenter presenter;
48    }
49
50    /**
51     * A ViewHolder for an actions bar.
52     */
53    class ViewHolder extends Presenter.ViewHolder {
54        ObjectAdapter mAdapter;
55        Presenter mPresenter;
56        ControlBar mControlBar;
57        SparseArray<Presenter.ViewHolder> mViewHolders =
58                new SparseArray<Presenter.ViewHolder>();
59        ObjectAdapter.DataObserver mDataObserver;
60
61        /**
62         * Constructor for the ViewHolder.
63         */
64        ViewHolder(View rootView) {
65            super(rootView);
66            mControlBar = (ControlBar) rootView.findViewById(R.id.control_bar);
67            if (mControlBar == null) {
68                throw new IllegalStateException("Couldn't find control_bar");
69            }
70            mDataObserver = new ObjectAdapter.DataObserver() {
71                @Override
72                public void onChanged() {
73                    showControls(mAdapter, mPresenter);
74                }
75                @Override
76                public void onItemRangeChanged(int positionStart, int itemCount) {
77                    for (int i = 0; i < itemCount; i++) {
78                        bindControlToAction(positionStart + i, mAdapter, mPresenter);
79                    }
80                }
81            };
82        }
83
84        int getChildMarginFromCenter(Context context, int numControls) {
85            // Includes margin between icons plus two times half the icon width.
86            return getChildMarginDefault(context) + getControlIconWidth(context);
87        }
88
89        void showControls(ObjectAdapter adapter, Presenter presenter) {
90            View focusedChild = mControlBar.getFocusedChild();
91            mControlBar.removeAllViews();
92            for (int position = 0; position < adapter.size() && position < MAX_CONTROLS;
93                    position++) {
94                bindControlToAction(position, adapter, presenter);
95            }
96            if (focusedChild != null) {
97                focusedChild.requestFocus();
98            }
99            mControlBar.setChildMarginFromCenter(
100                    getChildMarginFromCenter(mControlBar.getContext(), adapter.size()));
101        }
102
103        void bindControlToAction(final int position, ObjectAdapter adapter, Presenter presenter) {
104            Presenter.ViewHolder vh = mViewHolders.get(position);
105            Object item = adapter.get(position);
106            if (vh == null) {
107                vh = presenter.onCreateViewHolder(mControlBar);
108                mViewHolders.put(position, vh);
109                presenter.setOnClickListener(vh, new View.OnClickListener() {
110                    @Override
111                    public void onClick(View v) {
112                        Object item = getAdapter().get(position);
113                        if (mOnActionClickedListener != null && item instanceof Action) {
114                            mOnActionClickedListener.onActionClicked((Action) item);
115                        }
116                    }
117                });
118            }
119            if (vh.view.getParent() == null) {
120                mControlBar.addView(vh.view);
121            }
122            presenter.onBindViewHolder(vh, item);
123        }
124
125        ObjectAdapter getAdapter() {
126            return mAdapter;
127        }
128    }
129
130    private OnActionClickedListener mOnActionClickedListener;
131    private int mLayoutResourceId;
132    private static int sChildMarginDefault;
133    private static int sControlIconWidth;
134
135    /**
136     * Constructor for a ControlBarPresenter.
137     *
138     * @param layoutResourceId The resource id of the layout for this presenter.
139     */
140    public ControlBarPresenter(int layoutResourceId) {
141        mLayoutResourceId = layoutResourceId;
142    }
143
144    /**
145     * Returns the layout resource id.
146     */
147    public int getLayoutResourceId() {
148        return mLayoutResourceId;
149    }
150
151    /**
152     * Sets the listener for {@link Action} click events.
153     */
154    public void setOnActionClickedListener(OnActionClickedListener listener) {
155        mOnActionClickedListener = listener;
156    }
157
158    /**
159     * Gets the listener for {@link Action} click events.
160     */
161    public OnActionClickedListener getOnActionClickedListener() {
162        return mOnActionClickedListener;
163    }
164
165    @Override
166    public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
167        View v = LayoutInflater.from(parent.getContext())
168            .inflate(getLayoutResourceId(), parent, false);
169        return new ViewHolder(v);
170    }
171
172    @Override
173    public void onBindViewHolder(Presenter.ViewHolder holder, Object item) {
174        ViewHolder vh = (ViewHolder) holder;
175        BoundData data = (BoundData) item;
176        if (vh.mAdapter != data.adapter) {
177            vh.mAdapter = data.adapter;
178            vh.mAdapter.registerObserver(vh.mDataObserver);
179        }
180        vh.mPresenter = data.presenter;
181        vh.showControls(vh.mAdapter, vh.mPresenter);
182    }
183
184    @Override
185    public void onUnbindViewHolder(Presenter.ViewHolder holder) {
186        ViewHolder vh = (ViewHolder) holder;
187        vh.mAdapter.unregisterObserver(vh.mDataObserver);
188        vh.mAdapter = null;
189    }
190
191    int getChildMarginDefault(Context context) {
192        if (sChildMarginDefault == 0) {
193            sChildMarginDefault = context.getResources().getDimensionPixelSize(
194                    R.dimen.lb_playback_controls_child_margin_default);
195        }
196        return sChildMarginDefault;
197    }
198
199    int getControlIconWidth(Context context) {
200        if (sControlIconWidth == 0) {
201            sControlIconWidth = context.getResources().getDimensionPixelSize(
202                    R.dimen.lb_control_icon_width);
203        }
204        return sControlIconWidth;
205    }
206}
207