Add a mini-player
This will open in response to clicks on the notification. It provides a quick way to change a song or pause music. (Mainly it just looks legit)
This commit is contained in:
parent
ddb0193d65
commit
d1be1d80cc
@ -8,12 +8,18 @@
|
||||
android:name="Tumult">
|
||||
<activity
|
||||
android:name="NowPlayingActivity"
|
||||
android:label="@string/app_name" android:theme="@style/Theme.NoBackground">
|
||||
android:theme="@style/NoBackground"
|
||||
android:launchMode="singleTop" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="RemoteActivity"
|
||||
android:theme="@android:style/Theme.Dialog"
|
||||
android:excludeFromRecents="true"
|
||||
android:launchMode="singleInstance" />
|
||||
<service android:name="PlaybackService" />
|
||||
<activity android:name="PreferencesActivity" />
|
||||
<activity android:name="SongSelector"/>
|
||||
|
@ -36,27 +36,6 @@
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:background="#a000"
|
||||
android:orientation="horizontal">
|
||||
<ImageButton
|
||||
android:id="@+id/previous"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginLeft="15px"
|
||||
android:background="@null"
|
||||
android:src="@drawable/previous" />
|
||||
<ImageButton
|
||||
android:id="@+id/play_pause"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginLeft="25px"
|
||||
android:background="@null"
|
||||
android:src="@drawable/play" />
|
||||
<ImageButton
|
||||
android:id="@+id/next"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginLeft="25px"
|
||||
android:layout_marginRight="15px"
|
||||
android:background="@null"
|
||||
android:src="@drawable/next" />
|
||||
<include layout="@layout/playback_buttons" />
|
||||
</LinearLayout>
|
||||
</merge>
|
25
res/layout/playback_buttons.xml
Normal file
25
res/layout/playback_buttons.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<ImageButton
|
||||
android:id="@+id/previous"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginLeft="15px"
|
||||
android:background="@null"
|
||||
android:src="@drawable/previous" />
|
||||
<ImageButton
|
||||
android:id="@+id/play_pause"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginLeft="25px"
|
||||
android:background="@null"
|
||||
android:src="@drawable/play" />
|
||||
<ImageButton
|
||||
android:id="@+id/next"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginLeft="25px"
|
||||
android:layout_marginRight="15px"
|
||||
android:background="@null"
|
||||
android:src="@drawable/next" />
|
||||
</merge>
|
31
res/layout/remote_dialog.xml
Normal file
31
res/layout/remote_dialog.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.kreed.tumult.RemoteLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content">
|
||||
<org.kreed.tumult.CoverView
|
||||
android:id="@+id/cover_view"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content" />
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content">
|
||||
<include layout="@layout/playback_buttons" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content">
|
||||
<Button
|
||||
android:id="@+id/open_button"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="Open Player" />
|
||||
<Button
|
||||
android:id="@+id/kill_button"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="Kill Service" />
|
||||
</LinearLayout>
|
||||
</org.kreed.tumult.RemoteLayout>
|
@ -1,7 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Tumult</string>
|
||||
<string name="headset_only_summary_on">Audio only plays when a headset is plugged in</string>
|
||||
|
||||
<string name="headset_only_title">Headset only</string>
|
||||
<string name="headset_only_summary_on">Audio only plays when a headset is plugged in</string>
|
||||
<string name="headset_only_summary_off">Audio may play without a headset plugged in</string>
|
||||
|
||||
<string name="remote_player_title">Use Remote Player</string>
|
||||
<string name="remote_player_summary_on">Clicking the notification will open a mini-player dialog</string>
|
||||
<string name="remote_player_summary_off">Clicking the notification will open a the full player activity</string>
|
||||
</resources>
|
@ -1,5 +1,6 @@
|
||||
<resources>
|
||||
<style name="Theme.NoBackground" parent="android:Theme.NoTitleBar">
|
||||
<style name="NoBackground" parent="android:style/Theme">
|
||||
<item name="android:windowBackground">@null</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
</style>
|
||||
</resources>
|
@ -8,4 +8,10 @@
|
||||
android:defaultValue="false"
|
||||
android:summaryOn="@string/headset_only_summary_on"
|
||||
android:summaryOff="@string/headset_only_summary_off" />
|
||||
<CheckBoxPreference
|
||||
android:key="remote_player"
|
||||
android:title="@string/remote_player_title"
|
||||
android:defaultValue="true"
|
||||
android:summaryOn="@string/remote_player_summary_on"
|
||||
android:summaryOff="@string/remote_player_summary_off" />
|
||||
</PreferenceScreen>
|
@ -9,7 +9,11 @@ import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
@ -17,26 +21,20 @@ import android.widget.Scroller;
|
||||
|
||||
public class CoverView extends View {
|
||||
private static final int SNAP_VELOCITY = 1000;
|
||||
private static final int STORE_SIZE = 3;
|
||||
|
||||
private Scroller mScroller;
|
||||
private VelocityTracker mVelocityTracker;
|
||||
private float mLastMotionX;
|
||||
private float mStartX;
|
||||
private float mStartY;
|
||||
|
||||
private CoverViewWatcher mListener;
|
||||
private IPlaybackService mService;
|
||||
|
||||
Song[] mSongs = new Song[3];
|
||||
private Bitmap[] mBitmaps = new Bitmap[3];
|
||||
|
||||
private int mTentativeCover = -1;
|
||||
|
||||
public interface CoverViewWatcher {
|
||||
public void next();
|
||||
public void previous();
|
||||
public void clicked();
|
||||
}
|
||||
|
||||
public CoverView(Context context, AttributeSet attributes)
|
||||
{
|
||||
super(context, attributes);
|
||||
@ -44,14 +42,14 @@ public class CoverView extends View {
|
||||
mScroller = new Scroller(context);
|
||||
}
|
||||
|
||||
public void setWatcher(CoverViewWatcher listener)
|
||||
public void setPlaybackService(IPlaybackService service)
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
public Song getActiveSong()
|
||||
{
|
||||
return mSongs[1];
|
||||
try {
|
||||
mService = service;
|
||||
mService.registerWatcher(mWatcher);
|
||||
refreshSongs();
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
private void drawText(Canvas canvas, String text, float left, float top, float width, float maxWidth, Paint paint)
|
||||
@ -159,18 +157,15 @@ public class CoverView extends View {
|
||||
if (oldBitmap != null)
|
||||
oldBitmap.recycle();
|
||||
}
|
||||
|
||||
public void setSongs(Song[] songs)
|
||||
{
|
||||
mSongs = songs;
|
||||
regenerateBitmaps();
|
||||
}
|
||||
|
||||
public void setSong(int delta, Song song)
|
||||
private void refreshSongs()
|
||||
{
|
||||
int i = 1 + delta;
|
||||
mSongs[i] = song;
|
||||
createBitmap(i);
|
||||
try {
|
||||
mSongs = mService.getCurrentSongs();
|
||||
regenerateBitmaps();
|
||||
} catch (RemoteException e) {
|
||||
Log.e("Tumult", "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void regenerateBitmaps()
|
||||
@ -178,27 +173,58 @@ public class CoverView extends View {
|
||||
if (getWidth() == 0 || getHeight() == 0)
|
||||
return;
|
||||
|
||||
for (int i = mSongs.length; --i != -1; )
|
||||
for (int i = STORE_SIZE; --i != -1; )
|
||||
createBitmap(i);
|
||||
reset();
|
||||
}
|
||||
|
||||
public void shiftBackward()
|
||||
|
||||
public void nextCover()
|
||||
{
|
||||
System.arraycopy(mSongs, 1, mSongs, 0, mSongs.length - 1);
|
||||
System.arraycopy(mBitmaps, 1, mBitmaps, 0, mBitmaps.length - 1);
|
||||
mSongs[mSongs.length - 1] = null;
|
||||
mBitmaps[mBitmaps.length - 1] = null;
|
||||
reset();
|
||||
if (mService == null)
|
||||
return;
|
||||
|
||||
try {
|
||||
mService.nextSong();
|
||||
|
||||
System.arraycopy(mSongs, 1, mSongs, 0, STORE_SIZE - 1);
|
||||
System.arraycopy(mBitmaps, 1, mBitmaps, 0, STORE_SIZE - 1);
|
||||
mSongs[STORE_SIZE - 1] = null;
|
||||
mBitmaps[STORE_SIZE - 1] = null;
|
||||
reset();
|
||||
|
||||
mHandler.sendMessage(mHandler.obtainMessage(QUERY_SONG, 2, 0));
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void shiftForward()
|
||||
public void previousCover()
|
||||
{
|
||||
System.arraycopy(mSongs, 0, mSongs, 1, mSongs.length - 1);
|
||||
System.arraycopy(mBitmaps, 0, mBitmaps, 1, mBitmaps.length - 1);
|
||||
mSongs[0] = null;
|
||||
mBitmaps[0] = null;
|
||||
reset();
|
||||
if (mService == null)
|
||||
return;
|
||||
|
||||
try {
|
||||
mService.previousSong();
|
||||
|
||||
System.arraycopy(mSongs, 0, mSongs, 1, STORE_SIZE - 1);
|
||||
System.arraycopy(mBitmaps, 0, mBitmaps, 1, STORE_SIZE - 1);
|
||||
mSongs[0] = null;
|
||||
mBitmaps[0] = null;
|
||||
reset();
|
||||
|
||||
mHandler.sendMessage(mHandler.obtainMessage(QUERY_SONG, 0, 0));
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void togglePlayback()
|
||||
{
|
||||
if (mService == null)
|
||||
return;
|
||||
|
||||
try {
|
||||
mService.togglePlayback();
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void reset()
|
||||
@ -227,7 +253,7 @@ public class CoverView extends View {
|
||||
|
||||
canvas.drawColor(Color.BLACK);
|
||||
|
||||
for (int x = 0, i = 0; i != mBitmaps.length; ++i, x += width) {
|
||||
for (int x = 0, i = 0; i != STORE_SIZE; ++i, x += width) {
|
||||
if (mBitmaps[i] != null && clip.intersects(x, 0, x + width, height)) {
|
||||
int xOffset = (width - mBitmaps[i].getWidth()) / 2;
|
||||
int yOffset = (height - mBitmaps[i].getHeight()) / 2;
|
||||
@ -274,7 +300,7 @@ public class CoverView extends View {
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (Math.abs(mStartX - x) + Math.abs(mStartY - ev.getY()) < 10) {
|
||||
mListener.clicked();
|
||||
performClick();
|
||||
} else {
|
||||
VelocityTracker velocityTracker = mVelocityTracker;
|
||||
velocityTracker.computeCurrentVelocity(1000);
|
||||
@ -314,13 +340,46 @@ public class CoverView extends View {
|
||||
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
|
||||
postInvalidate();
|
||||
} else if (mTentativeCover != -1) {
|
||||
if (mListener != null) {
|
||||
if (mTentativeCover == 2)
|
||||
mListener.next();
|
||||
else if (mTentativeCover == 0)
|
||||
mListener.previous();
|
||||
}
|
||||
if (mTentativeCover == 2)
|
||||
nextCover();
|
||||
else if (mTentativeCover == 0)
|
||||
previousCover();
|
||||
|
||||
mTentativeCover = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final int REFRESH_SONGS = 0;
|
||||
private static final int QUERY_SONG = 1;
|
||||
|
||||
private Handler mHandler = new Handler() {
|
||||
public void handleMessage(Message message) {
|
||||
switch (message.what) {
|
||||
case REFRESH_SONGS:
|
||||
refreshSongs();
|
||||
break;
|
||||
case QUERY_SONG:
|
||||
try {
|
||||
int i = message.arg1;
|
||||
int delta = i - STORE_SIZE / 2;
|
||||
mSongs[i] = mService.getSong(delta);
|
||||
createBitmap(i);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private IMusicPlayerWatcher mWatcher = new IMusicPlayerWatcher.Stub() {
|
||||
public void songChanged(Song playingSong)
|
||||
{
|
||||
if (!playingSong.equals(mSongs[STORE_SIZE / 2]))
|
||||
mHandler.sendEmptyMessage(REFRESH_SONGS);
|
||||
}
|
||||
|
||||
public void stateChanged(int oldState, int newState)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
@ -115,9 +115,10 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
|
||||
|
||||
private PlaybackService mService;
|
||||
private RemoteCallbackList<IMusicPlayerWatcher> mWatchers;
|
||||
|
||||
private boolean mHeadsetOnly = true;
|
||||
|
||||
|
||||
private boolean mHeadsetOnly;
|
||||
private boolean mUseRemotePlayer;
|
||||
|
||||
private Handler mHandler;
|
||||
private MediaPlayer mMediaPlayer;
|
||||
private Random mRandom;
|
||||
@ -149,6 +150,7 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
|
||||
private static final int HANDLE_PLAY = 7;
|
||||
private static final int HANDLE_PAUSE = 8;
|
||||
private static final int RETRIEVE_SONGS = 9;
|
||||
private static final int REMOTE_PLAYER_PREF_CHANGED = 10;
|
||||
|
||||
private static final int ITEM_SONG = 0;
|
||||
private static final int ITEM_RESET = 1;
|
||||
@ -220,6 +222,11 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
|
||||
case RETRIEVE_SONGS:
|
||||
retrieveSongs();
|
||||
break;
|
||||
case REMOTE_PLAYER_PREF_CHANGED:
|
||||
mUseRemotePlayer = message.arg1 == 1;
|
||||
if (mState == STATE_PLAYING)
|
||||
mService.startForegroundCompat(NOTIFICATION_ID, createNotfication());
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -237,11 +244,12 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
|
||||
mMediaPlayer.setWakeMode(mService, PowerManager.PARTIAL_WAKE_LOCK);
|
||||
mMediaPlayer.setOnCompletionListener(this);
|
||||
retrieveSongs();
|
||||
|
||||
|
||||
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(mService);
|
||||
mHeadsetOnly = settings.getBoolean("headset_only", false);
|
||||
mUseRemotePlayer = settings.getBoolean("remote_player", true);
|
||||
settings.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
|
||||
setCurrentSong(1);
|
||||
|
||||
Looper.loop();
|
||||
@ -302,7 +310,7 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
|
||||
notification.contentView = views;
|
||||
notification.icon = R.drawable.status_icon;
|
||||
notification.flags |= Notification.FLAG_ONGOING_EVENT;
|
||||
Intent intent = new Intent(mService, NowPlayingActivity.class);
|
||||
Intent intent = new Intent(mService, mUseRemotePlayer ? RemoteActivity.class : NowPlayingActivity.class);
|
||||
notification.contentIntent = PendingIntent.getActivity(mService, 0, intent, 0);
|
||||
|
||||
return notification;
|
||||
@ -416,9 +424,15 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
|
||||
|
||||
public void onSharedPreferenceChanged(SharedPreferences settings, String key)
|
||||
{
|
||||
if ("headset_only".equals(key) && mHandler != null) {
|
||||
if (mHandler == null)
|
||||
return;
|
||||
|
||||
if ("headset_only".equals(key)) {
|
||||
int arg = settings.getBoolean(key, false) ? 1 : 0;
|
||||
mHandler.sendMessage(mHandler.obtainMessage(HEADSET_PREF_CHANGED, arg, 0));
|
||||
} else if ("remote_player".equals(key)) {
|
||||
int arg = settings.getBoolean(key, true) ? 1 : 0;
|
||||
mHandler.sendMessage(mHandler.obtainMessage(REMOTE_PLAYER_PREF_CHANGED, arg, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package org.kreed.tumult;
|
||||
|
||||
import org.kreed.tumult.CoverView.CoverViewWatcher;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@ -25,7 +23,7 @@ import android.widget.LinearLayout;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class NowPlayingActivity extends Activity implements CoverViewWatcher, ServiceConnection, View.OnClickListener, SeekBar.OnSeekBarChangeListener, View.OnFocusChangeListener {
|
||||
public class NowPlayingActivity extends Activity implements ServiceConnection, View.OnClickListener, SeekBar.OnSeekBarChangeListener, View.OnFocusChangeListener {
|
||||
private IPlaybackService mService;
|
||||
|
||||
private ViewGroup mLayout;
|
||||
@ -55,8 +53,8 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
||||
setContentView(R.layout.nowplaying);
|
||||
|
||||
mCoverView = (CoverView)findViewById(R.id.cover_view);
|
||||
mCoverView.setWatcher(this);
|
||||
|
||||
mCoverView.setOnClickListener(this);
|
||||
|
||||
mLayout = (ViewGroup)mCoverView.getParent();
|
||||
|
||||
mControlsTop = findViewById(R.id.controls_top);
|
||||
@ -139,21 +137,12 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
||||
unbindService(this);
|
||||
}
|
||||
|
||||
private void refreshSongs()
|
||||
{
|
||||
try {
|
||||
mCoverView.setSongs(mService.getCurrentSongs());
|
||||
} catch (RemoteException e) {
|
||||
Log.e("Tumult", "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceConnected(ComponentName name, IBinder service)
|
||||
{
|
||||
mService = IPlaybackService.Stub.asInterface(service);
|
||||
try {
|
||||
mService.registerWatcher(mWatcher);
|
||||
refreshSongs();
|
||||
mCoverView.setPlaybackService(mService);
|
||||
setState(mService.getState());
|
||||
mDuration = mService.getDuration();
|
||||
} catch (RemoteException e) {
|
||||
@ -175,15 +164,6 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
||||
mHandler.sendEmptyMessage(UPDATE_PROGRESS);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
|
||||
if (!playingSong.equals(mCoverView.getActiveSong())) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run()
|
||||
{
|
||||
refreshSongs();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void stateChanged(final int oldState, final int newState)
|
||||
@ -197,34 +177,6 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
||||
}
|
||||
};
|
||||
|
||||
public void next()
|
||||
{
|
||||
try {
|
||||
mService.nextSong();
|
||||
mCoverView.shiftBackward();
|
||||
mHandler.sendMessage(mHandler.obtainMessage(QUERY_SONG, 1, 0));
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void previous()
|
||||
{
|
||||
try {
|
||||
mService.previousSong();
|
||||
mCoverView.shiftForward();
|
||||
mHandler.sendMessage(mHandler.obtainMessage(QUERY_SONG, -1, 0));
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
private void togglePlayback()
|
||||
{
|
||||
try {
|
||||
mService.togglePlayback();
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
{
|
||||
@ -261,30 +213,13 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_DPAD_CENTER:
|
||||
case KeyEvent.KEYCODE_ENTER:
|
||||
clicked();
|
||||
onClick(mCoverView);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void clicked()
|
||||
{
|
||||
if (mControlsTop.getVisibility() == View.VISIBLE) {
|
||||
mControlsTop.setVisibility(View.GONE);
|
||||
if (mState == MusicPlayer.STATE_PLAYING)
|
||||
mControlsBottom.setVisibility(View.GONE);
|
||||
} else {
|
||||
mControlsTop.setVisibility(View.VISIBLE);
|
||||
mControlsBottom.setVisibility(View.VISIBLE);
|
||||
|
||||
mPlayPauseButton.requestFocus();
|
||||
|
||||
updateProgress();
|
||||
sendHideMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private String stringForTime(int ms)
|
||||
{
|
||||
int seconds = ms / 1000;
|
||||
@ -331,18 +266,30 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
||||
{
|
||||
sendHideMessage();
|
||||
|
||||
if (view == mNextButton) {
|
||||
next();
|
||||
if (view == mCoverView) {
|
||||
if (mControlsTop.getVisibility() == View.VISIBLE) {
|
||||
mControlsTop.setVisibility(View.GONE);
|
||||
if (mState == MusicPlayer.STATE_PLAYING)
|
||||
mControlsBottom.setVisibility(View.GONE);
|
||||
} else {
|
||||
mControlsTop.setVisibility(View.VISIBLE);
|
||||
mControlsBottom.setVisibility(View.VISIBLE);
|
||||
|
||||
mPlayPauseButton.requestFocus();
|
||||
|
||||
updateProgress();
|
||||
}
|
||||
} else if (view == mNextButton) {
|
||||
mCoverView.nextCover();
|
||||
} else if (view == mPreviousButton) {
|
||||
previous();
|
||||
mCoverView.previousCover();
|
||||
} else if (view == mPlayPauseButton) {
|
||||
togglePlayback();
|
||||
mCoverView.togglePlayback();
|
||||
}
|
||||
}
|
||||
|
||||
private static final int HIDE = 0;
|
||||
private static final int UPDATE_PROGRESS = 1;
|
||||
private static final int QUERY_SONG = 2;
|
||||
|
||||
private Handler mHandler = new Handler() {
|
||||
public void handleMessage(Message message) {
|
||||
@ -355,12 +302,6 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
||||
case UPDATE_PROGRESS:
|
||||
updateProgress();
|
||||
break;
|
||||
case QUERY_SONG:
|
||||
try {
|
||||
int delta = message.arg1;
|
||||
mCoverView.setSong(delta, mService.getSong(delta));
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
125
src/org/kreed/tumult/RemoteActivity.java
Normal file
125
src/org/kreed/tumult/RemoteActivity.java
Normal file
@ -0,0 +1,125 @@
|
||||
package org.kreed.tumult;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.ImageButton;
|
||||
|
||||
public class RemoteActivity extends Activity implements ServiceConnection, View.OnClickListener {
|
||||
private CoverView mCoverView;
|
||||
|
||||
private View mOpenButton;
|
||||
private View mKillButton;
|
||||
private View mPreviousButton;
|
||||
private ImageButton mPlayPauseButton;
|
||||
private View mNextButton;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state)
|
||||
{
|
||||
super.onCreate(state);
|
||||
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.remote_dialog);
|
||||
|
||||
mCoverView = (CoverView)findViewById(R.id.cover_view);
|
||||
|
||||
mOpenButton = findViewById(R.id.open_button);
|
||||
mOpenButton.setOnClickListener(this);
|
||||
mKillButton = findViewById(R.id.kill_button);
|
||||
mKillButton.setOnClickListener(this);
|
||||
mPreviousButton = findViewById(R.id.previous);
|
||||
mPreviousButton.setOnClickListener(this);
|
||||
mPlayPauseButton = (ImageButton)findViewById(R.id.play_pause);
|
||||
mPlayPauseButton.setOnClickListener(this);
|
||||
mNextButton = findViewById(R.id.next);
|
||||
mNextButton.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
|
||||
reconnect();
|
||||
}
|
||||
|
||||
private void reconnect()
|
||||
{
|
||||
Intent intent = new Intent(this, PlaybackService.class);
|
||||
startService(intent);
|
||||
bindService(intent, this, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause()
|
||||
{
|
||||
super.onPause();
|
||||
|
||||
unbindService(this);
|
||||
}
|
||||
|
||||
public void onServiceConnected(ComponentName name, IBinder binder)
|
||||
{
|
||||
IPlaybackService service = IPlaybackService.Stub.asInterface(binder);
|
||||
mCoverView.setPlaybackService(service);
|
||||
try {
|
||||
service.registerWatcher(mWatcher);
|
||||
setState(service.getState());
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName name)
|
||||
{
|
||||
reconnect();
|
||||
}
|
||||
|
||||
public void onClick(View view)
|
||||
{
|
||||
if (view == mKillButton) {
|
||||
stopService(new Intent(this, PlaybackService.class));
|
||||
finish();
|
||||
} else if (view == mOpenButton) {
|
||||
startActivity(new Intent(this, NowPlayingActivity.class));
|
||||
finish();
|
||||
} else if (view == mNextButton) {
|
||||
mCoverView.nextCover();
|
||||
} else if (view == mPreviousButton) {
|
||||
mCoverView.previousCover();
|
||||
} else if (view == mPlayPauseButton) {
|
||||
mCoverView.togglePlayback();
|
||||
}
|
||||
}
|
||||
|
||||
private void setState(int state)
|
||||
{
|
||||
if (state == MusicPlayer.STATE_NO_MEDIA)
|
||||
finish();
|
||||
|
||||
mPlayPauseButton.setImageResource(state == MusicPlayer.STATE_PLAYING ? R.drawable.pause : R.drawable.play);
|
||||
}
|
||||
|
||||
private IMusicPlayerWatcher mWatcher = new IMusicPlayerWatcher.Stub() {
|
||||
public void songChanged(Song playingSong)
|
||||
{
|
||||
}
|
||||
|
||||
public void stateChanged(final int oldState, final int newState)
|
||||
{
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run()
|
||||
{
|
||||
setState(newState);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
76
src/org/kreed/tumult/RemoteLayout.java
Normal file
76
src/org/kreed/tumult/RemoteLayout.java
Normal file
@ -0,0 +1,76 @@
|
||||
package org.kreed.tumult;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/*
|
||||
* RemoteLayout acts like a very simple vertical LinearLayout with special
|
||||
* case: all CoverViews placed will be made square at all costs.
|
||||
*/
|
||||
|
||||
public class RemoteLayout extends ViewGroup {
|
||||
private int mCoverSize;
|
||||
|
||||
public RemoteLayout(Context context, AttributeSet attrs)
|
||||
{
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||
{
|
||||
int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
int measuredHeight = 0;
|
||||
int measuredWidth = 0;
|
||||
|
||||
View coverView = null;
|
||||
for (int i = getChildCount(); --i != -1; ) {
|
||||
View view = getChildAt(i);
|
||||
if (view instanceof CoverView) {
|
||||
coverView = view;
|
||||
} else {
|
||||
int spec = MeasureSpec.makeMeasureSpec(maxHeight - measuredHeight, MeasureSpec.AT_MOST);
|
||||
view.measure(widthMeasureSpec, spec);
|
||||
measuredHeight += view.getMeasuredHeight();
|
||||
if (view.getMeasuredWidth() > measuredWidth)
|
||||
measuredWidth = view.getMeasuredWidth();
|
||||
}
|
||||
}
|
||||
|
||||
if (coverView != null) {
|
||||
if (measuredHeight + measuredWidth > maxHeight) {
|
||||
mCoverSize = maxHeight - measuredHeight;
|
||||
measuredHeight = maxHeight;
|
||||
} else {
|
||||
mCoverSize = measuredWidth;
|
||||
measuredHeight += measuredWidth;
|
||||
}
|
||||
}
|
||||
|
||||
setMeasuredDimension(measuredWidth, measuredHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4)
|
||||
{
|
||||
int layoutWidth = getMeasuredWidth();
|
||||
int top = 0;
|
||||
|
||||
for (int i = 0, end = getChildCount(); i != end; ++i) {
|
||||
View view = getChildAt(i);
|
||||
if (view instanceof CoverView) {
|
||||
view.layout(0, top, layoutWidth, top + mCoverSize);
|
||||
top += mCoverSize;
|
||||
} else {
|
||||
int height = view.getMeasuredHeight();
|
||||
int width = view.getMeasuredWidth();
|
||||
int left = (layoutWidth - width) / 2;
|
||||
view.layout(left, top, layoutWidth - left, top + height);
|
||||
top += height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user