| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
| * in compliance with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package android.support.v17.leanback.widget; |
| |
| import android.content.Context; |
| import android.support.v17.leanback.R; |
| import android.util.SparseArray; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.widget.LinearLayout; |
| |
| /** |
| * A presenter that assumes a LinearLayout container for a series |
| * of control buttons backed by objects of type {@link Action}. |
| * |
| * Different layouts may be passed to the presenter constructor. |
| * The layout must contain a view with id control_bar. |
| */ |
| class ControlBarPresenter extends Presenter { |
| |
| private static final int MAX_CONTROLS = 7; |
| |
| /** |
| * The data type expected by this presenter. |
| */ |
| static class BoundData { |
| /** |
| * Adapter containing objects of type {@link Action}. |
| */ |
| ObjectAdapter adapter; |
| |
| /** |
| * The presenter to be used for the adapter objects. |
| */ |
| Presenter presenter; |
| } |
| |
| /** |
| * Listener for control selected events. |
| */ |
| interface OnControlSelectedListener { |
| void onControlSelected(Presenter.ViewHolder controlViewHolder, Object item, |
| BoundData data); |
| } |
| |
| /** |
| * Listener for control clicked events. |
| */ |
| interface OnControlClickedListener { |
| void onControlClicked(Presenter.ViewHolder controlViewHolder, Object item, |
| BoundData data); |
| } |
| |
| class ViewHolder extends Presenter.ViewHolder { |
| ObjectAdapter mAdapter; |
| BoundData mData; |
| Presenter mPresenter; |
| ControlBar mControlBar; |
| SparseArray<Presenter.ViewHolder> mViewHolders = |
| new SparseArray<Presenter.ViewHolder>(); |
| ObjectAdapter.DataObserver mDataObserver; |
| |
| /** |
| * Constructor for the ViewHolder. |
| */ |
| ViewHolder(View rootView) { |
| super(rootView); |
| mControlBar = (ControlBar) rootView.findViewById(R.id.control_bar); |
| if (mControlBar == null) { |
| throw new IllegalStateException("Couldn't find control_bar"); |
| } |
| mControlBar.setOnChildFocusedListener(new ControlBar.OnChildFocusedListener() { |
| @Override |
| public void onChildFocusedListener(View child, View focused) { |
| if (mOnControlSelectedListener == null) { |
| return; |
| } |
| for (int position = 0; position < mViewHolders.size(); position++) { |
| if (mViewHolders.get(position).view == child) { |
| mOnControlSelectedListener.onControlSelected( |
| mViewHolders.get(position), |
| getDisplayedAdapter().get(position), mData); |
| break; |
| } |
| } |
| } |
| }); |
| mDataObserver = new ObjectAdapter.DataObserver() { |
| @Override |
| public void onChanged() { |
| if (mAdapter == getDisplayedAdapter()) { |
| showControls(mPresenter); |
| } |
| } |
| @Override |
| public void onItemRangeChanged(int positionStart, int itemCount) { |
| if (mAdapter == getDisplayedAdapter()) { |
| for (int i = 0; i < itemCount; i++) { |
| bindControlToAction(positionStart + i, mPresenter); |
| } |
| } |
| } |
| }; |
| } |
| |
| int getChildMarginFromCenter(Context context, int numControls) { |
| // Includes margin between icons plus two times half the icon width. |
| return getChildMarginDefault(context) + getControlIconWidth(context); |
| } |
| |
| void showControls(Presenter presenter) { |
| ObjectAdapter adapter = getDisplayedAdapter(); |
| int adapterSize = adapter == null ? 0 : adapter.size(); |
| // Shrink the number of attached views |
| View focusedView = mControlBar.getFocusedChild(); |
| if (focusedView != null && adapterSize > 0 && |
| mControlBar.indexOfChild(focusedView) >= adapterSize) { |
| mControlBar.getChildAt(adapter.size() - 1).requestFocus(); |
| } |
| for (int i = mControlBar.getChildCount() - 1; i >= adapterSize; i--) { |
| mControlBar.removeViewAt(i); |
| } |
| for (int position = 0; position < adapterSize && position < MAX_CONTROLS; |
| position++) { |
| bindControlToAction(position, adapter, presenter); |
| } |
| mControlBar.setChildMarginFromCenter( |
| getChildMarginFromCenter(mControlBar.getContext(), adapterSize)); |
| } |
| |
| void bindControlToAction(int position, Presenter presenter) { |
| bindControlToAction(position, getDisplayedAdapter(), presenter); |
| } |
| |
| private void bindControlToAction(final int position, |
| ObjectAdapter adapter, Presenter presenter) { |
| Presenter.ViewHolder vh = mViewHolders.get(position); |
| Object item = adapter.get(position); |
| if (vh == null) { |
| vh = presenter.onCreateViewHolder(mControlBar); |
| mViewHolders.put(position, vh); |
| |
| final Presenter.ViewHolder itemViewHolder = vh; |
| presenter.setOnClickListener(vh, new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| Object item = getDisplayedAdapter().get(position); |
| if (mOnControlClickedListener != null) { |
| mOnControlClickedListener.onControlClicked(itemViewHolder, item, |
| mData); |
| } |
| } |
| }); |
| } |
| if (vh.view.getParent() == null) { |
| mControlBar.addView(vh.view); |
| } |
| presenter.onBindViewHolder(vh, item); |
| } |
| |
| /** |
| * Returns the adapter currently bound to the displayed controls. |
| * May be overridden in a subclass. |
| */ |
| ObjectAdapter getDisplayedAdapter() { |
| return mAdapter; |
| } |
| } |
| |
| private OnControlClickedListener mOnControlClickedListener; |
| private OnControlSelectedListener mOnControlSelectedListener; |
| private int mLayoutResourceId; |
| private static int sChildMarginDefault; |
| private static int sControlIconWidth; |
| |
| /** |
| * Constructor for a ControlBarPresenter. |
| * |
| * @param layoutResourceId The resource id of the layout for this presenter. |
| */ |
| public ControlBarPresenter(int layoutResourceId) { |
| mLayoutResourceId = layoutResourceId; |
| } |
| |
| /** |
| * Returns the layout resource id. |
| */ |
| public int getLayoutResourceId() { |
| return mLayoutResourceId; |
| } |
| |
| /** |
| * Sets the listener for control clicked events. |
| */ |
| public void setOnControlClickedListener(OnControlClickedListener listener) { |
| mOnControlClickedListener = listener; |
| } |
| |
| /** |
| * Returns the listener for control clicked events. |
| */ |
| public OnControlClickedListener getOnItemViewClickedListener() { |
| return mOnControlClickedListener; |
| } |
| |
| /** |
| * Sets the listener for control selection. |
| */ |
| public void setOnControlSelectedListener(OnControlSelectedListener listener) { |
| mOnControlSelectedListener = listener; |
| } |
| |
| /** |
| * Returns the listener for control selection. |
| */ |
| public OnControlSelectedListener getOnItemControlListener() { |
| return mOnControlSelectedListener; |
| } |
| |
| @Override |
| public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) { |
| View v = LayoutInflater.from(parent.getContext()) |
| .inflate(getLayoutResourceId(), parent, false); |
| return new ViewHolder(v); |
| } |
| |
| @Override |
| public void onBindViewHolder(Presenter.ViewHolder holder, Object item) { |
| ViewHolder vh = (ViewHolder) holder; |
| BoundData data = (BoundData) item; |
| if (vh.mAdapter != data.adapter) { |
| vh.mAdapter = data.adapter; |
| if (vh.mAdapter != null) { |
| vh.mAdapter.registerObserver(vh.mDataObserver); |
| } |
| } |
| vh.mPresenter = data.presenter; |
| vh.mData = data; |
| vh.showControls(vh.mPresenter); |
| } |
| |
| @Override |
| public void onUnbindViewHolder(Presenter.ViewHolder holder) { |
| ViewHolder vh = (ViewHolder) holder; |
| if (vh.mAdapter != null) { |
| vh.mAdapter.unregisterObserver(vh.mDataObserver); |
| vh.mAdapter = null; |
| } |
| vh.mData = null; |
| } |
| |
| int getChildMarginDefault(Context context) { |
| if (sChildMarginDefault == 0) { |
| sChildMarginDefault = context.getResources().getDimensionPixelSize( |
| R.dimen.lb_playback_controls_child_margin_default); |
| } |
| return sChildMarginDefault; |
| } |
| |
| int getControlIconWidth(Context context) { |
| if (sControlIconWidth == 0) { |
| sControlIconWidth = context.getResources().getDimensionPixelSize( |
| R.dimen.lb_control_icon_width); |
| } |
| return sControlIconWidth; |
| } |
| } |