1b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri/*
2b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * Copyright (C) 2016 The Android Open Source Project
3b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri *
4b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * in compliance with the License. You may obtain a copy of the License at
6b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri *
7b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * http://www.apache.org/licenses/LICENSE-2.0
8b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri *
9b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * Unless required by applicable law or agreed to in writing, software distributed under the License
10b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * or implied. See the License for the specific language governing permissions and limitations under
12b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * the License.
13b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri */
14b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiripackage android.support.v17.leanback.widget;
15b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
174fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport android.animation.ValueAnimator;
18b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.content.Context;
19b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.graphics.Color;
204fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport android.graphics.Rect;
21b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.support.v17.leanback.R;
224fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport android.support.v4.view.ViewCompat;
23b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.view.ContextThemeWrapper;
24b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.view.LayoutInflater;
25b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.view.View;
26b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.view.ViewGroup;
274fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport android.view.animation.DecelerateInterpolator;
28b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.widget.TextView;
29b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
304fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport java.util.ArrayList;
314fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport java.util.List;
324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
33b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri/**
34b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * Abstract {@link Presenter} class for rendering media items in a playlist format.
354fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Media item data provided for this presenter can implement the interface
364fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * {@link MultiActionsProvider}, if the media rows wish to contain custom actions.
374fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Media items in the playlist are arranged as a vertical list with each row holding each media
384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * item's details provided by the user of this class and a set of optional custom actions.
394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Each media item's details and actions are separately focusable.
404fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * The appearance of each one of the media row components can be controlled through setting
414fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * theme's attributes.
424fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * The presenter can optionally provide line separators between media rows by setting
434fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * {@link #setHasMediaRowSeparator(boolean)} to true.
444fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * <p>
454fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri *     Subclasses must override {@link #onBindMediaDetails} to implement their media item model
464fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri *     data binding to each row view.
474fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * </p>
48b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * <p>
494fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri *     The {@link OnItemViewClickedListener} and {@link OnItemViewSelectedListener}
504fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri *     can be used in the same fashion to handle selection or click events on either of
514fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri *     media details or each individual action views.
52b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * </p>
53b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * <p>
54b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri *     {@link AbstractMediaListHeaderPresenter} can be used in conjunction with this presenter in
554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri *     order to display a playlist with a header view.
56b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * </p>
57b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri */
58b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiripublic abstract class AbstractMediaItemPresenter extends RowPresenter {
59b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
604fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    final static Rect sTempRect = new Rect();
61b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    private int mBackgroundColor = Color.TRANSPARENT;
62b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    private boolean mBackgroundColorSet;
634fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    private boolean mMediaRowSeparator;
644fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    private int mThemeId;
654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
664fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    private Presenter mMediaItemActionPresenter = new MediaItemActionPresenter();
67b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
68b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    /**
694fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Constructor used for creating an abstract media item presenter.
70b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     */
714fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public AbstractMediaItemPresenter() {
724fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        this(0);
73b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
74b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
75b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    /**
76b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * Constructor used for creating an abstract media item presenter.
774fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param themeId The resource id of the theme that defines attributes controlling the
784fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *                appearance of different widgets in a media item row.
79b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     */
804fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public AbstractMediaItemPresenter(int themeId) {
814fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        mThemeId = themeId;
82b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        setHeaderPresenter(null);
83b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
84b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
85b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    /**
864fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Sets the theme used to style a media item row components.
874fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param themeId The resource id of the theme that defines attributes controlling the
884fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *                appearance of different widgets in a media item row.
894fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public void setThemeId(int themeId) {
914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        mThemeId = themeId;
924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
954fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Return The resource id of the theme that defines attributes controlling the appearance of
964fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * different widgets in a media item row.
974fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *
984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @return The resource id of the theme that defines attributes controlling the appearance of
994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * different widgets in a media item row.
1004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
1014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public int getThemeId() {
1024fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        return mThemeId;
1034fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
1044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
1054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
1064fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Sets the action presenter rendering each optional custom action within each media item row.
1074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param actionPresenter the presenter to be used for rendering a media item row actions.
1084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
1094fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public void setActionPresenter(Presenter actionPresenter) {
1104fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        mMediaItemActionPresenter = actionPresenter;
1114fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
1124fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
1134fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
1144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Return the presenter used to render a media item row actions.
1154fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *
1164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @return the presenter used to render a media item row actions.
1174fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
1184fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public Presenter getActionPresenter() {
1194fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        return mMediaItemActionPresenter;
1204fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
1214fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
1224fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
123b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * The ViewHolder for the {@link AbstractMediaItemPresenter}. It references different views
1244fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * that place different meta-data corresponding to a media item details, actions, selector,
1254fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * listeners, and presenters,
126b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     */
127b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    public static class ViewHolder extends RowPresenter.ViewHolder {
128b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
1294fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final View mMediaRowView;
1304fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final View mSelectorView;
1314fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final View mMediaItemDetailsView;
1324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final TextView mMediaItemNumberView;
1334fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final TextView mMediaItemNameView;
1344fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final TextView mMediaItemDurationView;
1354fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final View mMediaItemRowSeparator;
1364fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final ViewGroup mMediaItemActionsContainer;
1374fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final List<Presenter.ViewHolder> mActionViewHolders;
1384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private MultiActionsProvider.MultiAction[] mMediaItemRowActions;
1394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        AbstractMediaItemPresenter mRowPresenter;
1404fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private ValueAnimator mFocusViewAnimator;
141b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
142b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        public ViewHolder(View view) {
143b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri            super(view);
1444fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mSelectorView = view.findViewById(R.id.mediaRowSelector);
1454fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaRowView  = view.findViewById(R.id.mediaItemRow);
1464fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemDetailsView = view.findViewById(R.id.mediaItemDetails);
1474fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemNumberView = (TextView) view.findViewById(R.id.mediaItemNumber);
1484fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemNameView = (TextView) view.findViewById(R.id.mediaItemName);
1494fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemDurationView = (TextView) view.findViewById(R.id.mediaItemDuration);
1504fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemRowSeparator = view.findViewById(R.id.mediaRowSeparator);
1514fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemActionsContainer = (ViewGroup) view.findViewById(
1524fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    R.id.mediaItemActionsContainer);
1534fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mActionViewHolders = new ArrayList<Presenter.ViewHolder>();
1544fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            getMediaItemDetailsView().setOnClickListener(new View.OnClickListener(){
1554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                @Override
1564fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                public void onClick(View view) {
1574fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    if (getOnItemViewClickedListener() != null) {
1584fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        getOnItemViewClickedListener().onItemClicked(null, null,
1594fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                ViewHolder.this, getRowObject());
1604fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    }
1614fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                }
1624fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            });
1634fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            getMediaItemDetailsView().setOnFocusChangeListener(new View.OnFocusChangeListener() {
1644fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                @Override
1654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                public void onFocusChange(View view, boolean hasFocus) {
1664fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    mFocusViewAnimator = updateSelector(mSelectorView, view, mFocusViewAnimator,
1674fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                            true);
1684fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                }
1694fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            });
1704fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
1714fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
1724fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
1734fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
1744fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * Binds the actions in a media item row object to their views. This consists of creating
1754fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * (or reusing the existing) action view holders, and populating them with the actions'
1764fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * icons.
1774fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
1784fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public void onBindRowActions() {
1794fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            for (int i = getMediaItemActionsContainer().getChildCount() - 1;
1804fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                 i >= mActionViewHolders.size(); i--) {
1814fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                getMediaItemActionsContainer().removeViewAt(i);
1824fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                mActionViewHolders.remove(i);
1834fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
1844fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemRowActions = null;
1854fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
1864fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            Object rowObject = getRowObject();
1874fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            final MultiActionsProvider.MultiAction[] actionList;
1884fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (rowObject instanceof MultiActionsProvider) {
1894fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                actionList = ((MultiActionsProvider) rowObject).getActions();
1904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            } else {
1914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                return;
1924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
1934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            Presenter actionPresenter = mRowPresenter.getActionPresenter();
1944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (actionPresenter == null) {
1954fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                return;
1964fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
1974fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
1984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemRowActions = actionList;
1994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            for (int i = mActionViewHolders.size(); i < actionList.length; i++) {
2004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                final int actionIndex = i;
2014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                final Presenter.ViewHolder actionViewHolder = actionPresenter.
2024fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        onCreateViewHolder(getMediaItemActionsContainer());
2034fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                getMediaItemActionsContainer().addView(actionViewHolder.view);
2044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                mActionViewHolders.add(actionViewHolder);
2054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                actionViewHolder.view.setOnFocusChangeListener(new View.OnFocusChangeListener() {
2064fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    @Override
2074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    public void onFocusChange(View view, boolean hasFocus) {
2084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        mFocusViewAnimator = updateSelector(mSelectorView, view,
2094fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                mFocusViewAnimator, false);
2104fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    }
2114fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                });
2124fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                actionViewHolder.view.setOnClickListener(
2134fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        new View.OnClickListener() {
2144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                            @Override
2154fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                            public void onClick(View view) {
2164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                if (getOnItemViewClickedListener() != null) {
2174fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                    getOnItemViewClickedListener().onItemClicked(
2184fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                            actionViewHolder, mMediaItemRowActions[actionIndex],
2194fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                            ViewHolder.this, getRowObject());
2204fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                }
2214fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                            }
2224fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        });
2234fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
2244fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2254fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (mMediaItemActionsContainer != null) {
2264fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                for (int i = 0; i < actionList.length; i++) {
2274fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    Presenter.ViewHolder avh = mActionViewHolders.get(i);
2284fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    actionPresenter.onUnbindViewHolder(avh);
2294fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    actionPresenter.onBindViewHolder(avh, mMediaItemRowActions[i]);
2304fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                }
2314fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
2324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2334fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
2344fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2354fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        int findActionIndex(MultiActionsProvider.MultiAction action) {
2364fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (mMediaItemRowActions != null) {
2374fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                for (int i = 0; i < mMediaItemRowActions.length; i++) {
2384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    if (mMediaItemRowActions[i] == action) {
2394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        return i;
2404fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    }
2414fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                }
2424fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
2434fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return -1;
2444fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
2454fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2464fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
2474fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * Notifies an action has changed in this media row and the UI needs to be updated
2484fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * @param action The action whose state has changed
2494fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
2504fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public void notifyActionChanged(MultiActionsProvider.MultiAction action) {
2514fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            Presenter actionPresenter = mRowPresenter.getActionPresenter();
2524fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (actionPresenter == null) {
2534fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                return;
2544fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
2554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            int actionIndex = findActionIndex(action);
2564fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (actionIndex >= 0) {
2574fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                Presenter.ViewHolder actionViewHolder = mActionViewHolders.get(actionIndex);
2584fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                actionPresenter.onUnbindViewHolder(actionViewHolder);
2594fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                actionPresenter.onBindViewHolder(actionViewHolder, action);
2604fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
2614fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
2624fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2634fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
2644fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * Notifies the content of the media item details in a row has changed and triggers updating
2654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * the UI. This causes {@link #onBindMediaDetails(ViewHolder, Object)}
2664fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * on the user's provided presenter to be called back, allowing them to update UI
2674fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * accordingly.
2684fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
2694fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public void notifyDetailsChanged() {
2704fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mRowPresenter.onUnbindMediaDetails(this);
2714fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mRowPresenter.onBindMediaDetails(this, getRowObject());
2724fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
2734fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2744fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2754fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
2764fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * @return The SelectorView responsible for highlighting the in-focus view within each
2774fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * media item row
2784fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
2794fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public View getSelectorView() {
2804fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mSelectorView;
281b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        }
282b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
283b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        /**
284b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri         * @return The TextView responsible for rendering the track number
285b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri         */
2864fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public TextView getMediaItemNumberView() {
2874fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemNumberView;
288b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        }
289b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
290b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        /**
291b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri         * @return The TextView responsible for rendering the track name
292b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri         */
2934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public TextView getMediaItemNameView() {
2944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemNameView;
295b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        }
296b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
297b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        /**
298b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri         * @return The TextView responsible for rendering the track duration
299b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri         */
3004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public TextView getMediaItemDurationView() {
3014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemDurationView;
3024fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
3034fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
3054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * @return The view container of track details
3064fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
3074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public View getMediaItemDetailsView() {
3084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemDetailsView;
3094fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
3104fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3114fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
3124fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * @return The view responsible for rendering the separator line between media rows
3134fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
3144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public View getMediaItemRowSeparator() {
3154fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemRowSeparator;
3164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
3174fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3184fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
3194fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * @return The view containing the set of custom actions
3204fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
3214fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public ViewGroup getMediaItemActionsContainer() {
3224fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemActionsContainer;
3234fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
3244fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3254fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public MultiActionsProvider.MultiAction[] getMediaItemRowActions() {
3264fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemRowActions;
327b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        }
328b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
329b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
330b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    @Override
331b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
3324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        Context context = parent.getContext();
3334fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        if (mThemeId != 0) {
3344fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            context = new ContextThemeWrapper(context, mThemeId);
3354fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
336b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        View view = LayoutInflater.from(context).
337b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri                inflate(R.layout.lb_row_media_item, parent, false);
3384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        final ViewHolder vh = new ViewHolder(view);
3394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        vh.mRowPresenter = this;
340b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        if (mBackgroundColorSet) {
3414fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            vh.mMediaRowView.setBackgroundColor(mBackgroundColor);
342b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        }
3434fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        return vh;
344b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
345b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
346b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    @Override
347b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    public boolean isUsingDefaultSelectEffect() {
348b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        return false;
349b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
350b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
351b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    @Override
3524fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    protected boolean isClippingChildren() {
3534fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        return true;
3544fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
3554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3564fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    @Override
357b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    protected void onBindRowViewHolder(RowPresenter.ViewHolder vh, Object item) {
358b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        super.onBindRowViewHolder(vh, item);
3594fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3604fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        final ViewHolder mvh = (ViewHolder) vh;
3614fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3624fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        onBindRowActions(mvh);
3634fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3644fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        mvh.getMediaItemRowSeparator().setVisibility(hasMediaRowSeparator() ? View.VISIBLE :
3654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                View.GONE);
3664fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3674fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        onBindMediaDetails((ViewHolder) vh, item);
3684fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
3694fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3704fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
3714fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Binds the given media item object action to the given ViewHolder's action views.
3724fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param vh ViewHolder for the media item.
3734fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
3744fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    protected void onBindRowActions(ViewHolder vh) {
3754fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        vh.onBindRowActions();
376b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
377b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
378b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    /**
379b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * Sets the background color for the row views within the playlist.
380b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * If this is not set, a default color, defaultBrandColor, from theme is used.
381b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * This defaultBrandColor defaults to android:attr/colorPrimary on v21, if it's specified.
382b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * @param color The ARGB color used to set as the media list background color.
383b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     */
384b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    public void setBackgroundColor(int color) {
385b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        mBackgroundColorSet = true;
386b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        mBackgroundColor = color;
387b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
388b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
389b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    /**
3904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Specifies whether a line separator should be used between media item rows.
3914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param hasSeparator true if a separator should be displayed, false otherwise.
3924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
3934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public void setHasMediaRowSeparator(boolean hasSeparator) {
3944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        mMediaRowSeparator = hasSeparator;
3954fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
3964fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3974fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public boolean hasMediaRowSeparator() {
3984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        return mMediaRowSeparator;
3994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
4004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
4014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Binds the media item details to their views provided by the
402b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * {@link AbstractMediaItemPresenter}.
4034fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * This method is to be overridden by the users of this presenter.
4044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * The subclasses of this presenter can access and bind individual views for either of the
4054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * media item number, name, or duration (depending on whichever views are visible according to
4064fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * the providing theme attributes), by calling {@link ViewHolder#getMediaItemNumberView()},
4074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * {@link ViewHolder#getMediaItemNameView()}, and {@link ViewHolder#getMediaItemDurationView()},
4084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * on the {@link ViewHolder} provided as the argument {@code vh} of this presenter.
409b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     *
410b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * @param vh The ViewHolder for this {@link AbstractMediaItemPresenter}.
4114fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param item The media item row object being presented.
412b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     */
4134fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    protected abstract void onBindMediaDetails(ViewHolder vh, Object item);
4144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4154fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
4164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Unbinds the media item details from their views provided by the
4174fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * {@link AbstractMediaItemPresenter}.
4184fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * This method can be overridden by the subclasses of this presenter if required.
4194fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param vh ViewHolder to unbind from.
4204fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
4214fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    protected void onUnbindMediaDetails(ViewHolder vh) {
4224fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
423b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
4244fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
4254fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Each media item row can have multiple focusable elements; the details on the left and a set
4264fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * of optional custom actions on the right.
4274fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * The selector is a highlight that moves to highlight to cover whichever views is in focus.
4284fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *
4294fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param selectorView the selector view used to highlight an individual element within a row.
4304fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param focusChangedView The component within the media row whose focus got changed.
4314fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param layoutAnimator the ValueAnimator producing animation frames for the selector's width
4324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *                       and x-translation, generated by this method and stored for the each
4334fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *                       {@link ViewHolder}.
4344fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param isDetails Whether the changed-focused view is for a media item details (true) or
4354fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *                  an action (false).
4364fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
4374fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    private static ValueAnimator updateSelector(final View selectorView,
4384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            View focusChangedView, ValueAnimator layoutAnimator, boolean isDetails) {
4394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        int animationDuration = focusChangedView.getContext().getResources()
4404fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                .getInteger(android.R.integer.config_shortAnimTime);
4414fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        DecelerateInterpolator interpolator = new DecelerateInterpolator();
4424fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4434fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        int layoutDirection = ViewCompat.getLayoutDirection(selectorView);
4444fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        if (!focusChangedView.hasFocus()) {
4454fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            // if neither of the details or action views are in focus (ie. another row is in focus),
4464fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            // animate the selector out.
4474fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            selectorView.animate().cancel();
4484fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            selectorView.animate().alpha(0f).setDuration(animationDuration)
4494fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    .setInterpolator(interpolator).start();
4504fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            // keep existing layout animator
4514fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return layoutAnimator;
4524fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        } else {
4534fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            // cancel existing layout animator
4544fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (layoutAnimator != null) {
4554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator.cancel();
4564fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator = null;
4574fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
4584fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            float currentAlpha = selectorView.getAlpha();
4594fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            selectorView.animate().alpha(1f).setDuration(animationDuration)
4604fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    .setInterpolator(interpolator).start();
4614fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4624fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            final ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)
4634fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    selectorView.getLayoutParams();
4644fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            ViewGroup rootView = (ViewGroup) selectorView.getParent();
4654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            sTempRect.set(0, 0, focusChangedView.getWidth(), focusChangedView.getHeight());
4664fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            rootView.offsetDescendantRectToMyCoords(focusChangedView, sTempRect);
4674fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (isDetails) {
4684fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                if (layoutDirection == View.LAYOUT_DIRECTION_RTL ) {
4694fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    sTempRect.right += rootView.getHeight();
4704fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    sTempRect.left -= rootView.getHeight() / 2;
4714fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                } else {
4724fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    sTempRect.left -= rootView.getHeight();
4734fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    sTempRect.right += rootView.getHeight() / 2;
4744fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                }
4754fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
4764fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            final int targetLeft = sTempRect.left;
4774fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            final int targetWidth = sTempRect.width();
4784fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            final float deltaWidth = lp.width - targetWidth;
4794fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            final float deltaLeft = lp.leftMargin - targetLeft;
4804fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4814fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (deltaLeft == 0f && deltaWidth == 0f)
4824fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            {
4834fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                // no change needed
4844fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            } else if (currentAlpha == 0f) {
4854fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                // change selector to the proper width and marginLeft without animation.
4864fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                lp.width = targetWidth;
4874fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                lp.leftMargin = targetLeft;
4884fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                selectorView.requestLayout();
4894fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            } else {
4904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                // animate the selector to the proper width and marginLeft.
4914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator = ValueAnimator.ofFloat(0f, 1f);
4924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator.setDuration(animationDuration);
4934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator.setInterpolator(interpolator);
4944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4954fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
4964fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    @Override
4974fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
4984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        // Set width to the proper width for this animation step.
4994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        float fractionToEnd = 1f - valueAnimator.getAnimatedFraction();
5004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        lp.leftMargin = Math.round(targetLeft + deltaLeft * fractionToEnd);
5014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        lp.width = Math.round(targetWidth + deltaWidth * fractionToEnd);
5024fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        selectorView.requestLayout();
5034fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    }
5044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                });
5054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator.start();
5064fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
5074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return layoutAnimator;
5084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
5094fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
5104fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
511b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri}