android client v1.0.2

This commit is contained in:
Daniel Önnerby 2009-08-31 10:00:07 +00:00
parent e95ce2035c
commit a3dbc24aa8
20 changed files with 493 additions and 174 deletions

View File

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musikcube"
android:versionCode="1"
android:versionName="1.0">
android:versionName="1.0.2" android:versionCode="2">
<application android:icon="@drawable/icon" android:label="@string/app_name" android:name="App" android:debuggable="false">
<activity android:name=".main"
android:label="@string/app_name" android:launchMode="singleTask">
android:label="@string/app_name" android:launchMode="singleTask" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
@ -10,7 +10,8 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"/>
android:drawSelectorOnTop="false"
android:choiceMode="multipleChoice" android:fastScrollEnabled="true" />
<LinearLayout android:id="@id/android:empty"
android:orientation="horizontal"

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:textSize="22sp" android:text="Save" android:id="@+id/SaveButton"></Button>
</LinearLayout>

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<CheckBox android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="28sp" android:maxLines="1"></CheckBox>
</LinearLayout>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="28sp"
android:maxLines="1"
android:checkMark="?android:attr/listChoiceIndicatorMultiple" />

View File

@ -3,8 +3,10 @@
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/help_main" android:layout_margin="10sp"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="musikCube is a application that is able to play music from you own desktop computer or server. Although it can be a little bit tricky to get it up and running since you probably need to do some port forwarding in your gateway to be able to access the server from outside your network." android:padding="4sp"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="First of all, musikCube requires you to run a windows applications called musikServer that can be downloaded from:" android:padding="4sp"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="http://code.google.com/p/musikcube/" android:textColor="#ffffff" android:padding="4sp"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="On the project site you will also find help regarding gateway and firewall settings." android:padding="4sp"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Once installed and opened up in gateways and firewalls you go to the settings in this application and edit where to find your musikServer." android:padding="4sp"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Enjoy!" android:padding="4sp"></TextView>
</LinearLayout>

View File

@ -10,11 +10,13 @@
</LinearLayout>
<LinearLayout android:orientation="vertical" android:layout_height="wrap_content" android:layout_width="fill_parent" android:layout_weight="0.8">
<TextView android:id="@+id/TextView01" android:layout_height="wrap_content" android:text="Browse by:" android:layout_width="fill_parent" android:background="@color/headlineColor" android:textSize="16sp" android:padding="4sp"></TextView>
<TextView android:id="@+id/TextView01" android:layout_height="wrap_content" android:text="Browse by:" android:layout_width="fill_parent" android:background="@color/headlineColor" android:textSize="20sp" android:padding="4sp"></TextView>
<Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:textSize="22sp" android:text="Genre" android:id="@+id/GenresButton"></Button>
<Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:textSize="22sp" android:id="@+id/ArtistsButton" android:text="Artist"></Button>
<Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:textSize="22sp" android:id="@+id/YearButton" android:text="Year"></Button>
<Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:textSize="22sp" android:id="@+id/BPMButton" android:text="Workout mode"></Button>
<TextView android:id="@+id/TextView02" android:layout_height="wrap_content" android:text="Workout mode by:" android:layout_width="fill_parent" android:background="@color/headlineColor" android:textSize="20sp" android:padding="4sp"></TextView>
<Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:textSize="22sp" android:id="@+id/BPMGenreButton" android:text="Genre"></Button>
<Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:textSize="22sp" android:id="@+id/BPMArtistButton" android:text="Artist"></Button>
</LinearLayout>
<TextView android:id="@+id/StatusView" android:text="Status: -" android:layout_width="fill_parent" android:background="@color/headlineColor" android:textSize="16sp" android:padding="4sp" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_weight="0.1"></TextView>

View File

@ -4,42 +4,38 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp" android:gravity="center_vertical|center_horizontal">
android:paddingRight="8dp" android:gravity="center_horizontal">
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content">
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical">
<FrameLayout android:id="@+id/FrameLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10sp" android:padding="2sp" android:background="#666666">
<ImageView android:layout_marginTop="5sp" android:layout_marginBottom="5sp" android:id="@+id/AlbumCover" android:background="#000000" android:src="@drawable/running" android:layout_height="128sp" android:layout_width="128sp" android:scaleType="fitXY"></ImageView>
<ImageView android:layout_marginTop="5sp" android:layout_marginBottom="5sp" android:id="@+id/AlbumCover" android:background="#000000" android:src="@drawable/running" android:layout_height="128sp" android:layout_width="128sp" android:scaleType="fitXY"></ImageView>
</FrameLayout>
<LinearLayout android:id="@+id/LinearLayout01" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="left" android:layout_width="160sp" android:layout_gravity="left" android:paddingLeft="10sp">
<TextView android:layout_height="wrap_content" android:textSize="20sp" android:id="@+id/TrackTitle" android:lines="1" android:layout_width="wrap_content" android:text="Title:"></TextView>
<TextView android:layout_height="wrap_content" android:textSize="14sp" android:text="Album:" android:id="@+id/TrackAlbum" android:lines="1" android:layout_width="wrap_content"></TextView>
<TextView android:layout_width="wrap_content" android:textSize="14sp" android:layout_height="wrap_content" android:text="Artists:" android:id="@+id/TrackArtist" android:lines="1"></TextView>
</LinearLayout>
</LinearLayout>
<LinearLayout android:id="@+id/LinearLayout01" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="left" android:layout_width="wrap_content" android:layout_gravity="left" android:paddingLeft="20sp">
<TextView android:layout_height="wrap_content" android:textSize="24sp" android:id="@+id/TrackTitle" android:lines="1" android:layout_width="wrap_content" android:text="Title:"></TextView>
<TextView android:layout_height="wrap_content" android:text="Album:" android:id="@+id/TrackAlbum" android:lines="1" android:layout_width="wrap_content"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Artists:" android:id="@+id/TrackArtist" android:lines="1"></TextView>
<LinearLayout android:id="@+id/LinearLayout02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:layout_margin="20sp">
<TextView android:layout_height="wrap_content" android:textSize="20sp" android:id="@+id/BPMTitle" android:lines="1" android:layout_width="wrap_content" android:text="BPM:"></TextView>
<SeekBar android:layout_height="50sp" android:layout_width="200sp" android:max="1000" android:id="@+id/BPM" android:progress="500"></SeekBar>
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical">
<ToggleButton android:id="@+id/ToggleAccelerator" android:layout_width="wrap_content" android:layout_height="wrap_content"></ToggleButton>
<TextView android:layout_height="wrap_content" android:textSize="18sp" android:lines="1" android:layout_width="wrap_content" android:text="Accelerometer"></TextView>
</LinearLayout>
</LinearLayout>
<LinearLayout android:id="@+id/LinearLayout02" android:layout_weight="0.5" android:layout_width="wrap_content" android:layout_height="wrap_content"><TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:id="@+id/BPMText" android:textSize="32sp" android:text="Pace: - Bpm"></TextView></LinearLayout>
<LinearLayout android:id="@+id/LinearLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal">
<LinearLayout android:id="@+id/LinearLayout03" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal">
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:adjustViewBounds="true" android:id="@+id/MediaPause" android:src="@drawable/ic_media_pause" android:padding="15sp"></ImageButton>
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/MediaNext" android:adjustViewBounds="true" android:src="@drawable/ic_media_next" android:padding="15sp"></ImageButton>
</LinearLayout>
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0:00" android:id="@+id/TrackPosition" android:typeface="monospace"></TextView>
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="0:00" android:id="@+id/TrackDuration" android:typeface="monospace" android:gravity="right"></TextView>
</LinearLayout>
<SeekBar android:layout_height="wrap_content" android:layout_width="fill_parent" android:max="1000" android:id="@+id/TrackProgress" android:progress="0" android:secondaryProgress="0"></SeekBar>
</LinearLayout>

View File

@ -19,6 +19,6 @@
<string name="menu_controls">Player controls</string>
<string name="menu_browse">Browse</string>
<string name="menu_nowplaying">Now playing</string>
<string name="help_main">musikCube is a application that connects to you musikServer that you have installed on your desktop/server computer. Once musikCube is connected you are able to browse and play all your music directly on your phone without having to copy them to you SD card.</string>
<string name="help_main">musikCube is a application that connects to your musikServer that you have installed on your desktop/server computer. The musikServer can be downloaded from http://code.google.com/p/musikcube/\nOnce musikCube is connected you are able to browse and play all your music directly on your phone without having to copy them to you SD card.\n</string>
</resources>

View File

@ -5,7 +5,6 @@ package org.musikcube;
import java.util.ArrayList;
import org.musikcube.TrackListBase.TrackViewHolder;
import org.musikcube.core.IQuery;
import org.musikcube.core.ListQuery;
import org.musikcube.core.IQuery.OnQueryResultListener;
@ -21,7 +20,6 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

View File

@ -5,26 +5,28 @@ package org.musikcube;
import java.util.ArrayList;
import org.musikcube.TrackListBase.TrackViewHolder;
import org.musikcube.core.IQuery;
import org.musikcube.core.ListQuery;
import org.musikcube.core.Workout;
import org.musikcube.core.IQuery.OnQueryResultListener;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.Button;
import android.widget.CheckedTextView;
import android.widget.ListView;
import android.widget.TextView;
/**
* @author doy
@ -51,7 +53,7 @@ public class CategorySelect extends ListActivity implements OnQueryResultListene
};
static class CategoryViewHolder{
CheckBox title;
CheckedTextView title;
}
public class ResultAdapter extends BaseAdapter{
@ -66,28 +68,15 @@ public class CategorySelect extends ListActivity implements OnQueryResultListene
}
public int getCount() {
int size = this.query.resultsInts.size();
if(size==0){
return 0;
}else{
return size+1;
}
return this.query.resultsInts.size();
}
public Object getItem(int position) {
if(position==0){
return 0;
}else{
return this.query.resultsInts.get(position-1);
}
return this.query.resultsInts.get(position);
}
public long getItemId(int position) {
if(position==0){
return 0;
}else{
return this.query.resultsInts.get(position-1);
}
return this.query.resultsInts.get(position);
}
public View getView(int position, View view, ViewGroup parent) {
@ -95,23 +84,43 @@ public class CategorySelect extends ListActivity implements OnQueryResultListene
if(view==null){
view = inflator.inflate(R.layout.category_select_item, null);
holder = new CategoryViewHolder();
holder.title = (CheckBox) view.findViewById(R.id.text);
holder.title = (CheckedTextView) view.findViewById(R.id.text);
view.setTag(holder);
}else{
holder = (CategoryViewHolder)view.getTag();
}
//
if(position==0){
holder.title.setText("- All -");
}else{
holder.title.setText(this.query.resultsStrings.get(position-1));
}
holder.title.setText(this.query.resultsStrings.get(position));
return view;
}
}
private OnClickListener onSaveClick = new OnClickListener() {
public void onClick(View v){
final Intent intent = new Intent(CategorySelect.this, PlayerBPMControl.class);
// Get selection
final SparseBooleanArray selectionList = CategorySelect.this.getListView().getCheckedItemPositions();
final ArrayList<Integer> selections = new ArrayList<Integer>();
ArrayList<Integer> list = CategorySelect.this.query.resultsInts;
int listSize = list.size();
for(int i=0;i<listSize;i++){
if(selectionList.get(i)){
selections.add(list.get(i));
}
}
Workout.GetInstance().SetCategory(selections, CategorySelect.this.category);
Log.v("mC2::SAVE",CategorySelect.this.category);
Log.v("mC2::SAVE",selections.toString());
intent.putExtra("org.musikcube.PlayerBPMControl.category", CategorySelect.this.category);
intent.putExtra("org.musikcube.PlayerBPMControl.selection", selections);
startActivity(intent);
}
};
private ResultAdapter listAdapter;
@Override
@ -120,6 +129,15 @@ public class CategorySelect extends ListActivity implements OnQueryResultListene
//Log.v("musikcube.CategoryList", "start");
this.setContentView(R.layout.category_select);
final ListView list = this.getListView();
list.setItemsCanFocus(false);
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
View footer = this.getLayoutInflater().inflate(R.layout.category_select_footer, null);
list.addFooterView(footer);
Button saveButton = (Button)findViewById(R.id.SaveButton);
saveButton.setOnClickListener(this.onSaveClick);
Intent intent = this.getIntent();
this.query.SetResultListener(this);
@ -169,8 +187,6 @@ public class CategorySelect extends ListActivity implements OnQueryResultListene
}
//Log.v("musikcube.CategoryList", "onCreate end");
}
public void OnResults(){
@ -187,6 +203,7 @@ public class CategorySelect extends ListActivity implements OnQueryResultListene
this.callbackHandler.post(this.callbackRunnable);
}
/*
@SuppressWarnings("unchecked")
@Override
protected void onListItemClick(ListView l, View v, int position, long id){
@ -221,7 +238,7 @@ public class CategorySelect extends ListActivity implements OnQueryResultListene
intent.putExtra("org.musikcube.CategoryList.selectedCategoryId", selectedCategoryIds);
startActivity(intent);
}
}
}*/
@Override
protected void onPause() {

View File

@ -1,6 +1,6 @@
package org.musikcube;
import org.musikcube.core.Player;
import org.musikcube.core.Workout;
import android.app.Dialog;
import android.content.Context;
@ -20,7 +20,7 @@ public class Helper {
context.startActivity(new Intent(context, org.musikcube.main.class));
return true;
case R.id.context_controls:
if(Player.GetInstance().GetBPMMode()){
if(Workout.GetInstance().Active()){
context.startActivity(new Intent(context, org.musikcube.PlayerBPMControl.class));
}else{
context.startActivity(new Intent(context, org.musikcube.PlayerControl.class));

View File

@ -8,7 +8,6 @@ import org.musikcube.core.Player.OnTrackListUpdateListener;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
@ -40,8 +39,6 @@ public class NowPlayingList extends TrackListBase implements OnTrackListUpdateLi
this.setTitle("musikCube: Now playing");
org.musikcube.core.Library library = org.musikcube.core.Library.GetInstance();
this.registerForContextMenu(this.getListView());
}

View File

@ -6,7 +6,9 @@ import java.net.URL;
import org.musikcube.core.Library;
import org.musikcube.core.Player;
import org.musikcube.core.Track;
import org.musikcube.core.Workout;
import org.musikcube.core.Player.OnTrackUpdateListener;
import org.musikcube.core.Workout.OnWorkoutListener;
import android.app.Activity;
import android.content.Intent;
@ -15,18 +17,21 @@ import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CompoundButton;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.ToggleButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.SeekBar.OnSeekBarChangeListener;
public class PlayerBPMControl extends Activity implements OnTrackUpdateListener {
public class PlayerBPMControl extends Activity implements OnTrackUpdateListener, OnWorkoutListener {
private Track track = new Track();
private int duration = 0;
@ -36,7 +41,6 @@ public class PlayerBPMControl extends Activity implements OnTrackUpdateListener
@Override
public void onCreate(Bundle savedInstanceState) {
Log.v("MC2::PC","OnCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.play_bpm_control);
@ -44,12 +48,12 @@ public class PlayerBPMControl extends Activity implements OnTrackUpdateListener
nextButton.setOnClickListener(this.onNextClick);
ImageButton pauseButton = (ImageButton)findViewById(R.id.MediaPause);
pauseButton.setOnClickListener(this.onPauseClick);
ToggleButton acc = (ToggleButton)findViewById(R.id.ToggleAccelerator);
acc.setOnCheckedChangeListener(this.onAcceleratorToggle);
SeekBar bpmBar = (SeekBar)findViewById(R.id.BPM);
bpmBar.setOnSeekBarChangeListener(this.onBPMChanged);
this.callbackTrackPositionsUpdateHandler.postDelayed(callbackTrackPositionsUpdateRunnable,500);
Intent intent = new Intent(PlayerBPMControl.this, org.musikcube.Service.class);
intent.putExtra("org.musikcube.Service.action", "bpmstart");
startService(intent);
}
private OnClickListener onNextClick = new OnClickListener() {
@ -62,10 +66,44 @@ public class PlayerBPMControl extends Activity implements OnTrackUpdateListener
private OnClickListener onPauseClick = new OnClickListener() {
public void onClick(View v){
Intent intent = new Intent(PlayerBPMControl.this, org.musikcube.Service.class);
intent.putExtra("org.musikcube.Service.action", "stop");
if(Workout.GetInstance().Active()){
intent.putExtra("org.musikcube.Service.action", "workoutstop");
}else{
intent.putExtra("org.musikcube.Service.action", "workoutstart");
}
startService(intent);
// PlayerBPMControl.this.OnUpdateTrackUI();
}
};
private OnCheckedChangeListener onAcceleratorToggle = new OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
Workout.GetInstance().UseAccelerometer(isChecked);
}
};
private OnSeekBarChangeListener onBPMChanged = new OnSeekBarChangeListener(){
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
if(fromUser){
if(!Workout.GetInstance().Accelerometer()){
// Seek
float bpm = (float) ((float)progress*150.0/1000.0+50.0);
Workout.GetInstance().SetBPM(bpm);
TextView bpmTitle = (TextView)PlayerBPMControl.this.findViewById(R.id.BPMTitle);
bpmTitle.setText("BPM: "+bpm);
}
}
}
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onStopTrackingTouch(SeekBar seekBar) {
}
};
public void OnTrackBufferUpdate(int percent) {
this.callbackTrackPositionsUpdateHandler.post(this.callbackTrackPositionsUpdateRunnable);
@ -80,18 +118,24 @@ public class PlayerBPMControl extends Activity implements OnTrackUpdateListener
@Override
protected void onPause() {
this.enable = false;
Log.v("MC2::PC","OnPause");
org.musikcube.core.Library.GetInstance().RemovePointer();
Player.GetInstance().SetUpdateListener(null);
Workout.GetInstance().SetListener(null);
super.onPause();
}
@Override
protected void onResume() {
this.enable = true;
Log.v("MC2::PC","OnResume");
org.musikcube.core.Library.GetInstance().AddPointer();
Player.GetInstance().SetUpdateListener(this);
super.onResume();
this.OnUpdateTrackPositionsUI();
this.OnUpdateTrackUI();
Workout.GetInstance().SetListener(this);
ToggleButton acc = (ToggleButton)findViewById(R.id.ToggleAccelerator);
acc.setChecked(Workout.GetInstance().Accelerometer());
}
// Need handler for callbacks to the UI thread
@ -169,6 +213,15 @@ public class PlayerBPMControl extends Activity implements OnTrackUpdateListener
}
}
// Update play button
ImageButton playButton = (ImageButton)findViewById(R.id.MediaPause);
if(Workout.GetInstance().Active()){
playButton.setImageResource(R.drawable.ic_media_pause);
}else{
playButton.setImageResource(R.drawable.ic_media_play);
}
}
private class DownloadAlbumCoverTask extends AsyncTask<String,Integer,Bitmap>{
@ -184,7 +237,6 @@ public class PlayerBPMControl extends Activity implements OnTrackUpdateListener
Bitmap bm = BitmapFactory.decodeStream(is);
return bm;
} catch (Exception e) {
Log.v("mC2:PLAYER","Error "+e.getMessage());
// e.printStackTrace();
return null;
}
@ -231,6 +283,16 @@ public class PlayerBPMControl extends Activity implements OnTrackUpdateListener
}
}
// Update BPM
SeekBar bpmBar = (SeekBar)findViewById(R.id.BPM);
final int startBPM = 50;
final int endBPM = 200;
final float currentBPM = Workout.GetInstance().GetBPM();
bpmBar.setProgress( (int) (((float)currentBPM-startBPM)*1000/(endBPM-startBPM)) );
TextView bpmTitle = (TextView)findViewById(R.id.BPMTitle);
bpmTitle.setText("BPM: "+currentBPM);
// Next callback in 0.5 seconds
this.callbackTrackPositionsUpdateHandler.postDelayed(callbackTrackPositionsUpdateRunnable,500);
@ -249,5 +311,8 @@ public class PlayerBPMControl extends Activity implements OnTrackUpdateListener
return super.onContextItemSelected(item);
}
}
public void OnBPMUpdate() {
this.callbackTrackUpdateHandler.post(this.callbackTrackUpdateRunnable);
}
}

View File

@ -15,7 +15,6 @@ import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@ -33,10 +32,10 @@ public class PlayerControl extends Activity implements OnTrackUpdateListener {
private Object lock = new Object();
private boolean enable = false;
private int currentAlbumCoverId = 0;
private boolean playing = false;
@Override
public void onCreate(Bundle savedInstanceState) {
Log.v("MC2::PC","OnCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.play_control);
@ -74,7 +73,11 @@ public class PlayerControl extends Activity implements OnTrackUpdateListener {
private OnClickListener onPauseClick = new OnClickListener() {
public void onClick(View v){
Intent intent = new Intent(PlayerControl.this, org.musikcube.Service.class);
intent.putExtra("org.musikcube.Service.action", "stop");
if(Player.GetInstance().Playing()){
intent.putExtra("org.musikcube.Service.action", "stop");
}else{
intent.putExtra("org.musikcube.Service.action", "play");
}
startService(intent);
}
};
@ -124,14 +127,14 @@ public class PlayerControl extends Activity implements OnTrackUpdateListener {
@Override
protected void onPause() {
this.enable = false;
Log.v("MC2::PC","OnPause");
org.musikcube.core.Library.GetInstance().RemovePointer();
Player.GetInstance().SetUpdateListener(null);
super.onPause();
}
@Override
protected void onResume() {
this.enable = true;
Log.v("MC2::PC","OnResume");
org.musikcube.core.Library.GetInstance().AddPointer();
Player.GetInstance().SetUpdateListener(this);
super.onResume();
this.OnUpdateTrackPositionsUI();
@ -213,6 +216,14 @@ public class PlayerControl extends Activity implements OnTrackUpdateListener {
}
}
// Update play button
ImageButton playButton = (ImageButton)findViewById(R.id.MediaPause);
if(Player.GetInstance().Playing()){
playButton.setImageResource(R.drawable.ic_media_pause);
}else{
playButton.setImageResource(R.drawable.ic_media_play);
}
}
private class DownloadAlbumCoverTask extends AsyncTask<String,Integer,Bitmap>{
@ -228,8 +239,6 @@ public class PlayerControl extends Activity implements OnTrackUpdateListener {
Bitmap bm = BitmapFactory.decodeStream(is);
return bm;
} catch (Exception e) {
Log.v("mC2:PLAYER","Error "+e.getMessage());
// e.printStackTrace();
return null;
}
}

View File

@ -4,9 +4,9 @@
package org.musikcube;
import org.musikcube.core.Library;
import org.musikcube.core.PaceDetector;
import org.musikcube.core.Player;
import org.musikcube.core.Track;
import org.musikcube.core.Workout;
import android.app.Notification;
import android.app.NotificationManager;
@ -16,7 +16,6 @@ import android.content.Intent;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
/**
* @author doy
@ -27,7 +26,8 @@ public class Service extends android.app.Service {
Library library;
Player player;
boolean showingNotification = false;
PaceDetector paceDetector;
boolean bpmMode = false;
Workout workout;
/**
*
@ -47,7 +47,6 @@ public class Service extends android.app.Service {
@Override
public void onCreate(){
Log.i("musikcube::Service","CREATE");
this.player = Player.GetInstance();
this.player.service = this;
this.library = org.musikcube.core.Library.GetInstance();
@ -78,19 +77,22 @@ public class Service extends android.app.Service {
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
boolean stopWorkout = false;
String action = intent.getStringExtra("org.musikcube.Service.action");
if(action==null){
return;
}
if(action.equals("playlist")){
Player player = Player.GetInstance();
player.Play(intent.getIntegerArrayListExtra("org.musikcube.Service.tracklist"), intent.getIntExtra("org.musikcube.Service.position", 0));
stopWorkout = true;
}
if(action.equals("appendlist")){
Player player = Player.GetInstance();
player.Append(intent.getIntegerArrayListExtra("org.musikcube.Service.tracklist"));
stopWorkout = true;
}
if(action.equals("remove_from_list")){
Player player = Player.GetInstance();
@ -113,9 +115,7 @@ public class Service extends android.app.Service {
if(action.equals("stop")){
Player player = Player.GetInstance();
player.Stop();
if(this.paceDetector!=null){
this.paceDetector.StopSensor(this);
}
stopWorkout = true;
}
if(action.equals("play")){
Player player = Player.GetInstance();
@ -124,21 +124,30 @@ public class Service extends android.app.Service {
if(action.equals("shutdown")){
//Log.i("musikcube::Service","Shutdown");
this.stopSelf();
stopWorkout = true;
}
if(action.equals("bpmstart")){
Player.GetInstance().SetBPMMode(true);
if(this.paceDetector==null){
this.paceDetector = new PaceDetector();
this.paceDetector.StartSensor(this);
if(stopWorkout){
if(this.workout!=null){
this.workout.Stop();
this.workout = null;
}
}
if(action.equals("bpmstop")){
if(this.paceDetector!=null){
this.paceDetector.StopSensor(this);
if(action.equals("workoutstart")){
this.workout = Workout.GetInstance();
this.workout.Startup(this);
}
if(action.equals("workoutstop")){
if(this.workout!=null){
this.workout.Stop();
this.workout = null;
}
Player player = Player.GetInstance();
player.Stop();
}
if(action.equals("player_start")){
if(action.equals("player_start") || this.workout!=null){
Track track = Player.GetInstance().GetCurrentTrack();
this.showingNotification = true;
@ -165,7 +174,13 @@ public class Service extends android.app.Service {
contentText += trackArtist;
}
}
Intent notificationIntent = new Intent(this, Player.GetInstance().GetBPMMode()?PlayerBPMControl.class:PlayerControl.class);
Intent notificationIntent;
if(this.workout==null){
notificationIntent = new Intent(this, PlayerControl.class);
}else{
notificationIntent = new Intent(this, PlayerBPMControl.class);
}
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.flags |= Notification.FLAG_ONGOING_EVENT|Notification.FLAG_NO_CLEAR;
@ -174,7 +189,7 @@ public class Service extends android.app.Service {
mNotificationManager.notify(1, notification);
}
if(action.equals("player_end")){
if(action.equals("player_end") && this.workout==null){
this.showingNotification = false;
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);

View File

@ -2,31 +2,28 @@ package org.musikcube.core;
import java.util.Collections;
import org.musikcube.core.IQuery.OnQueryResultListener;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;
public class PaceDetector implements Runnable, SensorEventListener, OnQueryResultListener {
public class PaceDetector implements Runnable, SensorEventListener{
static public float MAX_BPM = 85;
static public float MIN_BPM = 40;
static public int WAVE_MEMORY = 20;
static public int WAVE_MIN_CALC = 10;
static public float WAVE_MIN_BPM_DIFF = 120; // This is in miliseconds
static public int WAVE_COMPARE = 4;
static public int MIN_PLAYTIME = 20000; // Play at leased 20 seconds of a track
static public float BPM_THRESHOLD = 10; // if BPM is off by more than 10 bpm, switch track
static final public float MAX_BPM = 100;
static final public float MIN_BPM = 40;
static final public int WAVE_MEMORY = 20;
static final public int WAVE_MIN_CALC = 10;
static final public float WAVE_MIN_BPM_DIFF = 100; // This is in miliseconds
static final public int WAVE_COMPARE = 4;
static final public int MIN_PLAYTIME = 20000; // Play at leased 20 seconds of a track
//static final public float BPM_THRESHOLD = 10; // if BPM is off by more than 10 bpm, switch track
private float currentBPM = 0;
private float currentAccuracy = 0;
private long currentBPMstart = 0;
private Object lock = new Object();
private Context context;
@ -43,7 +40,7 @@ public class PaceDetector implements Runnable, SensorEventListener, OnQueryResul
public float currentAccuracy = 0;
final public void NextValue(float value){
float diff = value-this.lastValue;
final float diff = value-this.lastValue;
if(value<this.currentMin){
this.currentMin = value;
@ -55,12 +52,10 @@ public class PaceDetector implements Runnable, SensorEventListener, OnQueryResul
if(this.lastDiff>=0 && diff<0){
// Amplitude must be at leased 5
if(this.currentMax-this.currentMin<7){
if(this.currentMax-this.currentMin<4){
this.currentMin = value;
this.currentMax = value;
// Log.v("APM","-- "+(this.currentMax-this.currentMin));
}else{
// Log.v("APM","B "+(this.currentMax-this.currentMin));
// this is a top on the curve
this.beatTimes.add(android.os.SystemClock.elapsedRealtime());
this.amplitude.add(this.currentMax-this.currentMin);
@ -143,6 +138,21 @@ public class PaceDetector implements Runnable, SensorEventListener, OnQueryResul
}
public interface OnBPMListener{
public void OnBPMUpdate();
}
protected OnBPMListener listener = null;
public void SetListener(OnBPMListener listener){
synchronized(this.lock){
this.listener = listener;
if(this.listener!=null){
this.listener.OnBPMUpdate();
}
}
}
private PaceDimension xAxis = new PaceDimension();
private PaceDimension yAxis = new PaceDimension();
private PaceDimension zAxis = new PaceDimension();
@ -159,38 +169,40 @@ public class PaceDetector implements Runnable, SensorEventListener, OnQueryResul
}
public void ChangeBPM(float bpm,float accuracy){
bpm *= 2; // BPM should be the double
while(bpm<85){
bpm *= 2;
}
while(bpm>200){
bpm *= 0.5;
}
if(accuracy>=this.xAxis.currentAccuracy && accuracy>=this.yAxis.currentAccuracy && accuracy>=this.zAxis.currentAccuracy && accuracy>150){
// The BPM has changed
long currentTime = android.os.SystemClock.elapsedRealtime();
if(currentTime>this.currentBPMstart+MIN_PLAYTIME){
// if(currentTime>this.currentBPMstart+MIN_PLAYTIME){
//Log.v("BPM","3 "+bpm);
// We have played more than minimum time
if(bpm>this.currentBPM+BPM_THRESHOLD || bpm<this.currentBPM-BPM_THRESHOLD){
Log.v("BPM","4 "+bpm);
// if(bpm>this.currentBPM+BPM_THRESHOLD || bpm<this.currentBPM-BPM_THRESHOLD){
// BPM has changed enough to switch track
this.currentBPMstart = currentTime;
this.currentBPM = bpm;
synchronized(lock){
this.currentBPM = bpm;
if(this.listener!=null){
this.listener.OnBPMUpdate();
}
}
this.currentAccuracy = accuracy;
BPMQuery query = new BPMQuery();
query.queryForBPM = this.currentBPM;
query.SetResultListener(this);
Library.GetInstance().AddQuery(query);
}
}
// }
// }
}
}
public void StartSensor(Context context){
this.context = context;
Log.v("mC2::ACC","Sensor");
SensorManager sensorMgr = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
Sensor accelerometer = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorMgr.registerListener(this,accelerometer,SensorManager.SENSOR_DELAY_GAME);
@ -204,19 +216,11 @@ public class PaceDetector implements Runnable, SensorEventListener, OnQueryResul
public void run() {
// TODO Auto-generated method stub
}
public void OnQueryResults(IQuery query) {
BPMQuery bpmQuery = (BPMQuery)query;
Log.v("mC2::PaceDetector","Change tracks "+bpmQuery.trackList.size());
if(!bpmQuery.trackList.isEmpty()){
Intent intent = new Intent(this.context, org.musikcube.Service.class);
intent.putExtra("org.musikcube.Service.tracklist", bpmQuery.trackList);
intent.putExtra("org.musikcube.Service.position", 0);
intent.putExtra("org.musikcube.Service.action", "playlist_prepare");
this.context.startService(intent);
public float GetBPM(){
synchronized(this.lock){
return currentBPM;
}
}

View File

@ -452,5 +452,11 @@ public final class Player implements TrackPlayer.OnTrackStatusListener, OnQueryR
}
}
public boolean Playing(){
synchronized(this.lock){
return (this.library!=null);
}
}
}

View File

@ -1,7 +1,7 @@
package org.musikcube.core;
import android.media.MediaPlayer;
import android.util.Log;
public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener,MediaPlayer.OnBufferingUpdateListener {
@ -33,7 +33,6 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener,
String url = Library.GetInstance().GetTrackURL(this.trackId);
synchronized(this.lock){
while(url==null && (this.status==STATUS_PREPARED || this.status==STATUS_PLAYING)){
Log.v("mC2::TrackPlayer","Retrying "+this.trackId);
this.lock.wait(250);
url = Library.GetInstance().GetTrackURL(this.trackId);
}
@ -64,6 +63,7 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener,
if(currentStatus==STATUS_PLAYING)
this.mediaPlayer.start();
synchronized(this.lock){
this.started = true;
@ -85,18 +85,21 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener,
}
this.started = false;
}
this.mediaPlayer.stop();
this.mediaPlayer.release();
synchronized(this.lock){
this.mediaPlayer = null;
}
} catch (Exception e) {
}
synchronized(this.lock){
this.status = STATUS_EXIT;
}
this.CallListener();

View File

@ -0,0 +1,188 @@
package org.musikcube.core;
import java.util.ArrayList;
import org.musikcube.core.IQuery.OnQueryResultListener;
import org.musikcube.core.PaceDetector.OnBPMListener;
import android.content.Context;
import android.content.Intent;
public class Workout implements OnBPMListener, Runnable, OnQueryResultListener {
private static org.musikcube.core.Workout workout = null;
private PaceDetector paceDetector;
private Context context;
private Object lock = new Object();
private float bpm = 100;
private Thread thread;
private boolean active = false;
private boolean useAccelerometer = false;
private long lastQueryTime = -30000;
private int minimumPlaytime = 30000;
static final public float BPM_THRESHOLD = 10; // if BPM is off by more than 10 bpm, switch track
private ArrayList<Integer> selectedCategories = new ArrayList<Integer>();
private String category = "";
public static final synchronized Workout GetInstance(){
if(Workout.workout==null){
Workout.workout = new org.musikcube.core.Workout();
}
return Workout.workout;
}
protected Workout(){
this.bpm = 100+(float)Math.random();
}
public void Startup(Context context){
synchronized (lock) {
this.context = context;
if(this.active==false){
org.musikcube.core.Library.GetInstance().AddPointer();
}
this.active = true;
if(this.listener!=null){
this.listener.OnBPMUpdate();
}
this.UseAccelerometer(this.useAccelerometer);
this.QueryTracks(true);
}
}
public void Stop(){
synchronized (lock) {
if(this.active==true){
org.musikcube.core.Library.GetInstance().RemovePointer();
}
this.active = false;
this.UseAccelerometer(this.useAccelerometer);
if(this.listener!=null){
this.listener.OnBPMUpdate();
}
}
}
public void SetCategory(ArrayList<Integer> selectedCategories,String category){
synchronized (lock) {
this.selectedCategories = selectedCategories;
this.category = category;
}
}
public boolean Active(){
synchronized (lock) {
return this.active;
}
}
public void UseAccelerometer(boolean use){
synchronized(lock){
this.useAccelerometer = use;
if(this.context!=null){
if(use && this.active){
if(this.paceDetector==null){
this.paceDetector = new PaceDetector();
this.paceDetector.SetListener(this);
this.paceDetector.StartSensor(this.context);
}
}
if(!use || !this.active){
if(this.paceDetector!=null){
this.paceDetector.StopSensor(this.context);
this.paceDetector = null;
}
}
}
}
}
public boolean Accelerometer(){
synchronized(lock){
return this.useAccelerometer;
}
}
public void SetBPM(float bpm){
synchronized(lock){
if(this.paceDetector==null){
this.bpm = bpm;
if(this.active){
this.QueryTracks(true);
}
}
}
}
public float GetBPM(){
synchronized(lock){
return this.bpm;
}
}
public void OnBPMUpdate() {
synchronized(lock){
final float bpm = this.paceDetector.GetBPM();
if(bpm>0.0){
if(bpm>this.bpm+BPM_THRESHOLD || bpm<this.bpm-BPM_THRESHOLD){
this.bpm = bpm;
if(this.listener!=null){
this.listener.OnBPMUpdate();
}
this.QueryTracks(false);
}
}
}
}
private void QueryTracks(boolean force){
long currentTime = android.os.SystemClock.elapsedRealtime();
// Check that minimum time has passed
synchronized(lock){
if(currentTime>this.lastQueryTime+this.minimumPlaytime || force){
this.lastQueryTime = currentTime;
// Get new tracks
BPMQuery query = new BPMQuery();
query.queryForBPM = this.bpm;
query.selectionInts = (ArrayList<Integer>) this.selectedCategories.clone();
query.selectionStrings.add(this.category);
query.SetResultListener(this);
Library.GetInstance().AddQuery(query);
}
}
}
public interface OnWorkoutListener{
public void OnBPMUpdate();
}
protected OnWorkoutListener listener = null;
public void SetListener(OnWorkoutListener listener){
synchronized(this.lock){
this.listener = listener;
if(this.listener!=null){
this.listener.OnBPMUpdate();
}
}
}
public void run() {
}
public void OnQueryResults(IQuery query) {
synchronized(this.lock){
this.lastQueryTime = android.os.SystemClock.elapsedRealtime();
BPMQuery bpmQuery = (BPMQuery)query;
if(!bpmQuery.trackList.isEmpty() && this.context!=null){
Intent intent = new Intent(this.context, org.musikcube.Service.class);
intent.putExtra("org.musikcube.Service.tracklist", bpmQuery.trackList);
intent.putExtra("org.musikcube.Service.position", 0);
intent.putExtra("org.musikcube.Service.action", "playlist_prepare");
this.context.startService(intent);
}
}
}
}

View File

@ -4,7 +4,6 @@ import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@ -38,9 +37,12 @@ public class main extends Activity implements OnLibraryStatusListener {
yearButton.setOnClickListener(this.onYearClick);
yearButton.setEnabled(false);
Button bpmButton = (Button)findViewById(R.id.BPMButton);
bpmButton.setOnClickListener(this.onBPMClick);
bpmButton.setEnabled(false);
Button bpmGenreButton = (Button)findViewById(R.id.BPMGenreButton);
bpmGenreButton.setOnClickListener(this.onBPMGenreClick);
bpmGenreButton.setEnabled(false);
Button bpmArtistButton = (Button)findViewById(R.id.BPMArtistButton);
bpmArtistButton.setOnClickListener(this.onBPMArtistClick);
bpmArtistButton.setEnabled(false);
}
@ -68,18 +70,22 @@ public class main extends Activity implements OnLibraryStatusListener {
}
};
private OnClickListener onBPMClick = new OnClickListener() {
private OnClickListener onBPMGenreClick = new OnClickListener() {
public void onClick(View v){
/* Log.v("mC2::main","onBPMClick 1");
Intent intent2 = new Intent(main.this, PlayerBPMControl.class);
startActivity(intent2);
Log.v("mC2::main","onBPMClick 2");*/
Intent intent = new Intent(main.this, CategorySelect.class);
intent.putExtra("org.musikcube.CategorySelect.listCategory", "genre");
startActivity(intent);
}
};
private OnClickListener onBPMArtistClick = new OnClickListener() {
public void onClick(View v){
Intent intent = new Intent(main.this, CategorySelect.class);
intent.putExtra("org.musikcube.CategorySelect.listCategory", "artist");
startActivity(intent);
}
};
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.default_menu, menu);
@ -104,7 +110,6 @@ public class main extends Activity implements OnLibraryStatusListener {
@Override
protected void onResume() {
Log.v("mC2::Main","onResume");
super.onResume();
startService(new Intent(this, org.musikcube.Service.class));
org.musikcube.core.Library.GetInstance().AddPointer();
@ -129,18 +134,21 @@ public class main extends Activity implements OnLibraryStatusListener {
Button genreButton = (Button)findViewById(R.id.GenresButton);
Button artistsButton = (Button)findViewById(R.id.ArtistsButton);
Button yearButton = (Button)findViewById(R.id.YearButton);
Button bpmButton = (Button)findViewById(R.id.BPMButton);
Button bpmGenreButton = (Button)findViewById(R.id.BPMGenreButton);
Button bpmArtistButton = (Button)findViewById(R.id.BPMArtistButton);
if(status==Library.STATUS_CONNECTED){
genreButton.setEnabled(true);
artistsButton.setEnabled(true);
yearButton.setEnabled(true);
bpmButton.setEnabled(false);
bpmGenreButton.setEnabled(true);
bpmArtistButton.setEnabled(true);
}else{
genreButton.setEnabled(false);
artistsButton.setEnabled(false);
yearButton.setEnabled(false);
bpmButton.setEnabled(false);
bpmGenreButton.setEnabled(false);
bpmArtistButton.setEnabled(false);
}
TextView statusText = (TextView)findViewById(R.id.StatusView);