Showcase app: Added media row actions to the music fragment

am: f797f525ce

* commit 'f797f525ce3b5ce0338a18e64ece25e7bd5d8b1f':
  Showcase app: Added media row actions to the music fragment

Change-Id: I975255da9e985ae65951cf02502bbd9d0354defe
This commit is contained in:
Keyvan Amiri
2016-05-10 05:20:47 +00:00
committed by android-build-merger
15 changed files with 386 additions and 283 deletions

View File

@@ -16,6 +16,7 @@
android:allowBackup="true"
android:icon="@mipmap/app_banner_sample_app"
android:label="@string/app_name"
android:supportsRtl="true"
android:largeHeap="true"
android:theme="@style/Theme.Example.LeanbackLauncher">
<activity

View File

@@ -24,6 +24,7 @@ import android.net.Uri;
import android.os.Handler;
import android.support.v17.leanback.app.PlaybackControlGlue;
import android.support.v17.leanback.app.PlaybackOverlayFragment;
import android.support.v17.leanback.supportleanbackshowcase.R;
import android.support.v17.leanback.widget.Action;
import android.support.v17.leanback.widget.ArrayObjectAdapter;
import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
@@ -66,7 +67,6 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
private PlaybackControlsRow mControlsRow;
private Runnable mRunnable;
private Handler mHandler = new Handler();
private boolean mPaused = false;
private boolean mInitialized = false; // true when the MediaPlayer is prepared/initialized
private OnMediaFileFinishedPlayingListener mMediaFileFinishedPlayingListener;
private Action mSelectedAction; // the action which is currently selected by the user
@@ -87,10 +87,6 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsAction.OUTLINE);
// Setup controls and notify UI about change.
setFadingEnabled(false);
onStateChanged();
// Register selected listener such that we know what action the user currently has focused.
fragment.setOnItemViewSelectedListener(this);
}
@@ -100,8 +96,8 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
* not required to call this method before playing the first file. However you have to call it
* before playing a second one.
*/
public void reset() {
mPaused = mInitialized = false;
void reset() {
mInitialized = false;
mPlayer.reset();
}
@@ -137,8 +133,8 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
*/
public void setupControlsRowPresenter(PlaybackControlsRowPresenter presenter) {
// TODO: hahnr@ move into resources
presenter.setProgressColor(Color.parseColor("#feab91"));
presenter.setBackgroundColor(Color.parseColor("#db2a0f"));
presenter.setProgressColor(getContext().getColor(R.color.player_progress_color));
presenter.setBackgroundColor(getContext().getColor(R.color.player_background_color));
}
@Override public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
@@ -260,47 +256,12 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
}
@Override protected void startPlayback(int speed) throws IllegalStateException {
if (mPaused) {
mPlayer.start();
} else if (!isMediaPlaying()) {
reset();
try {
if (mMediaSourceUri != null) mPlayer.setDataSource(getContext(), mMediaSourceUri);
else mPlayer.setDataSource(mMediaSourcePath);
} catch (IOException e) {
throw new RuntimeException(e);
}
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override public void onPrepared(MediaPlayer mp) {
mInitialized = true;
mPaused = false;
mPlayer.start();
onMetadataChanged();
onStateChanged();
updateProgress();
}
});
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override public void onCompletion(MediaPlayer mp) {
if (mInitialized && mMediaFileFinishedPlayingListener != null)
mMediaFileFinishedPlayingListener.onMediaFileFinishedPlaying(mMetaData);
}
});
mPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override public void onBufferingUpdate(MediaPlayer mp, int percent) {
mControlsRow.setBufferedProgress((int) (mp.getDuration() * (percent / 100f)));
}
});
mPlayer.prepareAsync();
onStateChanged();
}
mPlayer.start();
}
@Override protected void pausePlayback() {
if (mPlayer.isPlaying()) {
mPlayer.pause();
mPaused = true;
}
}
@@ -326,7 +287,40 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
* @see MediaPlayer#setDataSource(Context, Uri)
*/
public void setMediaSource(Uri uri) {
if (mMediaSourceUri != null && mMediaSourceUri.equals(uri)) {
return;
}
mMediaSourceUri = uri;
reset();
try {
if (mMediaSourceUri != null) mPlayer.setDataSource(getContext(), mMediaSourceUri);
else mPlayer.setDataSource(mMediaSourcePath);
} catch (IOException e) {
throw new RuntimeException(e);
}
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override public void onPrepared(MediaPlayer mp) {
mInitialized = true;
mPlayer.start();
onMetadataChanged();
onStateChanged();
updateProgress();
}
});
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override public void onCompletion(MediaPlayer mp) {
if (mInitialized && mMediaFileFinishedPlayingListener != null)
mMediaFileFinishedPlayingListener.onMediaFileFinishedPlaying(mMetaData);
}
});
mPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override public void onBufferingUpdate(MediaPlayer mp, int percent) {
mControlsRow.setBufferedProgress((int) (mp.getDuration() * (percent / 100f)));
}
});
mPlayer.prepareAsync();
onStateChanged();
}
/**
@@ -417,7 +411,6 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
private String mArtist;
private Drawable mCover;
public String getTitle() {
return mTitle;
}
@@ -441,6 +434,7 @@ public abstract class MediaPlayerGlue extends PlaybackControlGlue implements
public void setCover(Drawable cover) {
this.mCover = cover;
}
}
}

View File

@@ -14,25 +14,19 @@
package android.support.v17.leanback.supportleanbackshowcase.app.media;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.v17.leanback.app.PlaybackOverlayFragment;
import android.support.v17.leanback.supportleanbackshowcase.utils.Constants;
import android.support.v17.leanback.supportleanbackshowcase.app.media.MediaPlayerGlue;
import android.support.v17.leanback.supportleanbackshowcase.R;
import android.support.v17.leanback.supportleanbackshowcase.app.media.TrackListHeader;
import android.support.v17.leanback.supportleanbackshowcase.utils.Utils;
import android.support.v17.leanback.supportleanbackshowcase.models.Song;
import android.support.v17.leanback.supportleanbackshowcase.models.SongList;
import android.support.v17.leanback.widget.Action;
import android.support.v17.leanback.widget.ArrayObjectAdapter;
import android.support.v17.leanback.widget.ClassPresenterSelector;
import android.support.v17.leanback.widget.OnItemViewClickedListener;
import android.support.v17.leanback.widget.PlaybackControlsRow;
import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
import android.support.v17.leanback.widget.Presenter;
import android.support.v17.leanback.widget.Row;
import android.support.v17.leanback.widget.RowPresenter;
import android.support.v17.leanback.widget.*;
import android.support.v17.leanback.widget.AbstractMediaItemPresenter;
import android.util.Log;
import com.google.gson.Gson;
@@ -43,10 +37,12 @@ import java.util.List;
* This example shows how to play music files and build a simple track list.
*/
public class MusicConsumptionExampleFragment extends PlaybackOverlayFragment implements
OnItemViewClickedListener, Song.OnSongRowClickListener,
BaseOnItemViewClickedListener, BaseOnItemViewSelectedListener,
MediaPlayerGlue.OnMediaFileFinishedPlayingListener {
private static final String TAG = "MusicConsumptionExampleFragment";
private static final int PLAYLIST_ACTION_ID = 0;
private static final int FAVORITE_ACTION_ID = 1;
private ArrayObjectAdapter mRowsAdapter;
private MediaPlayerGlue mGlue;
private int mCurrentSongIndex = 0;
@@ -69,7 +65,38 @@ public class MusicConsumptionExampleFragment extends PlaybackOverlayFragment imp
String json = Utils.inputStreamToString(
getResources().openRawResource(R.raw.music_consumption_example));
mSongList = new Gson().fromJson(json, SongList.class).getSongs();
Resources res = getActivity().getResources();
// For each song add a playlist and favorite actions.
for(Song song : mSongList) {
MultiActionsProvider.MultiAction[] mediaRowActions = new
MultiActionsProvider.MultiAction[2];
MultiActionsProvider.MultiAction playlistAction = new
MultiActionsProvider.MultiAction(PLAYLIST_ACTION_ID);
Drawable[] playlistActionDrawables = new Drawable[] {
res.getDrawable(R.drawable.ic_playlist_add_white_24dp,
getActivity().getTheme()),
res.getDrawable(R.drawable.ic_playlist_add_filled_24dp,
getActivity().getTheme())};
playlistAction.setDrawables(playlistActionDrawables);
mediaRowActions[0] = playlistAction;
MultiActionsProvider.MultiAction favoriteAction = new
MultiActionsProvider.MultiAction(FAVORITE_ACTION_ID);
Drawable[] favoriteActionDrawables = new Drawable[] {
res.getDrawable(R.drawable.ic_favorite_border_white_24dp,
getActivity().getTheme()),
res.getDrawable(R.drawable.ic_favorite_filled_24dp,
getActivity().getTheme())};
favoriteAction.setDrawables(favoriteActionDrawables);
mediaRowActions[1] = favoriteAction;
song.setMediaRowActions(mediaRowActions);
}
Song song = mSongList.get(mCurrentSongIndex);
MediaPlayerGlue.MetaData metaData = new MediaPlayerGlue.MetaData();
metaData.setArtist(song.getDescription());
@@ -79,7 +106,6 @@ public class MusicConsumptionExampleFragment extends PlaybackOverlayFragment imp
mGlue.setMetaData(metaData);
mGlue.setMediaSource(uri);
setBackgroundType(PlaybackOverlayFragment.BG_LIGHT);
addPlaybackControlsRow();
}
@@ -94,48 +120,175 @@ public class MusicConsumptionExampleFragment extends PlaybackOverlayFragment imp
mGlue.reset();
}
static class SongPresenter extends AbstractMediaItemPresenter {
SongPresenter() {
super();
}
SongPresenter(Context context, int themeResId) {
super(themeResId);
setHasMediaRowSeparator(true);
}
@Override
protected void onBindMediaDetails(ViewHolder vh, Object item) {
int favoriteTextColor = vh.view.getContext().getResources().getColor(
R.color.song_row_favorite_color);
Song song = (Song) item;
vh.getMediaItemNumberView().setText("" + song.getNumber());
String songTitle = song.getTitle() + " / " + song.getDescription();
vh.getMediaItemNameView().setText(songTitle);
vh.getMediaItemDurationView().setText("" + song.getDuration());
if (song.isFavorite()) {
vh.getMediaItemNumberView().setTextColor(favoriteTextColor);
vh.getMediaItemNameView().setTextColor(favoriteTextColor);
vh.getMediaItemDurationView().setTextColor(favoriteTextColor);
} else {
vh.getMediaItemNumberView().setTextAppearance(
R.style.TextAppearance_Leanback_PlaybackMediaItemNumber);
vh.getMediaItemNameView().setTextAppearance(
R.style.TextAppearance_Leanback_PlaybackMediaItemName);
vh.getMediaItemDurationView().setTextAppearance(
R.style.TextAppearance_Leanback_PlaybackMediaItemDuration);
}
}
};
static class SongPresenterSelector extends PresenterSelector {
Presenter mRegularPresenter;
Presenter mFavoritePresenter;
/**
* Adds a presenter to be used for the given class.
*/
public SongPresenterSelector setSongPresenterRegular(Presenter presenter) {
mRegularPresenter = presenter;
return this;
}
/**
* Adds a presenter to be used for the given class.
*/
public SongPresenterSelector setSongPresenterFavorite(Presenter presenter) {
mFavoritePresenter = presenter;
return this;
}
@Override
public Presenter[] getPresenters() {
return new Presenter[]{mRegularPresenter, mFavoritePresenter};
}
@Override
public Presenter getPresenter(Object item) {
return ( (Song) item).isFavorite() ? mFavoritePresenter : mRegularPresenter;
}
}
static class TrackListHeaderPresenter extends AbstractMediaListHeaderPresenter {
TrackListHeaderPresenter() {
super();
}
@Override
protected void onBindMediaListHeaderViewHolder(ViewHolder vh, Object item) {
vh.getHeaderView().setText("Tracklist");
}
};
private void addPlaybackControlsRow() {
final PlaybackControlsRowPresenter controlsPresenter = mGlue
.createControlsRowAndPresenter();
ClassPresenterSelector selector = new ClassPresenterSelector();
Song.Presenter songPresenter = new Song.Presenter(getActivity());
songPresenter.setOnClickListener(this);
selector.addClassPresenter(Song.class, songPresenter);
selector.addClassPresenter(TrackListHeader.class,
new TrackListHeader.Presenter(getActivity()));
selector.addClassPresenter(PlaybackControlsRow.class, controlsPresenter);
mRowsAdapter = new ArrayObjectAdapter(selector);
mRowsAdapter = new ArrayObjectAdapter(new ClassPresenterSelector()
.addClassPresenterSelector(Song.class, new SongPresenterSelector()
.setSongPresenterRegular(new SongPresenter(getActivity(),
R.style.Theme_Example_LeanbackMusic_RegularSongNumbers))
.setSongPresenterFavorite(new SongPresenter(getActivity(),
R.style.Theme_Example_LeanbackMusic_FavoriteSongNumbers)))
.addClassPresenter(TrackListHeader.class, new TrackListHeaderPresenter())
.addClassPresenter(PlaybackControlsRow.class,
mGlue.createControlsRowAndPresenter()));
mRowsAdapter.add(mGlue.getControlsRow());
mRowsAdapter.add(new TrackListHeader());
mRowsAdapter.addAll(2, mSongList);
setAdapter(mRowsAdapter);
setOnItemViewClickedListener(this);
setOnItemViewSelectedListener(this);
}
public MusicConsumptionExampleFragment() {
super();
}
@Override public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
RowPresenter.ViewHolder rowViewHolder, Row row) {
if (!(item instanceof Action)) return;
mGlue.onActionClicked((Action) item);
RowPresenter.ViewHolder rowViewHolder, Object row) {
if (item instanceof Action) {
// if the clicked item is a primary or secondary action in the playback controller
mGlue.onActionClicked((Action) item);
} else if (row instanceof Song) {
// if a media item row is clicked
Song clickedSong = (Song) row;
AbstractMediaItemPresenter.ViewHolder songRowVh =
(AbstractMediaItemPresenter.ViewHolder) rowViewHolder;
// if an action within a media item row is clicked
if (item instanceof MultiActionsProvider.MultiAction) {
if ( ((MultiActionsProvider.MultiAction) item).getId() == FAVORITE_ACTION_ID) {
MultiActionsProvider.MultiAction favoriteAction =
(MultiActionsProvider.MultiAction) item;
MultiActionsProvider.MultiAction playlistAction =
songRowVh.getMediaItemRowActions()[0];
favoriteAction.incrementIndex();
playlistAction.incrementIndex();;
clickedSong.setFavorite(!clickedSong.isFavorite());
songRowVh.notifyDetailsChanged();
songRowVh.notifyActionChanged(playlistAction);
songRowVh.notifyActionChanged(favoriteAction);
}
} else if (item == null){
// if a media item details is clicked, start playing that media item
onSongDetailsClicked(clickedSong);
}
}
}
@Override
public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
RowPresenter.ViewHolder rowViewHolder, Object row) {
}
@Override public void onSongRowClicked(Song song) {
mCurrentSongIndex = mSongList.indexOf(song);
public void onSongDetailsClicked(Song song) {
int nextSongIndex = mSongList.indexOf(song);
mCurrentSongIndex = nextSongIndex;
startPlayback();
}
@Override public void onMediaFileFinishedPlaying(MediaPlayerGlue.MetaData song) {
if (mGlue.repeatOne()) {
startPlayback();
return;
}
if (mGlue.useShuffle()) {
} else if (mGlue.useShuffle()) {
mCurrentSongIndex = (int) (Math.random() * mSongList.size());
} else mCurrentSongIndex++;
if (mCurrentSongIndex >= mSongList.size()) {
mCurrentSongIndex = 0;
if (!mGlue.repeatAll()) return;
} else {
mCurrentSongIndex++;
if (mCurrentSongIndex >= mSongList.size()) {
mCurrentSongIndex = 0;
if (!mGlue.repeatAll()) {
return;
}
}
}
startPlayback();
}

View File

@@ -15,36 +15,7 @@
package android.support.v17.leanback.supportleanbackshowcase.app.media;
import android.content.Context;
import android.support.v17.leanback.supportleanbackshowcase.R;
import android.support.v17.leanback.widget.Row;
import android.support.v17.leanback.widget.RowPresenter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class TrackListHeader extends Row {
public static class Presenter extends RowPresenter {
private final Context mContext;
public Presenter(Context context) {
mContext = context;
setHeaderPresenter(null);
}
@Override public boolean isUsingDefaultSelectEffect() {
return false;
}
@Override protected ViewHolder createRowViewHolder(ViewGroup parent) {
View view = LayoutInflater.from(mContext).inflate(R.layout.row_track_list_header, parent, false);
view.setFocusable(false);
view.setFocusableInTouchMode(false);
return new ViewHolder(view);
}
}
}

View File

@@ -16,17 +16,22 @@
package android.support.v17.leanback.supportleanbackshowcase.models;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.v17.leanback.supportleanbackshowcase.R;
import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
import android.support.v17.leanback.widget.MultiActionsProvider;
import android.support.v17.leanback.widget.Row;
import android.support.v17.leanback.widget.RowPresenter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class Song extends Row {
public class Song implements MultiActionsProvider {
@SerializedName("title") private String mTitle = "";
@SerializedName("description") private String mDescription = "";
@@ -35,12 +40,27 @@ public class Song extends Row {
@SerializedName("file") private String mFile = null;
@SerializedName("duration") private String mDuration = null;
@SerializedName("number") private int mNumber = 0;
@SerializedName("favorite") private boolean mFavorite = false;
private MultiAction[] mMediaRowActions;
public void setMediaRowActions(MultiAction[] mediaRowActions) {
mMediaRowActions = mediaRowActions;
}
public MultiAction[] getMediaRowActions() {
return mMediaRowActions;
}
public String getDuration() {
return mDuration;
}
public void setDuration(String duration) {
mDuration = duration;
}
public int getNumber() {
return mNumber;
}
@@ -53,10 +73,26 @@ public class Song extends Row {
return mDescription;
}
public void setDescription(String description) {
mDescription = description;
}
public String getTitle() {
return mTitle;
}
public void setTitle(String title) {
mTitle = title;
}
public boolean isFavorite() {
return mFavorite;
}
public void setFavorite(boolean favorite) {
mFavorite = favorite;
}
public int getFileResource(Context context) {
return context.getResources()
.getIdentifier(mFile, "raw", context.getPackageName());
@@ -67,50 +103,9 @@ public class Song extends Row {
.getIdentifier(mImage, "drawable", context.getPackageName());
}
public interface OnSongRowClickListener {
void onSongRowClicked(Song song);
@Override
public MultiAction[] getActions() {
return mMediaRowActions;
}
public static class Presenter extends RowPresenter implements View.OnClickListener {
private final Context mContext;
private OnSongRowClickListener mClickListener;
public Presenter(Context context) {
mContext = context;
setHeaderPresenter(null);
}
public void setOnClickListener(OnSongRowClickListener listener) {
mClickListener = listener;
}
@Override protected ViewHolder createRowViewHolder(ViewGroup parent) {
View view = LayoutInflater.from(mContext).inflate(R.layout.row_song, parent, false);
view.findViewById(R.id.rowContainer).setOnClickListener(this);
return new ViewHolder(view);
}
@Override public boolean isUsingDefaultSelectEffect() {
return false;
}
@Override protected void onBindRowViewHolder(ViewHolder vh, Object item) {
super.onBindRowViewHolder(vh, item);
Song song = (Song) item;
((TextView) vh.view.findViewById(R.id.trackNumber)).setText("" + song.getNumber());
((TextView) vh.view.findViewById(R.id.trackDuration)).setText(song.getDuration());
String text = song.getTitle() + " / " + song.getDescription();
((TextView) vh.view.findViewById(R.id.trackName)).setText(text);
vh.view.findViewById(R.id.rowContainer).setTag(item);
}
@Override public void onClick(View v) {
if (mClickListener == null) return;
mClickListener.onSongRowClicked((Song) v.getTag());
}
}
}

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3 4.42,3 2,5.42 2,8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5 22,5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1 -0.1,-0.1C7.14,14.24 4,11.39 4,8.5 4,6.5 5.5,5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5 0,2.89 -3.14,5.74 -7.9,10.05z"
android:fillColor="#FFFFFF"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"
android:fillColor="@color/song_row_favorite_color"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="M14,10L2,10v2h12v-2zM14,6L2,6v2h12L14,6zM18,14v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zM2,16h8v-2L2,14v2z"
android:fillColor="@color/song_row_favorite_color"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="M14,10L2,10v2h12v-2zM14,6L2,6v2h12L14,6zM18,14v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zM2,16h8v-2L2,14v2z"
android:fillColor="#FFFFFF"/>
</vector>

View File

@@ -1,77 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:lb="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="horizontal"
android:paddingEnd="@dimen/lb_playback_controls_margin_end"
android:paddingStart="@dimen/lb_playback_controls_margin_start"
lb:rowHeight="wrap_content">
<RelativeLayout
android:id="@+id/rowContainer"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@drawable/song_row_background"
android:focusable="true"
android:focusableInTouchMode="true">
<TextView
android:id="@+id/trackNumber"
android:layout_width="56dp"
android:layout_height="match_parent"
android:layout_marginLeft="32dp"
android:fontFamily="sans-serif-regular"
android:gravity="center_vertical"
android:text="1"
android:textColor="#FFFFFF"
android:textSize="18sp"/>
<TextView
android:id="@+id/trackName"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_alignParentTop="true"
android:layout_toEndOf="@+id/trackNumber"
android:layout_toLeftOf="@+id/trackDuration"
android:fontFamily="sans-serif-regular"
android:gravity="center_vertical"
android:singleLine="true"
android:text="A Song!!11"
android:textColor="#FFFFFF"
android:textSize="18sp"/>
<TextView
android:id="@+id/trackDuration"
android:layout_width="66dp"
android:layout_height="48dp"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_marginRight="32dp"
android:fontFamily="sans-serif-regular"
android:gravity="center_vertical|right"
android:text="1:13:54"
android:textColor="#80FFFFFF"
android:textSize="18sp"/>
</RelativeLayout>
</LinearLayout>

View File

@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:lb="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingEnd="@dimen/lb_playback_controls_margin_end"
android:paddingStart="@dimen/lb_playback_controls_margin_start"
lb:rowHeight="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:background="#263238"
android:fontFamily="sans-serif-regular"
android:gravity="center_vertical"
android:paddingLeft="32dp"
android:text="Tracks"
android:textColor="#80EEEEEE"
android:textSize="18sp"/>
</RelativeLayout>
</RelativeLayout>

View File

@@ -31,6 +31,7 @@
<color name="default_card_footer_background_color">#37474F</color>
<color name="selected_card_footer_background_color">#F0F</color>
<color name="lb_default_brand_color">#FF455A64</color>
<color name="card_primary_text">#EEEEEE</color>
<color name="card_secondary_text">#99EEEEEE</color>
@@ -41,10 +42,15 @@
<color name="detail_view_actionbar_background">#04549D</color>
<color name="detail_view_background">#0374BF</color>
<color name="detail_view_related_background">#022A4E</color>
<color name="song_row_favorite_color">#FF6E40</color>
<color name="app_guidedstep_actions_background">#C03800</color>
<color name="app_guidedstep_subactions_background">#C03800</color>
<color name="app_guidedstep_dialog_actions_background">#263238</color>
<color name="settings_card_background">#0277BD</color>
<color name="settings_card_background_focussed">#01579B</color>
<color name="player_progress_color">#feab91</color>
<color name="player_background_color">#db2a0f</color>
</resources>

View File

@@ -46,7 +46,7 @@
<string name="wizard_example_watch_sd">Watch in standard definition on the web and supported devices</string>
<string name="wizard_example_rental_period">Rental period: start within 30 days,\nfinish within 24 hours</string>
<string name="wizard_example_input_card">Enter credit card number</string>
<string name="wizard_example_expiration_date">Exp. date</string>
<string name="wizard_example_expiration_date">Exp Date</string>
<string name="wizard_example_payment_method">Payment Method</string>
<string name="wizard_example_toast_payment_method_clicked">\'Payment Method\' clicked.</string>
<string name="wizard_example_rent">Rent</string>

View File

@@ -44,19 +44,18 @@
</style>
<style name="MovieCardSimpleStyle" parent="Widget.Leanback.ImageCardViewStyle">
<style name="MovieCardTitleOnlyStyle" parent="Widget.Leanback.ImageCardViewStyle">
<item name="lbImageCardViewType">Title</item>
<item name="cardBackground">@null</item>
</style>
<!-- Theme corresponding to the MovieCardSimpleStyle -->
<style name="MovieCardSimpleTheme" parent="Theme.Leanback">
<item name="imageCardViewStyle"> @style/MovieCardSimpleStyle </item>
<item name="imageCardViewStyle"> @style/MovieCardTitleOnlyStyle </item>
<item name="imageCardViewImageStyle">@style/MovieCardImageStyle</item>
</style>
<style name="MovieCardCompleteStyle" parent="MovieCardSimpleStyle">
<style name="MovieCardCompleteStyle" parent="MovieCardTitleOnlyStyle">
<item name="lbImageCardViewType">Title|Content|IconOnLeft</item>
</style>
@@ -147,7 +146,7 @@
</style>
<style name="GameCardStyle" parent="DefaultCardStyle">
<item name="lbImageCardViewType">Title|Content|IconOnLeft</item>
<item name="lbImageCardViewType">Title|Content|IconOnRight</item>
</style>
<!-- Theme corresponding to the GameCardStyle -->
@@ -218,4 +217,55 @@
<item name="imageCardViewInfoAreaStyle">@style/IconCardInfoAreaStyle</item>
</style>
<style name="MediaListHeaderStyle" parent="Widget.Leanback.PlaybackMediaListHeaderStyle">
<item name="android:background">#282248</item>
</style>
<style name="SharedMediaItemRowStyle" parent="Widget.Leanback.PlaybackMediaItemRowStyle">
<item name="android:background">#282248</item>
</style>
<style name="RegularMediaItemTextStyle" parent="TextAppearance.Leanback.PlaybackMediaItemNumber">
<item name="android:textColor">#FF6255</item>
<item name="android:textSize">18sp</item>
<item name="android:fontFamily">sans-serif-light</item>
</style>
<style name="RegularMediaItemNumberStyle" parent="Widget.Leanback.PlaybackMediaItemNumberStyle">
<item name="android:visibility">visible</item>
<!--<item name="android:textAppearance">@style/OddMediaItemNumberTextStyle</item>-->
</style>
<style name="RegularMediaItemNameStyle" parent="Widget.Leanback.PlaybackMediaItemNameStyle">
<!--<item name="android:textAppearance">@style/OddMediaItemNumberTextStyle</item>-->
</style>
<style name="RegularMediaItemDurationStyle" parent="Widget.Leanback.PlaybackMediaItemDurationStyle">
<item name="android:visibility">visible</item>
<!--<item name="android:textAppearance">@style/OddMediaItemNumberTextStyle</item>-->
</style>
<style name="FavoriteMediaItemTextStyle" parent="TextAppearance.Leanback.PlaybackMediaItemNumber">
<item name="android:textColor">#FF6E40</item>
<item name="android:textSize">18sp</item>
<item name="android:fontFamily">sans-serif-medium</item>
</style>
<style name="FavoriteMediaItemNumberStyle" parent="Widget.Leanback.PlaybackMediaItemNumberStyle">
<item name="android:visibility">visible</item>
<item name="android:textAppearance">@style/FavoriteMediaItemTextStyle</item>
</style>
<style name="FavoriteMediaItemNameStyle" parent="Widget.Leanback.PlaybackMediaItemNameStyle">
<item name="android:textAppearance">@style/FavoriteMediaItemTextStyle</item>
</style>
<style name="FavoriteMediaItemDurationStyle" parent="Widget.Leanback.PlaybackMediaItemDurationStyle">
<item name="android:visibility">visible</item>
<item name="android:textAppearance">@style/FavoriteMediaItemTextStyle</item>
</style>
</resources>

View File

@@ -73,4 +73,22 @@
<item name="android:windowBackground">@drawable/background_sax</item>
</style>
<style name="Theme.Example.LeanbackMusic.RegularSongNumbers">
<!--<item name="playbackMediaItemRowStyle">@style/SharedMediaItemRowStyle</item>-->
<item name="playbackMediaItemNumberStyle">@style/RegularMediaItemNumberStyle</item>
<item name="playbackMediaItemNameStyle">@style/RegularMediaItemNameStyle</item>
<item name="playbackMediaItemDurationStyle">@style/RegularMediaItemDurationStyle</item>
</style>
<style name="Theme.Example.LeanbackMusic.FavoriteSongNumbers">
<!--<item name="playbackMediaItemRowStyle">@style/SharedMediaItemRowStyle</item>-->
<item name="playbackMediaItemNumberStyle">@style/FavoriteMediaItemNumberStyle</item>
<item name="playbackMediaItemNameStyle">@style/FavoriteMediaItemNameStyle</item>
<item name="playbackMediaItemDurationStyle">@style/FavoriteMediaItemDurationStyle</item>
</style>
<style name="Theme.Example.LeanbackMusic.TrackListHeader">
<item name="playbackMediaListHeaderStyle">@style/MediaListHeaderStyle</item>
</style>
</resources>