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;
237adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiriimport android.util.TypedValue;
24b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.view.ContextThemeWrapper;
25b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.view.LayoutInflater;
26b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.view.View;
27b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.view.ViewGroup;
284fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport android.view.animation.DecelerateInterpolator;
29b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.widget.TextView;
307adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiriimport android.widget.ViewFlipper;
31b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport java.util.ArrayList;
334fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport java.util.List;
344fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
35b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri/**
36b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * Abstract {@link Presenter} class for rendering media items in a playlist format.
374fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Media item data provided for this presenter can implement the interface
384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * {@link MultiActionsProvider}, if the media rows wish to contain custom actions.
394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Media items in the playlist are arranged as a vertical list with each row holding each media
404fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * item's details provided by the user of this class and a set of optional custom actions.
414fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Each media item's details and actions are separately focusable.
424fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * The appearance of each one of the media row components can be controlled through setting
434fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * theme's attributes.
447adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri * Each media item row provides a view flipper for switching between different views depending on
457adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri * the playback state.
467adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri * A default layout is provided by this presenter for rendering different playback states, or a
477adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri * custom layout can be provided by the user by overriding the
487adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri * playbackMediaItemNumberViewFlipperLayout attribute in the currently specified theme.
497adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri * Subclasses should also override {@link #getMediaPlayState(Object)} to provide the current play
507adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri * state of their media item model in case they wish to use different views depending on the
517adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri * playback state.
524fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * The presenter can optionally provide line separators between media rows by setting
534fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * {@link #setHasMediaRowSeparator(boolean)} to true.
544fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * <p>
554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri *     Subclasses must override {@link #onBindMediaDetails} to implement their media item model
564fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri *     data binding to each row view.
574fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * </p>
58b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * <p>
594fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri *     The {@link OnItemViewClickedListener} and {@link OnItemViewSelectedListener}
604fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri *     can be used in the same fashion to handle selection or click events on either of
614fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri *     media details or each individual action views.
62b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * </p>
63b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * <p>
64b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri *     {@link AbstractMediaListHeaderPresenter} can be used in conjunction with this presenter in
654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri *     order to display a playlist with a header view.
66b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * </p>
67b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri */
68b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiripublic abstract class AbstractMediaItemPresenter extends RowPresenter {
69b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
707adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    /**
717adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * Different playback states of a media item
727adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     */
737adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri
747adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    /**
757adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * Indicating that the media item is currently neither playing nor paused.
767adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     */
777adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    public static final int PLAY_STATE_INITIAL = 0;
787adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    /**
797adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * Indicating that the media item is currently paused.
807adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     */
817adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    public static final int PLAY_STATE_PAUSED = 1;
827adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    /**
837adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * Indicating that the media item is currently playing
847adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     */
857adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    public static final int PLAY_STATE_PLAYING = 2;
867adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri
874fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    final static Rect sTempRect = new Rect();
88b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    private int mBackgroundColor = Color.TRANSPARENT;
89b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    private boolean mBackgroundColorSet;
904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    private boolean mMediaRowSeparator;
914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    private int mThemeId;
924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    private Presenter mMediaItemActionPresenter = new MediaItemActionPresenter();
94b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
95b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    /**
964fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Constructor used for creating an abstract media item presenter.
97b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     */
984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public AbstractMediaItemPresenter() {
994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        this(0);
100b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
101b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
102b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    /**
103b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * Constructor used for creating an abstract media item presenter.
1044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param themeId The resource id of the theme that defines attributes controlling the
1054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *                appearance of different widgets in a media item row.
106b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     */
1074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public AbstractMediaItemPresenter(int themeId) {
1084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        mThemeId = themeId;
109b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        setHeaderPresenter(null);
110b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
111b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
112b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    /**
1134fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Sets the theme used to style a media item row components.
1144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param themeId The resource id of the theme that defines attributes controlling the
1154fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *                appearance of different widgets in a media item row.
1164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
1174fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public void setThemeId(int themeId) {
1184fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        mThemeId = themeId;
1194fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
1204fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
1214fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
1224fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Return The resource id of the theme that defines attributes controlling the appearance of
1234fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * different widgets in a media item row.
1244fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *
1254fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @return The resource id of the theme that defines attributes controlling the appearance of
1264fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * different widgets in a media item row.
1274fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
1284fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public int getThemeId() {
1294fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        return mThemeId;
1304fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
1314fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
1324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
1334fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Sets the action presenter rendering each optional custom action within each media item row.
1344fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param actionPresenter the presenter to be used for rendering a media item row actions.
1354fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
1364fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public void setActionPresenter(Presenter actionPresenter) {
1374fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        mMediaItemActionPresenter = actionPresenter;
1384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
1394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
1404fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
1414fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Return the presenter used to render a media item row actions.
1424fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *
1434fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @return the presenter used to render a media item row actions.
1444fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
1454fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public Presenter getActionPresenter() {
1464fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        return mMediaItemActionPresenter;
1474fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
1484fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
1494fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
150b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * The ViewHolder for the {@link AbstractMediaItemPresenter}. It references different views
1514fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * that place different meta-data corresponding to a media item details, actions, selector,
1524fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * listeners, and presenters,
153b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     */
154b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    public static class ViewHolder extends RowPresenter.ViewHolder {
155b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
15699ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        final View mMediaRowView;
15799ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        final View mSelectorView;
1584fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final View mMediaItemDetailsView;
15999ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        final ViewFlipper mMediaItemNumberViewFlipper;
16099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        final TextView mMediaItemNumberView;
16199ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        final View mMediaItemPausedView;
1627adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri
16399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        final View mMediaItemPlayingView;
1644fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final TextView mMediaItemNameView;
1654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final TextView mMediaItemDurationView;
1664fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final View mMediaItemRowSeparator;
1674fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final ViewGroup mMediaItemActionsContainer;
1684fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        private final List<Presenter.ViewHolder> mActionViewHolders;
16999ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        MultiActionsProvider.MultiAction[] mMediaItemRowActions;
1704fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        AbstractMediaItemPresenter mRowPresenter;
17199ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas        ValueAnimator mFocusViewAnimator;
172b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
173b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        public ViewHolder(View view) {
174b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri            super(view);
1754fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mSelectorView = view.findViewById(R.id.mediaRowSelector);
1764fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaRowView  = view.findViewById(R.id.mediaItemRow);
1774fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemDetailsView = view.findViewById(R.id.mediaItemDetails);
1784fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemNameView = (TextView) view.findViewById(R.id.mediaItemName);
1794fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemDurationView = (TextView) view.findViewById(R.id.mediaItemDuration);
1804fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemRowSeparator = view.findViewById(R.id.mediaRowSeparator);
1814fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemActionsContainer = (ViewGroup) view.findViewById(
1824fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    R.id.mediaItemActionsContainer);
1834fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mActionViewHolders = new ArrayList<Presenter.ViewHolder>();
1844fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            getMediaItemDetailsView().setOnClickListener(new View.OnClickListener(){
1854fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                @Override
1864fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                public void onClick(View view) {
1874fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    if (getOnItemViewClickedListener() != null) {
1884fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        getOnItemViewClickedListener().onItemClicked(null, null,
1894fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                ViewHolder.this, getRowObject());
1904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    }
1914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                }
1924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            });
1934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            getMediaItemDetailsView().setOnFocusChangeListener(new View.OnFocusChangeListener() {
1944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                @Override
1954fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                public void onFocusChange(View view, boolean hasFocus) {
1964fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    mFocusViewAnimator = updateSelector(mSelectorView, view, mFocusViewAnimator,
1974fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                            true);
1984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                }
1994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            });
2007adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            mMediaItemNumberViewFlipper =
2017adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                    (ViewFlipper) view.findViewById(R.id.mediaItemNumberViewFlipper);
2027adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri
2037adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            TypedValue typedValue = new TypedValue();
2047adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            boolean found = view.getContext().getTheme().resolveAttribute(
2057adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                    R.attr.playbackMediaItemNumberViewFlipperLayout, typedValue, true);
2067adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            View mergeView = LayoutInflater.from(view.getContext()).
2077adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                    inflate(found ? typedValue.resourceId :
2087adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                            R.layout.lb_media_item_number_view_flipper,
2097adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                            mMediaItemNumberViewFlipper, true);
2107adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri
2117adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            mMediaItemNumberView = (TextView) mergeView.findViewById(R.id.initial);
2127adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            mMediaItemPausedView = mergeView.findViewById(R.id.paused);
2137adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            mMediaItemPlayingView = mergeView.findViewById(R.id.playing);
2144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
2154fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
2174fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * Binds the actions in a media item row object to their views. This consists of creating
2184fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * (or reusing the existing) action view holders, and populating them with the actions'
2194fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * icons.
2204fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
2214fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public void onBindRowActions() {
2224fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            for (int i = getMediaItemActionsContainer().getChildCount() - 1;
2234fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                 i >= mActionViewHolders.size(); i--) {
2244fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                getMediaItemActionsContainer().removeViewAt(i);
2254fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                mActionViewHolders.remove(i);
2264fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
2274fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemRowActions = null;
2284fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2294fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            Object rowObject = getRowObject();
2304fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            final MultiActionsProvider.MultiAction[] actionList;
2314fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (rowObject instanceof MultiActionsProvider) {
2324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                actionList = ((MultiActionsProvider) rowObject).getActions();
2334fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            } else {
2344fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                return;
2354fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
2364fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            Presenter actionPresenter = mRowPresenter.getActionPresenter();
2374fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (actionPresenter == null) {
2384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                return;
2394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
2404fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2414fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mMediaItemRowActions = actionList;
2424fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            for (int i = mActionViewHolders.size(); i < actionList.length; i++) {
2434fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                final int actionIndex = i;
2444fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                final Presenter.ViewHolder actionViewHolder = actionPresenter.
2454fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        onCreateViewHolder(getMediaItemActionsContainer());
2464fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                getMediaItemActionsContainer().addView(actionViewHolder.view);
2474fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                mActionViewHolders.add(actionViewHolder);
2484fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                actionViewHolder.view.setOnFocusChangeListener(new View.OnFocusChangeListener() {
2494fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    @Override
2504fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    public void onFocusChange(View view, boolean hasFocus) {
2514fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        mFocusViewAnimator = updateSelector(mSelectorView, view,
2524fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                mFocusViewAnimator, false);
2534fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    }
2544fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                });
2554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                actionViewHolder.view.setOnClickListener(
2564fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        new View.OnClickListener() {
2574fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                            @Override
2584fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                            public void onClick(View view) {
2594fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                if (getOnItemViewClickedListener() != null) {
2604fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                    getOnItemViewClickedListener().onItemClicked(
2614fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                            actionViewHolder, mMediaItemRowActions[actionIndex],
2624fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                            ViewHolder.this, getRowObject());
2634fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                                }
2644fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                            }
2654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        });
2664fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
2674fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2684fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (mMediaItemActionsContainer != null) {
2694fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                for (int i = 0; i < actionList.length; i++) {
2704fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    Presenter.ViewHolder avh = mActionViewHolders.get(i);
2714fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    actionPresenter.onUnbindViewHolder(avh);
2724fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    actionPresenter.onBindViewHolder(avh, mMediaItemRowActions[i]);
2734fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                }
2744fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
2754fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2764fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
2774fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2784fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        int findActionIndex(MultiActionsProvider.MultiAction action) {
2794fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (mMediaItemRowActions != null) {
2804fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                for (int i = 0; i < mMediaItemRowActions.length; i++) {
2814fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    if (mMediaItemRowActions[i] == action) {
2824fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        return i;
2834fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    }
2844fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                }
2854fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
2864fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return -1;
2874fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
2884fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
2894fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
2904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * Notifies an action has changed in this media row and the UI needs to be updated
2914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * @param action The action whose state has changed
2924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
2934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public void notifyActionChanged(MultiActionsProvider.MultiAction action) {
2944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            Presenter actionPresenter = mRowPresenter.getActionPresenter();
2954fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (actionPresenter == null) {
2964fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                return;
2974fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
2984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            int actionIndex = findActionIndex(action);
2994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (actionIndex >= 0) {
3004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                Presenter.ViewHolder actionViewHolder = mActionViewHolders.get(actionIndex);
3014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                actionPresenter.onUnbindViewHolder(actionViewHolder);
3024fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                actionPresenter.onBindViewHolder(actionViewHolder, action);
3034fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
3044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
3054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3064fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
3074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * Notifies the content of the media item details in a row has changed and triggers updating
3084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * the UI. This causes {@link #onBindMediaDetails(ViewHolder, Object)}
3094fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * on the user's provided presenter to be called back, allowing them to update UI
3104fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * accordingly.
3114fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
3124fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public void notifyDetailsChanged() {
3134fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mRowPresenter.onUnbindMediaDetails(this);
3144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            mRowPresenter.onBindMediaDetails(this, getRowObject());
3154fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
3164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3177adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        /**
3187adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * Notifies the playback state of the media item row has changed. This in turn triggers
3197adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * updating of the UI for that media item row if corresponding views are specified for each
3207adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * playback state.
3217adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * By default, 3 views are provided for each playback state, or these views can be provided
3227adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * by the user.
3237adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         */
3247adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        public void notifyPlayStateChanged() {
3257adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            mRowPresenter.onBindMediaPlayState(this);
3267adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        }
3274fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3284fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
3294fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * @return The SelectorView responsible for highlighting the in-focus view within each
3304fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * media item row
3314fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
3324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public View getSelectorView() {
3334fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mSelectorView;
334b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        }
335b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
336b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        /**
3377adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * @return The FlipperView responsible for flipping between different media item number
3387adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * views depending on the playback state
3397adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         */
3407adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        public ViewFlipper getMediaItemNumberViewFlipper() {
3417adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            return mMediaItemNumberViewFlipper;
3427adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        }
3437adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri
3447adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        /**
3457adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * @return The TextView responsible for rendering the media item number.
3467adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * This view is rendered when the media item row is neither playing nor paused.
347b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri         */
3484fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public TextView getMediaItemNumberView() {
3494fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemNumberView;
350b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        }
351b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
352b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        /**
3537adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * @return The view rendered when the media item row is paused.
3547adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         */
3557adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        public View getMediaItemPausedView() {
3567adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            return mMediaItemPausedView;
3577adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        }
3587adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri
3597adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        /**
3607adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * @return The view rendered when the media item row is playing.
3617adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         */
3627adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        public View getMediaItemPlayingView() {
3637adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            return mMediaItemPlayingView;
3647adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        }
3657adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri
3667adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri
3677adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        /**
36878be4412362eafffe14b60a20b7ddd4bf86a515bKeyvan Amiri         * Flips to the view at index 'position'. This position corresponds to the index of a
36978be4412362eafffe14b60a20b7ddd4bf86a515bKeyvan Amiri         * particular view within the ViewFlipper layout specified for the MediaItemNumberView
37078be4412362eafffe14b60a20b7ddd4bf86a515bKeyvan Amiri         * (see playbackMediaItemNumberViewFlipperLayout attribute).
37178be4412362eafffe14b60a20b7ddd4bf86a515bKeyvan Amiri         * @param position The index of the child view to display.
3727adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         */
3737adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        public void setSelectedMediaItemNumberView(int position) {
3747adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            if (position >= 0 & position < mMediaItemNumberViewFlipper.getChildCount()) {
3757adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                mMediaItemNumberViewFlipper.setDisplayedChild(position);
3767adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            }
3777adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        }
3787adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        /**
3797adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * Returns the view displayed when the media item is neither playing nor paused,
3807adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * corresponding to the playback state of PLAY_STATE_INITIAL.
3817adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * @return The TextView responsible for rendering the media item name.
382b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri         */
3834fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public TextView getMediaItemNameView() {
3844fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemNameView;
385b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        }
386b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
387b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        /**
3887adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * @return The TextView responsible for rendering the media item duration
389b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri         */
3904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public TextView getMediaItemDurationView() {
3914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemDurationView;
3924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
3934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
3944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
3957adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * @return The view container of media item details
3964fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
3974fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public View getMediaItemDetailsView() {
3984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemDetailsView;
3994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
4004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
4024fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * @return The view responsible for rendering the separator line between media rows
4034fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
4044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public View getMediaItemRowSeparator() {
4054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemRowSeparator;
4064fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
4074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        /**
4094fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         * @return The view containing the set of custom actions
4104fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri         */
4114fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public ViewGroup getMediaItemActionsContainer() {
4124fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemActionsContainer;
4134fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
4144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4157adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        /**
4167adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         * @return Array of MultiActions displayed for this media item row
4177adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri         */
4184fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        public MultiActionsProvider.MultiAction[] getMediaItemRowActions() {
4194fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return mMediaItemRowActions;
420b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        }
421b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
422b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
423b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    @Override
424b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
4254fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        Context context = parent.getContext();
4264fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        if (mThemeId != 0) {
4274fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            context = new ContextThemeWrapper(context, mThemeId);
4284fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
429b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        View view = LayoutInflater.from(context).
430b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri                inflate(R.layout.lb_row_media_item, parent, false);
4314fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        final ViewHolder vh = new ViewHolder(view);
4324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        vh.mRowPresenter = this;
433b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        if (mBackgroundColorSet) {
4344fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            vh.mMediaRowView.setBackgroundColor(mBackgroundColor);
435b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        }
4364fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        return vh;
437b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
438b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
439b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    @Override
440b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    public boolean isUsingDefaultSelectEffect() {
441b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        return false;
442b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
443b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
444b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    @Override
4454fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    protected boolean isClippingChildren() {
4464fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        return true;
4474fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
4484fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4494fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    @Override
450b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    protected void onBindRowViewHolder(RowPresenter.ViewHolder vh, Object item) {
451b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        super.onBindRowViewHolder(vh, item);
4524fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4534fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        final ViewHolder mvh = (ViewHolder) vh;
4544fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        onBindRowActions(mvh);
4564fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4574fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        mvh.getMediaItemRowSeparator().setVisibility(hasMediaRowSeparator() ? View.VISIBLE :
4584fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                View.GONE);
4594fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4607adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        onBindMediaPlayState(mvh);
4614fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        onBindMediaDetails((ViewHolder) vh, item);
4624fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
4634fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4644fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
4654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Binds the given media item object action to the given ViewHolder's action views.
4664fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param vh ViewHolder for the media item.
4674fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
4684fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    protected void onBindRowActions(ViewHolder vh) {
4694fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        vh.onBindRowActions();
470b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
471b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
472b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    /**
473b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * Sets the background color for the row views within the playlist.
474b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * If this is not set, a default color, defaultBrandColor, from theme is used.
475b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * This defaultBrandColor defaults to android:attr/colorPrimary on v21, if it's specified.
476b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * @param color The ARGB color used to set as the media list background color.
477b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     */
478b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    public void setBackgroundColor(int color) {
479b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        mBackgroundColorSet = true;
480b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri        mBackgroundColor = color;
481b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    }
482b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
483b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri    /**
4844fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Specifies whether a line separator should be used between media item rows.
4854fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param hasSeparator true if a separator should be displayed, false otherwise.
4864fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
4874fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public void setHasMediaRowSeparator(boolean hasSeparator) {
4884fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        mMediaRowSeparator = hasSeparator;
4894fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
4904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
4914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    public boolean hasMediaRowSeparator() {
4924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        return mMediaRowSeparator;
4934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
4944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
4954fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Binds the media item details to their views provided by the
496b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * {@link AbstractMediaItemPresenter}.
4974fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * This method is to be overridden by the users of this presenter.
4984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * The subclasses of this presenter can access and bind individual views for either of the
4994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * media item number, name, or duration (depending on whichever views are visible according to
5004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * the providing theme attributes), by calling {@link ViewHolder#getMediaItemNumberView()},
5014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * {@link ViewHolder#getMediaItemNameView()}, and {@link ViewHolder#getMediaItemDurationView()},
5024fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * on the {@link ViewHolder} provided as the argument {@code vh} of this presenter.
503b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     *
504b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     * @param vh The ViewHolder for this {@link AbstractMediaItemPresenter}.
5054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param item The media item row object being presented.
506b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri     */
5074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    protected abstract void onBindMediaDetails(ViewHolder vh, Object item);
5084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
5094fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
5104fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Unbinds the media item details from their views provided by the
5114fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * {@link AbstractMediaItemPresenter}.
5124fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * This method can be overridden by the subclasses of this presenter if required.
5134fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param vh ViewHolder to unbind from.
5144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
5154fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    protected void onUnbindMediaDetails(ViewHolder vh) {
5164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
517b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri
5184fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    /**
5197adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * Binds the media item number view to the appropriate play state view of the media item.
5207adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * The play state of the media item is extracted by calling {@link #getMediaPlayState(Object)} for
5217adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * the media item embedded within this view.
5227adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * This method triggers updating of the playback state UI if corresponding views are specified
5237adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * for the current playback state.
5247adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * By default, 3 views are provided for each playback state, or these views can be provided
5257adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * by the user.
5267adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     */
5277adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    public void onBindMediaPlayState(ViewHolder vh) {
5287adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        int childIndex = calculateMediaItemNumberFlipperIndex(vh);
5297adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        if (childIndex != -1 && vh.mMediaItemNumberViewFlipper.getDisplayedChild() != childIndex) {
5307adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            vh.mMediaItemNumberViewFlipper.setDisplayedChild(childIndex);
5317adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        }
5327adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    }
5337adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri
5347adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    static int calculateMediaItemNumberFlipperIndex(ViewHolder vh) {
5357adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        int childIndex = -1;
5367adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        int newPlayState = vh.mRowPresenter.getMediaPlayState(vh.getRowObject());
5377adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        switch (newPlayState) {
5387adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            case PLAY_STATE_INITIAL:
5397adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                childIndex = (vh.mMediaItemNumberView == null) ? -1 :
5407adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                        vh.mMediaItemNumberViewFlipper.indexOfChild(vh.mMediaItemNumberView);
5417adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                break;
5427adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            case PLAY_STATE_PAUSED:
5437adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                childIndex = (vh.mMediaItemPausedView == null) ? -1 :
5447adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                        vh.mMediaItemNumberViewFlipper.indexOfChild(vh.mMediaItemPausedView);
5457adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                break;
5467adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri            case PLAY_STATE_PLAYING:
5477adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                childIndex = (vh.mMediaItemPlayingView == null) ? -1 :
5487adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri                        vh.mMediaItemNumberViewFlipper.indexOfChild(vh.mMediaItemPlayingView);
5497adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        }
5507adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        return childIndex;
5517adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    }
5527adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri
5537adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    /**
55478be4412362eafffe14b60a20b7ddd4bf86a515bKeyvan Amiri     * Called when the given ViewHolder wants to unbind the play state view.
55578be4412362eafffe14b60a20b7ddd4bf86a515bKeyvan Amiri     * @param vh The ViewHolder to unbind from.
5567adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     */
5577adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    public void onUnbindMediaPlayState(ViewHolder vh) {
5587adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    }
5597adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri
5607adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    /**
5617adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * Returns the current play state of the given media item. By default, this method returns
5627adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * PLAY_STATE_INITIAL which causes the media item number
5637adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * {@link ViewHolder#getMediaItemNameView()} to be displayed for different
5647adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * playback states. Users of this class should override this method in order to provide the
5657adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * play state of their custom media item data model.
5667adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * @param item The media item
5677adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     * @return The current play state of this media item
5687adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri     */
5697adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    protected int getMediaPlayState(Object item) {
5707adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri        return PLAY_STATE_INITIAL;
5717adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    }
5727adf7fdd0c2978bb0a87096c89d6356e4e26ad98Keyvan Amiri    /**
5734fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * Each media item row can have multiple focusable elements; the details on the left and a set
5744fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * of optional custom actions on the right.
5754fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * The selector is a highlight that moves to highlight to cover whichever views is in focus.
5764fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *
5774fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param selectorView the selector view used to highlight an individual element within a row.
5784fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param focusChangedView The component within the media row whose focus got changed.
5794fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param layoutAnimator the ValueAnimator producing animation frames for the selector's width
5804fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *                       and x-translation, generated by this method and stored for the each
5814fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *                       {@link ViewHolder}.
5824fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     * @param isDetails Whether the changed-focused view is for a media item details (true) or
5834fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     *                  an action (false).
5844fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri     */
58599ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    static ValueAnimator updateSelector(final View selectorView,
5864fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            View focusChangedView, ValueAnimator layoutAnimator, boolean isDetails) {
5874fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        int animationDuration = focusChangedView.getContext().getResources()
5884fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                .getInteger(android.R.integer.config_shortAnimTime);
5894fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        DecelerateInterpolator interpolator = new DecelerateInterpolator();
5904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
5914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        int layoutDirection = ViewCompat.getLayoutDirection(selectorView);
5924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        if (!focusChangedView.hasFocus()) {
5934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            // if neither of the details or action views are in focus (ie. another row is in focus),
5944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            // animate the selector out.
5954fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            selectorView.animate().cancel();
5964fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            selectorView.animate().alpha(0f).setDuration(animationDuration)
5974fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    .setInterpolator(interpolator).start();
5984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            // keep existing layout animator
5994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return layoutAnimator;
6004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        } else {
6014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            // cancel existing layout animator
6024fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (layoutAnimator != null) {
6034fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator.cancel();
6044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator = null;
6054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
6064fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            float currentAlpha = selectorView.getAlpha();
6074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            selectorView.animate().alpha(1f).setDuration(animationDuration)
6084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    .setInterpolator(interpolator).start();
6094fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
6104fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            final ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)
6114fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    selectorView.getLayoutParams();
6124fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            ViewGroup rootView = (ViewGroup) selectorView.getParent();
6134fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            sTempRect.set(0, 0, focusChangedView.getWidth(), focusChangedView.getHeight());
6144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            rootView.offsetDescendantRectToMyCoords(focusChangedView, sTempRect);
6154fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (isDetails) {
6164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                if (layoutDirection == View.LAYOUT_DIRECTION_RTL ) {
6174fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    sTempRect.right += rootView.getHeight();
6184fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    sTempRect.left -= rootView.getHeight() / 2;
6194fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                } else {
6204fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    sTempRect.left -= rootView.getHeight();
6214fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    sTempRect.right += rootView.getHeight() / 2;
6224fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                }
6234fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
6244fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            final int targetLeft = sTempRect.left;
6254fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            final int targetWidth = sTempRect.width();
6264fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            final float deltaWidth = lp.width - targetWidth;
6274fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            final float deltaLeft = lp.leftMargin - targetLeft;
6284fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
6294fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            if (deltaLeft == 0f && deltaWidth == 0f)
6304fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            {
6314fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                // no change needed
6324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            } else if (currentAlpha == 0f) {
6334fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                // change selector to the proper width and marginLeft without animation.
6344fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                lp.width = targetWidth;
6354fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                lp.leftMargin = targetLeft;
6364fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                selectorView.requestLayout();
6374fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            } else {
6384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                // animate the selector to the proper width and marginLeft.
6394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator = ValueAnimator.ofFloat(0f, 1f);
6404fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator.setDuration(animationDuration);
6414fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator.setInterpolator(interpolator);
6424fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
6434fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
6444fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    @Override
6454fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
6464fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        // Set width to the proper width for this animation step.
6474fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        float fractionToEnd = 1f - valueAnimator.getAnimatedFraction();
6484fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        lp.leftMargin = Math.round(targetLeft + deltaLeft * fractionToEnd);
6494fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        lp.width = Math.round(targetWidth + deltaWidth * fractionToEnd);
6504fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                        selectorView.requestLayout();
6514fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                    }
6524fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                });
6534fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri                layoutAnimator.start();
6544fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            }
6554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri            return layoutAnimator;
6564fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri
6574fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri        }
6584fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri    }
65978be4412362eafffe14b60a20b7ddd4bf86a515bKeyvan Amiri}
660