Rework playback activity layout.

Display all info in the table layout, including title, artist and album.
Add queue position display.
This commit is contained in:
Christopher Eby 2012-03-13 10:01:44 -05:00
parent 95debe778b
commit 7cc59120d4
8 changed files with 245 additions and 108 deletions

View File

@ -26,6 +26,7 @@ THE SOFTWARE.
android:layout_height="fill_parent"
android:layout_width="fill_parent" />
<LinearLayout
android:id="@+id/controls_top"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_gravity="top"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2010, 2011 Christopher Eby <kreed@kreed.org>
Copyright (C) 2012 Christopher Eby <kreed@kreed.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -25,93 +25,125 @@ THE SOFTWARE.
android:id="@+id/cover_view"
android:layout_height="fill_parent"
android:layout_width="fill_parent" />
<LinearLayout
android:id="@+id/controls_top"
android:layout_height="wrap_content"
<TableLayout
android:id="@+id/info_table"
android:layout_width="fill_parent"
android:layout_gravity="top|left"
android:layout_margin="0dip"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:collapseColumns="0"
android:stretchColumns="1"
android:shrinkColumns="1"
android:background="#a000"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:ellipsize="marquee"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:gravity="center"
android:singleLine="true"
android:textStyle="bold" />
<TextView
android:id="@+id/artist"
android:ellipsize="marquee"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:gravity="center"
android:singleLine="true" />
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal">
android:paddingLeft="5dip"
android:paddingRight="5dip">
<TableRow>
<TextView
android:text="@string/_title"
android:paddingRight="5dip"
android:singleLine="true"
android:gravity="right" />
<TextView
android:id="@+id/title"
android:textStyle="bold"
android:singleLine="true" />
<TextView
android:id="@+id/queue_pos"
android:singleLine="true"
android:layout_gravity="top" />
</TableRow>
<TableRow>
<TextView
android:text="@string/_artist"
android:paddingRight="5dip"
android:singleLine="true"
android:gravity="right" />
<TextView
android:id="@+id/artist"
android:singleLine="true" />
</TableRow>
<TableRow>
<TextView
android:text="@string/_album"
android:paddingRight="5dip"
android:singleLine="true"
android:gravity="right" />
<TextView
android:id="@+id/album"
android:singleLine="true" />
</TableRow>
<TableRow>
<TextView
android:text="@string/_genre"
android:paddingRight="5dip"
android:singleLine="true"
android:gravity="right" />
<TextView
android:id="@+id/genre"
android:singleLine="true" />
</TableRow>
<TableRow>
<TextView
android:text="@string/_track"
android:paddingRight="5dip"
android:singleLine="true"
android:gravity="right" />
<TextView
android:id="@+id/track"
android:singleLine="true" />
</TableRow>
<TableRow>
<TextView
android:text="@string/_year"
android:paddingRight="5dip"
android:singleLine="true"
android:gravity="right" />
<TextView
android:id="@+id/year"
android:singleLine="true" />
</TableRow>
<TableRow>
<TextView
android:text="@string/_composer"
android:paddingRight="5dip"
android:singleLine="true"
android:gravity="right" />
<TextView
android:id="@+id/composer"
android:singleLine="true" />
</TableRow>
<TableRow>
<TextView
android:text="@string/_format"
android:paddingRight="5dip"
android:singleLine="true"
android:gravity="right" />
<TextView
android:id="@+id/format"
android:singleLine="true" />
</TableRow>
<LinearLayout android:id="@+id/controls_top">
<TextView
android:id="@+id/elapsed"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:gravity="bottom"
android:textSize="10sp"
android:paddingLeft="5dip" />
<TextView
android:id="@+id/album"
android:ellipsize="marquee"
android:layout_gravity="center" />
<SeekBar
android:id="@+id/seek_bar"
android:layout_height="wrap_content"
android:layout_width="0px"
android:layout_gravity="center"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:gravity="center"
android:singleLine="true" />
android:paddingLeft="18dip"
android:paddingRight="18dip" />
<TextView
android:id="@+id/duration"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:gravity="bottom"
android:textSize="10sp"
android:paddingRight="5dip" />
android:layout_gravity="center" />
</LinearLayout>
<SeekBar
android:id="@+id/seek_bar"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:paddingLeft="15dip"
android:paddingRight="15dip" />
<TableLayout
android:id="@+id/extra_info"
android:visibility="gone"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TableRow>
<TextView android:text="@string/genre" />
<TextView android:id="@+id/genre" android:paddingLeft="5dip" />
</TableRow>
<TableRow>
<TextView android:text="@string/track" />
<TextView android:id="@+id/track" android:paddingLeft="5dip" />
</TableRow>
<TableRow>
<TextView android:text="@string/year" />
<TextView android:id="@+id/year" android:paddingLeft="5dip" />
</TableRow>
<TableRow>
<TextView android:text="@string/composer" />
<TextView android:id="@+id/composer" android:paddingLeft="5dip" />
</TableRow>
<TableRow>
<TextView android:text="@string/format" />
<TextView android:id="@+id/format" android:paddingLeft="5dip" />
</TableRow>
</TableLayout>
</LinearLayout>
</TableLayout>
<LinearLayout
android:id="@+id/controls_bottom"
android:layout_height="wrap_content"

View File

@ -41,10 +41,14 @@ THE SOFTWARE.
<string name="queue_cleared">Queue cleared.</string>
<string name="cover_art">Cover art</string>
<string name="close_notification">Close notification</string>
<string name="genre">Genre</string>
<string name="track">Track</string>
<string name="composer">Composer</string>
<string name="format">Format</string>
<string name="_genre">genre</string>
<string name="_track">track</string>
<string name="_composer">composer</string>
<string name="_format">format</string>
<string name="_title">title</string>
<string name="_artist">artist</string>
<string name="_album">album</string>
<string name="_year">year</string>
<!-- New Playlist Dialog -->
<string name="choose_playlist_name">Choose Playlist Name</string>

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010, 2011 Christopher Eby <kreed@kreed.org>
* Copyright (C) 2012 Christopher Eby <kreed@kreed.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -55,12 +55,14 @@ public class FullPlaybackActivity extends PlaybackActivity
public static final int DISPLAY_INFO_WIDGETS = 2;
private TextView mOverlayText;
private View mControlsTop;
private View mControlsBottom;
private SeekBar mSeekBar;
private TableLayout mInfoTable;
private TextView mElapsedView;
private TextView mDurationView;
private TableLayout mExtraInfo;
private TextView mQueuePosView;
private TextView mTitle;
private TextView mAlbum;
@ -155,23 +157,25 @@ public class FullPlaybackActivity extends PlaybackActivity
View nextButton = findViewById(R.id.next);
nextButton.setOnClickListener(this);
View controlsTop = findViewById(R.id.controls_top);
if (controlsTop != null) {
controlsTop.setOnClickListener(this);
controlsTop.setOnLongClickListener(this);
TableLayout table = (TableLayout)findViewById(R.id.info_table);
if (table != null) {
table.setOnClickListener(this);
table.setOnLongClickListener(this);
mInfoTable = table;
}
mTitle = (TextView)findViewById(R.id.title);
mAlbum = (TextView)findViewById(R.id.album);
mArtist = (TextView)findViewById(R.id.artist);
mControlsTop = findViewById(R.id.controls_top);
mElapsedView = (TextView)findViewById(R.id.elapsed);
mDurationView = (TextView)findViewById(R.id.duration);
mSeekBar = (SeekBar)findViewById(R.id.seek_bar);
mSeekBar.setMax(1000);
mSeekBar.setOnSeekBarChangeListener(this);
mQueuePosView = (TextView)findViewById(R.id.queue_pos);
mExtraInfo = (TableLayout)findViewById(R.id.extra_info);
mGenreView = (TextView)findViewById(R.id.genre);
mTrackView = (TextView)findViewById(R.id.track);
mYearView = (TextView)findViewById(R.id.year);
@ -210,7 +214,7 @@ public class FullPlaybackActivity extends PlaybackActivity
{
super.onResume();
mPaused = false;
updateProgress();
updateElapsedTime();
}
@Override
@ -272,7 +276,10 @@ public class FullPlaybackActivity extends PlaybackActivity
}
if ((state & PlaybackService.FLAG_PLAYING) != 0)
updateProgress();
updateElapsedTime();
if (mQueuePosView != null)
updateQueuePosition();
}
@Override
@ -292,16 +299,40 @@ public class FullPlaybackActivity extends PlaybackActivity
mAlbum.setText(song.album);
mArtist.setText(song.artist);
}
updateQueuePosition();
}
mCurrentSong = song;
updateProgress();
updateElapsedTime();
if (mExtraInfoVisible) {
mHandler.sendEmptyMessage(MSG_LOAD_EXTRA_INFO);
}
}
/**
* Update the queue position display. mQueuePos must not be null.
*/
private void updateQueuePosition()
{
if (PlaybackService.finishAction(mState) == SongTimeline.FINISH_RANDOM) {
// Not very useful in random mode; it will always show something
// like 11/13 since the timeline is trimmed to 10 previous songs.
// So just hide it.
mQueuePosView.setText(null);
} else {
PlaybackService service = PlaybackService.get(this);
mQueuePosView.setText((service.getTimelinePosition() + 1) + "/" + service.getTimelineLength());
}
}
@Override
public void onPositionInfoChanged()
{
if (mQueuePosView != null)
mUiHandler.sendEmptyMessage(MSG_UPDATE_POSITION);
}
/**
* Update the current song duration fields.
*
@ -400,7 +431,7 @@ public class FullPlaybackActivity extends PlaybackActivity
/**
* Update seek bar progress and schedule another update in one second
*/
private void updateProgress()
private void updateElapsedTime()
{
long position = PlaybackService.hasInstance() ? PlaybackService.get(this).getPosition() : 0;
@ -427,15 +458,13 @@ public class FullPlaybackActivity extends PlaybackActivity
private void setControlsVisible(boolean visible)
{
int mode = visible ? View.VISIBLE : View.GONE;
mSeekBar.setVisibility(mode);
mElapsedView.setVisibility(mode);
mDurationView.setVisibility(mode);
mControlsTop.setVisibility(mode);
mControlsBottom.setVisibility(mode);
mControlsVisible = visible;
if (visible) {
mPlayPauseButton.requestFocus();
updateProgress();
updateElapsedTime();
}
}
@ -446,10 +475,17 @@ public class FullPlaybackActivity extends PlaybackActivity
*/
private void setExtraInfoVisible(boolean visible)
{
if (mExtraInfo == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD_MR1)
TableLayout table = mInfoTable;
if (table == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD_MR1)
return;
mExtraInfo.setVisibility(visible ? View.VISIBLE : View.GONE);
table.setColumnCollapsed(0, !visible);
int visibility = visible ? View.VISIBLE : View.GONE;
// toggle visibility of all but the first three rows (the title/artist/
// album rows) and the last row (the seek bar)
for (int i = table.getChildCount() - 1; --i != 2; ) {
table.getChildAt(i).setVisibility(visibility);
}
mExtraInfoVisible = visible;
if (visible && !mHandler.hasMessages(MSG_LOAD_EXTRA_INFO)) {
mHandler.sendEmptyMessage(MSG_LOAD_EXTRA_INFO);
@ -539,6 +575,10 @@ public class FullPlaybackActivity extends PlaybackActivity
* Pass obj to mExtraInfo.setText()
*/
private static final int MSG_COMMIT_INFO = 16;
/**
* Calls {@link #updateQueuePosition()}.
*/
private static final int MSG_UPDATE_POSITION = 17;
@Override
public boolean handleMessage(Message message)
@ -552,7 +592,7 @@ public class FullPlaybackActivity extends PlaybackActivity
break;
}
case MSG_UPDATE_PROGRESS:
updateProgress();
updateElapsedTime();
break;
case MSG_LOAD_EXTRA_INFO:
loadExtraInfo();
@ -565,6 +605,9 @@ public class FullPlaybackActivity extends PlaybackActivity
mFormatView.setText(mFormat);
break;
}
case MSG_UPDATE_POSITION:
updateQueuePosition();
break;
default:
return super.handleMessage(message);
}
@ -575,8 +618,10 @@ public class FullPlaybackActivity extends PlaybackActivity
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
if (fromUser)
if (fromUser) {
mElapsedView.setText(DateUtils.formatElapsedTime(mTimeBuilder, progress * mDuration / 1000000));
PlaybackService.get(this).seekToProgress(progress);
}
}
@Override
@ -608,7 +653,7 @@ public class FullPlaybackActivity extends PlaybackActivity
setState(PlaybackService.get(this).setFinishAction(SongTimeline.FINISH_RANDOM));
} else if (view == mCoverView) {
performAction(mCoverPressAction);
} else if (view.getId() == R.id.controls_top) {
} else if (view.getId() == R.id.info_table) {
openLibrary(mCurrentSong);
} else {
super.onClick(view);
@ -622,7 +667,7 @@ public class FullPlaybackActivity extends PlaybackActivity
case R.id.cover_view:
performAction(mCoverLongPressAction);
break;
case R.id.controls_top:
case R.id.info_table:
setExtraInfoVisible(!mExtraInfoVisible);
mHandler.sendEmptyMessage(MSG_SAVE_CONTROLS);
break;

View File

@ -299,6 +299,13 @@ public abstract class PlaybackActivity extends Activity
mCoverView.setSong(delta + 1, song);
}
/**
* Called when the song timeline position/size has changed.
*/
public void onPositionInfoChanged()
{
}
/**
* Called when the content of the media store has changed.
*/

View File

@ -1464,6 +1464,14 @@ public final class PlaybackService extends Service
mHandler.sendEmptyMessageDelayed(SAVE_STATE, 5000);
}
@Override
public void positionInfoChanged()
{
ArrayList<PlaybackActivity> list = sActivities;
for (int i = list.size(); --i != -1; )
list.get(i).onPositionInfoChanged();
}
private final ContentObserver mObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange)
@ -1821,4 +1829,20 @@ public final class PlaybackService extends Service
throw new IllegalArgumentException("Invalid action: " + action);
}
}
/**
* Returns the position of the current song in the song timeline.
*/
public int getTimelinePosition()
{
return mTimeline.getPosition();
}
/**
* Returns the number of songs in the song timeline.
*/
public int getTimelineLength()
{
return mTimeline.getLength();
}
}

View File

@ -224,6 +224,8 @@ public final class SongTimeline {
private Song mSavedPrevious;
private Song mSavedCurrent;
private Song mSavedNext;
private int mSavedPos;
private int mSavedSize;
/**
* Interface to respond to timeline changes.
@ -244,6 +246,11 @@ public final class SongTimeline {
* storage.
*/
public void timelineChanged();
/**
* Called when the length of the timeline has changed.
*/
public void positionInfoChanged();
}
/**
* The current Callback, if any.
@ -710,6 +717,7 @@ public final class SongTimeline {
}
mCallback.activeSongReplaced(+1, getSong(+1));
mCallback.positionInfoChanged();
changed();
}
@ -724,6 +732,8 @@ public final class SongTimeline {
mSavedPrevious = getSong(-1);
mSavedCurrent = getSong(0);
mSavedNext = getSong(+1);
mSavedPos = mCurrentPos;
mSavedSize = mSongs.size();
}
/**
@ -738,16 +748,15 @@ public final class SongTimeline {
Song current = getSong(0);
Song next = getSong(+1);
if (mCallback != null) {
if (Song.getId(mSavedPrevious) != Song.getId(previous))
mCallback.activeSongReplaced(-1, previous);
if (Song.getId(mSavedNext) != Song.getId(next))
mCallback.activeSongReplaced(1, next);
}
if (Song.getId(mSavedCurrent) != Song.getId(current)) {
if (mCallback != null)
mCallback.activeSongReplaced(0, current);
}
if (Song.getId(mSavedPrevious) != Song.getId(previous))
mCallback.activeSongReplaced(-1, previous);
if (Song.getId(mSavedNext) != Song.getId(next))
mCallback.activeSongReplaced(1, next);
if (Song.getId(mSavedCurrent) != Song.getId(current))
mCallback.activeSongReplaced(0, current);
if (mCurrentPos != mSavedPos || mSongs.size() != mSavedSize)
mCallback.positionInfoChanged();
}
/**
@ -796,4 +805,20 @@ public final class SongTimeline {
return mFinishAction == FINISH_STOP && mCurrentPos == mSongs.size() - 1;
}
}
/**
* Returns the position of the current song in the timeline.
*/
public int getPosition()
{
return mCurrentPos;
}
/**
* Returns the current number of songs in the timeline.
*/
public int getLength()
{
return mSongs.size();
}
}

View File

@ -88,7 +88,6 @@ public class TabOrderActivity extends Activity implements View.OnClickListener,
*/
public void restoreDefault()
{
android.util.Log.i("VanillaMusic", "restore default");
mAdapter.setTabIds(LibraryPagerAdapter.DEFAULT_ORDER.clone());
DragListView list = mList;
for (int i = 0; i != LibraryPagerAdapter.MAX_ADAPTER_COUNT; ++i) {