diff --git a/src/android/res/layout/main.xml b/src/android/res/layout/main.xml index 9d98aaa43..f22ed39fe 100644 --- a/src/android/res/layout/main.xml +++ b/src/android/res/layout/main.xml @@ -13,6 +13,7 @@ + diff --git a/src/android/res/menu/default_menu.xml b/src/android/res/menu/default_menu.xml index db3e37809..5bfe7ed97 100644 --- a/src/android/res/menu/default_menu.xml +++ b/src/android/res/menu/default_menu.xml @@ -1,2 +1,5 @@ - + + + + diff --git a/src/android/res/values/strings.xml b/src/android/res/values/strings.xml index e38e756f2..6c8b96f80 100644 --- a/src/android/res/values/strings.xml +++ b/src/android/res/values/strings.xml @@ -16,4 +16,6 @@ 10543 10544 #333333 +Player controls +Browse diff --git a/src/android/src/org/musikcube/CategoryList.java b/src/android/src/org/musikcube/CategoryList.java index 903dcc3ef..74ac63277 100644 --- a/src/android/src/org/musikcube/CategoryList.java +++ b/src/android/src/org/musikcube/CategoryList.java @@ -14,6 +14,9 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; @@ -219,4 +222,26 @@ public class CategoryList extends ListActivity implements OnQueryResultListener startService(new Intent(this, org.musikcube.Service.class)); } + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.default_menu, menu); + return true; + } + + public boolean onOptionsItemSelected(MenuItem item) { + //Log.i("MC2.onContextItemSelected","item "+item.getItemId()+" "+R.id.context_settings); + switch (item.getItemId()) { + case R.id.context_settings: + startActivity(new Intent(this, org.musikcube.Preferences.class)); + return true; + case R.id.context_browse: + startActivity(new Intent(this, org.musikcube.main.class)); + return true; + case R.id.context_controls: + startActivity(new Intent(this, org.musikcube.PlayerControl.class)); + return true; + default: + return super.onContextItemSelected(item); + } + } } diff --git a/src/android/src/org/musikcube/PlayerControl.java b/src/android/src/org/musikcube/PlayerControl.java index a313799bc..9666460b5 100644 --- a/src/android/src/org/musikcube/PlayerControl.java +++ b/src/android/src/org/musikcube/PlayerControl.java @@ -15,6 +15,9 @@ import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageButton; @@ -219,4 +222,29 @@ public class PlayerControl extends Activity implements OnTrackUpdateListener, On seconds+=0.1; updatecount(); } }, 100, 100); */ + + + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.default_menu, menu); + return true; + } + + public boolean onOptionsItemSelected(MenuItem item) { + //Log.i("MC2.onContextItemSelected","item "+item.getItemId()+" "+R.id.context_settings); + switch (item.getItemId()) { + case R.id.context_settings: + startActivity(new Intent(this, org.musikcube.Preferences.class)); + return true; + case R.id.context_browse: + startActivity(new Intent(this, org.musikcube.main.class)); + return true; + case R.id.context_controls: + startActivity(new Intent(this, org.musikcube.PlayerControl.class)); + return true; + default: + return super.onContextItemSelected(item); + } + } + } diff --git a/src/android/src/org/musikcube/core/Player.java b/src/android/src/org/musikcube/core/Player.java index 0fa0d752d..2eab2b4dd 100644 --- a/src/android/src/org/musikcube/core/Player.java +++ b/src/android/src/org/musikcube/core/Player.java @@ -16,6 +16,7 @@ public class Player implements TrackPlayer.OnTrackStatusListener{ private ArrayList playingTracks = new ArrayList(); private TrackPlayer currentPlayer; + private TrackPlayer nextPlayer; public android.app.Service service; @@ -52,28 +53,56 @@ public class Player implements TrackPlayer.OnTrackStatusListener{ this.Play(); } + private TrackPlayer PrepareTrack(int position){ + synchronized(this.lock){ + if(this.nowPlaying.size()>position && position>=0){ + int trackId = this.nowPlaying.get(position); + String url = "http://"+this.library.host+":"+this.library.httpPort+"/track/?track_id="+trackId+"&auth_key="+this.library.authorization; + TrackPlayer player = new TrackPlayer(url,trackId); + return player; + } + } + return null; + } + public void Play(){ this.Startup(); this.StopAllTracks(); - + + TrackPlayer newPlayer = null; synchronized(this.lock){ - String url = "http://"+this.library.host+":"+this.library.httpPort+"/track/?track_id="+this.nowPlaying.get(this.position)+"&auth_key="+this.library.authorization; - TrackPlayer player = new TrackPlayer(url,true); - player.listener = this; - this.playingTracks.add(player); - this.currentPlayer = player; - - if(this.listener!=null){ - this.listener.OnTrackUpdate(); - this.listener.OnTrackBufferUpdate(0); - this.listener.OnTrackPositionUpdate(0); + if(this.nowPlaying.size()>position && position>=0){ + int trackId = this.nowPlaying.get(position); + if(this.nextPlayer!=null){ + if(this.nextPlayer.trackId==trackId){ + newPlayer = this.nextPlayer; + this.nextPlayer = null; + }else{ + // Something wrong here, not the prepared track + this.nextPlayer.Stop(); + this.nextPlayer = null; + } + } + if(newPlayer==null){ + newPlayer = this.PrepareTrack(this.position); + } + this.playingTracks.add(newPlayer); + this.currentPlayer = newPlayer; + newPlayer.listener = this; + newPlayer.Play(); + + if(this.listener!=null){ + this.listener.OnTrackUpdate(); + this.listener.OnTrackBufferUpdate(0); + this.listener.OnTrackPositionUpdate(0); + } } } } /////////////////////////////// - // Inteface for updated track + // Interface for updated track public interface OnTrackUpdateListener{ public void OnTrackUpdate(); public void OnTrackBufferUpdate(int percent); @@ -147,10 +176,12 @@ public class Player implements TrackPlayer.OnTrackStatusListener{ } public void OnTrackStatusUpdate(TrackPlayer trackPlayer,int status) { -// this.Next(); - Intent intent = new Intent(this.service, org.musikcube.Service.class); + if(status==TrackPlayer.STATUS_EXIT){ + this.Next(); + } +/* Intent intent = new Intent(this.service, org.musikcube.Service.class); intent.putExtra("org.musikcube.Service.action", "next"); - this.service.startService(intent); + this.service.startService(intent);*/ } public int GetCurrentTrackId(){ @@ -183,4 +214,12 @@ public class Player implements TrackPlayer.OnTrackStatusListener{ return 0; } + public void OnTrackAlmostDone(TrackPlayer trackPlayer) { + synchronized(this.lock){ + if(this.nextPlayer==null){ + this.nextPlayer = this.PrepareTrack(this.position+1); + } + } + } + } diff --git a/src/android/src/org/musikcube/core/TrackPlayer.java b/src/android/src/org/musikcube/core/TrackPlayer.java index 8ddecebaa..4a0c6d876 100644 --- a/src/android/src/org/musikcube/core/TrackPlayer.java +++ b/src/android/src/org/musikcube/core/TrackPlayer.java @@ -4,18 +4,20 @@ import android.media.MediaPlayer; public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener,MediaPlayer.OnBufferingUpdateListener { + public int trackId = 0; private Thread thread; private String url; private java.lang.Object lock = new java.lang.Object(); private MediaPlayer mediaPlayer; private int buffer = 0; + private boolean almostDoneSend = false; private int status = 1; - private static final int STATUS_PREPARED = 1; - private static final int STATUS_PLAYING = 2; - private static final int STATUS_PAUSE = 3; - private static final int STATUS_EXIT = 10; + public static final int STATUS_PREPARED = 1; + public static final int STATUS_PLAYING = 2; + public static final int STATUS_PAUSE = 3; + public static final int STATUS_EXIT = 10; public void run() { synchronized(this.lock){ @@ -44,37 +46,50 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener, this.mediaPlayer.start(); synchronized(this.lock){ - while(this.status==STATUS_PLAYING) - this.lock.wait(); + while(this.status==STATUS_PLAYING){ + if(!this.almostDoneSend){ + int duration = this.mediaPlayer.getDuration(); + int position = this.mediaPlayer.getCurrentPosition(); + if(duration>0 && position+10000>duration){ + // The track is almost done + this.almostDoneSend = true; + if(this.listener!=null){ + this.listener.OnTrackAlmostDone(this); + } + } + } + this.lock.wait(3000); + + } } this.mediaPlayer.stop(); } catch (Exception e) { - // TODO Auto-generated catch block - synchronized(this.lock){ - this.status = STATUS_EXIT; - } + } + synchronized(this.lock){ + this.status = STATUS_EXIT; } this.CallListener(); } - public TrackPlayer(String url){ + public TrackPlayer(String url,int trackId){ + this.trackId = trackId; this.url = url; this.thread = new Thread(this); this.thread.start(); } - public TrackPlayer(String url,boolean start){ +/* public TrackPlayer(String url,boolean start){ this.url = url; if(start==true){ this.status = STATUS_PLAYING; } this.thread = new Thread(this); this.thread.start(); - } + }*/ private void Exit(){ synchronized(this.lock){ @@ -101,15 +116,13 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener, } } - public boolean Play(){ + public void Play(){ synchronized(this.lock){ if(this.status==STATUS_PLAYING || this.status==STATUS_PREPARED){ this.status = STATUS_PLAYING; - this.lock.notifyAll(); - return true; } + this.lock.notifyAll(); } - return false; } private void CallListener(){ @@ -126,6 +139,7 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener, public interface OnTrackStatusListener{ public void OnTrackStatusUpdate(TrackPlayer trackPlayer,int status); + public void OnTrackAlmostDone(TrackPlayer trackPlayer); } public OnTrackStatusListener listener = null; diff --git a/src/android/src/org/musikcube/main.java b/src/android/src/org/musikcube/main.java index b1d70c84b..738693566 100644 --- a/src/android/src/org/musikcube/main.java +++ b/src/android/src/org/musikcube/main.java @@ -68,10 +68,15 @@ public class main extends Activity implements OnLibraryStatusListener { public boolean onOptionsItemSelected(MenuItem item) { //Log.i("MC2.onContextItemSelected","item "+item.getItemId()+" "+R.id.context_settings); switch (item.getItemId()) { - case R.id.context_settings: - Intent intent = new Intent(main.this, Preferences.class); - startActivity(intent); - return true; + case R.id.context_settings: + startActivity(new Intent(this, org.musikcube.Preferences.class)); + return true; + case R.id.context_browse: + startActivity(new Intent(this, org.musikcube.main.class)); + return true; + case R.id.context_controls: + startActivity(new Intent(this, org.musikcube.PlayerControl.class)); + return true; default: return super.onContextItemSelected(item); }