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