Code reformat, fix view reuse, image quality

This commit is contained in:
Joshua Bahnsen 2013-12-03 23:36:02 -07:00
parent f841b26023
commit ecc078e30f
134 changed files with 18472 additions and 14424 deletions

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value>
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings>
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
</value>
</option>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default (1)" />
</component>
</project>

View File

@ -4,9 +4,6 @@
<option name="DEFAULT_COMPILER" value="Javac" />
<excludeFromCompile>
<directory url="file://$PROJECT_DIR$/gen" includeSubdirectories="true" />
<directory url="file://$PROJECT_DIR$/menudrawer/library/target/generated-sources/r" includeSubdirectories="true" />
<directory url="file://$PROJECT_DIR$/menudrawer/samples/target/generated-sources/r" includeSubdirectories="true" />
<directory url="file://$PROJECT_DIR$/menudrawer/samples/gen-external-apklibs/com.actionbarsherlock_actionbarsherlock_4.3.1/gen" includeSubdirectories="true" />
<directory url="file://$PROJECT_DIR$/menudrawer/library/gen" includeSubdirectories="true" />
<directory url="file://$PROJECT_DIR$/pulltorefresh/library/gen" includeSubdirectories="true" />
</excludeFromCompile>

View File

@ -0,0 +1,14 @@
<component name="ProjectDictionaryState">
<dictionary name="Josh">
<words>
<w>bitrate</w>
<w>deserialize</w>
<w>deserialized</w>
<w>gapless</w>
<w>looper</w>
<w>playlists</w>
<w>transcoded</w>
<w>vizualizer</w>
</words>
</dictionary>
</component>

View File

@ -0,0 +1,20 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0" is_locked="false">
<option name="myName" value="Project Default" />
<option name="myLocal" value="false" />
<inspection_tool class="ClassReferencesSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DeclareCollectionAsInterface" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreLocalVariables" value="false" />
<option name="ignorePrivateMethodsAndFields" value="false" />
</inspection_tool>
<inspection_tool class="OverlyStrongTypeCast" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreInMatchingInstanceof" value="false" />
</inspection_tool>
<inspection_tool class="TypeMayBeWeakened" enabled="true" level="WARNING" enabled_by_default="true">
<option name="useRighthandTypeAsWeakestTypeInAssignments" value="true" />
<option name="useParameterizedTypeForCollectionMethods" value="true" />
<option name="doNotWeakenToJavaLangObject" value="true" />
<option name="onlyWeakentoInterface" value="true" />
</inspection_tool>
</profile>
</component>

View File

@ -0,0 +1,7 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="PROJECT_PROFILE" />
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

View File

@ -2,20 +2,21 @@
<manifest xmlns:a="http://schemas.android.com/apk/res/android"
package="com.thejoshwa.ultrasonic.androidapp"
a:installLocation="auto"
a:versionCode="34"
a:versionName="1.2.0.7" >
a:versionCode="35"
a:versionName="1.2.0.8" >
<uses-permission a:name="android.permission.INTERNET" />
<uses-permission a:name="android.permission.READ_PHONE_STATE" />
<uses-permission a:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission a:name="android.permission.WAKE_LOCK" />
<uses-permission a:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission a:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission a:name="android.permission.RECORD_AUDIO" />
<uses-permission a:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-sdk
a:minSdkVersion="14"
a:targetSdkVersion="17" />
a:targetSdkVersion="19" />
<supports-screens
a:anyDensity="true"
@ -98,6 +99,7 @@
a:launchMode="singleTask" >
<intent-filter>
<action a:name="android.intent.action.SEARCH" />
<category a:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data

View File

@ -17,9 +17,9 @@
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
</content>
<orderEntry type="jdk" jdkName="Android 4.2.2" jdkType="Android SDK" />
<orderEntry type="jdk" jdkName="Android API 19 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="menudrawer" />
<orderEntry type="module" module-name="pulltorefresh" />

View File

@ -1,10 +1,11 @@
# This file is automatically generated by Android Tools.
## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must *NOT* be checked in Version Control Systems,
# This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
# location of the SDK. This is only used by Ant
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
sdk.dir=c:/progs/android-sdk-windows
#Sat Nov 30 23:46:41 MST 2013
sdk.dir=C\:/Program Files (x86)/Android/android-studio/sdk

View File

@ -8,6 +8,9 @@
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/menudrawer/library/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/menudrawer/library/res" />
<option name="LIBRARY_PROJECT" value="true" />
<proGuardCfgFiles>
<file>file://D:/Data/Android/adt-bundle-windows/sdk/tools/proguard/proguard-android.txt</file>
</proGuardCfgFiles>
</configuration>
</facet>
</component>
@ -15,7 +18,7 @@
<exclude-output />
<content url="file://$MODULE_DIR$/menudrawer">
<sourceFolder url="file://$MODULE_DIR$/menudrawer/library/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/menudrawer/library/gen" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/menudrawer/library/gen" isTestSource="false" generated="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

View File

@ -8,7 +8,7 @@
# project structure.
# Project target.
target=android-17
target=android-19
android.library=false
android.library.reference.1=menudrawer
android.library.reference.2=pulltorefresh

View File

@ -8,6 +8,9 @@
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/pulltorefresh/library/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/pulltorefresh/library/res" />
<option name="LIBRARY_PROJECT" value="true" />
<proGuardCfgFiles>
<file>file://D:/Data/Android/adt-bundle-windows/sdk/tools/proguard/proguard-android.txt</file>
</proGuardCfgFiles>
</configuration>
</facet>
</component>
@ -15,7 +18,7 @@
<exclude-output />
<content url="file://$MODULE_DIR$/pulltorefresh">
<sourceFolder url="file://$MODULE_DIR$/pulltorefresh/library/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/pulltorefresh/library/gen" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/pulltorefresh/library/gen" isTestSource="false" generated="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -5,8 +5,8 @@
<ImageView
a:id="@+id/select_album_art"
a:layout_width="120dip"
a:layout_height="120dip"
a:layout_width="160dip"
a:layout_height="160dip"
a:layout_alignParentLeft="true"
a:layout_alignParentTop="true"
a:layout_marginRight="10dip"

View File

@ -45,264 +45,325 @@ import com.thejoshwa.ultrasonic.androidapp.view.EntryAdapter;
import java.util.ArrayList;
import java.util.List;
public class BookmarkActivity extends SubsonicTabActivity {
public class BookmarkActivity extends SubsonicTabActivity
{
private PullToRefreshListView refreshAlbumListView;
private ListView albumListView;
private View albumButtons;
private View emptyView;
private ImageView playNowButton;
private ImageView pinButton;
private ImageView unpinButton;
private ImageView downloadButton;
private ImageView deleteButton;
private PullToRefreshListView refreshAlbumListView;
private ListView albumListView;
private View albumButtons;
private View emptyView;
private ImageView playNowButton;
private ImageView pinButton;
private ImageView unpinButton;
private ImageView downloadButton;
private ImageView deleteButton;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.select_album);
albumButtons = findViewById(R.id.menu_album);
refreshAlbumListView = (PullToRefreshListView) findViewById(R.id.select_album_entries);
albumListView = refreshAlbumListView.getRefreshableView();
refreshAlbumListView.setOnRefreshListener(new OnRefreshListener<ListView>() {
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) {
new GetDataTask().execute();
}
});
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.select_album);
albumListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
albumListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position >= 0) {
Entry entry = (Entry) parent.getItemAtPosition(position);
albumButtons = findViewById(R.id.menu_album);
if (entry != null) {
if (entry.isVideo()) {
playVideo(entry);
} else {
enableButtons();
}
}
}
}
});
refreshAlbumListView = (PullToRefreshListView) findViewById(R.id.select_album_entries);
albumListView = refreshAlbumListView.getRefreshableView();
ImageView selectButton = (ImageView) findViewById(R.id.select_album_select);
playNowButton = (ImageView) findViewById(R.id.select_album_play_now);
ImageView playNextButton = (ImageView) findViewById(R.id.select_album_play_next);
ImageView playLastButton = (ImageView) findViewById(R.id.select_album_play_last);
pinButton = (ImageView) findViewById(R.id.select_album_pin);
unpinButton = (ImageView) findViewById(R.id.select_album_unpin);
downloadButton = (ImageView) findViewById(R.id.select_album_download);
deleteButton = (ImageView) findViewById(R.id.select_album_delete);
ImageView oreButton = (ImageView) findViewById(R.id.select_album_more);
refreshAlbumListView.setOnRefreshListener(new OnRefreshListener<ListView>()
{
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView)
{
new GetDataTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
});
albumListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
albumListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
if (position >= 0)
{
Entry entry = (Entry) parent.getItemAtPosition(position);
if (entry != null)
{
if (entry.isVideo())
{
playVideo(entry);
}
else
{
enableButtons();
}
}
}
}
});
ImageView selectButton = (ImageView) findViewById(R.id.select_album_select);
playNowButton = (ImageView) findViewById(R.id.select_album_play_now);
ImageView playNextButton = (ImageView) findViewById(R.id.select_album_play_next);
ImageView playLastButton = (ImageView) findViewById(R.id.select_album_play_last);
pinButton = (ImageView) findViewById(R.id.select_album_pin);
unpinButton = (ImageView) findViewById(R.id.select_album_unpin);
downloadButton = (ImageView) findViewById(R.id.select_album_download);
deleteButton = (ImageView) findViewById(R.id.select_album_delete);
ImageView oreButton = (ImageView) findViewById(R.id.select_album_more);
emptyView = findViewById(R.id.select_album_empty);
selectButton.setVisibility(View.GONE);
playNextButton.setVisibility(View.GONE);
playLastButton.setVisibility(View.GONE);
oreButton.setVisibility(View.GONE);
playNowButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
playNow(getSelectedSongs(albumListView));
}
});
selectButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
selectAllOrNone();
}
});
pinButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
downloadBackground(true);
selectAll(false, false);
}
});
unpinButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
unpin();
selectAll(false, false);
}
});
downloadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
downloadBackground(false);
selectAll(false, false);
}
});
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
delete();
selectAll(false, false);
}
});
playNowButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
playNow(getSelectedSongs(albumListView));
}
});
registerForContextMenu(albumListView);
selectButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
selectAllOrNone();
}
});
pinButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
downloadBackground(true);
selectAll(false, false);
}
});
unpinButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
unpin();
selectAll(false, false);
}
});
downloadButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
downloadBackground(false);
selectAll(false, false);
}
});
deleteButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
delete();
selectAll(false, false);
}
});
enableButtons();
registerForContextMenu(albumListView);
View browseMenuItem = findViewById(R.id.menu_bookmarks);
menuDrawer.setActiveView(browseMenuItem);
getBookmarks();
}
private void getBookmarks() {
setActionBarSubtitle(R.string.button_bar_bookmarks);
enableButtons();
new LoadTask() {
@Override
protected MusicDirectory load(MusicService service) throws Exception {
return Util.getSongsFromBookmarks(service.getBookmarks(BookmarkActivity.this, this));
}
}.execute();
}
private void playNow(List<Entry> songs) {
if(getSelectedSongs(albumListView).size() > 0) {
View browseMenuItem = findViewById(R.id.menu_bookmarks);
menuDrawer.setActiveView(browseMenuItem);
getBookmarks();
}
private void getBookmarks()
{
setActionBarSubtitle(R.string.button_bar_bookmarks);
new LoadTask()
{
@Override
protected MusicDirectory load(MusicService service) throws Exception
{
return Util.getSongsFromBookmarks(service.getBookmarks(BookmarkActivity.this, this));
}
}.execute();
}
private void playNow(List<Entry> songs)
{
if (getSelectedSongs(albumListView).size() > 0)
{
int position = songs.get(0).getBookmarkPosition();
getDownloadService().restore(songs, 0, position, true, true);
selectAll(false, false);
}
}
private List<MusicDirectory.Entry> getSelectedSongs(ListView albumListView) {
private static List<MusicDirectory.Entry> getSelectedSongs(ListView albumListView)
{
List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(10);
if (albumListView != null) {
int count = albumListView.getCount();
for (int i = 0; i < count; i++) {
if (albumListView.isItemChecked(i)) {
songs.add((MusicDirectory.Entry) albumListView.getItemAtPosition(i));
}
}
}
return songs;
}
private void refresh() {
finish();
Intent intent = getIntent();
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
Util.startActivityWithoutTransition(this, intent);
}
if (albumListView != null)
{
int count = albumListView.getCount();
for (int i = 0; i < count; i++)
{
if (albumListView.isItemChecked(i))
{
songs.add((MusicDirectory.Entry) albumListView.getItemAtPosition(i));
}
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
return songs;
}
private void refresh()
{
finish();
Intent intent = getIntent();
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
Util.startActivityWithoutTransition(this, intent);
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case android.R.id.home:
menuDrawer.toggleMenu();
return true;
}
return false;
}
private void selectAllOrNone() {
boolean someUnselected = false;
int count = albumListView.getCount();
for (int i = 0; i < count; i++) {
if (!albumListView.isItemChecked(i) && albumListView.getItemAtPosition(i) instanceof MusicDirectory.Entry) {
someUnselected = true;
break;
}
}
selectAll(someUnselected, true);
}
private void selectAll(boolean selected, boolean toast) {
int count = albumListView.getCount();
int selectedCount = 0;
for (int i = 0; i < count; i++) {
MusicDirectory.Entry entry = (MusicDirectory.Entry) albumListView.getItemAtPosition(i);
if (entry != null && !entry.isDirectory() && !entry.isVideo()) {
albumListView.setItemChecked(i, selected);
selectedCount++;
}
}
// Display toast: N tracks selected / N tracks unselected
if (toast) {
int toastResId = selected ? R.string.select_album_n_selected : R.string.select_album_n_unselected;
Util.toast(this, getString(toastResId, selectedCount));
}
enableButtons();
}
private void enableButtons() {
if (getDownloadService() == null) {
return;
}
List<MusicDirectory.Entry> selection = getSelectedSongs(albumListView);
boolean enabled = !selection.isEmpty();
boolean unpinEnabled = false;
boolean deleteEnabled = false;
int pinnedCount = 0;
for (MusicDirectory.Entry song : selection) {
DownloadFile downloadFile = getDownloadService().forSong(song);
if (downloadFile.isWorkDone()) {
deleteEnabled = true;
}
if (downloadFile.isSaved()) {
pinnedCount++;
unpinEnabled = true;
}
}
playNowButton.setVisibility(enabled && deleteEnabled ? View.VISIBLE : View.GONE);
pinButton.setVisibility((enabled && !Util.isOffline(this) && selection.size() > pinnedCount) ? View.VISIBLE : View.GONE);
unpinButton.setVisibility(enabled && unpinEnabled ? View.VISIBLE : View.GONE);
downloadButton.setVisibility(enabled && !deleteEnabled && !Util.isOffline(this) ? View.VISIBLE : View.GONE);
deleteButton.setVisibility(enabled && deleteEnabled ? View.VISIBLE : View.GONE);
}
private void downloadBackground(final boolean save) {
List<MusicDirectory.Entry> songs = getSelectedSongs(albumListView);
if(songs.isEmpty()) {
selectAll(true, false);
songs = getSelectedSongs(albumListView);
return true;
}
downloadBackground(save, songs);
return false;
}
private void downloadBackground(final boolean save, final List<MusicDirectory.Entry> songs) {
if (getDownloadService() == null) {
private void selectAllOrNone()
{
boolean someUnselected = false;
int count = albumListView.getCount();
for (int i = 0; i < count; i++)
{
if (!albumListView.isItemChecked(i) && albumListView.getItemAtPosition(i) instanceof MusicDirectory.Entry)
{
someUnselected = true;
break;
}
}
selectAll(someUnselected, true);
}
private void selectAll(boolean selected, boolean toast)
{
int count = albumListView.getCount();
int selectedCount = 0;
for (int i = 0; i < count; i++)
{
MusicDirectory.Entry entry = (MusicDirectory.Entry) albumListView.getItemAtPosition(i);
if (entry != null && !entry.isDirectory() && !entry.isVideo())
{
albumListView.setItemChecked(i, selected);
selectedCount++;
}
}
// Display toast: N tracks selected / N tracks unselected
if (toast)
{
int toastResId = selected ? R.string.select_album_n_selected : R.string.select_album_n_unselected;
Util.toast(this, getString(toastResId, selectedCount));
}
enableButtons();
}
private void enableButtons()
{
if (getDownloadService() == null)
{
return;
}
Runnable onValid = new Runnable() {
List<MusicDirectory.Entry> selection = getSelectedSongs(albumListView);
boolean enabled = !selection.isEmpty();
boolean unpinEnabled = false;
boolean deleteEnabled = false;
int pinnedCount = 0;
for (MusicDirectory.Entry song : selection)
{
DownloadFile downloadFile = getDownloadService().forSong(song);
if (downloadFile.isWorkDone())
{
deleteEnabled = true;
}
if (downloadFile.isSaved())
{
pinnedCount++;
unpinEnabled = true;
}
}
playNowButton.setVisibility(enabled && deleteEnabled ? View.VISIBLE : View.GONE);
pinButton.setVisibility((enabled && !Util.isOffline(this) && selection.size() > pinnedCount) ? View.VISIBLE : View.GONE);
unpinButton.setVisibility(enabled && unpinEnabled ? View.VISIBLE : View.GONE);
downloadButton.setVisibility(enabled && !deleteEnabled && !Util.isOffline(this) ? View.VISIBLE : View.GONE);
deleteButton.setVisibility(enabled && deleteEnabled ? View.VISIBLE : View.GONE);
}
private void downloadBackground(final boolean save)
{
List<MusicDirectory.Entry> songs = getSelectedSongs(albumListView);
if (songs.isEmpty())
{
selectAll(true, false);
songs = getSelectedSongs(albumListView);
}
downloadBackground(save, songs);
}
private void downloadBackground(final boolean save, final List<MusicDirectory.Entry> songs)
{
if (getDownloadService() == null)
{
return;
}
Runnable onValid = new Runnable()
{
@Override
public void run() {
public void run()
{
warnIfNetworkOrStorageUnavailable();
getDownloadService().downloadBackground(songs, save);
if (save) {
if (save)
{
Util.toast(BookmarkActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_pinned, songs.size(), songs.size()));
} else {
}
else
{
Util.toast(BookmarkActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_downloaded, songs.size(), songs.size()));
}
}
@ -310,94 +371,114 @@ public class BookmarkActivity extends SubsonicTabActivity {
checkLicenseAndTrialPeriod(onValid);
}
private void delete() {
private void delete()
{
List<MusicDirectory.Entry> songs = getSelectedSongs(albumListView);
if(songs.isEmpty()) {
if (songs.isEmpty())
{
selectAll(true, false);
songs = getSelectedSongs(albumListView);
}
if (getDownloadService() != null) {
getDownloadService().delete(songs);
}
}
private void unpin() {
if (getDownloadService() != null) {
List<MusicDirectory.Entry> songs = getSelectedSongs(albumListView);
Util.toast(BookmarkActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_unpinned, songs.size(), songs.size()));
getDownloadService().unpin(songs);
}
}
if (getDownloadService() != null)
{
getDownloadService().delete(songs);
}
}
private abstract class LoadTask extends TabActivityBackgroundTask<Pair<MusicDirectory, Boolean>> {
private void unpin()
{
if (getDownloadService() != null)
{
List<MusicDirectory.Entry> songs = getSelectedSongs(albumListView);
Util.toast(BookmarkActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_unpinned, songs.size(), songs.size()));
getDownloadService().unpin(songs);
}
}
public LoadTask() {
super(BookmarkActivity.this, true);
}
private abstract class LoadTask extends TabActivityBackgroundTask<Pair<MusicDirectory, Boolean>>
{
protected abstract MusicDirectory load(MusicService service) throws Exception;
public LoadTask()
{
super(BookmarkActivity.this, true);
}
@Override
protected Pair<MusicDirectory, Boolean> doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(BookmarkActivity.this);
MusicDirectory dir = load(musicService);
boolean valid = musicService.isLicenseValid(BookmarkActivity.this, this);
return new Pair<MusicDirectory, Boolean>(dir, valid);
}
@Override
protected void done(Pair<MusicDirectory, Boolean> result) {
MusicDirectory musicDirectory = result.getFirst();
List<MusicDirectory.Entry> entries = musicDirectory.getChildren();
int songCount = 0;
for (MusicDirectory.Entry entry : entries) {
if (!entry.isDirectory()) {
songCount++;
}
}
final int listSize = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0);
if (songCount > 0) {
pinButton.setVisibility(View.VISIBLE);
unpinButton.setVisibility(View.VISIBLE);
downloadButton.setVisibility(View.VISIBLE);
deleteButton.setVisibility(View.VISIBLE);
playNowButton.setVisibility(View.VISIBLE);
} else {
pinButton.setVisibility(View.GONE);
unpinButton.setVisibility(View.GONE);
downloadButton.setVisibility(View.GONE);
deleteButton.setVisibility(View.GONE);
playNowButton.setVisibility(View.GONE);
if (listSize == 0 || result.getFirst().getChildren().size() < listSize) {
albumButtons.setVisibility(View.GONE);
}
}
enableButtons();
emptyView.setVisibility(entries.isEmpty() ? View.VISIBLE : View.GONE);
albumListView.setAdapter(new EntryAdapter(BookmarkActivity.this, getImageLoader(), entries, true));
licenseValid = result.getSecond();
}
}
private class GetDataTask extends AsyncTask<Void, Void, String[]> {
@Override
protected void onPostExecute(String[] result) {
refreshAlbumListView.onRefreshComplete();
super.onPostExecute(result);
}
protected abstract MusicDirectory load(MusicService service) throws Exception;
@Override
protected String[] doInBackground(Void... params) {
protected Pair<MusicDirectory, Boolean> doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(BookmarkActivity.this);
MusicDirectory dir = load(musicService);
boolean valid = musicService.isLicenseValid(BookmarkActivity.this, this);
return new Pair<MusicDirectory, Boolean>(dir, valid);
}
@Override
protected void done(Pair<MusicDirectory, Boolean> result)
{
MusicDirectory musicDirectory = result.getFirst();
List<MusicDirectory.Entry> entries = musicDirectory.getChildren();
int songCount = 0;
for (MusicDirectory.Entry entry : entries)
{
if (!entry.isDirectory())
{
songCount++;
}
}
final int listSize = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0);
if (songCount > 0)
{
pinButton.setVisibility(View.VISIBLE);
unpinButton.setVisibility(View.VISIBLE);
downloadButton.setVisibility(View.VISIBLE);
deleteButton.setVisibility(View.VISIBLE);
playNowButton.setVisibility(View.VISIBLE);
}
else
{
pinButton.setVisibility(View.GONE);
unpinButton.setVisibility(View.GONE);
downloadButton.setVisibility(View.GONE);
deleteButton.setVisibility(View.GONE);
playNowButton.setVisibility(View.GONE);
if (listSize == 0 || result.getFirst().getChildren().size() < listSize)
{
albumButtons.setVisibility(View.GONE);
}
}
enableButtons();
emptyView.setVisibility(entries.isEmpty() ? View.VISIBLE : View.GONE);
albumListView.setAdapter(new EntryAdapter(BookmarkActivity.this, getImageLoader(), entries, true));
licenseValid = result.getSecond();
}
}
private class GetDataTask extends AsyncTask<Void, Void, String[]>
{
@Override
protected void onPostExecute(String[] result)
{
refreshAlbumListView.onRefreshComplete();
super.onPostExecute(result);
}
@Override
protected String[] doInBackground(Void... params)
{
refresh();
return null;
}
}
}
}

View File

@ -1,11 +1,5 @@
package com.thejoshwa.ultrasonic.androidapp.activity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
@ -15,13 +9,14 @@ import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
import com.handmark.pulltorefresh.library.PullToRefreshListView;
import com.handmark.pulltorefresh.library.PullToRefreshBase.OnRefreshListener;
import com.handmark.pulltorefresh.library.PullToRefreshListView;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.ChatMessage;
import com.thejoshwa.ultrasonic.androidapp.service.MusicService;
@ -31,133 +26,164 @@ import com.thejoshwa.ultrasonic.androidapp.util.TabActivityBackgroundTask;
import com.thejoshwa.ultrasonic.androidapp.util.Util;
import com.thejoshwa.ultrasonic.androidapp.view.ChatAdapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
/**
* @author Joshua Bahnsen
*/
public final class ChatActivity extends SubsonicTabActivity {
private PullToRefreshListView refreshChatListView;
private ListView chatListView;
private EditText messageEditText;
private ImageButton sendButton;
private Timer timer = null;
private volatile static Long lastChatMessageTime = (long) 0;
private volatile static ArrayList<ChatMessage> messageList = new ArrayList<ChatMessage>();
public final class ChatActivity extends SubsonicTabActivity
{
private PullToRefreshListView refreshChatListView;
private ListView chatListView;
private EditText messageEditText;
private ImageButton sendButton;
private Timer timer;
private volatile static Long lastChatMessageTime = (long) 0;
private volatile static ArrayList<ChatMessage> messageList = new ArrayList<ChatMessage>();
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.chat);
refreshChatListView = (PullToRefreshListView) findViewById(R.id.chat_entries);
refreshChatListView.setMode(Mode.PULL_FROM_END);
@Override
protected void onCreate(Bundle bundle)
{
super.onCreate(bundle);
setContentView(R.layout.chat);
messageEditText = (EditText) findViewById(R.id.chat_edittext);
sendButton = (ImageButton) findViewById(R.id.chat_send);
sendButton.setOnClickListener(new View.OnClickListener() {
refreshChatListView = (PullToRefreshListView) findViewById(R.id.chat_entries);
refreshChatListView.setMode(Mode.PULL_FROM_END);
messageEditText = (EditText) findViewById(R.id.chat_edittext);
sendButton = (ImageButton) findViewById(R.id.chat_send);
sendButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view) {
public void onClick(View view)
{
sendMessage();
}
});
chatListView = refreshChatListView.getRefreshableView();
chatListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
chatListView.setStackFromBottom(true);
String serverName = Util.getServerName(this, Util.getActiveServer(this));
String userName = Util.getUserName(this, Util.getActiveServer(this));
String title = String.format("%s [%s@%s]", getResources().getString(R.string.button_bar_chat), userName, serverName);
});
setActionBarSubtitle(title);
chatListView = refreshChatListView.getRefreshableView();
chatListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
chatListView.setStackFromBottom(true);
messageEditText.setImeActionLabel("Send", KeyEvent.KEYCODE_ENTER);
messageEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
String serverName = Util.getServerName(this, Util.getActiveServer(this));
String userName = Util.getUserName(this, Util.getActiveServer(this));
String title = String.format("%s [%s@%s]", getResources().getString(R.string.button_bar_chat), userName, serverName);
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
setActionBarSubtitle(title);
@Override
public void afterTextChanged(Editable editable) {
sendButton.setEnabled(!Util.isNullOrWhiteSpace(editable.toString()));
}
});
messageEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
messageEditText.setImeActionLabel("Send", KeyEvent.KEYCODE_ENTER);
messageEditText.addTextChangedListener(new TextWatcher()
{
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
}
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE || (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_DOWN)) {
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
}
@Override
public void afterTextChanged(Editable editable)
{
sendButton.setEnabled(!Util.isNullOrWhiteSpace(editable.toString()));
}
});
messageEditText.setOnEditorActionListener(new TextView.OnEditorActionListener()
{
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event)
{
if (actionId == EditorInfo.IME_ACTION_DONE || (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_DOWN))
{
sendMessage();
return true;
}
return false;
}
});
refreshChatListView.setOnRefreshListener(new OnRefreshListener<ListView>() {
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) {
new GetDataTask().execute();
}
});
View chatMenuItem = findViewById(R.id.menu_chat);
menuDrawer.setActiveView(chatMenuItem);
load();
}
});
refreshChatListView.setOnRefreshListener(new OnRefreshListener<ListView>()
{
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView)
{
new GetDataTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
});
View chatMenuItem = findViewById(R.id.menu_chat);
menuDrawer.setActiveView(chatMenuItem);
load();
}
@Override
protected void onPostCreate(Bundle bundle) {
protected void onPostCreate(Bundle bundle)
{
super.onPostCreate(bundle);
timerMethod();
}
@Override
protected void onResume() {
super.onResume();
if (!messageList.isEmpty()) {
ChatAdapter chatAdapter = new ChatAdapter(ChatActivity.this, messageList);
chatListView.setAdapter(chatAdapter);
}
if (timer == null) {
timerMethod();
}
}
@Override
protected void onPause() {
protected void onResume()
{
super.onResume();
if (!messageList.isEmpty())
{
ListAdapter chatAdapter = new ChatAdapter(ChatActivity.this, messageList);
chatListView.setAdapter(chatAdapter);
}
if (timer == null)
{
timerMethod();
}
}
@Override
protected void onPause()
{
super.onPause();
if (timer != null) {
if (timer != null)
{
timer.cancel();
timer = null;
}
}
private void timerMethod()
{
int refreshInterval = Util.getChatRefreshInterval(this);
if (refreshInterval > 0) {
if (refreshInterval > 0)
{
timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
ChatActivity.this.runOnUiThread(new Runnable() {
timer.schedule(new TimerTask()
{
@Override
public void run()
{
ChatActivity.this.runOnUiThread(new Runnable()
{
@Override
public void run() {
public void run()
{
load();
}
});
@ -166,81 +192,98 @@ public final class ChatActivity extends SubsonicTabActivity {
}
}
private void sendMessage() {
if (messageEditText != null) {
final String message;
Editable text = messageEditText.getText();
private void sendMessage()
{
if (messageEditText != null)
{
final String message;
Editable text = messageEditText.getText();
if (text == null) {
return;
}
if (text == null)
{
return;
}
message = text.toString();
message = text.toString();
if (!Util.isNullOrWhiteSpace(message)) {
messageEditText.setText("");
if (!Util.isNullOrWhiteSpace(message))
{
messageEditText.setText("");
BackgroundTask<Void> task = new TabActivityBackgroundTask<Void>(ChatActivity.this, false) {
@Override
protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(ChatActivity.this);
musicService.addChatMessage(message, ChatActivity.this, this);
return null;
}
BackgroundTask<Void> task = new TabActivityBackgroundTask<Void>(ChatActivity.this, false)
{
@Override
protected Void doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(ChatActivity.this);
musicService.addChatMessage(message, ChatActivity.this, this);
return null;
}
@Override
protected void done(Void result) {
load();
}
};
@Override
protected void done(Void result)
{
load();
}
};
task.execute();
}
}
}
private synchronized void load() {
BackgroundTask<List<ChatMessage>> task = new TabActivityBackgroundTask<List<ChatMessage>>(this, false) {
@Override
protected List<ChatMessage> doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(ChatActivity.this);
return musicService.getChatMessages(lastChatMessageTime, ChatActivity.this, this);
}
task.execute();
}
}
}
@Override
protected void done(List<ChatMessage> result) {
if (result != null && !result.isEmpty()) {
// Reset lastChatMessageTime if we have a newer message
for (ChatMessage message : result) {
if (message.getTime() > lastChatMessageTime) {
lastChatMessageTime = message.getTime();
}
}
// Reverse results to show them on the bottom
Collections.reverse(result);
messageList.addAll(result);
ChatAdapter chatAdapter = new ChatAdapter(ChatActivity.this, messageList);
chatListView.setAdapter(chatAdapter);
}
}
};
task.execute();
}
private class GetDataTask extends AsyncTask<Void, Void, String[]> {
@Override
protected void onPostExecute(String[] result) {
load();
refreshChatListView.onRefreshComplete();
super.onPostExecute(result);
}
private synchronized void load()
{
BackgroundTask<List<ChatMessage>> task = new TabActivityBackgroundTask<List<ChatMessage>>(this, false)
{
@Override
protected List<ChatMessage> doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(ChatActivity.this);
return musicService.getChatMessages(lastChatMessageTime, ChatActivity.this, this);
}
@Override
protected void done(List<ChatMessage> result)
{
if (result != null && !result.isEmpty())
{
// Reset lastChatMessageTime if we have a newer message
for (ChatMessage message : result)
{
if (message.getTime() > lastChatMessageTime)
{
lastChatMessageTime = message.getTime();
}
}
// Reverse results to show them on the bottom
Collections.reverse(result);
messageList.addAll(result);
ListAdapter chatAdapter = new ChatAdapter(ChatActivity.this, messageList);
chatListView.setAdapter(chatAdapter);
}
}
};
task.execute();
}
private class GetDataTask extends AsyncTask<Void, Void, String[]>
{
@Override
protected void onPostExecute(String[] result)
{
load();
refreshChatListView.onRefreshComplete();
super.onPostExecute(result);
}
@Override
protected String[] doInBackground(Void... params) {
protected String[] doInBackground(Void... params)
{
return null;
}
}
}
}

View File

@ -33,6 +33,7 @@ import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.audiofx.EqualizerController;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadServiceImpl;
@ -43,150 +44,179 @@ import com.thejoshwa.ultrasonic.androidapp.service.DownloadServiceImpl;
* @author Sindre Mehus
* @version $Id$
*/
public class EqualizerActivity extends Activity {
public class EqualizerActivity extends Activity
{
private static final int MENU_GROUP_PRESET = 100;
private static final int MENU_GROUP_PRESET = 100;
private final Map<Short, SeekBar> bars = new HashMap<Short, SeekBar>();
private EqualizerController equalizerController;
private Equalizer equalizer;
private final Map<Short, SeekBar> bars = new HashMap<Short, SeekBar>();
private EqualizerController equalizerController;
private Equalizer equalizer;
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.equalizer);
equalizerController = DownloadServiceImpl.getInstance().getEqualizerController();
equalizer = equalizerController.getEqualizer();
@Override
public void onCreate(Bundle bundle)
{
super.onCreate(bundle);
setContentView(R.layout.equalizer);
equalizerController = DownloadServiceImpl.getInstance().getEqualizerController();
equalizer = equalizerController.getEqualizer();
initEqualizer();
initEqualizer();
final View presetButton = findViewById(R.id.equalizer_preset);
registerForContextMenu(presetButton);
presetButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
presetButton.showContextMenu();
}
});
final View presetButton = findViewById(R.id.equalizer_preset);
registerForContextMenu(presetButton);
presetButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
presetButton.showContextMenu();
}
});
CheckBox enabledCheckBox = (CheckBox) findViewById(R.id.equalizer_enabled);
enabledCheckBox.setChecked(equalizer.getEnabled());
enabledCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
setEqualizerEnabled(b);
}
});
}
CheckBox enabledCheckBox = (CheckBox) findViewById(R.id.equalizer_enabled);
enabledCheckBox.setChecked(equalizer.getEnabled());
enabledCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b)
{
setEqualizerEnabled(b);
}
});
}
@Override
protected void onPause() {
super.onPause();
equalizerController.saveSettings();
}
@Override
protected void onPause()
{
super.onPause();
equalizerController.saveSettings();
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, view, menuInfo);
short currentPreset;
try {
currentPreset = equalizer.getCurrentPreset();
} catch (Exception x) {
currentPreset = -1;
}
short currentPreset;
try
{
currentPreset = equalizer.getCurrentPreset();
}
catch (Exception x)
{
currentPreset = -1;
}
for (short preset = 0; preset < equalizer.getNumberOfPresets(); preset++) {
MenuItem menuItem = menu.add(MENU_GROUP_PRESET, preset, preset, equalizer.getPresetName(preset));
if (preset == currentPreset) {
menuItem.setChecked(true);
}
}
menu.setGroupCheckable(MENU_GROUP_PRESET, true, true);
}
for (short preset = 0; preset < equalizer.getNumberOfPresets(); preset++)
{
MenuItem menuItem = menu.add(MENU_GROUP_PRESET, preset, preset, equalizer.getPresetName(preset));
if (preset == currentPreset)
{
menuItem.setChecked(true);
}
}
menu.setGroupCheckable(MENU_GROUP_PRESET, true, true);
}
@Override
public boolean onContextItemSelected(MenuItem menuItem) {
short preset = (short) menuItem.getItemId();
equalizer.usePreset(preset);
updateBars();
return true;
}
@Override
public boolean onContextItemSelected(MenuItem menuItem)
{
short preset = (short) menuItem.getItemId();
equalizer.usePreset(preset);
updateBars();
return true;
}
private void setEqualizerEnabled(boolean enabled) {
equalizer.setEnabled(enabled);
updateBars();
}
private void setEqualizerEnabled(boolean enabled)
{
equalizer.setEnabled(enabled);
updateBars();
}
private void updateBars() {
private void updateBars()
{
for (Map.Entry<Short, SeekBar> entry : bars.entrySet()) {
short band = entry.getKey();
SeekBar bar = entry.getValue();
bar.setEnabled(equalizer.getEnabled());
short minEQLevel = equalizer.getBandLevelRange()[0];
bar.setProgress(equalizer.getBandLevel(band) - minEQLevel);
}
}
for (Map.Entry<Short, SeekBar> entry : bars.entrySet())
{
short band = entry.getKey();
SeekBar bar = entry.getValue();
bar.setEnabled(equalizer.getEnabled());
short minEQLevel = equalizer.getBandLevelRange()[0];
bar.setProgress(equalizer.getBandLevel(band) - minEQLevel);
}
}
private void initEqualizer() {
LinearLayout layout = (LinearLayout) findViewById(R.id.equalizer_layout);
private void initEqualizer()
{
LinearLayout layout = (LinearLayout) findViewById(R.id.equalizer_layout);
try {
short[] bandLevelRange = equalizer.getBandLevelRange();
short numberOfBands = equalizer.getNumberOfBands();
final short minEQLevel = bandLevelRange[0];
final short maxEQLevel = bandLevelRange[1];
try
{
short[] bandLevelRange = equalizer.getBandLevelRange();
short numberOfBands = equalizer.getNumberOfBands();
for (short i = 0; i < numberOfBands; i++) {
final short band = i;
final short minEQLevel = bandLevelRange[0];
final short maxEQLevel = bandLevelRange[1];
View bandBar = LayoutInflater.from(this).inflate(R.layout.equalizer_bar, null);
TextView freqTextView;
for (short i = 0; i < numberOfBands; i++)
{
final short band = i;
if (bandBar != null) {
freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency);
final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level);
SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar);
View bandBar = LayoutInflater.from(this).inflate(R.layout.equalizer_bar, null);
TextView freqTextView;
freqTextView.setText((equalizer.getCenterFreq(band) / 1000) + " Hz");
if (bandBar != null)
{
freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency);
final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level);
SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar);
bars.put(band, bar);
bar.setMax(maxEQLevel - minEQLevel);
short level = equalizer.getBandLevel(band);
bar.setProgress(level - minEQLevel);
bar.setEnabled(equalizer.getEnabled());
updateLevelText(levelTextView, level);
freqTextView.setText((equalizer.getCenterFreq(band) / 1000) + " Hz");
bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
short level = (short) (progress + minEQLevel);
if (fromUser) {
equalizer.setBandLevel(band, level);
}
updateLevelText(levelTextView, level);
}
bars.put(band, bar);
bar.setMax(maxEQLevel - minEQLevel);
short level = equalizer.getBandLevel(band);
bar.setProgress(level - minEQLevel);
bar.setEnabled(equalizer.getEnabled());
updateLevelText(levelTextView, level);
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
short level = (short) (progress + minEQLevel);
if (fromUser)
{
equalizer.setBandLevel(band, level);
}
updateLevelText(levelTextView, level);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
layout.addView(bandBar);
}
}
} catch (Exception e) {
//TODO: Show a dialog
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar)
{
}
private void updateLevelText(TextView levelTextView, short level) {
levelTextView.setText((level > 0 ? "+" : "") + level / 100 + " dB");
}
@Override
public void onStopTrackingTouch(SeekBar seekBar)
{
}
});
layout.addView(bandBar);
}
}
}
catch (Exception e)
{
//TODO: Show a dialog
}
}
private static void updateLevelText(TextView levelTextView, short level)
{
levelTextView.setText((level > 0 ? "+" : "") + level / 100 + " dB");
}
}

View File

@ -45,251 +45,286 @@ import net.simonvt.menudrawer.Position;
*
* @author Sindre Mehus
*/
public final class HelpActivity extends Activity implements OnClickListener {
private WebView webView;
private ImageView backButton;
private ImageView forwardButton;
private static final String STATE_MENUDRAWER = "com.thejoshwa.ultrasonic.androidapp.menuDrawer";
private static final String STATE_ACTIVE_VIEW_ID = "com.thejoshwa.ultrasonic.androidapp.activeViewId";
private static final String STATE_ACTIVE_POSITION = "com.thejoshwa.ultrasonic.androidapp.activePosition";
public MenuDrawer menuDrawer;
private int activePosition = 1;
private int menuActiveViewId;
View chatMenuItem = null;
View bookmarksMenuItem = null;
public final class HelpActivity extends Activity implements OnClickListener
{
private WebView webView;
private ImageView backButton;
private ImageView forwardButton;
@Override
protected void onCreate(Bundle bundle) {
applyTheme();
super.onCreate(bundle);
getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
private static final String STATE_MENUDRAWER = "com.thejoshwa.ultrasonic.androidapp.menuDrawer";
private static final String STATE_ACTIVE_VIEW_ID = "com.thejoshwa.ultrasonic.androidapp.activeViewId";
private static final String STATE_ACTIVE_POSITION = "com.thejoshwa.ultrasonic.androidapp.activePosition";
setContentView(R.layout.help);
if (bundle != null) {
activePosition = bundle.getInt(STATE_ACTIVE_POSITION);
menuActiveViewId = bundle.getInt(STATE_ACTIVE_VIEW_ID);
}
menuDrawer = MenuDrawer.attach(this, MenuDrawer.Type.BEHIND, Position.LEFT, MenuDrawer.MENU_DRAG_WINDOW);
menuDrawer.setMenuView(R.layout.menu_main);
chatMenuItem = findViewById(R.id.menu_chat);
bookmarksMenuItem = findViewById(R.id.menu_bookmarks);
findViewById(R.id.menu_home).setOnClickListener(this);
findViewById(R.id.menu_browse).setOnClickListener(this);
findViewById(R.id.menu_search).setOnClickListener(this);
findViewById(R.id.menu_playlists).setOnClickListener(this);
chatMenuItem.setOnClickListener(this);
bookmarksMenuItem.setOnClickListener(this);
findViewById(R.id.menu_now_playing).setOnClickListener(this);
findViewById(R.id.menu_settings).setOnClickListener(this);
findViewById(R.id.menu_about).setOnClickListener(this);
findViewById(R.id.menu_exit).setOnClickListener(this);
public MenuDrawer menuDrawer;
private int activePosition = 1;
private int menuActiveViewId;
View chatMenuItem;
View bookmarksMenuItem;
ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
View aboutMenuItem = findViewById(R.id.menu_about);
menuDrawer.setActiveView(aboutMenuItem);
webView = (WebView) findViewById(R.id.help_contents);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new HelpClient());
if (bundle != null) {
webView.restoreState(bundle);
} else {
webView.loadUrl(getResources().getString(R.string.help_url));
}
backButton = (ImageView) findViewById(R.id.help_back);
backButton.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View view) {
webView.goBack();
}
});
ImageView stopButton = (ImageView) findViewById(R.id.help_stop);
stopButton.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View view) {
webView.stopLoading();
setProgressBarIndeterminateVisibility(false);
}
});
forwardButton = (ImageView) findViewById(R.id.help_forward);
forwardButton.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View view) {
webView.goForward();
}
});
}
@Override
protected void onPostCreate(Bundle bundle) {
super.onPostCreate(bundle);
int visibility = Util.isOffline(this) ? View.GONE : View.VISIBLE;
chatMenuItem.setVisibility(visibility);
bookmarksMenuItem.setVisibility(visibility);
protected void onCreate(Bundle bundle)
{
applyTheme();
super.onCreate(bundle);
getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.help);
if (bundle != null)
{
activePosition = bundle.getInt(STATE_ACTIVE_POSITION);
menuActiveViewId = bundle.getInt(STATE_ACTIVE_VIEW_ID);
}
menuDrawer = MenuDrawer.attach(this, MenuDrawer.Type.BEHIND, Position.LEFT, MenuDrawer.MENU_DRAG_WINDOW);
menuDrawer.setMenuView(R.layout.menu_main);
chatMenuItem = findViewById(R.id.menu_chat);
bookmarksMenuItem = findViewById(R.id.menu_bookmarks);
View aboutMenuItem = findViewById(R.id.menu_about);
findViewById(R.id.menu_home).setOnClickListener(this);
findViewById(R.id.menu_browse).setOnClickListener(this);
findViewById(R.id.menu_search).setOnClickListener(this);
findViewById(R.id.menu_playlists).setOnClickListener(this);
chatMenuItem.setOnClickListener(this);
bookmarksMenuItem.setOnClickListener(this);
findViewById(R.id.menu_now_playing).setOnClickListener(this);
findViewById(R.id.menu_settings).setOnClickListener(this);
aboutMenuItem.setOnClickListener(this);
findViewById(R.id.menu_exit).setOnClickListener(this);
ActionBar actionBar = getActionBar();
if (actionBar != null)
{
actionBar.setDisplayHomeAsUpEnabled(true);
}
menuDrawer.setActiveView(aboutMenuItem);
webView = (WebView) findViewById(R.id.help_contents);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new HelpClient());
if (bundle != null)
{
webView.restoreState(bundle);
}
else
{
webView.loadUrl(getResources().getString(R.string.help_url));
}
backButton = (ImageView) findViewById(R.id.help_back);
backButton.setOnClickListener(new Button.OnClickListener()
{
@Override
public void onClick(View view)
{
webView.goBack();
}
});
ImageView stopButton = (ImageView) findViewById(R.id.help_stop);
stopButton.setOnClickListener(new Button.OnClickListener()
{
@Override
public void onClick(View view)
{
webView.stopLoading();
setProgressBarIndeterminateVisibility(false);
}
});
forwardButton = (ImageView) findViewById(R.id.help_forward);
forwardButton.setOnClickListener(new Button.OnClickListener()
{
@Override
public void onClick(View view)
{
webView.goForward();
}
});
}
@Override
public void onResume() {
super.onResume();
}
@Override
protected void onPostCreate(Bundle bundle)
{
super.onPostCreate(bundle);
@Override
protected void onSaveInstanceState(Bundle state) {
webView.saveState(state);
super.onSaveInstanceState(state);
state.putParcelable(STATE_MENUDRAWER, menuDrawer.saveState());
state.putInt(STATE_ACTIVE_VIEW_ID, menuActiveViewId);
state.putInt(STATE_ACTIVE_POSITION, activePosition);
}
int visibility = Util.isOffline(this) ? View.GONE : View.VISIBLE;
chatMenuItem.setVisibility(visibility);
bookmarksMenuItem.setVisibility(visibility);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (webView.canGoBack()) {
webView.goBack();
return true;
}
}
return super.onKeyDown(keyCode, event);
}
private void applyTheme() {
String theme = Util.getTheme(this);
if ("dark".equalsIgnoreCase(theme) || "fullscreen".equalsIgnoreCase(theme)) {
setTheme(R.style.UltraSonicTheme);
} else if ("light".equalsIgnoreCase(theme) || "fullscreenlight".equalsIgnoreCase(theme)) {
setTheme(R.style.UltraSonicTheme_Light);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
menuDrawer.toggleMenu();
return true;
}
@Override
public void onResume()
{
super.onResume();
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
menuDrawer.restoreState(state.getParcelable(STATE_MENUDRAWER));
}
@Override
protected void onSaveInstanceState(Bundle state)
{
webView.saveState(state);
super.onSaveInstanceState(state);
state.putParcelable(STATE_MENUDRAWER, menuDrawer.saveState());
state.putInt(STATE_ACTIVE_VIEW_ID, menuActiveViewId);
state.putInt(STATE_ACTIVE_POSITION, activePosition);
}
@Override
public void onBackPressed() {
final int drawerState = menuDrawer.getDrawerState();
if (drawerState == MenuDrawer.STATE_OPEN || drawerState == MenuDrawer.STATE_OPENING) {
menuDrawer.closeMenu(true);
return;
}
finish();
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
if (webView.canGoBack())
{
webView.goBack();
return true;
}
}
return super.onKeyDown(keyCode, event);
}
super.onBackPressed();
}
private void applyTheme()
{
String theme = Util.getTheme(this);
@Override
public void onClick(View v) {
menuActiveViewId = v.getId();
menuDrawer.setActiveView(v);
Intent intent;
switch (menuActiveViewId) {
case R.id.menu_home:
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(this, intent);
break;
case R.id.menu_browse:
intent = new Intent(this, SelectArtistActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(this, intent);
break;
case R.id.menu_search:
intent = new Intent(this, SearchActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, true);
Util.startActivityWithoutTransition(this, intent);
break;
case R.id.menu_playlists:
intent = new Intent(this, SelectPlaylistActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(this, intent);
break;
case R.id.menu_chat:
Util.startActivityWithoutTransition(this, ChatActivity.class);
break;
case R.id.menu_bookmarks:
Util.startActivityWithoutTransition(this, BookmarkActivity.class);
break;
case R.id.menu_now_playing:
Util.startActivityWithoutTransition(this, DownloadActivity.class);
break;
case R.id.menu_settings:
Util.startActivityWithoutTransition(this, SettingsActivity.class);
break;
case R.id.menu_about:
Util.startActivityWithoutTransition(this, HelpActivity.class);
break;
case R.id.menu_exit:
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
Util.startActivityWithoutTransition(this, intent);
break;
}
menuDrawer.closeMenu(true);
}
if ("dark".equalsIgnoreCase(theme) || "fullscreen".equalsIgnoreCase(theme))
{
setTheme(R.style.UltraSonicTheme);
}
else if ("light".equalsIgnoreCase(theme) || "fullscreenlight".equalsIgnoreCase(theme))
{
setTheme(R.style.UltraSonicTheme_Light);
}
}
private final class HelpClient extends WebViewClient {
@Override
public void onLoadResource(WebView webView, String url) {
setProgressBarIndeterminateVisibility(true);
super.onLoadResource(webView, url);
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case android.R.id.home:
menuDrawer.toggleMenu();
return true;
}
@Override
public void onPageFinished(WebView view, String url) {
setProgressBarIndeterminateVisibility(false);
String versionName = Util.getVersionName(HelpActivity.this);
String title = view.getTitle() + " (" + versionName + ")";
ActionBar actionBar = getActionBar();
return super.onOptionsItemSelected(item);
}
if (actionBar != null) {
actionBar.setSubtitle(title);
}
@Override
protected void onRestoreInstanceState(Bundle state)
{
super.onRestoreInstanceState(state);
menuDrawer.restoreState(state.getParcelable(STATE_MENUDRAWER));
}
backButton.setEnabled(view.canGoBack());
forwardButton.setEnabled(view.canGoForward());
}
@Override
public void onBackPressed()
{
final int drawerState = menuDrawer.getDrawerState();
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Util.toast(HelpActivity.this, description);
}
}
if (drawerState == MenuDrawer.STATE_OPEN || drawerState == MenuDrawer.STATE_OPENING)
{
menuDrawer.closeMenu(true);
return;
}
finish();
super.onBackPressed();
}
@Override
public void onClick(View v)
{
menuActiveViewId = v.getId();
menuDrawer.setActiveView(v);
Intent intent;
switch (menuActiveViewId)
{
case R.id.menu_home:
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(this, intent);
break;
case R.id.menu_browse:
intent = new Intent(this, SelectArtistActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(this, intent);
break;
case R.id.menu_search:
intent = new Intent(this, SearchActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, true);
Util.startActivityWithoutTransition(this, intent);
break;
case R.id.menu_playlists:
intent = new Intent(this, SelectPlaylistActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(this, intent);
break;
case R.id.menu_chat:
Util.startActivityWithoutTransition(this, ChatActivity.class);
break;
case R.id.menu_bookmarks:
Util.startActivityWithoutTransition(this, BookmarkActivity.class);
break;
case R.id.menu_now_playing:
Util.startActivityWithoutTransition(this, DownloadActivity.class);
break;
case R.id.menu_settings:
Util.startActivityWithoutTransition(this, SettingsActivity.class);
break;
case R.id.menu_about:
Util.startActivityWithoutTransition(this, HelpActivity.class);
break;
case R.id.menu_exit:
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
Util.startActivityWithoutTransition(this, intent);
break;
}
menuDrawer.closeMenu(true);
}
private final class HelpClient extends WebViewClient
{
@Override
public void onLoadResource(WebView webView, String url)
{
setProgressBarIndeterminateVisibility(true);
super.onLoadResource(webView, url);
}
@Override
public void onPageFinished(WebView view, String url)
{
setProgressBarIndeterminateVisibility(false);
String versionName = Util.getVersionName(HelpActivity.this);
String title = String.format("%s (%s)", view.getTitle(), versionName);
ActionBar actionBar = getActionBar();
if (actionBar != null)
{
actionBar.setSubtitle(title);
}
backButton.setEnabled(view.canGoBack());
forwardButton.setEnabled(view.canGoForward());
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl)
{
Util.toast(HelpActivity.this, description);
}
}
}

View File

@ -22,6 +22,7 @@ package com.thejoshwa.ultrasonic.androidapp.activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.Lyrics;
import com.thejoshwa.ultrasonic.androidapp.service.MusicService;
@ -35,45 +36,54 @@ import com.thejoshwa.ultrasonic.androidapp.util.TabActivityBackgroundTask;
*
* @author Sindre Mehus
*/
public final class LyricsActivity extends SubsonicTabActivity {
public final class LyricsActivity extends SubsonicTabActivity
{
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.lyrics);
@Override
protected void onCreate(Bundle bundle)
{
super.onCreate(bundle);
setContentView(R.layout.lyrics);
View nowPlayingMenuItem = findViewById(R.id.menu_now_playing);
menuDrawer.setActiveView(nowPlayingMenuItem);
load();
}
View nowPlayingMenuItem = findViewById(R.id.menu_now_playing);
menuDrawer.setActiveView(nowPlayingMenuItem);
private void load() {
BackgroundTask<Lyrics> task = new TabActivityBackgroundTask<Lyrics>(this, true) {
@Override
protected Lyrics doInBackground() throws Throwable {
String artist = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ARTIST);
String title = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_TITLE);
MusicService musicService = MusicServiceFactory.getMusicService(LyricsActivity.this);
return musicService.getLyrics(artist, title, LyricsActivity.this, this);
}
load();
}
@Override
protected void done(Lyrics result) {
TextView artistView = (TextView) findViewById(R.id.lyrics_artist);
TextView titleView = (TextView) findViewById(R.id.lyrics_title);
TextView textView = (TextView) findViewById(R.id.lyrics_text);
if (result != null && result.getArtist() != null) {
artistView.setText(result.getArtist());
titleView.setText(result.getTitle());
textView.setText(result.getText());
} else {
artistView.setText(R.string.lyrics_nomatch);
}
}
};
task.execute();
}
private void load()
{
BackgroundTask<Lyrics> task = new TabActivityBackgroundTask<Lyrics>(this, true)
{
@Override
protected Lyrics doInBackground() throws Throwable
{
String artist = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ARTIST);
String title = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_TITLE);
MusicService musicService = MusicServiceFactory.getMusicService(LyricsActivity.this);
return musicService.getLyrics(artist, title, LyricsActivity.this, this);
}
@Override
protected void done(Lyrics result)
{
TextView artistView = (TextView) findViewById(R.id.lyrics_artist);
TextView titleView = (TextView) findViewById(R.id.lyrics_title);
TextView textView = (TextView) findViewById(R.id.lyrics_text);
if (result != null && result.getArtist() != null)
{
artistView.setText(result.getArtist());
titleView.setText(result.getTitle());
textView.setText(result.getText());
}
else
{
artistView.setText(R.string.lyrics_nomatch);
}
}
};
task.execute();
}
}

View File

@ -23,10 +23,16 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.*;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadService;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadServiceImpl;
@ -35,406 +41,484 @@ import com.thejoshwa.ultrasonic.androidapp.util.FileUtil;
import com.thejoshwa.ultrasonic.androidapp.util.MergeAdapter;
import com.thejoshwa.ultrasonic.androidapp.util.Util;
import java.util.Arrays;
import java.util.Collections;
public class MainActivity extends SubsonicTabActivity {
import static java.util.Arrays.asList;
private static final int MENU_GROUP_SERVER = 10;
private static final int MENU_ITEM_OFFLINE = 111;
private static final int MENU_ITEM_SERVER_1 = 101;
private static final int MENU_ITEM_SERVER_2 = 102;
private static final int MENU_ITEM_SERVER_3 = 103;
private static final int MENU_ITEM_SERVER_4 = 104;
private static final int MENU_ITEM_SERVER_5 = 105;
private static final int MENU_ITEM_SERVER_6 = 106;
private static final int MENU_ITEM_SERVER_7 = 107;
private static final int MENU_ITEM_SERVER_8 = 108;
private static final int MENU_ITEM_SERVER_9 = 109;
private static final int MENU_ITEM_SERVER_10 = 110;
public class MainActivity extends SubsonicTabActivity
{
private static boolean infoDialogDisplayed;
private static boolean shouldUseId3;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) {
exit();
return;
}
setContentView(R.layout.main);
private static final int MENU_GROUP_SERVER = 10;
private static final int MENU_ITEM_OFFLINE = 111;
private static final int MENU_ITEM_SERVER_1 = 101;
private static final int MENU_ITEM_SERVER_2 = 102;
private static final int MENU_ITEM_SERVER_3 = 103;
private static final int MENU_ITEM_SERVER_4 = 104;
private static final int MENU_ITEM_SERVER_5 = 105;
private static final int MENU_ITEM_SERVER_6 = 106;
private static final int MENU_ITEM_SERVER_7 = 107;
private static final int MENU_ITEM_SERVER_8 = 108;
private static final int MENU_ITEM_SERVER_9 = 109;
private static final int MENU_ITEM_SERVER_10 = 110;
loadSettings();
final View buttons = LayoutInflater.from(this).inflate(R.layout.main_buttons, null);
final View serverButton = buttons.findViewById(R.id.main_select_server);
final TextView serverTextView = (TextView) serverButton.findViewById(R.id.main_select_server_2);
final View musicTitle = buttons.findViewById(R.id.main_music);
final View artistsButton = buttons.findViewById(R.id.main_artists_button);
final View albumsButton = buttons.findViewById(R.id.main_albums_button);
final View genresButton = buttons.findViewById(R.id.main_genres_button);
final View videosTitle = buttons.findViewById(R.id.main_videos_title);
final View songsTitle = buttons.findViewById(R.id.main_songs);
final View randomSongsButton = buttons.findViewById(R.id.main_songs_button);
final View songsStarredButton = buttons.findViewById(R.id.main_songs_starred);
final View albumsTitle = buttons.findViewById(R.id.main_albums);
final View albumsNewestButton = buttons.findViewById(R.id.main_albums_newest);
final View albumsRandomButton = buttons.findViewById(R.id.main_albums_random);
final View albumsHighestButton = buttons.findViewById(R.id.main_albums_highest);
final View albumsStarredButton = buttons.findViewById(R.id.main_albums_starred);
final View albumsRecentButton = buttons.findViewById(R.id.main_albums_recent);
final View albumsFrequentButton = buttons.findViewById(R.id.main_albums_frequent);
final View albumsAlphaByNameButton = buttons.findViewById(R.id.main_albums_alphaByName);
final View albumsAlphaByArtistButton = buttons.findViewById(R.id.main_albums_alphaByArtist);
final View videosButton = buttons.findViewById(R.id.main_videos);
final View dummyView = findViewById(R.id.main_dummy);
private static boolean infoDialogDisplayed;
private static boolean shouldUseId3;
boolean shouldShowDialog = false;
if (!getActiveServerEnabled()) {
shouldShowDialog = true;
Util.setActiveServer(this, 0);
}
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
int instance = Util.getActiveServer(this);
String name = Util.getServerName(this, instance);
if (name == null) {
shouldShowDialog = true;
Util.setActiveServer(this, 0);
instance = Util.getActiveServer(this);
name = Util.getServerName(this, instance);
}
serverTextView.setText(name);
if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT))
{
exit();
return;
}
final ListView list = (ListView) findViewById(R.id.main_list);
final MergeAdapter adapter = new MergeAdapter();
adapter.addViews(Arrays.asList(serverButton), true);
if (!Util.isOffline(this)) {
adapter.addView(musicTitle, false);
adapter.addViews(Arrays.asList(artistsButton, albumsButton, genresButton), true);
adapter.addView(songsTitle, false);
adapter.addViews(Arrays.asList(randomSongsButton, songsStarredButton), true);
adapter.addView(albumsTitle, false);
if (Util.getShouldUseId3Tags(MainActivity.this)) {
shouldUseId3 = true;
adapter.addViews(Arrays.asList(albumsNewestButton, albumsRecentButton, albumsFrequentButton, albumsRandomButton, albumsStarredButton, albumsAlphaByNameButton, albumsAlphaByArtistButton), true);
} else {
shouldUseId3 = false;
adapter.addViews(Arrays.asList(albumsNewestButton, albumsRecentButton, albumsFrequentButton, albumsHighestButton, albumsRandomButton, albumsStarredButton, albumsAlphaByNameButton, albumsAlphaByArtistButton), true);
}
adapter.addView(videosTitle, false);
adapter.addViews(Arrays.asList(videosButton), true);
}
list.setAdapter(adapter);
registerForContextMenu(dummyView);
setContentView(R.layout.main);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (view == serverButton) {
dummyView.showContextMenu();
} else if (view == albumsNewestButton) {
showAlbumList("newest", R.string.main_albums_newest);
} else if (view == albumsRandomButton) {
showAlbumList("random", R.string.main_albums_random);
} else if (view == albumsHighestButton) {
showAlbumList("highest", R.string.main_albums_highest);
} else if (view == albumsRecentButton) {
showAlbumList("recent", R.string.main_albums_recent);
} else if (view == albumsFrequentButton) {
showAlbumList("frequent", R.string.main_albums_frequent);
} else if (view == albumsStarredButton) {
showAlbumList(Constants.STARRED, R.string.main_albums_starred);
} else if (view == albumsAlphaByNameButton) {
showAlbumList(Constants.ALPHABETICAL_BY_NAME, R.string.main_albums_alphaByName);
} else if (view == albumsAlphaByArtistButton) {
showAlbumList("alphabeticalByArtist", R.string.main_albums_alphaByArtist);
} else if (view == songsStarredButton) {
showStarredSongs();
} else if (view == artistsButton) {
showArtists();
} else if (view == albumsButton) {
showAlbumList(Constants.ALPHABETICAL_BY_NAME, R.string.main_albums_title);
} else if (view == randomSongsButton) {
showRandomSongs();
} else if (view == genresButton) {
showGenres();
} else if (view == videosButton) {
showVideos();
}
}
});
final View homeMenuItem = findViewById(R.id.menu_home);
menuDrawer.setActiveView(homeMenuItem);
loadSettings();
setActionBarTitle(R.string.common_appname);
setTitle(R.string.common_appname);
final View buttons = LayoutInflater.from(this).inflate(R.layout.main_buttons, null);
final View serverButton = buttons.findViewById(R.id.main_select_server);
final TextView serverTextView = (TextView) serverButton.findViewById(R.id.main_select_server_2);
final View musicTitle = buttons.findViewById(R.id.main_music);
final View artistsButton = buttons.findViewById(R.id.main_artists_button);
final View albumsButton = buttons.findViewById(R.id.main_albums_button);
final View genresButton = buttons.findViewById(R.id.main_genres_button);
final View videosTitle = buttons.findViewById(R.id.main_videos_title);
final View songsTitle = buttons.findViewById(R.id.main_songs);
final View randomSongsButton = buttons.findViewById(R.id.main_songs_button);
final View songsStarredButton = buttons.findViewById(R.id.main_songs_starred);
final View albumsTitle = buttons.findViewById(R.id.main_albums);
final View albumsNewestButton = buttons.findViewById(R.id.main_albums_newest);
final View albumsRandomButton = buttons.findViewById(R.id.main_albums_random);
final View albumsHighestButton = buttons.findViewById(R.id.main_albums_highest);
final View albumsStarredButton = buttons.findViewById(R.id.main_albums_starred);
final View albumsRecentButton = buttons.findViewById(R.id.main_albums_recent);
final View albumsFrequentButton = buttons.findViewById(R.id.main_albums_frequent);
final View albumsAlphaByNameButton = buttons.findViewById(R.id.main_albums_alphaByName);
final View albumsAlphaByArtistButton = buttons.findViewById(R.id.main_albums_alphaByArtist);
final View videosButton = buttons.findViewById(R.id.main_videos);
final View dummyView = findViewById(R.id.main_dummy);
// Remember the current theme.
theme = Util.getTheme(this);
boolean shouldShowDialog = false;
showInfoDialog(shouldShowDialog);
}
if (!getActiveServerEnabled())
{
shouldShowDialog = true;
Util.setActiveServer(this, 0);
}
private void loadSettings() {
PreferenceManager.setDefaultValues(this, R.xml.settings, false);
final SharedPreferences preferences = Util.getPreferences(this);
if (!preferences.contains(Constants.PREFERENCES_KEY_CACHE_LOCATION)) {
final SharedPreferences.Editor editor = preferences.edit();
editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory().getPath());
editor.commit();
}
}
int instance = Util.getActiveServer(this);
String name = Util.getServerName(this, instance);
@Override
protected void onResume() {
super.onResume();
if (name == null)
{
shouldShowDialog = true;
Util.setActiveServer(this, 0);
instance = Util.getActiveServer(this);
name = Util.getServerName(this, instance);
}
boolean id3 = Util.getShouldUseId3Tags(MainActivity.this);
if (id3 != shouldUseId3) {
shouldUseId3 = id3;
restart();
}
}
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
final MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.main, menu);
super.onCreateOptionsMenu(menu);
return true;
}
serverTextView.setText(name);
@Override
public void onCreateContextMenu(final ContextMenu menu, final View view, final ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
final ListView list = (ListView) findViewById(R.id.main_list);
final int activeServer = Util.getActiveServer(this);
boolean checked = false;
for (int i = 0; i <= Util.getActiveServers(this); i++) {
final String serverName = Util.getServerName(this, i);
if (serverName == null) {
continue;
}
if (Util.getServerEnabled(this, i)) {
final int menuItemNum = getMenuItem(i);
final MenuItem menuItem = menu.add(MENU_GROUP_SERVER, menuItemNum, menuItemNum, serverName);
if (activeServer == i) {
checked = true;
menuItem.setChecked(true);
}
}
}
final MergeAdapter adapter = new MergeAdapter();
adapter.addViews(Collections.singletonList(serverButton), true);
if (!checked) {
MenuItem menuItem = menu.findItem(getMenuItem(0));
if (!Util.isOffline(this))
{
adapter.addView(musicTitle, false);
adapter.addViews(asList(artistsButton, albumsButton, genresButton), true);
adapter.addView(songsTitle, false);
adapter.addViews(asList(randomSongsButton, songsStarredButton), true);
adapter.addView(albumsTitle, false);
if (menuItem != null) {
menuItem.setChecked(true);
}
}
menu.setGroupCheckable(MENU_GROUP_SERVER, true, true);
menu.setHeaderTitle(R.string.main_select_server);
}
private boolean getActiveServerEnabled() {
if (Util.getShouldUseId3Tags(MainActivity.this))
{
shouldUseId3 = true;
adapter.addViews(asList(albumsNewestButton, albumsRecentButton, albumsFrequentButton, albumsRandomButton, albumsStarredButton, albumsAlphaByNameButton, albumsAlphaByArtistButton), true);
}
else
{
shouldUseId3 = false;
adapter.addViews(asList(albumsNewestButton, albumsRecentButton, albumsFrequentButton, albumsHighestButton, albumsRandomButton, albumsStarredButton, albumsAlphaByNameButton, albumsAlphaByArtistButton), true);
}
adapter.addView(videosTitle, false);
adapter.addViews(Collections.singletonList(videosButton), true);
}
list.setAdapter(adapter);
registerForContextMenu(dummyView);
list.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
if (view == serverButton)
{
dummyView.showContextMenu();
}
else if (view == albumsNewestButton)
{
showAlbumList("newest", R.string.main_albums_newest);
}
else if (view == albumsRandomButton)
{
showAlbumList("random", R.string.main_albums_random);
}
else if (view == albumsHighestButton)
{
showAlbumList("highest", R.string.main_albums_highest);
}
else if (view == albumsRecentButton)
{
showAlbumList("recent", R.string.main_albums_recent);
}
else if (view == albumsFrequentButton)
{
showAlbumList("frequent", R.string.main_albums_frequent);
}
else if (view == albumsStarredButton)
{
showAlbumList(Constants.STARRED, R.string.main_albums_starred);
}
else if (view == albumsAlphaByNameButton)
{
showAlbumList(Constants.ALPHABETICAL_BY_NAME, R.string.main_albums_alphaByName);
}
else if (view == albumsAlphaByArtistButton)
{
showAlbumList("alphabeticalByArtist", R.string.main_albums_alphaByArtist);
}
else if (view == songsStarredButton)
{
showStarredSongs();
}
else if (view == artistsButton)
{
showArtists();
}
else if (view == albumsButton)
{
showAlbumList(Constants.ALPHABETICAL_BY_NAME, R.string.main_albums_title);
}
else if (view == randomSongsButton)
{
showRandomSongs();
}
else if (view == genresButton)
{
showGenres();
}
else if (view == videosButton)
{
showVideos();
}
}
});
final View homeMenuItem = findViewById(R.id.menu_home);
menuDrawer.setActiveView(homeMenuItem);
setActionBarTitle(R.string.common_appname);
setTitle(R.string.common_appname);
// Remember the current theme.
theme = Util.getTheme(this);
showInfoDialog(shouldShowDialog);
}
private void loadSettings()
{
PreferenceManager.setDefaultValues(this, R.xml.settings, false);
final SharedPreferences preferences = Util.getPreferences(this);
if (!preferences.contains(Constants.PREFERENCES_KEY_CACHE_LOCATION))
{
final SharedPreferences.Editor editor = preferences.edit();
editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory().getPath());
editor.commit();
}
}
@Override
protected void onResume()
{
super.onResume();
boolean id3 = Util.getShouldUseId3Tags(MainActivity.this);
if (id3 != shouldUseId3)
{
shouldUseId3 = id3;
restart();
}
}
@Override
public boolean onCreateOptionsMenu(final Menu menu)
{
final MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.main, menu);
super.onCreateOptionsMenu(menu);
return true;
}
@Override
public void onCreateContextMenu(final ContextMenu menu, final View view, final ContextMenu.ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, view, menuInfo);
final int activeServer = Util.getActiveServer(this);
boolean checked = false;
for (int i = 0; i <= Util.getActiveServers(this); i++)
{
final String serverName = Util.getServerName(this, i);
if (serverName == null)
{
continue;
}
if (Util.getServerEnabled(this, i))
{
final int menuItemNum = getMenuItem(i);
final MenuItem menuItem = menu.add(MENU_GROUP_SERVER, menuItemNum, menuItemNum, serverName);
if (activeServer == i)
{
checked = true;
menuItem.setChecked(true);
}
}
}
if (!checked)
{
MenuItem menuItem = menu.findItem(getMenuItem(0));
if (menuItem != null)
{
menuItem.setChecked(true);
}
}
menu.setGroupCheckable(MENU_GROUP_SERVER, true, true);
menu.setHeaderTitle(R.string.main_select_server);
}
private boolean getActiveServerEnabled()
{
final int activeServer = Util.getActiveServer(this);
boolean activeServerEnabled = false;
for (int i = 0; i <= Util.getActiveServers(this); i++) {
if (Util.getServerEnabled(this, i)) {
if (activeServer == i) {
for (int i = 0; i <= Util.getActiveServers(this); i++)
{
if (Util.getServerEnabled(this, i))
{
if (activeServer == i)
{
activeServerEnabled = true;
}
}
}
return activeServerEnabled;
}
private static int getMenuItem(final int serverInstance) {
switch (serverInstance) {
case 0:
return MENU_ITEM_OFFLINE;
case 1:
return MENU_ITEM_SERVER_1;
case 2:
return MENU_ITEM_SERVER_2;
case 3:
return MENU_ITEM_SERVER_3;
case 4:
return MENU_ITEM_SERVER_4;
case 5:
return MENU_ITEM_SERVER_5;
case 6:
return MENU_ITEM_SERVER_6;
case 7:
return MENU_ITEM_SERVER_7;
case 8:
return MENU_ITEM_SERVER_8;
case 9:
return MENU_ITEM_SERVER_9;
case 10:
return MENU_ITEM_SERVER_10;
}
}
private static int getMenuItem(final int serverInstance)
{
switch (serverInstance)
{
case 0:
return MENU_ITEM_OFFLINE;
case 1:
return MENU_ITEM_SERVER_1;
case 2:
return MENU_ITEM_SERVER_2;
case 3:
return MENU_ITEM_SERVER_3;
case 4:
return MENU_ITEM_SERVER_4;
case 5:
return MENU_ITEM_SERVER_5;
case 6:
return MENU_ITEM_SERVER_6;
case 7:
return MENU_ITEM_SERVER_7;
case 8:
return MENU_ITEM_SERVER_8;
case 9:
return MENU_ITEM_SERVER_9;
case 10:
return MENU_ITEM_SERVER_10;
}
return 0;
}
@Override
public boolean onContextItemSelected(final MenuItem menuItem) {
switch (menuItem.getItemId()) {
case MENU_ITEM_OFFLINE:
setActiveServer(0);
break;
case MENU_ITEM_SERVER_1:
setActiveServer(1);
break;
case MENU_ITEM_SERVER_2:
setActiveServer(2);
break;
case MENU_ITEM_SERVER_3:
setActiveServer(3);
break;
case MENU_ITEM_SERVER_4:
setActiveServer(4);
break;
case MENU_ITEM_SERVER_5:
setActiveServer(5);
break;
case MENU_ITEM_SERVER_6:
setActiveServer(6);
break;
case MENU_ITEM_SERVER_7:
setActiveServer(7);
break;
case MENU_ITEM_SERVER_8:
setActiveServer(8);
break;
case MENU_ITEM_SERVER_9:
setActiveServer(9);
break;
case MENU_ITEM_SERVER_10:
setActiveServer(10);
break;
default:
return super.onContextItemSelected(menuItem);
}
}
// Restart activity
restart();
return true;
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
menuDrawer.toggleMenu();
return true;
case R.id.main_shuffle:
final Intent intent1 = new Intent(this, DownloadActivity.class);
intent1.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
Util.startActivityWithoutTransition(this, intent1);
return true;
}
@Override
public boolean onContextItemSelected(final MenuItem menuItem)
{
switch (menuItem.getItemId())
{
case MENU_ITEM_OFFLINE:
setActiveServer(0);
break;
case MENU_ITEM_SERVER_1:
setActiveServer(1);
break;
case MENU_ITEM_SERVER_2:
setActiveServer(2);
break;
case MENU_ITEM_SERVER_3:
setActiveServer(3);
break;
case MENU_ITEM_SERVER_4:
setActiveServer(4);
break;
case MENU_ITEM_SERVER_5:
setActiveServer(5);
break;
case MENU_ITEM_SERVER_6:
setActiveServer(6);
break;
case MENU_ITEM_SERVER_7:
setActiveServer(7);
break;
case MENU_ITEM_SERVER_8:
setActiveServer(8);
break;
case MENU_ITEM_SERVER_9:
setActiveServer(9);
break;
case MENU_ITEM_SERVER_10:
setActiveServer(10);
break;
default:
return super.onContextItemSelected(menuItem);
}
return false;
}
private void setActiveServer(final int instance) {
final DownloadService service = getDownloadService();
if (Util.getActiveServer(this) != instance) {
if (service != null) {
service.clearIncomplete();
}
}
Util.setActiveServer(this, instance);
if (service != null) {
service.setJukeboxEnabled(Util.getJukeboxEnabled(this, instance));
}
}
// Restart activity
restart();
return true;
}
private void exit() {
stopService(new Intent(this, DownloadServiceImpl.class));
Util.unregisterMediaButtonEventReceiver(this);
finish();
}
@Override
public boolean onOptionsItemSelected(final MenuItem item)
{
switch (item.getItemId())
{
case android.R.id.home:
menuDrawer.toggleMenu();
return true;
case R.id.main_shuffle:
final Intent intent1 = new Intent(this, DownloadActivity.class);
intent1.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
Util.startActivityWithoutTransition(this, intent1);
return true;
}
private void showInfoDialog(final boolean show) {
if (!infoDialogDisplayed) {
infoDialogDisplayed = true;
return false;
}
if (show || Util.getRestUrl(this, null).contains("yourhost")) {
Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text);
}
}
}
private void setActiveServer(final int instance)
{
final DownloadService service = getDownloadService();
private void showAlbumList(final String type, final int title) {
final Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, title);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, Util.getMaxAlbums(this));
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
if (Util.getActiveServer(this) != instance)
{
if (service != null)
{
service.clearIncomplete();
}
}
Util.setActiveServer(this, instance);
if (service != null)
{
service.setJukeboxEnabled(Util.getJukeboxEnabled(this, instance));
}
}
private void exit()
{
stopService(new Intent(this, DownloadServiceImpl.class));
Util.unregisterMediaButtonEventReceiver(this);
finish();
}
private void showInfoDialog(final boolean show)
{
if (!infoDialogDisplayed)
{
infoDialogDisplayed = true;
if (show || Util.getRestUrl(this, null).contains("yourhost"))
{
Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text);
}
}
}
private void showAlbumList(final String type, final int title)
{
final Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, title);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, Util.getMaxAlbums(this));
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
Util.startActivityWithoutTransition(this, intent);
}
private void showStarredSongs()
{
final Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_STARRED, 1);
Util.startActivityWithoutTransition(this, intent);
}
private void showRandomSongs()
{
final Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_RANDOM, 1);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, Util.getMaxSongs(this));
Util.startActivityWithoutTransition(this, intent);
}
private void showArtists()
{
final Intent intent = new Intent(this, SelectArtistActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, getResources().getString(R.string.main_artists_title));
Util.startActivityWithoutTransition(this, intent);
}
private void showGenres()
{
final Intent intent = new Intent(this, SelectGenreActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(this, intent);
}
private void showVideos()
{
final Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_VIDEOS, 1);
Util.startActivityWithoutTransition(this, intent);
}
private void showStarredSongs() {
final Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_STARRED, 1);
Util.startActivityWithoutTransition(this, intent);
}
private void showRandomSongs() {
final Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_RANDOM, 1);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, Util.getMaxSongs(this));
Util.startActivityWithoutTransition(this, intent);
}
private void showArtists() {
final Intent intent = new Intent(this, SelectArtistActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, getResources().getString(R.string.main_artists_title));
Util.startActivityWithoutTransition(this, intent);
}
private void showGenres() {
final Intent intent = new Intent(this, SelectGenreActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(this, intent);
}
private void showVideos() {
final Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_VIDEOS, 1);
Util.startActivityWithoutTransition(this, intent);
}
}

View File

@ -24,6 +24,7 @@ import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.provider.SearchRecentSuggestions;
import com.thejoshwa.ultrasonic.androidapp.util.Constants;
import com.thejoshwa.ultrasonic.androidapp.util.Util;
import com.thejoshwa.ultrasonic.androidapp.provider.SearchSuggestionProvider;
@ -33,24 +34,26 @@ import com.thejoshwa.ultrasonic.androidapp.provider.SearchSuggestionProvider;
*
* @author Sindre Mehus
*/
public class QueryReceiverActivity extends Activity {
public class QueryReceiverActivity extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
String query = getIntent().getStringExtra(SearchManager.QUERY);
String query = getIntent().getStringExtra(SearchManager.QUERY);
if (query != null) {
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this, SearchSuggestionProvider.AUTHORITY,
SearchSuggestionProvider.MODE);
suggestions.saveRecentQuery(query, null);
if (query != null)
{
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this, SearchSuggestionProvider.AUTHORITY, SearchSuggestionProvider.MODE);
suggestions.saveRecentQuery(query, null);
Intent intent = new Intent(QueryReceiverActivity.this, SearchActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query);
Util.startActivityWithoutTransition(QueryReceiverActivity.this, intent);
}
finish();
Util.disablePendingTransition(this);
}
Intent intent = new Intent(QueryReceiverActivity.this, SearchActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query);
Util.startActivityWithoutTransition(QueryReceiverActivity.this, intent);
}
finish();
Util.disablePendingTransition(this);
}
}

View File

@ -19,30 +19,27 @@
package com.thejoshwa.ultrasonic.androidapp.activity;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
import android.content.Intent;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.View;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.Artist;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory.Entry;
import com.thejoshwa.ultrasonic.androidapp.domain.SearchCriteria;
import com.thejoshwa.ultrasonic.androidapp.domain.SearchResult;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadService;
import com.thejoshwa.ultrasonic.androidapp.service.MusicService;
import com.thejoshwa.ultrasonic.androidapp.service.MusicServiceFactory;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadService;
import com.thejoshwa.ultrasonic.androidapp.util.BackgroundTask;
import com.thejoshwa.ultrasonic.androidapp.util.Constants;
import com.thejoshwa.ultrasonic.androidapp.util.MergeAdapter;
@ -51,397 +48,474 @@ import com.thejoshwa.ultrasonic.androidapp.util.Util;
import com.thejoshwa.ultrasonic.androidapp.view.ArtistAdapter;
import com.thejoshwa.ultrasonic.androidapp.view.EntryAdapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Performs searches and displays the matching artists, albums and songs.
*
* @author Sindre Mehus
*/
public class SearchActivity extends SubsonicTabActivity {
public class SearchActivity extends SubsonicTabActivity
{
private static int DEFAULT_ARTISTS;
private static int DEFAULT_ALBUMS;
private static int DEFAULT_SONGS;
private static int DEFAULT_ARTISTS;
private static int DEFAULT_ALBUMS;
private static int DEFAULT_SONGS;
private ListView list;
private ListView list;
private View artistsHeading;
private View albumsHeading;
private View songsHeading;
private TextView searchButton;
private View moreArtistsButton;
private View moreAlbumsButton;
private View moreSongsButton;
private SearchResult searchResult;
private MergeAdapter mergeAdapter;
private ArtistAdapter artistAdapter;
private ListAdapter moreArtistsAdapter;
private EntryAdapter albumAdapter;
private ListAdapter moreAlbumsAdapter;
private ListAdapter moreSongsAdapter;
private EntryAdapter songAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search);
private View artistsHeading;
private View albumsHeading;
private View songsHeading;
private TextView searchButton;
private View moreArtistsButton;
private View moreAlbumsButton;
private View moreSongsButton;
private SearchResult searchResult;
private MergeAdapter mergeAdapter;
private ArtistAdapter artistAdapter;
private ListAdapter moreArtistsAdapter;
private EntryAdapter albumAdapter;
private ListAdapter moreAlbumsAdapter;
private ListAdapter moreSongsAdapter;
private EntryAdapter songAdapter;
setActionBarTitle(R.string.common_appname);
setActionBarSubtitle(R.string.search_title);
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.search);
View searchMenuItem = findViewById(R.id.menu_search);
menuDrawer.setActiveView(searchMenuItem);
setActionBarTitle(R.string.common_appname);
setActionBarSubtitle(R.string.search_title);
DEFAULT_ARTISTS = Util.getDefaultArtists(this);
DEFAULT_ALBUMS = Util.getDefaultAlbums(this);
DEFAULT_SONGS = Util.getDefaultSongs(this);
View buttons = LayoutInflater.from(this).inflate(R.layout.search_buttons, null);
View searchMenuItem = findViewById(R.id.menu_search);
menuDrawer.setActiveView(searchMenuItem);
artistsHeading = buttons.findViewById(R.id.search_artists);
albumsHeading = buttons.findViewById(R.id.search_albums);
songsHeading = buttons.findViewById(R.id.search_songs);
DEFAULT_ARTISTS = Util.getDefaultArtists(this);
DEFAULT_ALBUMS = Util.getDefaultAlbums(this);
DEFAULT_SONGS = Util.getDefaultSongs(this);
searchButton = (TextView) buttons.findViewById(R.id.search_search);
moreArtistsButton = buttons.findViewById(R.id.search_more_artists);
moreAlbumsButton = buttons.findViewById(R.id.search_more_albums);
moreSongsButton = buttons.findViewById(R.id.search_more_songs);
View buttons = LayoutInflater.from(this).inflate(R.layout.search_buttons, null);
list = (ListView) findViewById(R.id.search_list);
artistsHeading = buttons.findViewById(R.id.search_artists);
albumsHeading = buttons.findViewById(R.id.search_albums);
songsHeading = buttons.findViewById(R.id.search_songs);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (view == searchButton) {
onSearchRequested();
} else if (view == moreArtistsButton) {
expandArtists();
} else if (view == moreAlbumsButton) {
expandAlbums();
} else if (view == moreSongsButton) {
expandSongs();
} else {
Object item = parent.getItemAtPosition(position);
if (item instanceof Artist) {
onArtistSelected((Artist) item);
} else if (item instanceof MusicDirectory.Entry) {
MusicDirectory.Entry entry = (MusicDirectory.Entry) item;
if (entry.isDirectory()) {
onAlbumSelected(entry, false);
} else if (entry.isVideo()) {
onVideoSelected(entry);
} else {
onSongSelected(entry, false, true, true, false);
}
searchButton = (TextView) buttons.findViewById(R.id.search_search);
moreArtistsButton = buttons.findViewById(R.id.search_more_artists);
moreAlbumsButton = buttons.findViewById(R.id.search_more_albums);
moreSongsButton = buttons.findViewById(R.id.search_more_songs);
}
}
}
});
registerForContextMenu(list);
list = (ListView) findViewById(R.id.search_list);
onNewIntent(getIntent());
}
list.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
if (view == searchButton)
{
onSearchRequested();
}
else if (view == moreArtistsButton)
{
expandArtists();
}
else if (view == moreAlbumsButton)
{
expandAlbums();
}
else if (view == moreSongsButton)
{
expandSongs();
}
else
{
Object item = parent.getItemAtPosition(position);
if (item instanceof Artist)
{
onArtistSelected((Artist) item);
}
else if (item instanceof MusicDirectory.Entry)
{
MusicDirectory.Entry entry = (MusicDirectory.Entry) item;
if (entry.isDirectory())
{
onAlbumSelected(entry, false);
}
else if (entry.isVideo())
{
onVideoSelected(entry);
}
else
{
onSongSelected(entry, false, true, true, false);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
String query = intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY);
boolean autoplay = intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false);
boolean requestsearch = intent.getBooleanExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, false);
}
}
}
});
if (query != null) {
mergeAdapter = new MergeAdapter();
list.setAdapter(mergeAdapter);
search(query, autoplay);
} else {
populateList();
if (requestsearch)
onSearchRequested();
}
}
registerForContextMenu(list);
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
Object selectedItem = list.getItemAtPosition(info.position);
onNewIntent(getIntent());
}
boolean isArtist = selectedItem instanceof Artist;
boolean isAlbum = selectedItem instanceof MusicDirectory.Entry && ((MusicDirectory.Entry) selectedItem).isDirectory();
if (!isArtist && !isAlbum) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.select_song_context, menu);
} else {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.select_album_context, menu);
}
}
@Override
protected void onNewIntent(Intent intent)
{
super.onNewIntent(intent);
String query = intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY);
boolean autoplay = intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false);
boolean requestsearch = intent.getBooleanExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, false);
@Override
public boolean onContextItemSelected(MenuItem menuItem) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
if (query != null)
{
mergeAdapter = new MergeAdapter();
list.setAdapter(mergeAdapter);
search(query, autoplay);
}
else
{
populateList();
if (requestsearch) onSearchRequested();
}
}
if (info == null) {
return true;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, view, menuInfo);
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
Object selectedItem = list.getItemAtPosition(info.position);
Object selectedItem = list.getItemAtPosition(info.position);
boolean isArtist = selectedItem instanceof Artist;
boolean isAlbum = selectedItem instanceof MusicDirectory.Entry && ((MusicDirectory.Entry) selectedItem).isDirectory();
Artist artist = selectedItem instanceof Artist ? (Artist) selectedItem : null;
Entry entry = selectedItem instanceof Entry ? (Entry) selectedItem : null;
if (!isArtist && !isAlbum)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.select_song_context, menu);
}
else
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.select_album_context, menu);
}
}
String entryId = null;
@Override
public boolean onContextItemSelected(MenuItem menuItem)
{
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
if (entry != null) {
entryId = entry.getId();
}
if (info == null)
{
return true;
}
String id = artist != null ? artist.getId() : entryId;
Object selectedItem = list.getItemAtPosition(info.position);
if (id == null ){
return true;
}
Artist artist = selectedItem instanceof Artist ? (Artist) selectedItem : null;
Entry entry = selectedItem instanceof Entry ? (Entry) selectedItem : null;
List<Entry> songs = new ArrayList<Entry>(1);
String entryId = null;
switch (menuItem.getItemId()) {
case R.id.album_menu_play_now:
downloadRecursively(id, false, false, true, false, false, false, false, false);
break;
case R.id.album_menu_play_next:
downloadRecursively(id, false, true, false, true, false, true, false, false);
break;
case R.id.album_menu_play_last:
downloadRecursively(id, false, true, false, false, false, false, false, false);
break;
case R.id.album_menu_pin:
downloadRecursively(id, true, true, false, false, false, false, false, false);
break;
case R.id.album_menu_unpin:
downloadRecursively(id, false, false, false, false, false, false, true, false);
break;
case R.id.album_menu_download:
downloadRecursively(id, false, false, false, false, true, false, false, false);
break;
case R.id.song_menu_play_now:
if (entry != null) {
songs = new ArrayList<MusicDirectory.Entry>(1);
songs.add(entry);
download(false, false, true, false, false, songs);
}
break;
case R.id.song_menu_play_next:
if (entry != null) {
songs = new ArrayList<MusicDirectory.Entry>(1);
songs.add(entry);
download(true, false, false, true, false, songs);
}
break;
case R.id.song_menu_play_last:
if (entry != null) {
songs = new ArrayList<MusicDirectory.Entry>(1);
songs.add(entry);
download(true, false, false, false, false, songs);
}
break;
case R.id.song_menu_pin:
if (entry != null) {
songs.add(entry);
Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_pinned, songs.size(), songs.size()));
downloadBackground(true, songs);
}
break;
case R.id.song_menu_download:
if (entry != null) {
songs.add(entry);
Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_downloaded, songs.size(), songs.size()));
downloadBackground(false, songs);
}
break;
case R.id.song_menu_unpin:
if (entry != null) {
songs.add(entry);
Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_unpinned, songs.size(), songs.size()));
getDownloadService().unpin(songs);
}
break;
default:
return super.onContextItemSelected(menuItem);
}
if (entry != null)
{
entryId = entry.getId();
}
return true;
}
private void downloadBackground(final boolean save, final List<MusicDirectory.Entry> songs) {
if (getDownloadService() == null) {
String id = artist != null ? artist.getId() : entryId;
if (id == null)
{
return true;
}
List<Entry> songs = new ArrayList<Entry>(1);
switch (menuItem.getItemId())
{
case R.id.album_menu_play_now:
downloadRecursively(id, false, false, true, false, false, false, false, false);
break;
case R.id.album_menu_play_next:
downloadRecursively(id, false, true, false, true, false, true, false, false);
break;
case R.id.album_menu_play_last:
downloadRecursively(id, false, true, false, false, false, false, false, false);
break;
case R.id.album_menu_pin:
downloadRecursively(id, true, true, false, false, false, false, false, false);
break;
case R.id.album_menu_unpin:
downloadRecursively(id, false, false, false, false, false, false, true, false);
break;
case R.id.album_menu_download:
downloadRecursively(id, false, false, false, false, true, false, false, false);
break;
case R.id.song_menu_play_now:
if (entry != null)
{
songs = new ArrayList<MusicDirectory.Entry>(1);
songs.add(entry);
download(false, false, true, false, false, songs);
}
break;
case R.id.song_menu_play_next:
if (entry != null)
{
songs = new ArrayList<MusicDirectory.Entry>(1);
songs.add(entry);
download(true, false, false, true, false, songs);
}
break;
case R.id.song_menu_play_last:
if (entry != null)
{
songs = new ArrayList<MusicDirectory.Entry>(1);
songs.add(entry);
download(true, false, false, false, false, songs);
}
break;
case R.id.song_menu_pin:
if (entry != null)
{
songs.add(entry);
Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_pinned, songs.size(), songs.size()));
downloadBackground(true, songs);
}
break;
case R.id.song_menu_download:
if (entry != null)
{
songs.add(entry);
Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_downloaded, songs.size(), songs.size()));
downloadBackground(false, songs);
}
break;
case R.id.song_menu_unpin:
if (entry != null)
{
songs.add(entry);
Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_unpinned, songs.size(), songs.size()));
getDownloadService().unpin(songs);
}
break;
default:
return super.onContextItemSelected(menuItem);
}
return true;
}
private void downloadBackground(final boolean save, final List<MusicDirectory.Entry> songs)
{
if (getDownloadService() == null)
{
return;
}
Runnable onValid = new Runnable() {
Runnable onValid = new Runnable()
{
@Override
public void run() {
public void run()
{
warnIfNetworkOrStorageUnavailable();
getDownloadService().downloadBackground(songs, save);
}
};
checkLicenseAndTrialPeriod(onValid);
}
private void search(final String query, final boolean autoplay) {
final int maxArtists = Util.getMaxArtists(this);
final int maxAlbums = Util.getMaxAlbums(this);
final int maxSongs = Util.getMaxSongs(this);
BackgroundTask<SearchResult> task = new TabActivityBackgroundTask<SearchResult>(this, true) {
@Override
protected SearchResult doInBackground() throws Throwable {
SearchCriteria criteria = new SearchCriteria(query, maxArtists, maxAlbums, maxSongs);
MusicService service = MusicServiceFactory.getMusicService(SearchActivity.this);
licenseValid = service.isLicenseValid(SearchActivity.this, this);
return service.search(criteria, SearchActivity.this, this);
}
@Override
protected void done(SearchResult result) {
searchResult = result;
populateList();
if (autoplay) {
autoplay();
}
private void search(final String query, final boolean autoplay)
{
final int maxArtists = Util.getMaxArtists(this);
final int maxAlbums = Util.getMaxAlbums(this);
final int maxSongs = Util.getMaxSongs(this);
}
};
task.execute();
}
BackgroundTask<SearchResult> task = new TabActivityBackgroundTask<SearchResult>(this, true)
{
@Override
protected SearchResult doInBackground() throws Throwable
{
SearchCriteria criteria = new SearchCriteria(query, maxArtists, maxAlbums, maxSongs);
MusicService service = MusicServiceFactory.getMusicService(SearchActivity.this);
licenseValid = service.isLicenseValid(SearchActivity.this, this);
return service.search(criteria, SearchActivity.this, this);
}
private void populateList() {
mergeAdapter = new MergeAdapter();
mergeAdapter.addView(searchButton, true);
@Override
protected void done(SearchResult result)
{
searchResult = result;
if (searchResult != null) {
List<Artist> artists = searchResult.getArtists();
if (!artists.isEmpty()) {
mergeAdapter.addView(artistsHeading);
List<Artist> displayedArtists = new ArrayList<Artist>(artists.subList(0, Math.min(DEFAULT_ARTISTS, artists.size())));
artistAdapter = new ArtistAdapter(this, displayedArtists);
mergeAdapter.addAdapter(artistAdapter);
if (artists.size() > DEFAULT_ARTISTS) {
moreArtistsAdapter = mergeAdapter.addView(moreArtistsButton, true);
}
}
populateList();
List<MusicDirectory.Entry> albums = searchResult.getAlbums();
if (!albums.isEmpty()) {
mergeAdapter.addView(albumsHeading);
List<MusicDirectory.Entry> displayedAlbums = new ArrayList<MusicDirectory.Entry>(albums.subList(0, Math.min(DEFAULT_ALBUMS, albums.size())));
albumAdapter = new EntryAdapter(this, getImageLoader(), displayedAlbums, false);
mergeAdapter.addAdapter(albumAdapter);
if (albums.size() > DEFAULT_ALBUMS) {
moreAlbumsAdapter = mergeAdapter.addView(moreAlbumsButton, true);
}
}
if (autoplay)
{
autoplay();
}
List<MusicDirectory.Entry> songs = searchResult.getSongs();
if (!songs.isEmpty()) {
mergeAdapter.addView(songsHeading);
List<MusicDirectory.Entry> displayedSongs = new ArrayList<MusicDirectory.Entry>(songs.subList(0, Math.min(DEFAULT_SONGS, songs.size())));
songAdapter = new EntryAdapter(this, getImageLoader(), displayedSongs, false);
mergeAdapter.addAdapter(songAdapter);
if (songs.size() > DEFAULT_SONGS) {
moreSongsAdapter = mergeAdapter.addView(moreSongsButton, true);
}
}
}
};
task.execute();
}
boolean empty = searchResult.getArtists().isEmpty() && searchResult.getAlbums().isEmpty() && searchResult.getSongs().isEmpty();
searchButton.setText(empty ? R.string.search_no_match : R.string.search_search);
}
private void populateList()
{
mergeAdapter = new MergeAdapter();
mergeAdapter.addView(searchButton, true);
list.setAdapter(mergeAdapter);
}
if (searchResult != null)
{
List<Artist> artists = searchResult.getArtists();
if (!artists.isEmpty())
{
mergeAdapter.addView(artistsHeading);
List<Artist> displayedArtists = new ArrayList<Artist>(artists.subList(0, Math.min(DEFAULT_ARTISTS, artists.size())));
artistAdapter = new ArtistAdapter(this, displayedArtists);
mergeAdapter.addAdapter(artistAdapter);
if (artists.size() > DEFAULT_ARTISTS)
{
moreArtistsAdapter = mergeAdapter.addView(moreArtistsButton, true);
}
}
private void expandArtists() {
artistAdapter.clear();
for (Artist artist : searchResult.getArtists()) {
artistAdapter.add(artist);
}
artistAdapter.notifyDataSetChanged();
mergeAdapter.removeAdapter(moreArtistsAdapter);
mergeAdapter.notifyDataSetChanged();
}
List<MusicDirectory.Entry> albums = searchResult.getAlbums();
if (!albums.isEmpty())
{
mergeAdapter.addView(albumsHeading);
List<MusicDirectory.Entry> displayedAlbums = new ArrayList<MusicDirectory.Entry>(albums.subList(0, Math.min(DEFAULT_ALBUMS, albums.size())));
albumAdapter = new EntryAdapter(this, getImageLoader(), displayedAlbums, false);
mergeAdapter.addAdapter(albumAdapter);
if (albums.size() > DEFAULT_ALBUMS)
{
moreAlbumsAdapter = mergeAdapter.addView(moreAlbumsButton, true);
}
}
private void expandAlbums() {
albumAdapter.clear();
for (MusicDirectory.Entry album : searchResult.getAlbums()) {
albumAdapter.add(album);
}
albumAdapter.notifyDataSetChanged();
mergeAdapter.removeAdapter(moreAlbumsAdapter);
mergeAdapter.notifyDataSetChanged();
}
List<MusicDirectory.Entry> songs = searchResult.getSongs();
if (!songs.isEmpty())
{
mergeAdapter.addView(songsHeading);
List<MusicDirectory.Entry> displayedSongs = new ArrayList<MusicDirectory.Entry>(songs.subList(0, Math.min(DEFAULT_SONGS, songs.size())));
songAdapter = new EntryAdapter(this, getImageLoader(), displayedSongs, false);
mergeAdapter.addAdapter(songAdapter);
if (songs.size() > DEFAULT_SONGS)
{
moreSongsAdapter = mergeAdapter.addView(moreSongsButton, true);
}
}
private void expandSongs() {
songAdapter.clear();
for (MusicDirectory.Entry song : searchResult.getSongs()) {
songAdapter.add(song);
}
songAdapter.notifyDataSetChanged();
mergeAdapter.removeAdapter(moreSongsAdapter);
mergeAdapter.notifyDataSetChanged();
}
boolean empty = searchResult.getArtists().isEmpty() && searchResult.getAlbums().isEmpty() && searchResult.getSongs().isEmpty();
searchButton.setText(empty ? R.string.search_no_match : R.string.search_search);
}
private void onArtistSelected(Artist artist) {
Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
Util.startActivityWithoutTransition(this, intent);
}
list.setAdapter(mergeAdapter);
}
private void onAlbumSelected(MusicDirectory.Entry album, boolean autoplay) {
Intent intent = new Intent(SearchActivity.this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, album.getId());
intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, album.getTitle());
intent.putExtra(Constants.INTENT_EXTRA_NAME_IS_ALBUM, album.isDirectory());
intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, autoplay);
Util.startActivityWithoutTransition(SearchActivity.this, intent);
}
private void expandArtists()
{
artistAdapter.clear();
private void onSongSelected(MusicDirectory.Entry song, boolean save, boolean append, boolean autoplay, boolean playNext) {
DownloadService downloadService = getDownloadService();
if (downloadService != null) {
if (!append && !playNext) {
downloadService.clear();
}
downloadService.download(Arrays.asList(song), save, false, playNext, false, false);
if (autoplay) {
downloadService.play(downloadService.size() - 1);
}
for (Artist artist : searchResult.getArtists())
{
artistAdapter.add(artist);
}
Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_added, 1, 1));
}
}
artistAdapter.notifyDataSetChanged();
mergeAdapter.removeAdapter(moreArtistsAdapter);
mergeAdapter.notifyDataSetChanged();
}
private void onVideoSelected(MusicDirectory.Entry entry) {
playVideo(entry);
}
private void expandAlbums()
{
albumAdapter.clear();
private void autoplay() {
if (!searchResult.getSongs().isEmpty()) {
onSongSelected(searchResult.getSongs().get(0), false, false, true, false);
} else if (!searchResult.getAlbums().isEmpty()) {
onAlbumSelected(searchResult.getAlbums().get(0), true);
}
}
for (MusicDirectory.Entry album : searchResult.getAlbums())
{
albumAdapter.add(album);
}
albumAdapter.notifyDataSetChanged();
mergeAdapter.removeAdapter(moreAlbumsAdapter);
mergeAdapter.notifyDataSetChanged();
}
private void expandSongs()
{
songAdapter.clear();
for (MusicDirectory.Entry song : searchResult.getSongs())
{
songAdapter.add(song);
}
songAdapter.notifyDataSetChanged();
mergeAdapter.removeAdapter(moreSongsAdapter);
mergeAdapter.notifyDataSetChanged();
}
private void onArtistSelected(Artist artist)
{
Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
Util.startActivityWithoutTransition(this, intent);
}
private void onAlbumSelected(MusicDirectory.Entry album, boolean autoplay)
{
Intent intent = new Intent(SearchActivity.this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, album.getId());
intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, album.getTitle());
intent.putExtra(Constants.INTENT_EXTRA_NAME_IS_ALBUM, album.isDirectory());
intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, autoplay);
Util.startActivityWithoutTransition(SearchActivity.this, intent);
}
private void onSongSelected(MusicDirectory.Entry song, boolean save, boolean append, boolean autoplay, boolean playNext)
{
DownloadService downloadService = getDownloadService();
if (downloadService != null)
{
if (!append && !playNext)
{
downloadService.clear();
}
downloadService.download(Collections.singletonList(song), save, false, playNext, false, false);
if (autoplay)
{
downloadService.play(downloadService.size() - 1);
}
Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_added, 1, 1));
}
}
private void onVideoSelected(MusicDirectory.Entry entry)
{
playVideo(entry);
}
private void autoplay()
{
if (!searchResult.getSongs().isEmpty())
{
onSongSelected(searchResult.getSongs().get(0), false, false, true, false);
}
else if (!searchResult.getAlbums().isEmpty())
{
onAlbumSelected(searchResult.getAlbums().get(0), true);
}
}
}

View File

@ -50,255 +50,304 @@ import com.thejoshwa.ultrasonic.androidapp.view.ArtistAdapter;
import java.util.ArrayList;
import java.util.List;
public class SelectArtistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener {
public class SelectArtistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener
{
private static final int MENU_GROUP_MUSIC_FOLDER = 10;
private static final int MENU_GROUP_MUSIC_FOLDER = 10;
private PullToRefreshListView refreshArtistListView;
private ListView artistListView;
private View folderButton;
private TextView folderName;
private List<MusicFolder> musicFolders;
private PullToRefreshListView refreshArtistListView;
private ListView artistListView;
private View folderButton;
private TextView folderName;
private List<MusicFolder> musicFolders;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.select_artist);
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.select_artist);
refreshArtistListView = (PullToRefreshListView) findViewById(R.id.select_artist_list);
artistListView = refreshArtistListView.getRefreshableView();
refreshArtistListView = (PullToRefreshListView) findViewById(R.id.select_artist_list);
artistListView = refreshArtistListView.getRefreshableView();
refreshArtistListView.setOnRefreshListener(new OnRefreshListener<ListView>() {
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) {
new GetDataTask().execute();
}
});
refreshArtistListView.setOnRefreshListener(new OnRefreshListener<ListView>()
{
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView)
{
new GetDataTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
});
artistListView.setOnItemClickListener(this);
artistListView.setOnItemClickListener(this);
folderButton = LayoutInflater.from(this).inflate(R.layout.select_artist_header, artistListView, false);
folderButton = LayoutInflater.from(this).inflate(R.layout.select_artist_header, artistListView, false);
if (folderButton != null) {
folderName = (TextView) folderButton.findViewById(R.id.select_artist_folder_2);
}
if (folderButton != null)
{
folderName = (TextView) folderButton.findViewById(R.id.select_artist_folder_2);
}
if (!Util.isOffline(this) && !Util.getShouldUseId3Tags(this)) {
artistListView.addHeaderView(folderButton);
}
if (!Util.isOffline(this) && !Util.getShouldUseId3Tags(this))
{
artistListView.addHeaderView(folderButton);
}
registerForContextMenu(artistListView);
registerForContextMenu(artistListView);
String title = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE);
if (title == null) {
setActionBarSubtitle(Util.isOffline(this) ? R.string.music_library_label_offline : R.string.music_library_label);
} else {
setActionBarSubtitle(title);
}
String title = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE);
if (title == null)
{
setActionBarSubtitle(Util.isOffline(this) ? R.string.music_library_label_offline : R.string.music_library_label);
}
else
{
setActionBarSubtitle(title);
}
View browseMenuItem = findViewById(R.id.menu_browse);
menuDrawer.setActiveView(browseMenuItem);
View browseMenuItem = findViewById(R.id.menu_browse);
menuDrawer.setActiveView(browseMenuItem);
musicFolders = null;
load();
}
musicFolders = null;
load();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
return true;
}
private void refresh() {
finish();
Intent intent = getIntent();
String title = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, title);
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
Util.startActivityWithoutTransition(this, intent);
}
private void refresh()
{
finish();
Intent intent = getIntent();
String title = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, title);
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
Util.startActivityWithoutTransition(this, intent);
}
private void selectFolder() {
folderButton.showContextMenu();
}
private void selectFolder()
{
folderButton.showContextMenu();
}
private void load() {
BackgroundTask<Indexes> task = new TabActivityBackgroundTask<Indexes>(this, true) {
@Override
protected Indexes doInBackground() throws Throwable {
boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false);
MusicService musicService = MusicServiceFactory.getMusicService(SelectArtistActivity.this);
private void load()
{
BackgroundTask<Indexes> task = new TabActivityBackgroundTask<Indexes>(this, true)
{
@Override
protected Indexes doInBackground() throws Throwable
{
boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false);
MusicService musicService = MusicServiceFactory.getMusicService(SelectArtistActivity.this);
boolean isOffline = Util.isOffline(SelectArtistActivity.this);
boolean useId3Tags = Util.getShouldUseId3Tags(SelectArtistActivity.this);
boolean isOffline = Util.isOffline(SelectArtistActivity.this);
boolean useId3Tags = Util.getShouldUseId3Tags(SelectArtistActivity.this);
if (!isOffline && !useId3Tags) {
musicFolders = musicService.getMusicFolders(refresh, SelectArtistActivity.this, this);
}
if (!isOffline && !useId3Tags)
{
musicFolders = musicService.getMusicFolders(refresh, SelectArtistActivity.this, this);
}
String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this);
String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this);
if (!isOffline && useId3Tags) {
return musicService.getArtists(refresh, SelectArtistActivity.this, this);
} else {
return musicService.getIndexes(musicFolderId, refresh, SelectArtistActivity.this, this);
}
}
return !isOffline && useId3Tags ? musicService.getArtists(refresh, SelectArtistActivity.this, this) : musicService.getIndexes(musicFolderId, refresh, SelectArtistActivity.this, this);
}
@Override
protected void done(Indexes result) {
if (result != null) {
List<Artist> artists = new ArrayList<Artist>(result.getShortcuts().size() + result.getArtists().size());
artists.addAll(result.getShortcuts());
artists.addAll(result.getArtists());
artistListView.setAdapter(new ArtistAdapter(SelectArtistActivity.this, artists));
}
@Override
protected void done(Indexes result)
{
if (result != null)
{
List<Artist> artists = new ArrayList<Artist>(result.getShortcuts().size() + result.getArtists().size());
artists.addAll(result.getShortcuts());
artists.addAll(result.getArtists());
artistListView.setAdapter(new ArtistAdapter(SelectArtistActivity.this, artists));
}
// Display selected music folder
if (musicFolders != null) {
String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this);
if (musicFolderId == null) {
if (folderName != null) {
folderName.setText(R.string.select_artist_all_folders);
}
} else {
for (MusicFolder musicFolder : musicFolders) {
if (musicFolder.getId().equals(musicFolderId)) {
if (folderName != null) {
folderName.setText(musicFolder.getName());
}
// Display selected music folder
if (musicFolders != null)
{
String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this);
if (musicFolderId == null)
{
if (folderName != null)
{
folderName.setText(R.string.select_artist_all_folders);
}
}
else
{
for (MusicFolder musicFolder : musicFolders)
{
if (musicFolder.getId().equals(musicFolderId))
{
if (folderName != null)
{
folderName.setText(musicFolder.getName());
}
break;
}
}
}
}
}
};
task.execute();
}
break;
}
}
}
}
}
};
task.execute();
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (view == folderButton) {
selectFolder();
} else {
Artist artist = (Artist) parent.getItemAtPosition(position);
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
if (view == folderButton)
{
selectFolder();
}
else
{
Artist artist = (Artist) parent.getItemAtPosition(position);
if (artist != null) {
Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
intent.putExtra(Constants.INTENT_EXTRA_NAME_ARTIST, true);
Util.startActivityWithoutTransition(this, intent);
}
}
}
if (artist != null)
{
Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
intent.putExtra(Constants.INTENT_EXTRA_NAME_ARTIST, true);
Util.startActivityWithoutTransition(this, intent);
}
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, view, menuInfo);
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
if (artistListView.getItemAtPosition(info.position) instanceof Artist) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.select_artist_context, menu);
} else if (info.position == 1) {
String musicFolderId = Util.getSelectedMusicFolderId(this);
MenuItem menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, -1, 0, R.string.select_artist_all_folders);
if (musicFolderId == null) {
menuItem.setChecked(true);
}
if (musicFolders != null) {
for (int i = 0; i < musicFolders.size(); i++) {
MusicFolder musicFolder = musicFolders.get(i);
menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, i, i + 1, musicFolder.getName());
if (musicFolder.getId().equals(musicFolderId)) {
menuItem.setChecked(true);
}
}
}
if (artistListView.getItemAtPosition(info.position) instanceof Artist)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.select_artist_context, menu);
}
else if (info.position == 1)
{
String musicFolderId = Util.getSelectedMusicFolderId(this);
MenuItem menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, -1, 0, R.string.select_artist_all_folders);
menu.setGroupCheckable(MENU_GROUP_MUSIC_FOLDER, true, true);
}
}
if (musicFolderId == null)
{
menuItem.setChecked(true);
}
@Override
public boolean onContextItemSelected(MenuItem menuItem) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
if (musicFolders != null)
{
for (int i = 0; i < musicFolders.size(); i++)
{
MusicFolder musicFolder = musicFolders.get(i);
menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, i, i + 1, musicFolder.getName());
if (info == null) {
return true;
}
if (musicFolder.getId().equals(musicFolderId))
{
menuItem.setChecked(true);
}
}
}
Artist artist = (Artist) artistListView.getItemAtPosition(info.position);
menu.setGroupCheckable(MENU_GROUP_MUSIC_FOLDER, true, true);
}
}
if (artist != null) {
switch (menuItem.getItemId()) {
case R.id.artist_menu_play_now:
downloadRecursively(artist.getId(), false, false, true, false, false, false, false, true);
break;
case R.id.artist_menu_play_next:
downloadRecursively(artist.getId(), false, false, true, true, false, true, false, true);
break;
case R.id.artist_menu_play_last:
downloadRecursively(artist.getId(), false, true, false, false, false, false, false, true);
break;
case R.id.artist_menu_pin:
downloadRecursively(artist.getId(), true, true, false, false, false, false, false, true);
break;
case R.id.artist_menu_unpin:
downloadRecursively(artist.getId(), false, false, false, false, false, false, true, true);
break;
case R.id.artist_menu_download:
downloadRecursively(artist.getId(), false, false, false, false, true, false, false, true);
break;
default:
return super.onContextItemSelected(menuItem);
}
} else if (info.position == 1) {
MusicFolder selectedFolder = menuItem.getItemId() == -1 ? null : musicFolders.get(menuItem.getItemId());
String musicFolderId = selectedFolder == null ? null : selectedFolder.getId();
String musicFolderName = selectedFolder == null ? getString(R.string.select_artist_all_folders) : selectedFolder.getName();
Util.setSelectedMusicFolderId(this, musicFolderId);
folderName.setText(musicFolderName);
refresh();
}
@Override
public boolean onContextItemSelected(MenuItem menuItem)
{
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
return true;
}
if (info == null)
{
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
menuDrawer.toggleMenu();
return true;
case R.id.main_shuffle:
Intent intent = new Intent(this, DownloadActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
Util.startActivityWithoutTransition(this, intent);
return true;
}
Artist artist = (Artist) artistListView.getItemAtPosition(info.position);
return false;
}
if (artist != null)
{
switch (menuItem.getItemId())
{
case R.id.artist_menu_play_now:
downloadRecursively(artist.getId(), false, false, true, false, false, false, false, true);
break;
case R.id.artist_menu_play_next:
downloadRecursively(artist.getId(), false, false, true, true, false, true, false, true);
break;
case R.id.artist_menu_play_last:
downloadRecursively(artist.getId(), false, true, false, false, false, false, false, true);
break;
case R.id.artist_menu_pin:
downloadRecursively(artist.getId(), true, true, false, false, false, false, false, true);
break;
case R.id.artist_menu_unpin:
downloadRecursively(artist.getId(), false, false, false, false, false, false, true, true);
break;
case R.id.artist_menu_download:
downloadRecursively(artist.getId(), false, false, false, false, true, false, false, true);
break;
default:
return super.onContextItemSelected(menuItem);
}
}
else if (info.position == 1)
{
MusicFolder selectedFolder = menuItem.getItemId() == -1 ? null : musicFolders.get(menuItem.getItemId());
String musicFolderId = selectedFolder == null ? null : selectedFolder.getId();
String musicFolderName = selectedFolder == null ? getString(R.string.select_artist_all_folders) : selectedFolder.getName();
Util.setSelectedMusicFolderId(this, musicFolderId);
folderName.setText(musicFolderName);
refresh();
}
private class GetDataTask extends AsyncTask<Void, Void, String[]> {
@Override
protected void onPostExecute(String[] result) {
refreshArtistListView.onRefreshComplete();
super.onPostExecute(result);
}
return true;
}
@Override
protected String[] doInBackground(Void... params) {
refresh();
return null;
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case android.R.id.home:
menuDrawer.toggleMenu();
return true;
case R.id.main_shuffle:
Intent intent = new Intent(this, DownloadActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
Util.startActivityWithoutTransition(this, intent);
return true;
}
return false;
}
private class GetDataTask extends AsyncTask<Void, Void, String[]>
{
@Override
protected void onPostExecute(String[] result)
{
refreshArtistListView.onRefreshComplete();
super.onPostExecute(result);
}
@Override
protected String[] doInBackground(Void... params)
{
refresh();
return null;
}
}
}

View File

@ -45,130 +45,151 @@ import com.thejoshwa.ultrasonic.androidapp.view.GenreAdapter;
import java.util.ArrayList;
import java.util.List;
public class SelectGenreActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener {
public class SelectGenreActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener
{
private static final String TAG = SelectGenreActivity.class.getSimpleName();
private PullToRefreshListView refreshGenreListView;
private ListView genreListView;
private View emptyView;
private View emptyView;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.select_genre);
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.select_genre);
refreshGenreListView = (PullToRefreshListView) findViewById(R.id.select_genre_list);
genreListView = refreshGenreListView.getRefreshableView();
refreshGenreListView.setOnRefreshListener(new OnRefreshListener<ListView>() {
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) {
new GetDataTask().execute();
}
});
genreListView.setOnItemClickListener(this);
emptyView = findViewById(R.id.select_genre_empty);
refreshGenreListView = (PullToRefreshListView) findViewById(R.id.select_genre_list);
genreListView = refreshGenreListView.getRefreshableView();
registerForContextMenu(genreListView);
View browseMenuItem = findViewById(R.id.menu_browse);
menuDrawer.setActiveView(browseMenuItem);
refreshGenreListView.setOnRefreshListener(new OnRefreshListener<ListView>()
{
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView)
{
new GetDataTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
});
setActionBarSubtitle(R.string.main_genres_title);
genreListView.setOnItemClickListener(this);
load();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
return true;
}
emptyView = findViewById(R.id.select_genre_empty);
private void refresh() {
finish();
Intent intent = getIntent();
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
Util.startActivityWithoutTransition(this, intent);
}
registerForContextMenu(genreListView);
View browseMenuItem = findViewById(R.id.menu_browse);
menuDrawer.setActiveView(browseMenuItem);
setActionBarSubtitle(R.string.main_genres_title);
load();
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
return true;
}
private void refresh()
{
finish();
Intent intent = getIntent();
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
Util.startActivityWithoutTransition(this, intent);
}
private void load()
{
BackgroundTask<List<Genre>> task = new TabActivityBackgroundTask<List<Genre>>(this, true)
{
@Override
protected List<Genre> doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(SelectGenreActivity.this);
List<Genre> genres = new ArrayList<Genre>();
try
{
genres = musicService.getGenres(SelectGenreActivity.this, this);
}
catch (Exception x)
{
Log.e(TAG, "Failed to load genres", x);
}
private void load() {
BackgroundTask<List<Genre>> task = new TabActivityBackgroundTask<List<Genre>>(this, true) {
@Override
protected List<Genre> doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(SelectGenreActivity.this);
List<Genre> genres = new ArrayList<Genre>();
try {
genres = musicService.getGenres(SelectGenreActivity.this, this);
} catch (Exception x) {
Log.e(TAG, "Failed to load genres", x);
}
return genres;
}
}
@Override
protected void done(List<Genre> result) {
emptyView.setVisibility(result == null || result.isEmpty() ? View.VISIBLE : View.GONE);
if (result != null) {
genreListView.setAdapter(new GenreAdapter(SelectGenreActivity.this, result));
}
}
};
task.execute();
}
@Override
protected void done(List<Genre> result)
{
emptyView.setVisibility(result == null || result.isEmpty() ? View.VISIBLE : View.GONE);
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Genre genre = (Genre) parent.getItemAtPosition(position);
if (result != null)
{
genreListView.setAdapter(new GenreAdapter(SelectGenreActivity.this, result));
}
if (genre != null) {
Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_GENRE_NAME, genre.getName());
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, Util.getMaxSongs(this));
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
Util.startActivityWithoutTransition(this, intent);
}
}
}
};
task.execute();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Genre genre = (Genre) parent.getItemAtPosition(position);
if (genre != null)
{
Intent intent = new Intent(this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_GENRE_NAME, genre.getName());
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, Util.getMaxSongs(this));
intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
Util.startActivityWithoutTransition(this, intent);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case android.R.id.home:
menuDrawer.toggleMenu();
return true;
case R.id.main_shuffle:
Intent intent = new Intent(this, DownloadActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
Util.startActivityWithoutTransition(this, intent);
return true;
}
return true;
case R.id.main_shuffle:
Intent intent = new Intent(this, DownloadActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
Util.startActivityWithoutTransition(this, intent);
return true;
}
return false;
}
private class GetDataTask extends AsyncTask<Void, Void, String[]> {
@Override
protected void onPostExecute(String[] result) {
refreshGenreListView.onRefreshComplete();
super.onPostExecute(result);
}
return false;
}
private class GetDataTask extends AsyncTask<Void, Void, String[]>
{
@Override
protected void onPostExecute(String[] result)
{
refreshGenreListView.onRefreshComplete();
super.onPostExecute(result);
}
@Override
protected String[] doInBackground(Void... params) {
protected String[] doInBackground(Void... params)
{
refresh();
return null;
}
}
}
}

View File

@ -53,94 +53,105 @@ import com.thejoshwa.ultrasonic.androidapp.view.PlaylistAdapter;
import java.util.List;
public class SelectPlaylistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener {
public class SelectPlaylistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener
{
private PullToRefreshListView refreshPlaylistsListView;
private ListView playlistsListView;
private View emptyTextView;
private PlaylistAdapter playlistAdapter;
private PullToRefreshListView refreshPlaylistsListView;
private ListView playlistsListView;
private View emptyTextView;
private PlaylistAdapter playlistAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.select_playlist);
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.select_playlist);
refreshPlaylistsListView = (PullToRefreshListView) findViewById(R.id.select_playlist_list);
playlistsListView = refreshPlaylistsListView.getRefreshableView();
refreshPlaylistsListView.setOnRefreshListener(new OnRefreshListener<ListView>() {
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) {
new GetDataTask().execute();
}
});
emptyTextView = findViewById(R.id.select_playlist_empty);
playlistsListView.setOnItemClickListener(this);
registerForContextMenu(playlistsListView);
refreshPlaylistsListView = (PullToRefreshListView) findViewById(R.id.select_playlist_list);
playlistsListView = refreshPlaylistsListView.getRefreshableView();
View playlistsMenuItem = findViewById(R.id.menu_playlists);
menuDrawer.setActiveView(playlistsMenuItem);
refreshPlaylistsListView.setOnRefreshListener(new OnRefreshListener<ListView>()
{
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView)
{
new GetDataTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
});
setActionBarTitle(R.string.common_appname);
setActionBarSubtitle(R.string.playlist_label);
emptyTextView = findViewById(R.id.select_playlist_empty);
playlistsListView.setOnItemClickListener(this);
registerForContextMenu(playlistsListView);
load();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
return true;
}
View playlistsMenuItem = findViewById(R.id.menu_playlists);
menuDrawer.setActiveView(playlistsMenuItem);
private void refresh() {
setActionBarTitle(R.string.common_appname);
setActionBarSubtitle(R.string.playlist_label);
load();
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
return true;
}
private void refresh()
{
finish();
Intent intent = new Intent(this, SelectPlaylistActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
Util.startActivityWithoutTransition(this, intent);
}
private void load() {
BackgroundTask<List<Playlist>> task = new TabActivityBackgroundTask<List<Playlist>>(this, true) {
@Override
protected List<Playlist> doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(SelectPlaylistActivity.this);
boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false);
List<Playlist> playlists = musicService.getPlaylists(refresh, SelectPlaylistActivity.this, this);
if(!Util.isOffline(SelectPlaylistActivity.this))
private void load()
{
BackgroundTask<List<Playlist>> task = new TabActivityBackgroundTask<List<Playlist>>(this, true)
{
@Override
protected List<Playlist> doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(SelectPlaylistActivity.this);
boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false);
List<Playlist> playlists = musicService.getPlaylists(refresh, SelectPlaylistActivity.this, this);
if (!Util.isOffline(SelectPlaylistActivity.this))
new CacheCleaner(SelectPlaylistActivity.this, getDownloadService()).cleanPlaylists(playlists);
return playlists;
}
}
@Override
protected void done(List<Playlist> result) {
playlistsListView.setAdapter(playlistAdapter = new PlaylistAdapter(SelectPlaylistActivity.this, result));
emptyTextView.setVisibility(result.isEmpty() ? View.VISIBLE : View.GONE);
}
};
task.execute();
}
@Override
protected void done(List<Playlist> result)
{
playlistsListView.setAdapter(playlistAdapter = new PlaylistAdapter(SelectPlaylistActivity.this, result));
emptyTextView.setVisibility(result.isEmpty() ? View.VISIBLE : View.GONE);
}
};
task.execute();
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, view, menuInfo);
MenuInflater inflater = getMenuInflater();
if (Util.isOffline(this))
inflater.inflate(R.menu.select_playlist_context_offline, menu);
else
inflater.inflate(R.menu.select_playlist_context, menu);
}
MenuInflater inflater = getMenuInflater();
if (Util.isOffline(this)) inflater.inflate(R.menu.select_playlist_context_offline, menu);
else inflater.inflate(R.menu.select_playlist_context, menu);
}
@Override
public boolean onContextItemSelected(MenuItem menuItem) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
Playlist playlist = (Playlist) playlistsListView.getItemAtPosition(info.position);
@Override
public boolean onContextItemSelected(MenuItem menuItem)
{
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
Playlist playlist = (Playlist) playlistsListView.getItemAtPosition(info.position);
Intent intent;
switch (menuItem.getItemId()) {
switch (menuItem.getItemId())
{
case R.id.playlist_menu_pin:
downloadPlaylist(playlist.getId(), playlist.getName(), true, true, false, false, true, false, false);
break;
@ -149,22 +160,22 @@ public class SelectPlaylistActivity extends SubsonicTabActivity implements Adapt
break;
case R.id.playlist_menu_download:
downloadPlaylist(playlist.getId(), playlist.getName(), false, false, false, false, true, false, false);
break;
case R.id.playlist_menu_play_now:
intent = new Intent(SelectPlaylistActivity.this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent);
break;
break;
case R.id.playlist_menu_play_now:
intent = new Intent(SelectPlaylistActivity.this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent);
break;
case R.id.playlist_menu_play_shuffled:
intent = new Intent(SelectPlaylistActivity.this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent);
break;
Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent);
break;
case R.id.playlist_menu_delete:
deletePlaylist(playlist);
break;
@ -174,64 +185,73 @@ public class SelectPlaylistActivity extends SubsonicTabActivity implements Adapt
case R.id.playlist_update_info:
updatePlaylistInfo(playlist);
break;
default:
return super.onContextItemSelected(menuItem);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
default:
return super.onContextItemSelected(menuItem);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case android.R.id.home:
menuDrawer.toggleMenu();
return true;
}
return true;
}
return false;
}
return false;
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Playlist playlist = (Playlist) parent.getItemAtPosition(position);
Playlist playlist = (Playlist) parent.getItemAtPosition(position);
Intent intent = new Intent(SelectPlaylistActivity.this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent);
}
private void deletePlaylist(final Playlist playlist) {
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.common_confirm)
.setMessage(getResources().getString(R.string.delete_playlist, playlist.getName()))
.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new LoadingTask<Void>(SelectPlaylistActivity.this, false) {
Intent intent = new Intent(SelectPlaylistActivity.this, SelectAlbumActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent);
}
private void deletePlaylist(final Playlist playlist)
{
new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert).setTitle(R.string.common_confirm).setMessage(getResources().getString(R.string.delete_playlist, playlist.getName())).setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
new LoadingTask<Void>(SelectPlaylistActivity.this, false)
{
@Override
protected Void doInBackground() throws Throwable {
protected Void doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(SelectPlaylistActivity.this);
musicService.deletePlaylist(playlist.getId(), SelectPlaylistActivity.this, null);
return null;
}
@Override
protected void done(Void result) {
protected void done(Void result)
{
playlistAdapter.remove(playlist);
playlistAdapter.notifyDataSetChanged();
Util.toast(SelectPlaylistActivity.this, getResources().getString(R.string.menu_deleted_playlist, playlist.getName()));
}
@Override
protected void error(Throwable error) {
protected void error(Throwable error)
{
String msg;
if (error instanceof OfflineException || error instanceof ServerTooOldException) {
if (error instanceof OfflineException || error instanceof ServerTooOldException)
{
msg = getErrorMessage(error);
} else {
msg = getResources().getString(R.string.menu_deleted_playlist_error, playlist.getName()) + " " + getErrorMessage(error);
}
else
{
msg = String.format("%s %s", getResources().getString(R.string.menu_deleted_playlist_error, playlist.getName()), getErrorMessage(error));
}
Util.toast(SelectPlaylistActivity.this, msg, false);
@ -239,90 +259,92 @@ public class SelectPlaylistActivity extends SubsonicTabActivity implements Adapt
}.execute();
}
})
.setNegativeButton(R.string.common_cancel, null)
.show();
}).setNegativeButton(R.string.common_cancel, null).show();
}
private void displayPlaylistInfo(final Playlist playlist) {
private void displayPlaylistInfo(final Playlist playlist)
{
String message = "Owner: " + playlist.getOwner() + "\nComments: " +
((playlist.getComment() == null) ? "" : playlist.getComment()) +
"\nSong Count: " + playlist.getSongCount() +
((playlist.getPublic() == null) ? "" : ("\nPublic: " + playlist.getPublic()) +
((playlist.getCreated() == null) ? "" : ("\nCreation Date: " + playlist.getCreated().replace('T', ' '))));
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(playlist.getName())
.setMessage(message)
.show();
((playlist.getComment() == null) ? "" : playlist.getComment()) +
"\nSong Count: " + playlist.getSongCount() +
((playlist.getPublic() == null) ? "" : ("\nPublic: " + playlist.getPublic()) + ((playlist.getCreated() == null) ? "" : ("\nCreation Date: " + playlist.getCreated().replace('T', ' '))));
new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert).setTitle(playlist.getName()).setMessage(message).show();
}
private void updatePlaylistInfo(final Playlist playlist) {
private void updatePlaylistInfo(final Playlist playlist)
{
View dialogView = getLayoutInflater().inflate(R.layout.update_playlist, null);
final EditText nameBox = (EditText)dialogView.findViewById(R.id.get_playlist_name);
final EditText commentBox = (EditText)dialogView.findViewById(R.id.get_playlist_comment);
final CheckBox publicBox = (CheckBox)dialogView.findViewById(R.id.get_playlist_public);
final EditText nameBox = (EditText) dialogView.findViewById(R.id.get_playlist_name);
final EditText commentBox = (EditText) dialogView.findViewById(R.id.get_playlist_comment);
final CheckBox publicBox = (CheckBox) dialogView.findViewById(R.id.get_playlist_public);
nameBox.setText(playlist.getName());
commentBox.setText(playlist.getComment());
Boolean pub = playlist.getPublic();
if(pub == null) {
if (pub == null)
{
publicBox.setEnabled(false);
} else {
}
else
{
publicBox.setChecked(pub);
}
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.playlist_update_info)
.setView(dialogView)
.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new LoadingTask<Void>(SelectPlaylistActivity.this, false) {
@Override
protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(SelectPlaylistActivity.this);
musicService.updatePlaylist(playlist.getId(), nameBox.getText().toString(), commentBox.getText().toString(), publicBox.isChecked(), SelectPlaylistActivity.this, null);
return null;
}
@Override
protected void done(Void result) {
refresh();
Util.toast(SelectPlaylistActivity.this, getResources().getString(R.string.playlist_updated_info, playlist.getName()));
}
new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert);
new AlertDialog.Builder(this).setTitle(R.string.playlist_update_info);
new AlertDialog.Builder(this).setView(dialogView);
new AlertDialog.Builder(this).setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
new LoadingTask<Void>(SelectPlaylistActivity.this, false)
{
@Override
protected Void doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(SelectPlaylistActivity.this);
musicService.updatePlaylist(playlist.getId(), nameBox.getText().toString(), commentBox.getText().toString(), publicBox.isChecked(), SelectPlaylistActivity.this, null);
return null;
}
@Override
protected void error(Throwable error) {
String msg;
if (error instanceof OfflineException || error instanceof ServerTooOldException) {
msg = getErrorMessage(error);
} else {
msg = getResources().getString(R.string.playlist_updated_info_error, playlist.getName()) + " " + getErrorMessage(error);
}
@Override
protected void done(Void result)
{
refresh();
Util.toast(SelectPlaylistActivity.this, getResources().getString(R.string.playlist_updated_info, playlist.getName()));
}
Util.toast(SelectPlaylistActivity.this, msg, false);
}
}.execute();
}
@Override
protected void error(Throwable error)
{
String msg;
msg = error instanceof OfflineException || error instanceof ServerTooOldException ? getErrorMessage(error) : String.format("%s %s", getResources().getString(R.string.playlist_updated_info_error, playlist.getName()), getErrorMessage(error));
})
.setNegativeButton(R.string.common_cancel, null)
.show();
Util.toast(SelectPlaylistActivity.this, msg, false);
}
}.execute();
}
});
new AlertDialog.Builder(this).setNegativeButton(R.string.common_cancel, null);
new AlertDialog.Builder(this).show();
}
private class GetDataTask extends AsyncTask<Void, Void, String[]> {
@Override
protected void onPostExecute(String[] result) {
refreshPlaylistsListView.onRefreshComplete();
super.onPostExecute(result);
}
private class GetDataTask extends AsyncTask<Void, Void, String[]>
{
@Override
protected void onPostExecute(String[] result)
{
refreshPlaylistsListView.onRefreshComplete();
super.onPostExecute(result);
}
@Override
protected String[] doInBackground(Void... params) {
protected String[] doInBackground(Void... params)
{
refresh();
return null;
}
}
}
}

View File

@ -24,36 +24,39 @@ import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.provider.SearchRecentSuggestions;
import com.thejoshwa.ultrasonic.androidapp.util.Constants;
import com.thejoshwa.ultrasonic.androidapp.util.Util;
import com.thejoshwa.ultrasonic.androidapp.provider.SearchSuggestionProvider;
/**
* Receives voice search queries and forwards to the SearchActivity.
*
* <p/>
* http://android-developers.blogspot.com/2010/09/supporting-new-music-voice-action.html
*
* @author Sindre Mehus
*/
public class VoiceQueryReceiverActivity extends Activity {
public class VoiceQueryReceiverActivity extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
String query = getIntent().getStringExtra(SearchManager.QUERY);
String query = getIntent().getStringExtra(SearchManager.QUERY);
if (query != null) {
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this, SearchSuggestionProvider.AUTHORITY,
SearchSuggestionProvider.MODE);
suggestions.saveRecentQuery(query, null);
if (query != null)
{
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this, SearchSuggestionProvider.AUTHORITY, SearchSuggestionProvider.MODE);
suggestions.saveRecentQuery(query, null);
Intent intent = new Intent(VoiceQueryReceiverActivity.this, SearchActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query);
intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
Util.startActivityWithoutTransition(VoiceQueryReceiverActivity.this, intent);
}
finish();
Util.disablePendingTransition(this);
}
Intent intent = new Intent(VoiceQueryReceiverActivity.this, SearchActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query);
intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
Util.startActivityWithoutTransition(VoiceQueryReceiverActivity.this, intent);
}
finish();
Util.disablePendingTransition(this);
}
}

View File

@ -18,142 +18,181 @@
*/
package com.thejoshwa.ultrasonic.androidapp.audiofx;
import java.io.Serializable;
import android.content.Context;
import android.media.MediaPlayer;
import android.media.audiofx.Equalizer;
import android.util.Log;
import com.thejoshwa.ultrasonic.androidapp.util.FileUtil;
import java.io.Serializable;
/**
* Backward-compatible wrapper for {@link Equalizer}, which is API Level 9.
*
* @author Sindre Mehus
* @version $Id$
*/
public class EqualizerController {
public class EqualizerController
{
private static final String TAG = EqualizerController.class.getSimpleName();
private static final String TAG = EqualizerController.class.getSimpleName();
private final Context context;
private Equalizer equalizer;
private boolean released = false;
private int audioSessionId = 0;
private final Context context;
private Equalizer equalizer;
private boolean released;
private int audioSessionId;
// Class initialization fails when this throws an exception.
static {
try {
Class.forName("android.media.audiofx.Equalizer");
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
// Class initialization fails when this throws an exception.
static
{
try
{
Class.forName("android.media.audiofx.Equalizer");
}
catch (Exception ex)
{
throw new RuntimeException(ex);
}
}
/**
* Throws an exception if the {@link Equalizer} class is not available.
*/
public static void checkAvailable() throws Throwable {
// Calling here forces class initialization.
}
/**
* Throws an exception if the {@link Equalizer} class is not available.
*/
public static void checkAvailable() throws Throwable
{
// Calling here forces class initialization.
}
public EqualizerController(Context context, MediaPlayer mediaPlayer) {
this.context = context;
try {
public EqualizerController(Context context, MediaPlayer mediaPlayer)
{
this.context = context;
try
{
audioSessionId = mediaPlayer.getAudioSessionId();
equalizer = new Equalizer(0, audioSessionId);
} catch (Throwable x) {
equalizer = null;
Log.w(TAG, "Failed to create equalizer.", x);
}
}
equalizer = new Equalizer(0, audioSessionId);
}
catch (Throwable x)
{
equalizer = null;
Log.w(TAG, "Failed to create equalizer.", x);
}
}
public void saveSettings() {
try {
if (isAvailable()) {
FileUtil.serialize(context, new EqualizerSettings(equalizer), "equalizer.dat");
}
} catch (Throwable x) {
Log.w(TAG, "Failed to save equalizer settings.", x);
}
}
public void saveSettings()
{
try
{
if (isAvailable())
{
FileUtil.serialize(context, new EqualizerSettings(equalizer), "equalizer.dat");
}
}
catch (Throwable x)
{
Log.w(TAG, "Failed to save equalizer settings.", x);
}
}
public void loadSettings() {
try {
if (isAvailable()) {
EqualizerSettings settings = FileUtil.deserialize(context, "equalizer.dat");
public void loadSettings()
{
try
{
if (isAvailable())
{
EqualizerSettings settings = FileUtil.deserialize(context, "equalizer.dat");
if (settings != null) {
settings.apply(equalizer);
}
}
} catch (Throwable x) {
Log.w(TAG, "Failed to load equalizer settings.", x);
}
}
if (settings != null)
{
settings.apply(equalizer);
}
}
}
catch (Throwable x)
{
Log.w(TAG, "Failed to load equalizer settings.", x);
}
}
public boolean isAvailable() {
return equalizer != null;
}
public boolean isAvailable()
{
return equalizer != null;
}
public void release() {
if (isAvailable()) {
public void release()
{
if (isAvailable())
{
released = true;
equalizer.release();
}
}
}
}
public Equalizer getEqualizer() {
if (released) {
public Equalizer getEqualizer()
{
if (released)
{
released = false;
try {
try
{
equalizer = new Equalizer(0, audioSessionId);
} catch (Throwable x) {
}
catch (Throwable x)
{
equalizer = null;
Log.w(TAG, "Failed to create equalizer.", x);
}
}
return equalizer;
}
private static class EqualizerSettings implements Serializable {
return equalizer;
}
/**
*
private static class EqualizerSettings implements Serializable
{
/**
*
*/
private static final long serialVersionUID = 626565082425206061L;
private final short[] bandLevels;
private short preset;
private final boolean enabled;
private short preset;
private final boolean enabled;
public EqualizerSettings(Equalizer equalizer) {
enabled = equalizer.getEnabled();
bandLevels = new short[equalizer.getNumberOfBands()];
for (short i = 0; i < equalizer.getNumberOfBands(); i++) {
bandLevels[i] = equalizer.getBandLevel(i);
}
try {
preset = equalizer.getCurrentPreset();
} catch (Exception x) {
preset = -1;
}
}
public EqualizerSettings(Equalizer equalizer)
{
enabled = equalizer.getEnabled();
bandLevels = new short[equalizer.getNumberOfBands()];
public void apply(Equalizer equalizer) {
for (short i = 0; i < bandLevels.length; i++) {
equalizer.setBandLevel(i, bandLevels[i]);
}
if (preset >= 0 && preset < equalizer.getNumberOfPresets()) {
equalizer.usePreset(preset);
}
equalizer.setEnabled(enabled);
}
}
for (short i = 0; i < equalizer.getNumberOfBands(); i++)
{
bandLevels[i] = equalizer.getBandLevel(i);
}
try
{
preset = equalizer.getCurrentPreset();
}
catch (Exception x)
{
preset = -1;
}
}
public void apply(Equalizer equalizer)
{
for (short i = 0; i < bandLevels.length; i++)
{
equalizer.setBandLevel(i, bandLevels[i]);
}
if (preset >= 0 && preset < equalizer.getNumberOfPresets())
{
equalizer.usePreset(preset);
}
equalizer.setEnabled(enabled);
}
}
}

View File

@ -28,70 +28,89 @@ import android.util.Log;
* @author Sindre Mehus
* @version $Id$
*/
public class VisualizerController {
public class VisualizerController
{
private static final String TAG = VisualizerController.class.getSimpleName();
private static final int PREFERRED_CAPTURE_SIZE = 128; // Must be a power of two.
private static final String TAG = VisualizerController.class.getSimpleName();
private static final int PREFERRED_CAPTURE_SIZE = 128; // Must be a power of two.
private Visualizer visualizer;
private Visualizer visualizer;
private boolean released = false;
private int audioSessionId = 0;
// Class initialization fails when this throws an exception.
static {
try {
Class.forName("android.media.audiofx.Visualizer");
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
// Class initialization fails when this throws an exception.
static
{
try
{
Class.forName("android.media.audiofx.Visualizer");
}
catch (Exception ex)
{
throw new RuntimeException(ex);
}
}
/**
* Throws an exception if the {@link Visualizer} class is not available.
*/
public static void checkAvailable() throws Throwable {
// Calling here forces class initialization.
}
/**
* Throws an exception if the {@link Visualizer} class is not available.
*/
public static void checkAvailable() throws Throwable
{
// Calling here forces class initialization.
}
public VisualizerController(MediaPlayer mediaPlayer) {
try {
public VisualizerController(MediaPlayer mediaPlayer)
{
try
{
audioSessionId = mediaPlayer.getAudioSessionId();
visualizer = new Visualizer(audioSessionId);
} catch (Throwable x) {
Log.w(TAG, "Failed to create visualizer.", x);
}
visualizer = new Visualizer(audioSessionId);
}
catch (Throwable x)
{
Log.w(TAG, "Failed to create visualizer.", x);
}
if (visualizer != null) {
int[] captureSizeRange = Visualizer.getCaptureSizeRange();
int captureSize = Math.max(PREFERRED_CAPTURE_SIZE, captureSizeRange[0]);
captureSize = Math.min(captureSize, captureSizeRange[1]);
visualizer.setCaptureSize(captureSize);
}
}
if (visualizer != null)
{
int[] captureSizeRange = Visualizer.getCaptureSizeRange();
int captureSize = Math.max(PREFERRED_CAPTURE_SIZE, captureSizeRange[0]);
captureSize = Math.min(captureSize, captureSizeRange[1]);
visualizer.setCaptureSize(captureSize);
}
}
public boolean isAvailable() {
return visualizer != null;
}
public boolean isAvailable()
{
return visualizer != null;
}
public void release() {
if (isAvailable()) {
visualizer.release();
public void release()
{
if (isAvailable())
{
visualizer.release();
released = true;
}
}
}
}
public Visualizer getVisualizer() {
if (released) {
public Visualizer getVisualizer()
{
if (released)
{
released = false;
try {
try
{
visualizer = new Visualizer(audioSessionId);
} catch (Throwable x) {
}
catch (Throwable x)
{
visualizer = null;
Log.w(TAG, "Failed to create visualizer.", x);
}
}
return visualizer;
}
return visualizer;
}
}

View File

@ -23,69 +23,83 @@ import java.io.Serializable;
/**
* @author Sindre Mehus
*/
public class Artist implements Serializable {
public class Artist implements Serializable
{
/**
*
/**
*
*/
private static final long serialVersionUID = -5790532593784846982L;
private String id;
private String name;
private String index;
private String coverArt;
private Long albumCount;
private int closeness;
private String name;
private String index;
private String coverArt;
private Long albumCount;
private int closeness;
public String getId() {
return id;
}
public String getId()
{
return id;
}
public void setId(String id) {
this.id = id;
}
public void setId(String id)
{
this.id = id;
}
public String getName() {
return name;
}
public String getName()
{
return name;
}
public void setName(String name) {
this.name = name;
}
public void setName(String name)
{
this.name = name;
}
public String getIndex() {
return index;
}
public String getIndex()
{
return index;
}
public void setIndex(String index) {
this.index = index;
}
public String getCoverArt() {
return coverArt;
}
public void setIndex(String index)
{
this.index = index;
}
public void setCoverArt(String coverArt) {
this.coverArt = coverArt;
}
public long getAlbumCount() {
public String getCoverArt()
{
return coverArt;
}
public void setCoverArt(String coverArt)
{
this.coverArt = coverArt;
}
public long getAlbumCount()
{
return albumCount;
}
public void setAlbumCount(Long albumCount) {
public void setAlbumCount(Long albumCount)
{
this.albumCount = albumCount;
}
public int getCloseness() {
public int getCloseness()
{
return closeness;
}
public void setCloseness(int closeness) {
public void setCloseness(int closeness)
{
this.closeness = closeness;
}
@Override
public String toString() {
return name;
}
@Override
public String toString()
{
return name;
}
}

View File

@ -9,79 +9,104 @@ import java.util.Locale;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory.Entry;
public class Bookmark implements Serializable {
public class Bookmark implements Serializable
{
/**
*
*
*/
private static final long serialVersionUID = 8988990025189807803L;
private int position;
private String username;
private String comment;
private Date created;
private Date changed;
private Entry entry;
public int getPosition() {
return position;
}
private String comment;
private Date created;
private Date changed;
private Entry entry;
public void setPosition(int position) {
this.position = position;
}
public String getUsername() {
return username;
}
public int getPosition()
{
return position;
}
public void setUsername(String username) {
this.username = username;
}
public String getComment() {
return comment;
}
public void setPosition(int position)
{
this.position = position;
}
public void setComment(String comment) {
this.comment = comment;
}
public Date getCreated() {
return created;
}
public String getUsername()
{
return username;
}
public void setCreated(String created) {
if (created != null) {
try {
public void setUsername(String username)
{
this.username = username;
}
public String getComment()
{
return comment;
}
public void setComment(String comment)
{
this.comment = comment;
}
public Date getCreated()
{
return created;
}
public void setCreated(String created)
{
if (created != null)
{
try
{
this.created = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(created);
} catch (ParseException e) {
}
catch (ParseException e)
{
this.created = null;
}
} else {
this.created = null;
}
}
public Date getChanged() {
return changed;
}
}
else
{
this.created = null;
}
}
public void setChanged(String changed) {
if (changed != null) {
try {
public Date getChanged()
{
return changed;
}
public void setChanged(String changed)
{
if (changed != null)
{
try
{
this.changed = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(changed);
} catch (ParseException e) {
}
catch (ParseException e)
{
this.changed = null;
}
} else {
this.changed = null;
}
}
public Entry getEntry() {
return this.entry;
}
public void setEntry(Entry entry) {
this.entry = entry;
}
}
else
{
this.changed = null;
}
}
public Entry getEntry()
{
return this.entry;
}
public void setEntry(Entry entry)
{
this.entry = entry;
}
}

View File

@ -2,36 +2,43 @@ package com.thejoshwa.ultrasonic.androidapp.domain;
import java.io.Serializable;
public class ChatMessage implements Serializable {
public class ChatMessage implements Serializable
{
/**
*
*
*/
private static final long serialVersionUID = 496544310289324167L;
private String username;
private Long time;
private String message;
public String getUsername() {
return username;
}
private Long time;
private String message;
public void setUsername(String username) {
this.username = username;
}
public Long getTime() {
return time;
}
public String getUsername()
{
return username;
}
public void setTime(Long time) {
this.time = time;
}
public String getMessage() {
return message;
}
public void setUsername(String username)
{
this.username = username;
}
public void setMessage(String message) {
this.message = message;
}
public Long getTime()
{
return time;
}
public void setTime(Long time)
{
this.time = time;
}
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
}

View File

@ -2,32 +2,38 @@ package com.thejoshwa.ultrasonic.androidapp.domain;
import java.io.Serializable;
public class Genre implements Serializable {
public class Genre implements Serializable
{
/**
*
*
*/
private static final long serialVersionUID = -3943025175219134028L;
private String name;
private String index;
public String getName() {
return name;
}
private String index;
public void setName(String name) {
this.name = name;
}
public String getIndex() {
return index;
}
public String getName()
{
return name;
}
public void setIndex(String index) {
this.index = index;
}
@Override
public String toString() {
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getIndex()
{
return index;
}
public void setIndex(String index)
{
this.index = index;
}
@Override
public String toString()
{
return name;
}
}

View File

@ -24,31 +24,36 @@ import java.io.Serializable;
/**
* @author Sindre Mehus
*/
public class Indexes implements Serializable {
public class Indexes implements Serializable
{
/**
*
/**
*
*/
private static final long serialVersionUID = 8156117238598414701L;
private final long lastModified;
private final List<com.thejoshwa.ultrasonic.androidapp.domain.Artist> shortcuts;
private final List<com.thejoshwa.ultrasonic.androidapp.domain.Artist> artists;
private final List<com.thejoshwa.ultrasonic.androidapp.domain.Artist> shortcuts;
private final List<com.thejoshwa.ultrasonic.androidapp.domain.Artist> artists;
public Indexes(long lastModified, List<com.thejoshwa.ultrasonic.androidapp.domain.Artist> shortcuts, List<com.thejoshwa.ultrasonic.androidapp.domain.Artist> artists) {
this.lastModified = lastModified;
this.shortcuts = shortcuts;
this.artists = artists;
}
public Indexes(long lastModified, List<com.thejoshwa.ultrasonic.androidapp.domain.Artist> shortcuts, List<com.thejoshwa.ultrasonic.androidapp.domain.Artist> artists)
{
this.lastModified = lastModified;
this.shortcuts = shortcuts;
this.artists = artists;
}
public long getLastModified() {
return lastModified;
}
public long getLastModified()
{
return lastModified;
}
public List<com.thejoshwa.ultrasonic.androidapp.domain.Artist> getShortcuts() {
return shortcuts;
}
public List<com.thejoshwa.ultrasonic.androidapp.domain.Artist> getShortcuts()
{
return shortcuts;
}
public List<com.thejoshwa.ultrasonic.androidapp.domain.Artist> getArtists() {
return artists;
}
public List<com.thejoshwa.ultrasonic.androidapp.domain.Artist> getArtists()
{
return artists;
}
}

View File

@ -22,42 +22,51 @@ package com.thejoshwa.ultrasonic.androidapp.domain;
* @author Sindre Mehus
* @version $Id$
*/
public class JukeboxStatus {
public class JukeboxStatus
{
private Integer positionSeconds;
private Integer currentPlayingIndex;
private Float gain;
private boolean playing;
private Integer positionSeconds;
private Integer currentPlayingIndex;
private Float gain;
private boolean playing;
public Integer getPositionSeconds() {
return positionSeconds;
}
public Integer getPositionSeconds()
{
return positionSeconds;
}
public void setPositionSeconds(Integer positionSeconds) {
this.positionSeconds = positionSeconds;
}
public void setPositionSeconds(Integer positionSeconds)
{
this.positionSeconds = positionSeconds;
}
public Integer getCurrentPlayingIndex() {
return currentPlayingIndex;
}
public Integer getCurrentPlayingIndex()
{
return currentPlayingIndex;
}
public void setCurrentIndex(Integer currentPlayingIndex) {
this.currentPlayingIndex = currentPlayingIndex;
}
public void setCurrentIndex(Integer currentPlayingIndex)
{
this.currentPlayingIndex = currentPlayingIndex;
}
public boolean isPlaying() {
return playing;
}
public boolean isPlaying()
{
return playing;
}
public void setPlaying(boolean playing) {
this.playing = playing;
}
public void setPlaying(boolean playing)
{
this.playing = playing;
}
public Float getGain() {
return gain;
}
public Float getGain()
{
return gain;
}
public void setGain(float gain) {
this.gain = gain;
}
public void setGain(float gain)
{
this.gain = gain;
}
}

View File

@ -23,33 +23,40 @@ package com.thejoshwa.ultrasonic.androidapp.domain;
*
* @author Sindre Mehus
*/
public class Lyrics {
public class Lyrics
{
private String artist;
private String title;
private String text;
private String artist;
private String title;
private String text;
public String getArtist() {
return artist;
}
public String getArtist()
{
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public void setArtist(String artist)
{
this.artist = artist;
}
public String getTitle() {
return title;
}
public String getTitle()
{
return title;
}
public void setTitle(String title) {
this.title = title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getText() {
return text;
}
public String getText()
{
return text;
}
public void setText(String text) {
this.text = text;
}
public void setText(String text)
{
this.text = text;
}
}

View File

@ -29,335 +29,413 @@ import java.io.Serializable;
/**
* @author Sindre Mehus
*/
public class MusicDirectory {
public class MusicDirectory
{
private String name;
private final List<Entry> children = new ArrayList<Entry>();
private String name;
private final List<Entry> children = new ArrayList<Entry>();
public String getName() {
return name;
}
public String getName()
{
return name;
}
public void setName(String name) {
this.name = name;
}
public void setName(String name)
{
this.name = name;
}
public void addChild(Entry child) {
children.add(child);
}
public void addChild(Entry child)
{
children.add(child);
}
public List<Entry> getChildren() {
return getChildren(true, true);
}
public List<Entry> getChildren()
{
return getChildren(true, true);
}
public List<Entry> getChildren(boolean includeDirs, boolean includeFiles) {
if (includeDirs && includeFiles) {
return children;
}
public List<Entry> getChildren(boolean includeDirs, boolean includeFiles)
{
if (includeDirs && includeFiles)
{
return children;
}
List<Entry> result = new ArrayList<Entry>(children.size());
for (Entry child : children) {
if (child.isDirectory() && includeDirs || !child.isDirectory() && includeFiles) {
result.add(child);
}
}
return result;
}
List<Entry> result = new ArrayList<Entry>(children.size());
for (Entry child : children)
{
if (child.isDirectory() && includeDirs || !child.isDirectory() && includeFiles)
{
result.add(child);
}
}
return result;
}
public static class Entry implements Serializable {
/**
*
public static class Entry implements Serializable
{
/**
*
*/
private static final long serialVersionUID = -3339106650010798108L;
/**
*
*
*/
private String id;
private String parent;
private boolean isDirectory;
private String title;
private String album;
private String albumId;
private String artist;
private String artistId;
private Integer track;
private Integer year;
private String genre;
private String contentType;
private String suffix;
private String transcodedContentType;
private String transcodedSuffix;
private String coverArt;
private Long size;
private Long songCount;
private Integer duration;
private Integer bitRate;
private String path;
private boolean isVideo;
private boolean isStarred;
private Integer discNumber;
private String type;
private Date created;
private int closeness;
private int bookmarkPosition;
public Integer getDiscNumber() {
return discNumber;
}
public void setDiscNumber(Integer discNumber) {
this.discNumber = discNumber;
}
private String parent;
private boolean isDirectory;
private String title;
private String album;
private String albumId;
private String artist;
private String artistId;
private Integer track;
private Integer year;
private String genre;
private String contentType;
private String suffix;
private String transcodedContentType;
private String transcodedSuffix;
private String coverArt;
private Long size;
private Long songCount;
private Integer duration;
private Integer bitRate;
private String path;
private boolean isVideo;
private boolean isStarred;
private Integer discNumber;
private String type;
private Date created;
private int closeness;
private int bookmarkPosition;
public boolean getStarred() {
return isStarred;
}
public void setStarred(boolean starred) {
this.isStarred = starred;
}
public String getId() {
return id;
}
public Integer getDiscNumber()
{
return discNumber;
}
public void setId(String id) {
this.id = id;
}
public void setDiscNumber(Integer discNumber)
{
this.discNumber = discNumber;
}
public String getParent() {
return parent;
}
public boolean getStarred()
{
return isStarred;
}
public void setParent(String parent) {
this.parent = parent;
}
public void setStarred(boolean starred)
{
this.isStarred = starred;
}
public boolean isDirectory() {
return isDirectory;
}
public String getId()
{
return id;
}
public void setIsDirectory(boolean directory) {
this.isDirectory = directory;
}
public void setId(String id)
{
this.id = id;
}
public String getTitle() {
return title;
}
public String getParent()
{
return parent;
}
public void setTitle(String title) {
this.title = title;
}
public void setParent(String parent)
{
this.parent = parent;
}
public String getAlbum() {
return album;
}
public boolean isDirectory()
{
return isDirectory;
}
public void setAlbum(String album) {
this.album = album;
}
public String getAlbumId() {
return albumId;
}
public void setIsDirectory(boolean directory)
{
this.isDirectory = directory;
}
public void setAlbumId(String albumId) {
this.albumId = albumId;
}
public String getTitle()
{
return title;
}
public String getArtist() {
return artist;
}
public void setTitle(String title)
{
this.title = title;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getArtistId() {
return artistId;
}
public String getAlbum()
{
return album;
}
public void setArtistId(String artistId) {
this.artistId = artistId;
}
public void setAlbum(String album)
{
this.album = album;
}
public Integer getTrack() {
return track == null ? 0 : track;
}
public String getAlbumId()
{
return albumId;
}
public void setTrack(Integer track) {
this.track = track;
}
public Long getSongcount() {
return songCount;
}
public void setAlbumId(String albumId)
{
this.albumId = albumId;
}
public void setSongCount(Long songCount) {
this.songCount = songCount;
}
public String getArtist()
{
return artist;
}
public Integer getYear() {
return year == null ? 0 : year;
}
public void setArtist(String artist)
{
this.artist = artist;
}
public void setYear(Integer year) {
this.year = year;
}
public String getArtistId()
{
return artistId;
}
public String getGenre() {
return genre;
}
public void setArtistId(String artistId)
{
this.artistId = artistId;
}
public void setGenre(String genre) {
this.genre = genre;
}
public Integer getTrack()
{
return track == null ? 0 : track;
}
public String getContentType() {
return contentType;
}
public void setTrack(Integer track)
{
this.track = track;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public Long getSongCount()
{
return songCount;
}
public String getSuffix() {
return suffix;
}
public void setSongCount(Long songCount)
{
this.songCount = songCount;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
public Integer getYear()
{
return year == null ? 0 : year;
}
public String getTranscodedContentType() {
return transcodedContentType;
}
public void setYear(Integer year)
{
this.year = year;
}
public void setTranscodedContentType(String transcodedContentType) {
this.transcodedContentType = transcodedContentType;
}
public String getGenre()
{
return genre;
}
public String getTranscodedSuffix() {
return transcodedSuffix;
}
public void setGenre(String genre)
{
this.genre = genre;
}
public void setTranscodedSuffix(String transcodedSuffix) {
this.transcodedSuffix = transcodedSuffix;
}
public String getContentType()
{
return contentType;
}
public Long getSize() {
return size;
}
public void setContentType(String contentType)
{
this.contentType = contentType;
}
public void setSize(Long size) {
this.size = size;
}
public String getSuffix()
{
return suffix;
}
public Integer getDuration() {
return duration;
}
public void setSuffix(String suffix)
{
this.suffix = suffix;
}
public void setDuration(Integer duration) {
this.duration = duration;
}
public void setDuration(long duration) {
this.duration = (int) duration;
}
public String getTranscodedContentType()
{
return transcodedContentType;
}
public Integer getBitRate() {
return bitRate;
}
public void setTranscodedContentType(String transcodedContentType)
{
this.transcodedContentType = transcodedContentType;
}
public void setBitRate(Integer bitRate) {
this.bitRate = bitRate;
}
public String getTranscodedSuffix()
{
return transcodedSuffix;
}
public String getCoverArt() {
return coverArt;
}
public void setTranscodedSuffix(String transcodedSuffix)
{
this.transcodedSuffix = transcodedSuffix;
}
public void setCoverArt(String coverArt) {
this.coverArt = coverArt;
}
public Long getSize()
{
return size;
}
public String getPath() {
return path;
}
public void setSize(Long size)
{
this.size = size;
}
public void setPath(String path) {
this.path = path;
}
public Integer getDuration()
{
return duration;
}
public boolean isVideo() {
return isVideo;
}
public void setDuration(Integer duration)
{
this.duration = duration;
}
public void setIsVideo(boolean video) {
this.isVideo = video;
}
public String getType() {
return type;
}
public void setDuration(long duration)
{
this.duration = (int) duration;
}
public void setType(String type) {
this.type = type;
}
public Date getCreated() {
return created;
}
public Integer getBitRate()
{
return bitRate;
}
public void setCreated(String created) {
if (created != null) {
try {
public void setBitRate(Integer bitRate)
{
this.bitRate = bitRate;
}
public String getCoverArt()
{
return coverArt;
}
public void setCoverArt(String coverArt)
{
this.coverArt = coverArt;
}
public String getPath()
{
return path;
}
public void setPath(String path)
{
this.path = path;
}
public boolean isVideo()
{
return isVideo;
}
public void setIsVideo(boolean video)
{
this.isVideo = video;
}
public String getType()
{
return type;
}
public void setType(String type)
{
this.type = type;
}
public Date getCreated()
{
return created;
}
public void setCreated(String created)
{
if (created != null)
{
try
{
this.created = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(created);
} catch (ParseException e) {
}
catch (ParseException e)
{
this.created = null;
}
} else {
this.created = null;
}
}
public int getCloseness() {
}
else
{
this.created = null;
}
}
public int getCloseness()
{
return closeness;
}
public void setCloseness(int closeness) {
public void setCloseness(int closeness)
{
this.closeness = closeness;
}
public int getBookmarkPosition() {
return bookmarkPosition;
}
public void setBookmarkPosition(int bookmarkPosition) {
public int getBookmarkPosition()
{
return bookmarkPosition;
}
public void setBookmarkPosition(int bookmarkPosition)
{
this.bookmarkPosition = bookmarkPosition;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
Entry entry = (Entry) o;
return id.equals(entry.id);
}
Entry entry = (Entry) o;
return id.equals(entry.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public int hashCode()
{
return id.hashCode();
}
@Override
public String toString() {
return title;
}
}
@Override
public String toString()
{
return title;
}
}
}

View File

@ -24,21 +24,25 @@ package com.thejoshwa.ultrasonic.androidapp.domain;
* @author Sindre Mehus
* @version $Id$
*/
public class MusicFolder {
public class MusicFolder
{
private final String id;
private final String name;
private final String id;
private final String name;
public MusicFolder(String id, String name) {
this.id = id;
this.name = name;
}
public MusicFolder(String id, String name)
{
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getId()
{
return id;
}
public String getName() {
return name;
}
public String getName()
{
return name;
}
}

View File

@ -22,13 +22,14 @@ package com.thejoshwa.ultrasonic.androidapp.domain;
* @author Sindre Mehus
* @version $Id$
*/
public enum PlayerState {
IDLE,
DOWNLOADING,
PREPARING,
PREPARED,
STARTED,
STOPPED,
PAUSED,
COMPLETED
public enum PlayerState
{
IDLE,
DOWNLOADING,
PREPARING,
PREPARED,
STARTED,
STOPPED,
PAUSED,
COMPLETED
}

View File

@ -23,91 +23,111 @@ import java.io.Serializable;
/**
* @author Sindre Mehus
*/
public class Playlist implements Serializable {
public class Playlist implements Serializable
{
/**
*
/**
*
*/
private static final long serialVersionUID = -4160515427075433798L;
private String id;
private String name;
private String name;
private String owner;
private String comment;
private String songCount;
private String created;
private Boolean pub;
public Playlist(String id, String name) {
this.id = id;
this.name = name;
}
public Playlist(String id, String name, String owner, String comment, String songCount, String created, String pub) {
this.id = id;
this.name = name;
public Playlist(String id, String name)
{
this.id = id;
this.name = name;
}
public Playlist(String id, String name, String owner, String comment, String songCount, String created, String pub)
{
this.id = id;
this.name = name;
this.owner = (owner == null) ? "" : owner;
this.comment = (comment == null) ? "" : comment;
this.songCount = (songCount == null) ? "" : songCount;
this.created = (created == null) ? "" : created;
this.pub = (pub == null) ? null : (pub.equals("true"));
}
}
public String getId() {
return id;
}
public String getId()
{
return id;
}
public void setId(String id) {
this.id = id;
}
public void setId(String id)
{
this.id = id;
}
public String getName() {
return name;
}
public String getName()
{
return name;
}
public void setName(String name) {
this.name = name;
}
public String getOwner() {
public void setName(String name)
{
this.name = name;
}
public String getOwner()
{
return this.owner;
}
public void setOwner(String owner) {
public void setOwner(String owner)
{
this.owner = owner;
}
public String getComment() {
public String getComment()
{
return this.comment;
}
public void setComment(String comment) {
public void setComment(String comment)
{
this.comment = comment;
}
public String getSongCount() {
public String getSongCount()
{
return this.songCount;
}
public void setSongCount(String songCount) {
public void setSongCount(String songCount)
{
this.songCount = songCount;
}
public String getCreated() {
public String getCreated()
{
return this.created;
}
public void setCreated(String created) {
public void setCreated(String created)
{
this.created = created;
}
public Boolean getPublic() {
public Boolean getPublic()
{
return this.pub;
}
public void setPublic(Boolean pub) {
public void setPublic(Boolean pub)
{
this.pub = pub;
}
@Override
public String toString() {
return name;
}
@Override
public String toString()
{
return name;
}
}

View File

@ -4,25 +4,32 @@ package com.thejoshwa.ultrasonic.androidapp.domain;
* @author Sindre Mehus
* @version $Id$
*/
public enum RepeatMode {
OFF {
@Override
public RepeatMode next() {
return ALL;
}
},
ALL {
@Override
public RepeatMode next() {
return SINGLE;
}
},
SINGLE {
@Override
public RepeatMode next() {
return OFF;
}
};
public enum RepeatMode
{
OFF
{
@Override
public RepeatMode next()
{
return ALL;
}
},
ALL
{
@Override
public RepeatMode next()
{
return SINGLE;
}
},
SINGLE
{
@Override
public RepeatMode next()
{
return OFF;
}
};
public abstract RepeatMode next();
public abstract RepeatMode next();
}

View File

@ -23,33 +23,39 @@ package com.thejoshwa.ultrasonic.androidapp.domain;
*
* @author Sindre Mehus
*/
public class SearchCritera {
public class SearchCritera
{
private final String query;
private final int artistCount;
private final int albumCount;
private final int songCount;
private final String query;
private final int artistCount;
private final int albumCount;
private final int songCount;
public SearchCritera(String query, int artistCount, int albumCount, int songCount) {
this.query = query;
this.artistCount = artistCount;
this.albumCount = albumCount;
this.songCount = songCount;
}
public SearchCritera(String query, int artistCount, int albumCount, int songCount)
{
this.query = query;
this.artistCount = artistCount;
this.albumCount = albumCount;
this.songCount = songCount;
}
public String getQuery() {
return query;
}
public String getQuery()
{
return query;
}
public int getArtistCount() {
return artistCount;
}
public int getArtistCount()
{
return artistCount;
}
public int getAlbumCount() {
return albumCount;
}
public int getAlbumCount()
{
return albumCount;
}
public int getSongCount() {
return songCount;
}
public int getSongCount()
{
return songCount;
}
}

View File

@ -23,33 +23,39 @@ package com.thejoshwa.ultrasonic.androidapp.domain;
*
* @author Sindre Mehus
*/
public class SearchCriteria {
public class SearchCriteria
{
private final String query;
private final int artistCount;
private final int albumCount;
private final int songCount;
private final String query;
private final int artistCount;
private final int albumCount;
private final int songCount;
public SearchCriteria(String query, int artistCount, int albumCount, int songCount) {
this.query = query;
this.artistCount = artistCount;
this.albumCount = albumCount;
this.songCount = songCount;
}
public SearchCriteria(String query, int artistCount, int albumCount, int songCount)
{
this.query = query;
this.artistCount = artistCount;
this.albumCount = albumCount;
this.songCount = songCount;
}
public String getQuery() {
return query;
}
public String getQuery()
{
return query;
}
public int getArtistCount() {
return artistCount;
}
public int getArtistCount()
{
return artistCount;
}
public int getAlbumCount() {
return albumCount;
}
public int getAlbumCount()
{
return albumCount;
}
public int getSongCount() {
return songCount;
}
public int getSongCount()
{
return songCount;
}
}

View File

@ -25,27 +25,32 @@ import java.util.List;
*
* @author Sindre Mehus
*/
public class SearchResult {
public class SearchResult
{
private final List<Artist> artists;
private final List<MusicDirectory.Entry> albums;
private final List<MusicDirectory.Entry> songs;
private final List<Artist> artists;
private final List<MusicDirectory.Entry> albums;
private final List<MusicDirectory.Entry> songs;
public SearchResult(List<Artist> artists, List<MusicDirectory.Entry> albums, List<MusicDirectory.Entry> songs) {
this.artists = artists;
this.albums = albums;
this.songs = songs;
}
public SearchResult(List<Artist> artists, List<MusicDirectory.Entry> albums, List<MusicDirectory.Entry> songs)
{
this.artists = artists;
this.albums = albums;
this.songs = songs;
}
public List<Artist> getArtists() {
return artists;
}
public List<Artist> getArtists()
{
return artists;
}
public List<MusicDirectory.Entry> getAlbums() {
return albums;
}
public List<MusicDirectory.Entry> getAlbums()
{
return albums;
}
public List<MusicDirectory.Entry> getSongs() {
return songs;
}
public List<MusicDirectory.Entry> getSongs()
{
return songs;
}
}

View File

@ -23,24 +23,29 @@ package com.thejoshwa.ultrasonic.androidapp.domain;
*
* @author Sindre Mehus
*/
public class ServerInfo {
public class ServerInfo
{
private boolean isLicenseValid;
private Version restVersion;
private boolean isLicenseValid;
private Version restVersion;
public boolean isLicenseValid() {
return isLicenseValid;
}
public boolean isLicenseValid()
{
return isLicenseValid;
}
public void setLicenseValid(boolean licenseValid) {
isLicenseValid = licenseValid;
}
public void setLicenseValid(boolean licenseValid)
{
isLicenseValid = licenseValid;
}
public Version getRestVersion() {
return restVersion;
}
public Version getRestVersion()
{
return restVersion;
}
public void setRestVersion(Version restVersion) {
this.restVersion = restVersion;
}
public void setRestVersion(Version restVersion)
{
this.restVersion = restVersion;
}
}

View File

@ -10,115 +10,153 @@ import java.util.Locale;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory.Entry;
public class Share implements Serializable {
public class Share implements Serializable
{
private static final long serialVersionUID = 1487561657691009668L;
private String id;
private String url;
private String description;
private String username;
private Date created;
private Date lastVisited;
private Date expires;
private Long visitCount;
private List<Entry> entries;
public Share() {
entries = new ArrayList<Entry>();
}
public String getId() {
return id;
}
private String url;
private String description;
private String username;
private Date created;
private Date lastVisited;
private Date expires;
private Long visitCount;
private List<Entry> entries;
public void setId(String id) {
this.id = id;
}
public String getUrl() {
return url;
}
public Share()
{
entries = new ArrayList<Entry>();
}
public void setUrl(String url) {
this.url = url;
}
public String getDescription() {
return description;
}
public String getId()
{
return id;
}
public void setDescription(String description) {
this.description = description;
}
public String getUsername() {
return username;
}
public void setId(String id)
{
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public Date getCreated() {
return created;
}
public String getUrl()
{
return url;
}
public void setCreated(String created) {
if (created != null) {
try {
public void setUrl(String url)
{
this.url = url;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public Date getCreated()
{
return created;
}
public void setCreated(String created)
{
if (created != null)
{
try
{
this.created = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(created);
} catch (ParseException e) {
}
catch (ParseException e)
{
this.created = null;
}
} else {
this.created = null;
}
}
public Date getLastVisited() {
return lastVisited;
}
}
else
{
this.created = null;
}
}
public void setLastVisited(String lastVisited) {
if (lastVisited != null) {
try {
public Date getLastVisited()
{
return lastVisited;
}
public void setLastVisited(String lastVisited)
{
if (lastVisited != null)
{
try
{
this.lastVisited = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(lastVisited);
} catch (ParseException e) {
}
catch (ParseException e)
{
this.lastVisited = null;
}
} else {
this.lastVisited = null;
}
}
public Date getExpires() {
return expires;
}
}
else
{
this.lastVisited = null;
}
}
public void setExpires(String expires) {
if (expires != null) {
try {
public Date getExpires()
{
return expires;
}
public void setExpires(String expires)
{
if (expires != null)
{
try
{
this.expires = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(expires);
} catch (ParseException e) {
}
catch (ParseException e)
{
this.expires = null;
}
} else {
this.expires = null;
}
}
}
else
{
this.expires = null;
}
}
public Long getVisitCount() {
return visitCount;
}
public void setVisitCount(Long visitCount) {
this.visitCount = visitCount;
}
public List<Entry> getEntries() {
return this.entries;
}
public void addEntry(Entry entry) {
entries.add(entry);
}
}
public Long getVisitCount()
{
return visitCount;
}
public void setVisitCount(Long visitCount)
{
this.visitCount = visitCount;
}
public List<Entry> getEntries()
{
return this.entries;
}
public void addEntry(Entry entry)
{
entries.add(entry);
}
}

View File

@ -18,124 +18,159 @@
*/
package com.thejoshwa.ultrasonic.androidapp.domain;
import java.util.regex.Pattern;
/**
* Represents the version number of the Subsonic Android app.
*
* @author Sindre Mehus
* @version $Revision: 1.3 $ $Date: 2006/01/20 21:25:16 $
*/
public class Version implements Comparable<Version> {
private int major;
private int minor;
private int beta;
private int bugfix;
public class Version implements Comparable<Version>
{
private static final Pattern COMPILE = Pattern.compile("\\.");
private int major;
private int minor;
private int beta;
private int bugfix;
/**
* Creates a new version instance by parsing the given string.
* @param version A string of the format "1.27", "1.27.2" or "1.27.beta3".
*/
public Version(String version) {
String[] s = version.split("\\.");
major = Integer.valueOf(s[0]);
minor = Integer.valueOf(s[1]);
/**
* Creates a new version instance by parsing the given string.
*
* @param version A string of the format "1.27", "1.27.2" or "1.27.beta3".
*/
public Version(String version)
{
String[] s = COMPILE.split(version);
major = Integer.valueOf(s[0]);
minor = Integer.valueOf(s[1]);
if (s.length > 2) {
if (s[2].contains("beta")) {
beta = Integer.valueOf(s[2].replace("beta", ""));
} else {
bugfix = Integer.valueOf(s[2]);
}
}
}
if (s.length > 2)
{
if (s[2].contains("beta"))
{
beta = Integer.valueOf(s[2].replace("beta", ""));
}
else
{
bugfix = Integer.valueOf(s[2]);
}
}
}
public int getMajor() {
return major;
}
public int getMajor()
{
return major;
}
public int getMinor() {
return minor;
}
public int getMinor()
{
return minor;
}
/**
* Return whether this object is equal to another.
* @param o Object to compare to.
* @return Whether this object is equals to another.
*/
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
/**
* Return whether this object is equal to another.
*
* @param o Object to compare to.
* @return Whether this object is equals to another.
*/
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Version version = (Version) o;
final Version version = (Version) o;
if (beta != version.beta) return false;
if (bugfix != version.bugfix) return false;
return major == version.major && minor == version.minor;
}
if (beta != version.beta) return false;
if (bugfix != version.bugfix) return false;
return major == version.major && minor == version.minor;
}
/**
* Returns a hash code for this object.
* @return A hash code for this object.
*/
public int hashCode() {
int result;
result = major;
result = 29 * result + minor;
result = 29 * result + beta;
result = 29 * result + bugfix;
return result;
}
/**
* Returns a hash code for this object.
*
* @return A hash code for this object.
*/
public int hashCode()
{
int result;
result = major;
result = 29 * result + minor;
result = 29 * result + beta;
result = 29 * result + bugfix;
return result;
}
/**
* Returns a string representation of the form "1.27", "1.27.2" or "1.27.beta3".
* @return A string representation of the form "1.27", "1.27.2" or "1.27.beta3".
*/
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append(major).append('.').append(minor);
if (beta != 0) {
buf.append(".beta").append(beta);
} else if (bugfix != 0) {
buf.append('.').append(bugfix);
}
/**
* Returns a string representation of the form "1.27", "1.27.2" or "1.27.beta3".
*
* @return A string representation of the form "1.27", "1.27.2" or "1.27.beta3".
*/
public String toString()
{
StringBuffer buf = new StringBuffer();
buf.append(major).append('.').append(minor);
if (beta != 0)
{
buf.append(".beta").append(beta);
}
else if (bugfix != 0)
{
buf.append('.').append(bugfix);
}
return buf.toString();
}
return buf.toString();
}
/**
* Compares this object with the specified object for order.
* @param version The object to compare to.
* @return A negative integer, zero, or a positive integer as this object is less than, equal to, or
* greater than the specified object.
*/
@Override
public int compareTo(Version version) {
if (major < version.major) {
return -1;
} else if (major > version.major) {
return 1;
}
/**
* Compares this object with the specified object for order.
*
* @param version The object to compare to.
* @return A negative integer, zero, or a positive integer as this object is less than, equal to, or
* greater than the specified object.
*/
@Override
public int compareTo(Version version)
{
if (major < version.major)
{
return -1;
}
else if (major > version.major)
{
return 1;
}
if (minor < version.minor) {
return -1;
} else if (minor > version.minor) {
return 1;
}
if (minor < version.minor)
{
return -1;
}
else if (minor > version.minor)
{
return 1;
}
if (bugfix < version.bugfix) {
return -1;
} else if (bugfix > version.bugfix) {
return 1;
}
if (bugfix < version.bugfix)
{
return -1;
}
else if (bugfix > version.bugfix)
{
return 1;
}
int thisBeta = beta == 0 ? Integer.MAX_VALUE : beta;
int otherBeta = version.beta == 0 ? Integer.MAX_VALUE : version.beta;
int thisBeta = beta == 0 ? Integer.MAX_VALUE : beta;
int otherBeta = version.beta == 0 ? Integer.MAX_VALUE : version.beta;
if (thisBeta < otherBeta) {
return -1;
} else if (thisBeta > otherBeta) {
return 1;
}
if (thisBeta < otherBeta)
{
return -1;
}
else if (thisBeta > otherBeta)
{
return 1;
}
return 0;
}
return 0;
}
}

View File

@ -25,12 +25,13 @@ import android.content.SearchRecentSuggestionsProvider;
*
* @author Sindre Mehus
*/
public class SearchSuggestionProvider extends SearchRecentSuggestionsProvider {
public class SearchSuggestionProvider extends SearchRecentSuggestionsProvider
{
public static final String AUTHORITY = SearchSuggestionProvider.class.getName();
public static final int MODE = DATABASE_MODE_QUERIES;
public static final String AUTHORITY = SearchSuggestionProvider.class.getName();
public static final int MODE = DATABASE_MODE_QUERIES;
public SearchSuggestionProvider() {
setupSuggestions(AUTHORITY, MODE);
}
public SearchSuggestionProvider()
{
setupSuggestions(AUTHORITY, MODE);
}
}

View File

@ -1,13 +1,5 @@
package com.thejoshwa.ultrasonic.androidapp.provider;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.activity.DownloadActivity;
import com.thejoshwa.ultrasonic.androidapp.activity.MainActivity;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadService;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadServiceImpl;
import com.thejoshwa.ultrasonic.androidapp.util.FileUtil;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
@ -22,172 +14,212 @@ import android.util.Log;
import android.view.KeyEvent;
import android.widget.RemoteViews;
public class UltraSonicAppWidgetProvider extends AppWidgetProvider {
private final static String TAG = UltraSonicAppWidgetProvider.class.getSimpleName();
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.activity.DownloadActivity;
import com.thejoshwa.ultrasonic.androidapp.activity.MainActivity;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadService;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadServiceImpl;
import com.thejoshwa.ultrasonic.androidapp.util.FileUtil;
public class UltraSonicAppWidgetProvider extends AppWidgetProvider
{
private final static String TAG = UltraSonicAppWidgetProvider.class.getSimpleName();
protected int layoutId;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
defaultAppWidget(context, appWidgetIds);
}
/**
* Initialize given widgets to default state, where we launch UltraSonic on default click
* and hide actions if service not running.
*/
private void defaultAppWidget(Context context, int[] appWidgetIds) {
final Resources res = context.getResources();
final RemoteViews views = new RemoteViews(context.getPackageName(), this.layoutId);
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
defaultAppWidget(context, appWidgetIds);
}
views.setTextViewText(R.id.artist, res.getText(R.string.widget_initial_text));
linkButtons(context, views, false);
pushUpdate(context, appWidgetIds, views);
}
private void pushUpdate(Context context, int[] appWidgetIds, RemoteViews views) {
// Update specific list of appWidgetIds if given, otherwise default to all
final AppWidgetManager manager = AppWidgetManager.getInstance(context);
/**
* Initialize given widgets to default state, where we launch UltraSonic on default click
* and hide actions if service not running.
*/
private void defaultAppWidget(Context context, int[] appWidgetIds)
{
final Resources res = context.getResources();
final RemoteViews views = new RemoteViews(context.getPackageName(), this.layoutId);
if (manager != null) {
if (appWidgetIds != null) {
manager.updateAppWidget(appWidgetIds, views);
} else {
manager.updateAppWidget(new ComponentName(context, this.getClass()), views);
}
}
}
/**
* Handle a change notification coming over from {@link DownloadService}
*/
public void notifyChange(Context context, DownloadService service, boolean playing, boolean setAlbum) {
if (hasInstances(context)) {
performUpdate(context, service, null, playing, setAlbum);
}
}
/**
* Check against {@link AppWidgetManager} if there are any instances of this widget.
*/
private boolean hasInstances(Context context) {
AppWidgetManager manager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = new int[0];
views.setTextViewText(R.id.artist, res.getText(R.string.widget_initial_text));
if (manager != null) {
appWidgetIds = manager.getAppWidgetIds(new ComponentName(context, getClass()));
}
linkButtons(context, views, false);
pushUpdate(context, appWidgetIds, views);
}
return (appWidgetIds.length > 0);
}
/**
* Update all active widget instances by pushing changes
*/
private void performUpdate(Context context, DownloadService service, int[] appWidgetIds, boolean playing, boolean setAlbum) {
final Resources res = context.getResources();
final RemoteViews views = new RemoteViews(context.getPackageName(), this.layoutId);
private void pushUpdate(Context context, int[] appWidgetIds, RemoteViews views)
{
// Update specific list of appWidgetIds if given, otherwise default to all
final AppWidgetManager manager = AppWidgetManager.getInstance(context);
MusicDirectory.Entry currentPlaying = service.getCurrentPlaying() == null ? null : service.getCurrentPlaying().getSong();
String title = currentPlaying == null ? null : currentPlaying.getTitle();
String artist = currentPlaying == null ? null : currentPlaying.getArtist();
String album = currentPlaying == null ? null : currentPlaying.getAlbum();
CharSequence errorState = null;
if (manager != null)
{
if (appWidgetIds != null)
{
manager.updateAppWidget(appWidgetIds, views);
}
else
{
manager.updateAppWidget(new ComponentName(context, this.getClass()), views);
}
}
}
// Show error message?
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_SHARED) ||
status.equals(Environment.MEDIA_UNMOUNTED)) {
errorState = res.getText(R.string.widget_sdcard_busy);
} else if (status.equals(Environment.MEDIA_REMOVED)) {
errorState = res.getText(R.string.widget_sdcard_missing);
} else if (currentPlaying == null) {
errorState = res.getText(R.string.widget_initial_text);
}
/**
* Handle a change notification coming over from {@link DownloadService}
*/
public void notifyChange(Context context, DownloadService service, boolean playing, boolean setAlbum)
{
if (hasInstances(context))
{
performUpdate(context, service, null, playing, setAlbum);
}
}
if (errorState != null) {
// Show error state to user
views.setTextViewText(R.id.title, null);
views.setTextViewText(R.id.artist, errorState);
if (setAlbum) {
views.setTextViewText(R.id.album, null);
}
views.setImageViewResource(R.id.appwidget_coverart, R.drawable.appwidget_art_default);
} else {
// No error, so show normal titles
views.setTextViewText(R.id.title, title);
views.setTextViewText(R.id.artist, artist);
if (setAlbum) {
views.setTextViewText(R.id.album, album);
}
}
/**
* Check against {@link AppWidgetManager} if there are any instances of this widget.
*/
private boolean hasInstances(Context context)
{
AppWidgetManager manager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = new int[0];
// Set correct drawable for pause state
if (playing) {
views.setImageViewResource(R.id.control_play, R.drawable.media_pause_normal_dark);
} else {
views.setImageViewResource(R.id.control_play, R.drawable.media_start_normal_dark);
}
if (manager != null)
{
appWidgetIds = manager.getAppWidgetIds(new ComponentName(context, getClass()));
}
// Set the cover art
try {
int size;
Resources resources = context.getResources();
Drawable drawable = resources.getDrawable(R.drawable.appwidget_art_default);
size = drawable != null ? drawable.getIntrinsicHeight() : 0;
return (appWidgetIds.length > 0);
}
Bitmap bitmap = currentPlaying == null ? null : FileUtil.getAlbumArtBitmap(context, currentPlaying, size, true);
/**
* Update all active widget instances by pushing changes
*/
private void performUpdate(Context context, DownloadService service, int[] appWidgetIds, boolean playing, boolean setAlbum)
{
final Resources res = context.getResources();
final RemoteViews views = new RemoteViews(context.getPackageName(), this.layoutId);
if (bitmap == null) {
// Set default cover art
views.setImageViewResource(R.id.appwidget_coverart, R.drawable.appwidget_art_default);
} else {
//bitmap = getRoundedCornerBitmap(bitmap);
views.setImageViewBitmap(R.id.appwidget_coverart, bitmap);
}
} catch (Exception x) {
Log.e(TAG, "Failed to load cover art", x);
views.setImageViewResource(R.id.appwidget_coverart, R.drawable.appwidget_art_default);
}
MusicDirectory.Entry currentPlaying = service.getCurrentPlaying() == null ? null : service.getCurrentPlaying().getSong();
String title = currentPlaying == null ? null : currentPlaying.getTitle();
String artist = currentPlaying == null ? null : currentPlaying.getArtist();
String album = currentPlaying == null ? null : currentPlaying.getAlbum();
CharSequence errorState = null;
// Link actions buttons to intents
linkButtons(context, views, currentPlaying != null);
// Show error message?
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_SHARED) || status.equals(Environment.MEDIA_UNMOUNTED))
{
errorState = res.getText(R.string.widget_sdcard_busy);
}
else if (status.equals(Environment.MEDIA_REMOVED))
{
errorState = res.getText(R.string.widget_sdcard_missing);
}
else if (currentPlaying == null)
{
errorState = res.getText(R.string.widget_initial_text);
}
pushUpdate(context, appWidgetIds, views);
}
/**
* Link up various button actions using {@link PendingIntent}.
*
* @param playerActive True if player is active in background, which means
* widget click will launch {@link DownloadActivity},
* otherwise we launch {@link MainActivity}.
*/
private void linkButtons(Context context, RemoteViews views, boolean playerActive) {
if (errorState != null)
{
// Show error state to user
views.setTextViewText(R.id.title, null);
views.setTextViewText(R.id.artist, errorState);
if (setAlbum)
{
views.setTextViewText(R.id.album, null);
}
views.setImageViewResource(R.id.appwidget_coverart, R.drawable.appwidget_art_default);
}
else
{
// No error, so show normal titles
views.setTextViewText(R.id.title, title);
views.setTextViewText(R.id.artist, artist);
if (setAlbum)
{
views.setTextViewText(R.id.album, album);
}
}
Intent intent = new Intent(context, playerActive ? DownloadActivity.class : MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.appwidget_coverart, pendingIntent);
views.setOnClickPendingIntent(R.id.appwidget_top, pendingIntent);
// Emulate media button clicks.
intent = new Intent("1");
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.control_play, pendingIntent);
// Set correct drawable for pause state
if (playing)
{
views.setImageViewResource(R.id.control_play, R.drawable.media_pause_normal_dark);
}
else
{
views.setImageViewResource(R.id.control_play, R.drawable.media_start_normal_dark);
}
intent = new Intent("2"); // Use a unique action name to ensure a different PendingIntent to be created.
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT));
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.control_next, pendingIntent);
intent = new Intent("3"); // Use a unique action name to ensure a different PendingIntent to be created.
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS));
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.control_previous, pendingIntent);
}
// Set the cover art
try
{
int size;
Resources resources = context.getResources();
Drawable drawable = resources.getDrawable(R.drawable.appwidget_art_default);
size = drawable != null ? drawable.getIntrinsicHeight() : 0;
Bitmap bitmap = currentPlaying == null ? null : FileUtil.getAlbumArtBitmap(context, currentPlaying, size, true);
if (bitmap == null)
{
// Set default cover art
views.setImageViewResource(R.id.appwidget_coverart, R.drawable.appwidget_art_default);
}
else
{
//bitmap = getRoundedCornerBitmap(bitmap);
views.setImageViewBitmap(R.id.appwidget_coverart, bitmap);
}
}
catch (Exception x)
{
Log.e(TAG, "Failed to load cover art", x);
views.setImageViewResource(R.id.appwidget_coverart, R.drawable.appwidget_art_default);
}
// Link actions buttons to intents
linkButtons(context, views, currentPlaying != null);
pushUpdate(context, appWidgetIds, views);
}
/**
* Link up various button actions using {@link PendingIntent}.
*
* @param playerActive True if player is active in background, which means
* widget click will launch {@link DownloadActivity},
* otherwise we launch {@link MainActivity}.
*/
private static void linkButtons(Context context, RemoteViews views, boolean playerActive)
{
Intent intent = new Intent(context, playerActive ? DownloadActivity.class : MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.appwidget_coverart, pendingIntent);
views.setOnClickPendingIntent(R.id.appwidget_top, pendingIntent);
// Emulate media button clicks.
intent = new Intent("1");
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.control_play, pendingIntent);
intent = new Intent("2"); // Use a unique action name to ensure a different PendingIntent to be created.
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT));
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.control_next, pendingIntent);
intent = new Intent("3"); // Use a unique action name to ensure a different PendingIntent to be created.
intent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS));
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.control_previous, pendingIntent);
}
}

View File

@ -20,19 +20,23 @@ package com.thejoshwa.ultrasonic.androidapp.provider;
import com.thejoshwa.ultrasonic.androidapp.R;
public class UltraSonicAppWidgetProvider4x1 extends UltraSonicAppWidgetProvider {
public class UltraSonicAppWidgetProvider4x1 extends UltraSonicAppWidgetProvider
{
public UltraSonicAppWidgetProvider4x1() {
public UltraSonicAppWidgetProvider4x1()
{
super();
this.layoutId = R.layout.appwidget4x1;
}
private static UltraSonicAppWidgetProvider4x1 instance;
public static synchronized UltraSonicAppWidgetProvider4x1 getInstance() {
if (instance == null) {
instance = new UltraSonicAppWidgetProvider4x1();
}
return instance;
}
public static synchronized UltraSonicAppWidgetProvider4x1 getInstance()
{
if (instance == null)
{
instance = new UltraSonicAppWidgetProvider4x1();
}
return instance;
}
}

View File

@ -20,19 +20,23 @@ package com.thejoshwa.ultrasonic.androidapp.provider;
import com.thejoshwa.ultrasonic.androidapp.R;
public class UltraSonicAppWidgetProvider4x2 extends UltraSonicAppWidgetProvider {
public class UltraSonicAppWidgetProvider4x2 extends UltraSonicAppWidgetProvider
{
public UltraSonicAppWidgetProvider4x2() {
public UltraSonicAppWidgetProvider4x2()
{
super();
this.layoutId = R.layout.appwidget4x2;
}
private static UltraSonicAppWidgetProvider4x2 instance;
public static synchronized UltraSonicAppWidgetProvider4x2 getInstance() {
if (instance == null) {
instance = new UltraSonicAppWidgetProvider4x2();
}
return instance;
}
public static synchronized UltraSonicAppWidgetProvider4x2 getInstance()
{
if (instance == null)
{
instance = new UltraSonicAppWidgetProvider4x2();
}
return instance;
}
}

View File

@ -20,19 +20,23 @@ package com.thejoshwa.ultrasonic.androidapp.provider;
import com.thejoshwa.ultrasonic.androidapp.R;
public class UltraSonicAppWidgetProvider4x3 extends UltraSonicAppWidgetProvider {
public class UltraSonicAppWidgetProvider4x3 extends UltraSonicAppWidgetProvider
{
public UltraSonicAppWidgetProvider4x3() {
public UltraSonicAppWidgetProvider4x3()
{
super();
this.layoutId = R.layout.appwidget4x3;
}
private static UltraSonicAppWidgetProvider4x3 instance;
public static synchronized UltraSonicAppWidgetProvider4x3 getInstance() {
if (instance == null) {
instance = new UltraSonicAppWidgetProvider4x3();
}
return instance;
}
public static synchronized UltraSonicAppWidgetProvider4x3 getInstance()
{
if (instance == null)
{
instance = new UltraSonicAppWidgetProvider4x3();
}
return instance;
}
}

View File

@ -20,19 +20,23 @@ package com.thejoshwa.ultrasonic.androidapp.provider;
import com.thejoshwa.ultrasonic.androidapp.R;
public class UltraSonicAppWidgetProvider4x4 extends UltraSonicAppWidgetProvider {
public class UltraSonicAppWidgetProvider4x4 extends UltraSonicAppWidgetProvider
{
public UltraSonicAppWidgetProvider4x4() {
public UltraSonicAppWidgetProvider4x4()
{
super();
this.layoutId = R.layout.appwidget4x4;
}
private static UltraSonicAppWidgetProvider4x4 instance;
public static synchronized UltraSonicAppWidgetProvider4x4 getInstance() {
if (instance == null) {
instance = new UltraSonicAppWidgetProvider4x4();
}
return instance;
}
public static synchronized UltraSonicAppWidgetProvider4x4 getInstance()
{
if (instance == null)
{
instance = new UltraSonicAppWidgetProvider4x4();
}
return instance;
}
}

View File

@ -1,32 +1,38 @@
package com.thejoshwa.ultrasonic.androidapp.receiver;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory.Entry;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadService;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadServiceImpl;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class A2dpIntentReceiver extends BroadcastReceiver {
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory.Entry;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadService;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadServiceImpl;
public class A2dpIntentReceiver extends BroadcastReceiver
{
private static final String PLAYSTATUS_RESPONSE = "com.android.music.playstatusresponse";
@Override
public void onReceive(Context context, Intent intent) {
public void onReceive(Context context, Intent intent)
{
DownloadService downloadService = DownloadServiceImpl.getInstance();
if (downloadService == null) {
if (downloadService == null)
{
return;
}
if (downloadService.getCurrentPlaying() == null) {
if (downloadService.getCurrentPlaying() == null)
{
return;
}
Entry song = downloadService.getCurrentPlaying().getSong();
if (song == null) {
if (song == null)
{
return;
}
@ -36,30 +42,32 @@ public class A2dpIntentReceiver extends BroadcastReceiver {
Integer playerPosition = downloadService.getPlayerPosition();
Integer listSize = downloadService.getDownloads().size();
if (duration != null) {
if (duration != null)
{
avrcpIntent.putExtra("duration", (long) duration);
}
avrcpIntent.putExtra("position", (long) playerPosition);
avrcpIntent.putExtra("ListSize", (long) listSize);
avrcpIntent.putExtra("position", (long) playerPosition);
avrcpIntent.putExtra("ListSize", (long) listSize);
switch (downloadService.getPlayerState()) {
case STARTED:
avrcpIntent.putExtra("playing", true);
break;
case STOPPED:
avrcpIntent.putExtra("playing", false);
break;
case PAUSED:
avrcpIntent.putExtra("playing", false);
break;
case COMPLETED:
avrcpIntent.putExtra("playing", false);
break;
default:
return;
switch (downloadService.getPlayerState())
{
case STARTED:
avrcpIntent.putExtra("playing", true);
break;
case STOPPED:
avrcpIntent.putExtra("playing", false);
break;
case PAUSED:
avrcpIntent.putExtra("playing", false);
break;
case COMPLETED:
avrcpIntent.putExtra("playing", false);
break;
default:
return;
}
context.sendBroadcast(avrcpIntent);
}
}

View File

@ -22,45 +22,55 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadServiceImpl;
import com.thejoshwa.ultrasonic.androidapp.util.Util;
/**
* Request media button focus when connected to Bluetooth A2DP.
*
*
* @author Sindre Mehus
*/
public class BluetoothIntentReceiver extends BroadcastReceiver {
public class BluetoothIntentReceiver extends BroadcastReceiver
{
private static final String TAG = BluetoothIntentReceiver.class.getSimpleName();
@Override
public void onReceive(Context context, Intent intent) {
public void onReceive(Context context, Intent intent)
{
int state = intent.getIntExtra("android.bluetooth.a2dp.extra.SINK_STATE", -1);
String action = intent.getAction();
Log.d(TAG, "Bluetooth Sink State: " + state);
Log.d(TAG, "Bluetooth Action: " + action);
boolean actionConnected = false;
boolean actionDisconnected = false;
boolean actionConnected = false;
boolean actionDisconnected = false;
if (action != null) {
if (action.equals(android.bluetooth.BluetoothDevice.ACTION_ACL_CONNECTED)) {
actionConnected = true;
if (action != null)
{
if (action.equals(android.bluetooth.BluetoothDevice.ACTION_ACL_CONNECTED))
{
actionConnected = true;
} else if (action.equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECTED) || action.equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED)) {
actionDisconnected = true;
}
}
}
else if (action.equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECTED) || action.equals(android.bluetooth.BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED))
{
actionDisconnected = true;
}
}
boolean connected = state == android.bluetooth.BluetoothA2dp.STATE_CONNECTED || actionConnected;
boolean disconnected = state == android.bluetooth.BluetoothA2dp.STATE_DISCONNECTED || actionDisconnected;
if (connected) {
if (connected)
{
Log.i(TAG, "Connected to Bluetooth A2DP, requesting media button focus.");
Util.registerMediaButtonEventReceiver(context);
} else if (disconnected) {
}
else if (disconnected)
{
Log.i(TAG, "Disconnected from Bluetooth A2DP, requesting pause.");
context.sendBroadcast(new Intent(DownloadServiceImpl.CMD_PAUSE));
}

View File

@ -24,44 +24,52 @@ import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadServiceImpl;
import com.thejoshwa.ultrasonic.androidapp.util.Util;
/**
* @author Sindre Mehus
*/
public class MediaButtonIntentReceiver extends BroadcastReceiver {
public class MediaButtonIntentReceiver extends BroadcastReceiver
{
private static final String TAG = MediaButtonIntentReceiver.class.getSimpleName();
private static final String TAG = MediaButtonIntentReceiver.class.getSimpleName();
@Override
public void onReceive(Context context, Intent intent) {
if (Util.getMediaButtonsPreference(context)) {
String intentAction = intent.getAction();
@Override
public void onReceive(Context context, Intent intent)
{
if (Util.getMediaButtonsPreference(context))
{
String intentAction = intent.getAction();
if (!Intent.ACTION_MEDIA_BUTTON.equals(intentAction))
return;
if (!Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) return;
Bundle extras = intent.getExtras();
Bundle extras = intent.getExtras();
if (extras == null) {
return;
}
if (extras == null)
{
return;
}
KeyEvent event = (KeyEvent) extras.get(Intent.EXTRA_KEY_EVENT);
Log.i(TAG, "Got MEDIA_BUTTON key event: " + event);
KeyEvent event = (KeyEvent) extras.get(Intent.EXTRA_KEY_EVENT);
Log.i(TAG, "Got MEDIA_BUTTON key event: " + event);
Intent serviceIntent = new Intent(context, DownloadServiceImpl.class);
serviceIntent.putExtra(Intent.EXTRA_KEY_EVENT, event);
context.startService(serviceIntent);
Intent serviceIntent = new Intent(context, DownloadServiceImpl.class);
serviceIntent.putExtra(Intent.EXTRA_KEY_EVENT, event);
context.startService(serviceIntent);
try {
if (isOrderedBroadcast()) {
abortBroadcast();
}
} catch (Exception x) {
// Ignored.
}
}
}
try
{
if (isOrderedBroadcast())
{
abortBroadcast();
}
}
catch (Exception x)
{
// Ignored.
}
}
}
}

View File

@ -18,11 +18,6 @@
*/
package com.thejoshwa.ultrasonic.androidapp.service;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpResponse;
import android.content.Context;
import android.graphics.Bitmap;
@ -46,359 +41,427 @@ import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import com.thejoshwa.ultrasonic.androidapp.util.TimeLimitedCache;
import com.thejoshwa.ultrasonic.androidapp.util.Util;
import org.apache.http.HttpResponse;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @author Sindre Mehus
*/
public class CachedMusicService implements MusicService {
public class CachedMusicService implements MusicService
{
private static final int MUSIC_DIR_CACHE_SIZE = 100;
private static final int MUSIC_DIR_CACHE_SIZE = 100;
private final MusicService musicService;
private final LRUCache<String, TimeLimitedCache<MusicDirectory>> cachedMusicDirectories;
private final LRUCache<String, TimeLimitedCache<MusicDirectory>> cachedArtist;
private final LRUCache<String, TimeLimitedCache<MusicDirectory>> cachedAlbum;
private final TimeLimitedCache<Boolean> cachedLicenseValid = new TimeLimitedCache<Boolean>(120, TimeUnit.SECONDS);
private final TimeLimitedCache<Indexes> cachedIndexes = new TimeLimitedCache<Indexes>(60 * 60, TimeUnit.SECONDS);
private final TimeLimitedCache<Indexes> cachedArtists = new TimeLimitedCache<Indexes>(60 * 60, TimeUnit.SECONDS);
private final TimeLimitedCache<List<Playlist>> cachedPlaylists = new TimeLimitedCache<List<Playlist>>(3600, TimeUnit.SECONDS);
private final TimeLimitedCache<List<MusicFolder>> cachedMusicFolders = new TimeLimitedCache<List<MusicFolder>>(10 * 3600, TimeUnit.SECONDS);
private final TimeLimitedCache<List<Genre>> cachedGenres = new TimeLimitedCache<List<Genre>>(10 * 3600, TimeUnit.SECONDS);
private String restUrl;
private final MusicService musicService;
private final LRUCache<String, TimeLimitedCache<MusicDirectory>> cachedMusicDirectories;
private final LRUCache<String, TimeLimitedCache<MusicDirectory>> cachedArtist;
private final LRUCache<String, TimeLimitedCache<MusicDirectory>> cachedAlbum;
private final TimeLimitedCache<Boolean> cachedLicenseValid = new TimeLimitedCache<Boolean>(120, TimeUnit.SECONDS);
private final TimeLimitedCache<Indexes> cachedIndexes = new TimeLimitedCache<Indexes>(60 * 60, TimeUnit.SECONDS);
private final TimeLimitedCache<Indexes> cachedArtists = new TimeLimitedCache<Indexes>(60 * 60, TimeUnit.SECONDS);
private final TimeLimitedCache<List<Playlist>> cachedPlaylists = new TimeLimitedCache<List<Playlist>>(3600, TimeUnit.SECONDS);
private final TimeLimitedCache<List<MusicFolder>> cachedMusicFolders = new TimeLimitedCache<List<MusicFolder>>(10 * 3600, TimeUnit.SECONDS);
private final TimeLimitedCache<List<Genre>> cachedGenres = new TimeLimitedCache<List<Genre>>(10 * 3600, TimeUnit.SECONDS);
public CachedMusicService(MusicService musicService) {
this.musicService = musicService;
cachedMusicDirectories = new LRUCache<String, TimeLimitedCache<MusicDirectory>>(MUSIC_DIR_CACHE_SIZE);
cachedArtist = new LRUCache<String, TimeLimitedCache<MusicDirectory>>(MUSIC_DIR_CACHE_SIZE);
cachedAlbum = new LRUCache<String, TimeLimitedCache<MusicDirectory>>(MUSIC_DIR_CACHE_SIZE);
}
private String restUrl;
@Override
public void ping(Context context, ProgressListener progressListener) throws Exception {
checkSettingsChanged(context);
musicService.ping(context, progressListener);
}
@Override
public boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception {
checkSettingsChanged(context);
Boolean result = cachedLicenseValid.get();
if (result == null) {
result = musicService.isLicenseValid(context, progressListener);
cachedLicenseValid.set(result, result ? 30L * 60L : 2L * 60L, TimeUnit.SECONDS);
}
return result;
}
@Override
public List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
checkSettingsChanged(context);
if (refresh) {
cachedMusicFolders.clear();
}
List<MusicFolder> result = cachedMusicFolders.get();
if (result == null) {
result = musicService.getMusicFolders(refresh, context, progressListener);
cachedMusicFolders.set(result);
}
return result;
}
@Override
public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
checkSettingsChanged(context);
if (refresh) {
cachedIndexes.clear();
cachedMusicFolders.clear();
cachedMusicDirectories.clear();
}
Indexes result = cachedIndexes.get();
if (result == null) {
result = musicService.getIndexes(musicFolderId, refresh, context, progressListener);
cachedIndexes.set(result);
}
return result;
}
@Override
public Indexes getArtists(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
checkSettingsChanged(context);
if (refresh) {
cachedArtists.clear();
}
Indexes result = cachedArtists.get();
if (result == null) {
result = musicService.getArtists(refresh, context, progressListener);
cachedArtists.set(result);
}
return result;
}
@Override
public MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
checkSettingsChanged(context);
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedMusicDirectories.get(id);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null) {
dir = musicService.getMusicDirectory(id, name, refresh, context, progressListener);
cache = new TimeLimitedCache<MusicDirectory>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
cache.set(dir);
cachedMusicDirectories.put(id, cache);
}
return dir;
}
@Override
public MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
checkSettingsChanged(context);
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedArtist.get(id);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null) {
dir = musicService.getArtist(id, name, refresh, context, progressListener);
cache = new TimeLimitedCache<MusicDirectory>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
cache.set(dir);
cachedArtist.put(id, cache);
}
return dir;
}
@Override
public MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
checkSettingsChanged(context);
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedAlbum.get(id);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null) {
dir = musicService.getAlbum(id, name, refresh, context, progressListener);
cache = new TimeLimitedCache<MusicDirectory>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
cache.set(dir);
cachedAlbum.put(id, cache);
}
return dir;
}
@Override
public SearchResult search(SearchCriteria criteria, Context context, ProgressListener progressListener) throws Exception {
return musicService.search(criteria, context, progressListener);
}
@Override
public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception {
return musicService.getPlaylist(id, name, context, progressListener);
}
@Override
public List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
checkSettingsChanged(context);
List<Playlist> result = refresh ? null : cachedPlaylists.get();
if (result == null) {
result = musicService.getPlaylists(refresh, context, progressListener);
cachedPlaylists.set(result);
}
return result;
}
@Override
public void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception {
cachedPlaylists.clear();
musicService.createPlaylist(id, name, entries, context, progressListener);
}
public CachedMusicService(MusicService musicService)
{
this.musicService = musicService;
cachedMusicDirectories = new LRUCache<String, TimeLimitedCache<MusicDirectory>>(MUSIC_DIR_CACHE_SIZE);
cachedArtist = new LRUCache<String, TimeLimitedCache<MusicDirectory>>(MUSIC_DIR_CACHE_SIZE);
cachedAlbum = new LRUCache<String, TimeLimitedCache<MusicDirectory>>(MUSIC_DIR_CACHE_SIZE);
}
@Override
public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception {
public void ping(Context context, ProgressListener progressListener) throws Exception
{
checkSettingsChanged(context);
musicService.ping(context, progressListener);
}
@Override
public boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception
{
checkSettingsChanged(context);
Boolean result = cachedLicenseValid.get();
if (result == null)
{
result = musicService.isLicenseValid(context, progressListener);
cachedLicenseValid.set(result, result ? 30L * 60L : 2L * 60L, TimeUnit.SECONDS);
}
return result;
}
@Override
public List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception
{
checkSettingsChanged(context);
if (refresh)
{
cachedMusicFolders.clear();
}
List<MusicFolder> result = cachedMusicFolders.get();
if (result == null)
{
result = musicService.getMusicFolders(refresh, context, progressListener);
cachedMusicFolders.set(result);
}
return result;
}
@Override
public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception
{
checkSettingsChanged(context);
if (refresh)
{
cachedIndexes.clear();
cachedMusicFolders.clear();
cachedMusicDirectories.clear();
}
Indexes result = cachedIndexes.get();
if (result == null)
{
result = musicService.getIndexes(musicFolderId, refresh, context, progressListener);
cachedIndexes.set(result);
}
return result;
}
@Override
public Indexes getArtists(boolean refresh, Context context, ProgressListener progressListener) throws Exception
{
checkSettingsChanged(context);
if (refresh)
{
cachedArtists.clear();
}
Indexes result = cachedArtists.get();
if (result == null)
{
result = musicService.getArtists(refresh, context, progressListener);
cachedArtists.set(result);
}
return result;
}
@Override
public MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception
{
checkSettingsChanged(context);
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedMusicDirectories.get(id);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null)
{
dir = musicService.getMusicDirectory(id, name, refresh, context, progressListener);
cache = new TimeLimitedCache<MusicDirectory>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
cache.set(dir);
cachedMusicDirectories.put(id, cache);
}
return dir;
}
@Override
public MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception
{
checkSettingsChanged(context);
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedArtist.get(id);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null)
{
dir = musicService.getArtist(id, name, refresh, context, progressListener);
cache = new TimeLimitedCache<MusicDirectory>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
cache.set(dir);
cachedArtist.put(id, cache);
}
return dir;
}
@Override
public MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception
{
checkSettingsChanged(context);
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedAlbum.get(id);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null)
{
dir = musicService.getAlbum(id, name, refresh, context, progressListener);
cache = new TimeLimitedCache<MusicDirectory>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
cache.set(dir);
cachedAlbum.put(id, cache);
}
return dir;
}
@Override
public SearchResult search(SearchCriteria criteria, Context context, ProgressListener progressListener) throws Exception
{
return musicService.search(criteria, context, progressListener);
}
@Override
public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception
{
return musicService.getPlaylist(id, name, context, progressListener);
}
@Override
public List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception
{
checkSettingsChanged(context);
List<Playlist> result = refresh ? null : cachedPlaylists.get();
if (result == null)
{
result = musicService.getPlaylists(refresh, context, progressListener);
cachedPlaylists.set(result);
}
return result;
}
@Override
public void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception
{
cachedPlaylists.clear();
musicService.createPlaylist(id, name, entries, context, progressListener);
}
@Override
public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception
{
musicService.deletePlaylist(id, context, progressListener);
}
@Override
public void updatePlaylist(String id, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception {
public void updatePlaylist(String id, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception
{
musicService.updatePlaylist(id, toAdd, context, progressListener);
}
@Override
public void removeFromPlaylist(String id, List<Integer> toRemove, Context context, ProgressListener progressListener) throws Exception {
public void removeFromPlaylist(String id, List<Integer> toRemove, Context context, ProgressListener progressListener) throws Exception
{
musicService.removeFromPlaylist(id, toRemove, context, progressListener);
}
@Override
public void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception {
public void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception
{
musicService.updatePlaylist(id, name, comment, pub, context, progressListener);
}
@Override
public Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception {
return musicService.getLyrics(artist, title, context, progressListener);
}
@Override
public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception {
musicService.scrobble(id, submission, context, progressListener);
}
@Override
public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception {
return musicService.getAlbumList(type, size, offset, context, progressListener);
}
@Override
public MusicDirectory getAlbumList2(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception {
return musicService.getAlbumList2(type, size, offset, context, progressListener);
}
@Override
public MusicDirectory getRandomSongs(int size, Context context, ProgressListener progressListener) throws Exception {
return musicService.getRandomSongs(size, context, progressListener);
}
@Override
public SearchResult getStarred(Context context, ProgressListener progressListener) throws Exception {
return musicService.getStarred(context, progressListener);
}
@Override
public SearchResult getStarred2(Context context, ProgressListener progressListener) throws Exception {
return musicService.getStarred2(context, progressListener);
}
@Override
public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception {
return musicService.getCoverArt(context, entry, size, saveToFile, highQuality, progressListener);
}
@Override
public HttpResponse getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, CancellableTask task) throws Exception {
return musicService.getDownloadInputStream(context, song, offset, maxBitrate, task);
}
@Override
public Version getLocalVersion(Context context) throws Exception {
return musicService.getLocalVersion(context);
}
@Override
public Version getLatestVersion(Context context, ProgressListener progressListener) throws Exception {
return musicService.getLatestVersion(context, progressListener);
}
@Override
public String getVideoUrl(Context context, String id, boolean useFlash) throws Exception {
public Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception
{
return musicService.getLyrics(artist, title, context, progressListener);
}
@Override
public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception
{
musicService.scrobble(id, submission, context, progressListener);
}
@Override
public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception
{
return musicService.getAlbumList(type, size, offset, context, progressListener);
}
@Override
public MusicDirectory getAlbumList2(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception
{
return musicService.getAlbumList2(type, size, offset, context, progressListener);
}
@Override
public MusicDirectory getRandomSongs(int size, Context context, ProgressListener progressListener) throws Exception
{
return musicService.getRandomSongs(size, context, progressListener);
}
@Override
public SearchResult getStarred(Context context, ProgressListener progressListener) throws Exception
{
return musicService.getStarred(context, progressListener);
}
@Override
public SearchResult getStarred2(Context context, ProgressListener progressListener) throws Exception
{
return musicService.getStarred2(context, progressListener);
}
@Override
public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception
{
return musicService.getCoverArt(context, entry, size, saveToFile, highQuality, progressListener);
}
@Override
public HttpResponse getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, CancellableTask task) throws Exception
{
return musicService.getDownloadInputStream(context, song, offset, maxBitrate, task);
}
@Override
public Version getLocalVersion(Context context) throws Exception
{
return musicService.getLocalVersion(context);
}
@Override
public Version getLatestVersion(Context context, ProgressListener progressListener) throws Exception
{
return musicService.getLatestVersion(context, progressListener);
}
@Override
public String getVideoUrl(Context context, String id, boolean useFlash) throws Exception
{
return musicService.getVideoUrl(context, id, useFlash);
}
@Override
public String getVideoStreamUrl(int maxBitrate, Context context, String id) {
return musicService.getVideoStreamUrl(maxBitrate, context, id);
}
@Override
public JukeboxStatus updateJukeboxPlaylist(List<String> ids, Context context, ProgressListener progressListener) throws Exception {
return musicService.updateJukeboxPlaylist(ids, context, progressListener);
}
@Override
public JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception {
return musicService.skipJukebox(index, offsetSeconds, context, progressListener);
}
@Override
public JukeboxStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception {
return musicService.stopJukebox(context, progressListener);
}
@Override
public JukeboxStatus startJukebox(Context context, ProgressListener progressListener) throws Exception {
return musicService.startJukebox(context, progressListener);
}
@Override
public JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception {
return musicService.getJukeboxStatus(context, progressListener);
}
@Override
public JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception {
return musicService.setJukeboxGain(gain, context, progressListener);
}
private void checkSettingsChanged(Context context) {
String newUrl = Util.getRestUrl(context, null);
if (!Util.equals(newUrl, restUrl)) {
cachedMusicFolders.clear();
cachedMusicDirectories.clear();
cachedLicenseValid.clear();
cachedIndexes.clear();
cachedPlaylists.clear();
restUrl = newUrl;
}
}
@Override
public void star(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception {
musicService.star(id, albumId, artistId, context, progressListener);
public String getVideoStreamUrl(int maxBitrate, Context context, String id)
{
return musicService.getVideoStreamUrl(maxBitrate, context, id);
}
@Override
public void unstar(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception {
public JukeboxStatus updateJukeboxPlaylist(List<String> ids, Context context, ProgressListener progressListener) throws Exception
{
return musicService.updateJukeboxPlaylist(ids, context, progressListener);
}
@Override
public JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception
{
return musicService.skipJukebox(index, offsetSeconds, context, progressListener);
}
@Override
public JukeboxStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception
{
return musicService.stopJukebox(context, progressListener);
}
@Override
public JukeboxStatus startJukebox(Context context, ProgressListener progressListener) throws Exception
{
return musicService.startJukebox(context, progressListener);
}
@Override
public JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception
{
return musicService.getJukeboxStatus(context, progressListener);
}
@Override
public JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception
{
return musicService.setJukeboxGain(gain, context, progressListener);
}
private void checkSettingsChanged(Context context)
{
String newUrl = Util.getRestUrl(context, null);
if (!Util.equals(newUrl, restUrl))
{
cachedMusicFolders.clear();
cachedMusicDirectories.clear();
cachedLicenseValid.clear();
cachedIndexes.clear();
cachedPlaylists.clear();
restUrl = newUrl;
}
}
@Override
public void star(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception
{
musicService.star(id, albumId, artistId, context, progressListener);
}
@Override
public void unstar(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception
{
musicService.unstar(id, albumId, artistId, context, progressListener);
}
@Override
public List<Genre> getGenres(Context context, ProgressListener progressListener) throws Exception {
checkSettingsChanged(context);
List<Genre> result = cachedGenres.get();
if (result == null) {
result = musicService.getGenres(context, progressListener);
cachedGenres.set(result);
}
return result;
public List<Genre> getGenres(Context context, ProgressListener progressListener) throws Exception
{
checkSettingsChanged(context);
List<Genre> result = cachedGenres.get();
if (result == null)
{
result = musicService.getGenres(context, progressListener);
cachedGenres.set(result);
}
return result;
}
@Override
public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception {
public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception
{
return musicService.getSongsByGenre(genre, count, offset, context, progressListener);
}
@Override
public List<Share> getShares(Context context, ProgressListener progressListener) throws Exception {
return musicService.getShares(context, progressListener);
public List<Share> getShares(Context context, ProgressListener progressListener) throws Exception
{
return musicService.getShares(context, progressListener);
}
@Override
public List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception {
public List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception
{
return musicService.getChatMessages(since, context, progressListener);
}
@Override
public void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception {
public void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception
{
musicService.addChatMessage(message, context, progressListener);
}
@Override
public List<Bookmark> getBookmarks(Context context, ProgressListener progressListener) throws Exception {
public List<Bookmark> getBookmarks(Context context, ProgressListener progressListener) throws Exception
{
return musicService.getBookmarks(context, progressListener);
}
@Override
public void deleteBookmark(String id, Context context, ProgressListener progressListener) throws Exception {
public void deleteBookmark(String id, Context context, ProgressListener progressListener) throws Exception
{
musicService.deleteBookmark(id, context, progressListener);
}
@Override
public void createBookmark(String id, int position, Context context, ProgressListener progressListener) throws Exception {
public void createBookmark(String id, int position, Context context, ProgressListener progressListener) throws Exception
{
musicService.createBookmark(id, position, context, progressListener);
}
@Override
public MusicDirectory getVideos(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
public MusicDirectory getVideos(boolean refresh, Context context, ProgressListener progressListener) throws Exception
{
checkSettingsChanged(context);
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedMusicDirectories.get(Constants.INTENT_EXTRA_NAME_VIDEOS);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null) {
if (dir == null)
{
dir = musicService.getVideos(refresh, context, progressListener);
cache = new TimeLimitedCache<MusicDirectory>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
cache.set(dir);

View File

@ -18,281 +18,369 @@
*/
package com.thejoshwa.ultrasonic.androidapp.service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.os.PowerManager;
import android.util.Log;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import com.thejoshwa.ultrasonic.androidapp.util.CacheCleaner;
import com.thejoshwa.ultrasonic.androidapp.util.CancellableTask;
import com.thejoshwa.ultrasonic.androidapp.util.FileUtil;
import com.thejoshwa.ultrasonic.androidapp.util.Util;
import com.thejoshwa.ultrasonic.androidapp.util.CacheCleaner;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.Header;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import static android.content.Context.POWER_SERVICE;
import static android.os.PowerManager.ON_AFTER_RELEASE;
import static android.os.PowerManager.SCREEN_DIM_WAKE_LOCK;
/**
* @author Sindre Mehus
* @version $Id$
*/
public class DownloadFile {
public class DownloadFile
{
private static final String TAG = DownloadFile.class.getSimpleName();
private final Context context;
private final MusicDirectory.Entry song;
private final File partialFile;
private final File completeFile;
private final File saveFile;
private static final String TAG = DownloadFile.class.getSimpleName();
private final Context context;
private final MusicDirectory.Entry song;
private final File partialFile;
private final File completeFile;
private final File saveFile;
private final MediaStoreService mediaStoreService;
private CancellableTask downloadTask;
private boolean save;
private boolean failed;
private int bitRate;
private volatile boolean isPlaying = false;
private volatile boolean saveWhenDone = false;
private volatile boolean completeWhenDone = false;
private Integer contentLength = null;
private final MediaStoreService mediaStoreService;
private CancellableTask downloadTask;
private boolean save;
private boolean failed;
private int bitRate;
private volatile boolean isPlaying;
private volatile boolean saveWhenDone;
private volatile boolean completeWhenDone;
private Integer contentLength;
public DownloadFile(Context context, MusicDirectory.Entry song, boolean save) {
this.context = context;
this.song = song;
this.save = save;
saveFile = FileUtil.getSongFile(context, song);
bitRate = Util.getMaxBitRate(context);
partialFile = new File(saveFile.getParent(), FileUtil.getBaseName(saveFile.getName()) + ".partial." + FileUtil.getExtension(saveFile.getName()));
completeFile = new File(saveFile.getParent(), FileUtil.getBaseName(saveFile.getName()) + ".complete." + FileUtil.getExtension(saveFile.getName()));
mediaStoreService = new MediaStoreService(context);
}
public DownloadFile(Context context, MusicDirectory.Entry song, boolean save)
{
super();
this.context = context;
this.song = song;
this.save = save;
public MusicDirectory.Entry getSong() {
return song;
}
saveFile = FileUtil.getSongFile(context, song);
bitRate = Util.getMaxBitRate(context);
partialFile = new File(saveFile.getParent(), String.format("%s.partial.%s", FileUtil.getBaseName(saveFile.getName()), FileUtil.getExtension(saveFile.getName())));
completeFile = new File(saveFile.getParent(), String.format("%s.complete.%s", FileUtil.getBaseName(saveFile.getName()), FileUtil.getExtension(saveFile.getName())));
mediaStoreService = new MediaStoreService(context);
}
/**
* Returns the effective bit rate.
*/
public int getBitRate() {
if (!partialFile.exists()) {
public MusicDirectory.Entry getSong()
{
return song;
}
/**
* Returns the effective bit rate.
*/
public int getBitRate()
{
if (!partialFile.exists())
{
bitRate = Util.getMaxBitRate(context);
}
if (bitRate > 0) {
return bitRate;
}
return song.getBitRate() == null ? 160 : song.getBitRate();
}
public Integer getContentLength() {
if (bitRate > 0)
{
return bitRate;
}
return song.getBitRate() == null ? 160 : song.getBitRate();
}
public Integer getContentLength()
{
return contentLength;
}
public synchronized void download() {
FileUtil.createDirectoryForParent(saveFile);
failed = false;
if (!partialFile.exists()) {
public synchronized void download()
{
FileUtil.createDirectoryForParent(saveFile);
failed = false;
if (!partialFile.exists())
{
bitRate = Util.getMaxBitRate(context);
}
downloadTask = new DownloadTask();
downloadTask.start();
}
public synchronized void cancelDownload() {
if (downloadTask != null) {
downloadTask.cancel();
}
}
downloadTask = new DownloadTask();
downloadTask.start();
}
public File getCompleteFile() {
if (saveFile.exists()) {
return saveFile;
}
public synchronized void cancelDownload()
{
if (downloadTask != null)
{
downloadTask.cancel();
}
}
if (completeFile.exists()) {
return completeFile;
}
public File getCompleteFile()
{
if (saveFile.exists())
{
return saveFile;
}
return saveFile;
}
if (completeFile.exists())
{
return completeFile;
}
public File getPartialFile() {
return partialFile;
}
return saveFile;
}
public boolean isSaved() {
return saveFile.exists();
}
public File getPartialFile()
{
return partialFile;
}
public synchronized boolean isCompleteFileAvailable() {
return saveFile.exists() || completeFile.exists();
}
public boolean isSaved()
{
return saveFile.exists();
}
public synchronized boolean isWorkDone() {
return saveFile.exists() || (completeFile.exists() && !save) || saveWhenDone || completeWhenDone;
}
public synchronized boolean isCompleteFileAvailable()
{
return saveFile.exists() || completeFile.exists();
}
public synchronized boolean isDownloading() {
return downloadTask != null && downloadTask.isRunning();
}
public synchronized boolean isWorkDone()
{
return saveFile.exists() || (completeFile.exists() && !save) || saveWhenDone || completeWhenDone;
}
public synchronized boolean isDownloadCancelled() {
return downloadTask != null && downloadTask.isCancelled();
}
public synchronized boolean isDownloading()
{
return downloadTask != null && downloadTask.isRunning();
}
public boolean shouldSave() {
return save;
}
public synchronized boolean isDownloadCancelled()
{
return downloadTask != null && downloadTask.isCancelled();
}
public boolean isFailed() {
return failed;
}
public boolean shouldSave()
{
return save;
}
public void delete() {
cancelDownload();
Util.delete(partialFile);
Util.delete(completeFile);
Util.delete(saveFile);
mediaStoreService.deleteFromMediaStore(this);
}
public boolean isFailed()
{
return failed;
}
public void unpin() {
if (saveFile.exists()) {
saveFile.renameTo(completeFile);
}
}
public void delete()
{
cancelDownload();
Util.delete(partialFile);
Util.delete(completeFile);
Util.delete(saveFile);
mediaStoreService.deleteFromMediaStore(this);
}
public boolean cleanup() {
boolean ok = true;
if (completeFile.exists() || saveFile.exists()) {
ok = Util.delete(partialFile);
}
if (saveFile.exists()) {
ok &= Util.delete(completeFile);
}
return ok;
}
public void unpin()
{
if (saveFile.exists())
{
saveFile.renameTo(completeFile);
}
}
// In support of LRU caching.
public void updateModificationDate() {
updateModificationDate(saveFile);
updateModificationDate(partialFile);
updateModificationDate(completeFile);
}
public boolean cleanup()
{
boolean ok = true;
private void updateModificationDate(File file) {
if (file.exists()) {
boolean ok = file.setLastModified(System.currentTimeMillis());
if (!ok) {
Log.w(TAG, "Failed to set last-modified date on " + file);
}
}
}
public void setPlaying(boolean isPlaying) {
try {
if (saveWhenDone && !isPlaying) {
if (completeFile.exists() || saveFile.exists())
{
ok = Util.delete(partialFile);
}
if (saveFile.exists())
{
ok &= Util.delete(completeFile);
}
return ok;
}
// In support of LRU caching.
public void updateModificationDate()
{
updateModificationDate(saveFile);
updateModificationDate(partialFile);
updateModificationDate(completeFile);
}
private static void updateModificationDate(File file)
{
if (file.exists())
{
boolean ok = file.setLastModified(System.currentTimeMillis());
if (!ok)
{
Log.i(TAG, String.format("Failed to set last-modified date on %s, trying alternate method", file));
try
{
// Try alternate method to update last modified date to current time
// Found at https://code.google.com/p/android/issues/detail?id=18624
RandomAccessFile raf = new RandomAccessFile(file, "rw");
long length = raf.length();
raf.setLength(length + 1);
raf.setLength(length);
raf.close();
}
catch (Exception e)
{
Log.w(TAG, String.format("Failed to set last-modified date on %s", file));
e.printStackTrace();
}
}
}
}
public void setPlaying(boolean isPlaying)
{
try
{
if (saveWhenDone && !isPlaying)
{
Util.renameFile(completeFile, saveFile);
saveWhenDone = false;
} else if (completeWhenDone && !isPlaying) {
if (save) {
}
else if (completeWhenDone && !isPlaying)
{
if (save)
{
Util.renameFile(partialFile, saveFile);
mediaStoreService.saveInMediaStore(DownloadFile.this);
} else {
mediaStoreService.saveInMediaStore(DownloadFile.this);
}
else
{
Util.renameFile(partialFile, completeFile);
}
completeWhenDone = false;
}
} catch(IOException ex) {
Log.w(TAG, "Failed to rename file " + completeFile + " to " + saveFile);
}
catch (IOException ex)
{
Log.w(TAG, String.format("Failed to rename file %s to %s", completeFile, saveFile));
}
this.isPlaying = isPlaying;
}
@Override
public String toString() {
return "DownloadFile (" + song + ")";
}
@Override
public String toString()
{
return String.format("DownloadFile (%s)", song);
}
private class DownloadTask extends CancellableTask {
private class DownloadTask extends CancellableTask
{
@Override
public void execute() {
@Override
public void execute()
{
InputStream in = null;
FileOutputStream out = null;
PowerManager.WakeLock wakeLock = null;
InputStream in = null;
FileOutputStream out = null;
PowerManager.WakeLock wakeLock = null;
WifiManager.WifiLock wifiLock = null;
try {
if (Util.isScreenLitOnDownload(context)) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, toString());
wakeLock.acquire();
Log.i(TAG, "Acquired wake lock " + wakeLock);
}
try
{
if (Util.isScreenLitOnDownload(context))
{
PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE);
wakeLock = pm.newWakeLock(SCREEN_DIM_WAKE_LOCK | ON_AFTER_RELEASE, toString());
wakeLock.acquire();
Log.i(TAG, String.format("Acquired wake lock %s", wakeLock));
}
wifiLock = Util.createWifiLock(context, toString());
wifiLock.acquire();
if (saveFile.exists()) {
Log.i(TAG, saveFile + " already exists. Skipping.");
return;
}
if (completeFile.exists()) {
if (save) {
if (isPlaying) {
if (saveFile.exists())
{
Log.i(TAG, String.format("%s already exists. Skipping.", saveFile));
return;
}
if (completeFile.exists())
{
if (save)
{
if (isPlaying)
{
saveWhenDone = true;
} else {
}
else
{
Util.renameFile(completeFile, saveFile);
}
} else {
Log.i(TAG, completeFile + " already exists. Skipping.");
}
return;
}
}
else
{
Log.i(TAG, String.format("%s already exists. Skipping.", completeFile));
}
return;
}
MusicService musicService = MusicServiceFactory.getMusicService(context);
MusicService musicService = MusicServiceFactory.getMusicService(context);
// Some devices seem to throw error on partial file which doesn't exist
boolean compare;
Integer duration = song.getDuration();
long fileLength = 0;
if (!partialFile.exists()) {
if (!partialFile.exists())
{
fileLength = partialFile.length();
}
try {
try
{
compare = (bitRate == 0) || (duration == null || duration == 0) || (fileLength == 0);
//(bitRate * song.getDuration() * 1000 / 8) > partialFile.length();
} catch(Exception e) {
}
catch (Exception e)
{
compare = true;
}
if (compare) {
if (compare)
{
// Attempt partial HTTP GET, appending to the file if it exists.
HttpResponse response = musicService.getDownloadInputStream(context, song, partialFile.length(), bitRate, DownloadTask.this);
Header contentLengthHeader = response.getFirstHeader("Content-Length");
if (contentLengthHeader != null) {
if (contentLengthHeader != null)
{
String contentLengthString = contentLengthHeader.getValue();
if (contentLengthString != null) {
if (contentLengthString != null)
{
Log.i(TAG, "Content Length: " + contentLengthString);
contentLength = Integer.parseInt(contentLengthString);
}
@ -300,113 +388,144 @@ public class DownloadFile {
in = response.getEntity().getContent();
boolean partial = response.getStatusLine().getStatusCode() == HttpStatus.SC_PARTIAL_CONTENT;
if (partial) {
Log.i(TAG, "Executed partial HTTP GET, skipping " + partialFile.length() + " bytes");
if (partial)
{
Log.i(TAG, String.format("Executed partial HTTP GET, skipping %d bytes", partialFile.length()));
}
out = new FileOutputStream(partialFile, partial);
long n = copy(in, out);
Log.i(TAG, "Downloaded " + n + " bytes to " + partialFile);
Log.i(TAG, String.format("Downloaded %d bytes to %s", n, partialFile));
out.flush();
out.close();
if (isCancelled()) {
throw new Exception("Download of '" + song + "' was cancelled");
if (isCancelled())
{
throw new Exception(String.format("Download of '%s' was cancelled", song));
}
downloadAndSaveCoverArt(musicService);
}
if (isPlaying) {
if (isPlaying)
{
completeWhenDone = true;
} else {
if (save) {
}
else
{
if (save)
{
Util.renameFile(partialFile, saveFile);
mediaStoreService.saveInMediaStore(DownloadFile.this);
} else {
}
else
{
Util.renameFile(partialFile, completeFile);
}
}
} catch (Exception x) {
Util.close(out);
Util.delete(completeFile);
Util.delete(saveFile);
if (!isCancelled()) {
failed = true;
Log.w(TAG, "Failed to download '" + song + "'.", x);
}
}
catch (Exception x)
{
Util.close(out);
Util.delete(completeFile);
Util.delete(saveFile);
if (!isCancelled())
{
failed = true;
Log.w(TAG, String.format("Failed to download '%s'.", song), x);
}
} finally {
Util.close(in);
Util.close(out);
if (wakeLock != null) {
wakeLock.release();
Log.i(TAG, "Released wake lock " + wakeLock);
}
if (wifiLock != null) {
}
finally
{
Util.close(in);
Util.close(out);
if (wakeLock != null)
{
wakeLock.release();
Log.i(TAG, String.format("Released wake lock %s", wakeLock));
}
if (wifiLock != null)
{
wifiLock.release();
}
new CacheCleaner(context, DownloadServiceImpl.getInstance()).cleanSpace();
if(DownloadServiceImpl.getInstance() != null) {
((DownloadServiceImpl)DownloadServiceImpl.getInstance()).checkDownloads();
new CacheCleaner(context, DownloadServiceImpl.getInstance()).cleanSpace();
if (DownloadServiceImpl.getInstance() != null)
{
((DownloadServiceImpl) DownloadServiceImpl.getInstance()).checkDownloads();
}
}
}
}
}
@Override
public String toString() {
return "DownloadTask (" + song + ")";
}
@Override
public String toString()
{
return String.format("DownloadTask (%s)", song);
}
private void downloadAndSaveCoverArt(MusicService musicService) throws Exception {
try {
if (song.getCoverArt() != null) {
int size = Util.getMinDisplayMetric(context);
musicService.getCoverArt(context, song, size, true, true, null);
}
} catch (Exception x) {
Log.e(TAG, "Failed to get cover art.", x);
}
}
private void downloadAndSaveCoverArt(MusicService musicService) throws Exception
{
try
{
if (song.getCoverArt() != null)
{
int size = Util.getMinDisplayMetric(context);
musicService.getCoverArt(context, song, size, true, true, null);
}
}
catch (Exception x)
{
Log.e(TAG, "Failed to get cover art.", x);
}
}
private long copy(final InputStream in, OutputStream out) throws IOException, InterruptedException {
private long copy(final InputStream in, OutputStream out) throws IOException
{
// Start a thread that will close the input stream if the task is
// cancelled, thus causing the copy() method to return.
new Thread()
{
@Override
public void run()
{
while (true)
{
Util.sleepQuietly(3000L);
// Start a thread that will close the input stream if the task is
// cancelled, thus causing the copy() method to return.
new Thread() {
@Override
public void run() {
while (true) {
Util.sleepQuietly(3000L);
if (isCancelled()) {
Util.close(in);
return;
}
if (!isRunning()) {
return;
}
}
}
}.start();
if (isCancelled())
{
Util.close(in);
return;
}
byte[] buffer = new byte[1024 * 16];
long count = 0;
int n;
long lastLog = System.currentTimeMillis();
if (!isRunning())
{
return;
}
}
}
}.start();
while (!isCancelled() && (n = in.read(buffer)) != -1) {
out.write(buffer, 0, n);
count += n;
byte[] buffer = new byte[1024 * 16];
long count = 0;
int n;
long lastLog = System.currentTimeMillis();
long now = System.currentTimeMillis();
if (now - lastLog > 3000L) { // Only every so often.
Log.i(TAG, "Downloaded " + Util.formatBytes(count) + " of " + song);
lastLog = now;
}
}
return count;
}
}
while (!isCancelled() && (n = in.read(buffer)) != -1)
{
out.write(buffer, 0, n);
count += n;
long now = System.currentTimeMillis();
if (now - lastLog > 3000L)
{ // Only every so often.
Log.i(TAG, String.format("Downloaded %s of %s", Util.formatBytes(count), song));
lastLog = now;
}
}
return count;
}
}
}

View File

@ -18,121 +18,122 @@
*/
package com.thejoshwa.ultrasonic.androidapp.service;
import java.util.List;
import com.thejoshwa.ultrasonic.androidapp.audiofx.EqualizerController;
import com.thejoshwa.ultrasonic.androidapp.audiofx.VisualizerController;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory.Entry;
import com.thejoshwa.ultrasonic.androidapp.domain.PlayerState;
import com.thejoshwa.ultrasonic.androidapp.domain.RepeatMode;
import java.util.List;
/**
* @author Sindre Mehus
* @version $Id$
*/
public interface DownloadService {
public interface DownloadService
{
void download(List<Entry> songs, boolean save, boolean autoplay, boolean playNext, boolean shuffle, boolean newPlaylist);
void downloadBackground(List<Entry> songs, boolean save);
void setShufflePlayEnabled(boolean enabled);
void downloadBackground(List<Entry> songs, boolean save);
boolean isShufflePlayEnabled();
void setShufflePlayEnabled(boolean enabled);
void shuffle();
boolean isShufflePlayEnabled();
RepeatMode getRepeatMode();
void shuffle();
void setRepeatMode(RepeatMode repeatMode);
RepeatMode getRepeatMode();
boolean getKeepScreenOn();
void setRepeatMode(RepeatMode repeatMode);
void setKeepScreenOn(boolean screenOn);
boolean getKeepScreenOn();
boolean getShowVisualization();
boolean getEqualizerAvailable();
boolean getVisualizerAvailable();
void setKeepScreenOn(boolean screenOn);
void setShowVisualization(boolean showVisualization);
boolean getShowVisualization();
void clear();
boolean getEqualizerAvailable();
boolean getVisualizerAvailable();
void setShowVisualization(boolean showVisualization);
void clear();
void clearBackground();
void clearIncomplete();
void clearIncomplete();
int size();
int size();
void remove(int which);
void remove(DownloadFile downloadFile);
long getDownloadListDuration();
void remove(DownloadFile downloadFile);
long getDownloadListDuration();
List<DownloadFile> getSongs();
List<DownloadFile> getDownloads();
List<DownloadFile> getDownloads();
List<DownloadFile> getBackgroundDownloads();
int getCurrentPlayingIndex();
int getCurrentPlayingIndex();
DownloadFile getCurrentPlaying();
DownloadFile getCurrentPlaying();
DownloadFile getCurrentDownloading();
DownloadFile getCurrentDownloading();
void play(int index);
void play(int index);
void seekTo(int position);
void seekTo(int position);
void previous();
void previous();
void next();
void next();
void pause();
void stop();
void pause();
void start();
void stop();
void reset();
void start();
PlayerState getPlayerState();
void reset();
int getPlayerPosition();
PlayerState getPlayerState();
int getPlayerDuration();
int getPlayerPosition();
void delete(List<Entry> songs);
int getPlayerDuration();
void unpin(List<Entry> songs);
void delete(List<Entry> songs);
DownloadFile forSong(Entry song);
void unpin(List<Entry> songs);
long getDownloadListUpdateRevision();
DownloadFile forSong(Entry song);
void setSuggestedPlaylistName(String name);
long getDownloadListUpdateRevision();
String getSuggestedPlaylistName();
void setSuggestedPlaylistName(String name);
EqualizerController getEqualizerController();
String getSuggestedPlaylistName();
VisualizerController getVisualizerController();
EqualizerController getEqualizerController();
boolean isJukeboxEnabled();
VisualizerController getVisualizerController();
void setJukeboxEnabled(boolean b);
boolean isJukeboxEnabled();
void adjustJukeboxVolume(boolean up);
void togglePlayPause();
void setVolume(float volume);
void swap(boolean mainList, int from, int to);
void restore(List<Entry> songs, int currentPlayingIndex, int currentPlayingPosition, boolean autoPlay, boolean newPlaylist);
void setJukeboxEnabled(boolean b);
void adjustJukeboxVolume(boolean up);
void togglePlayPause();
void setVolume(float volume);
void swap(boolean mainList, int from, int to);
void restore(List<Entry> songs, int currentPlayingIndex, int currentPlayingPosition, boolean autoPlay, boolean newPlaylist);
}

View File

@ -18,15 +18,6 @@
*/
package com.thejoshwa.ultrasonic.androidapp.service;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -36,169 +27,218 @@ import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.KeyEvent;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import com.thejoshwa.ultrasonic.androidapp.domain.PlayerState;
import com.thejoshwa.ultrasonic.androidapp.util.CacheCleaner;
import com.thejoshwa.ultrasonic.androidapp.util.FileUtil;
import com.thejoshwa.ultrasonic.androidapp.util.Util;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Sindre Mehus
*/
public class DownloadServiceLifecycleSupport {
public class DownloadServiceLifecycleSupport
{
private static final String TAG = DownloadServiceLifecycleSupport.class.getSimpleName();
private static final String FILENAME_DOWNLOADS_SER = "downloadstate.ser";
private static final String TAG = DownloadServiceLifecycleSupport.class.getSimpleName();
private static final String FILENAME_DOWNLOADS_SER = "downloadstate.ser";
private final DownloadServiceImpl downloadService;
private ScheduledExecutorService executorService;
private BroadcastReceiver headsetEventReceiver;
private BroadcastReceiver ejectEventReceiver;
private PhoneStateListener phoneStateListener;
private boolean externalStorageAvailable= true;
private ReentrantLock lock = new ReentrantLock();
private final DownloadServiceImpl downloadService;
private ScheduledExecutorService executorService;
private BroadcastReceiver headsetEventReceiver;
private BroadcastReceiver ejectEventReceiver;
private PhoneStateListener phoneStateListener;
private boolean externalStorageAvailable = true;
private ReentrantLock lock = new ReentrantLock();
private final AtomicBoolean setup = new AtomicBoolean(false);
/**
* This receiver manages the intent that could come from other applications.
*/
private BroadcastReceiver intentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.i(TAG, "intentReceiver.onReceive: " + action);
if (DownloadServiceImpl.CMD_PLAY.equals(action)) {
downloadService.play();
} else if (DownloadServiceImpl.CMD_NEXT.equals(action)) {
downloadService.next();
} else if (DownloadServiceImpl.CMD_PREVIOUS.equals(action)) {
downloadService.previous();
} else if (DownloadServiceImpl.CMD_TOGGLEPAUSE.equals(action)) {
downloadService.togglePlayPause();
} else if (DownloadServiceImpl.CMD_PAUSE.equals(action)) {
downloadService.pause();
} else if (DownloadServiceImpl.CMD_STOP.equals(action)) {
downloadService.pause();
downloadService.seekTo(0);
}
}
};
/**
* This receiver manages the intent that could come from other applications.
*/
private BroadcastReceiver intentReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
Log.i(TAG, "intentReceiver.onReceive: " + action);
if (DownloadServiceImpl.CMD_PLAY.equals(action))
{
downloadService.play();
}
else if (DownloadServiceImpl.CMD_NEXT.equals(action))
{
downloadService.next();
}
else if (DownloadServiceImpl.CMD_PREVIOUS.equals(action))
{
downloadService.previous();
}
else if (DownloadServiceImpl.CMD_TOGGLEPAUSE.equals(action))
{
downloadService.togglePlayPause();
}
else if (DownloadServiceImpl.CMD_PAUSE.equals(action))
{
downloadService.pause();
}
else if (DownloadServiceImpl.CMD_STOP.equals(action))
{
downloadService.pause();
downloadService.seekTo(0);
}
}
};
public DownloadServiceLifecycleSupport(DownloadServiceImpl downloadService) {
this.downloadService = downloadService;
}
public DownloadServiceLifecycleSupport(DownloadServiceImpl downloadService)
{
this.downloadService = downloadService;
}
public void onCreate() {
Runnable downloadChecker = new Runnable() {
@Override
public void run() {
try {
downloadService.checkDownloads();
} catch (Throwable x) {
Log.e(TAG, "checkDownloads() failed.", x);
}
}
};
public void onCreate()
{
Runnable downloadChecker = new Runnable()
{
@Override
public void run()
{
try
{
downloadService.checkDownloads();
}
catch (Throwable x)
{
Log.e(TAG, "checkDownloads() failed.", x);
}
}
};
executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(downloadChecker, 5, 5, TimeUnit.SECONDS);
executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(downloadChecker, 5, 5, TimeUnit.SECONDS);
// Pause when headset is unplugged.
headsetEventReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Headset event for: " + intent.getExtras().get("name"));
if (intent.getExtras().getInt("state") == 0) {
if(!downloadService.isJukeboxEnabled()) {
// Pause when headset is unplugged.
headsetEventReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
Log.i(TAG, String.format("Headset event for: %s", intent.getExtras().get("name")));
if (intent.getExtras().getInt("state") == 0)
{
if (!downloadService.isJukeboxEnabled())
{
downloadService.pause();
}
}
}
};
downloadService.registerReceiver(headsetEventReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG));
}
}
};
downloadService.registerReceiver(headsetEventReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG));
// Stop when SD card is ejected.
ejectEventReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
externalStorageAvailable = Intent.ACTION_MEDIA_MOUNTED.equals(intent.getAction());
if (!externalStorageAvailable) {
Log.i(TAG, "External media is ejecting. Stopping playback.");
downloadService.reset();
} else {
Log.i(TAG, "External media is available.");
}
}
};
IntentFilter ejectFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT);
ejectFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
ejectFilter.addDataScheme("file");
downloadService.registerReceiver(ejectEventReceiver, ejectFilter);
// Stop when SD card is ejected.
ejectEventReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
externalStorageAvailable = Intent.ACTION_MEDIA_MOUNTED.equals(intent.getAction());
if (!externalStorageAvailable)
{
Log.i(TAG, "External media is ejecting. Stopping playback.");
downloadService.reset();
}
else
{
Log.i(TAG, "External media is available.");
}
}
};
IntentFilter ejectFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT);
ejectFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
ejectFilter.addDataScheme("file");
downloadService.registerReceiver(ejectEventReceiver, ejectFilter);
// React to media buttons.
Util.registerMediaButtonEventReceiver(downloadService);
// React to media buttons.
Util.registerMediaButtonEventReceiver(downloadService);
// Pause temporarily on incoming phone calls.
phoneStateListener = new MyPhoneStateListener();
TelephonyManager telephonyManager = (TelephonyManager) downloadService.getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
// Pause temporarily on incoming phone calls.
phoneStateListener = new MyPhoneStateListener();
TelephonyManager telephonyManager = (TelephonyManager) downloadService.getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
// Register the handler for outside intents.
IntentFilter commandFilter = new IntentFilter();
commandFilter.addAction(DownloadServiceImpl.CMD_PLAY);
commandFilter.addAction(DownloadServiceImpl.CMD_TOGGLEPAUSE);
commandFilter.addAction(DownloadServiceImpl.CMD_PAUSE);
commandFilter.addAction(DownloadServiceImpl.CMD_STOP);
commandFilter.addAction(DownloadServiceImpl.CMD_PREVIOUS);
commandFilter.addAction(DownloadServiceImpl.CMD_NEXT);
downloadService.registerReceiver(intentReceiver, commandFilter);
int instance = Util.getActiveServer(downloadService);
downloadService.setJukeboxEnabled(Util.getJukeboxEnabled(downloadService, instance));
// Register the handler for outside intents.
IntentFilter commandFilter = new IntentFilter();
commandFilter.addAction(DownloadServiceImpl.CMD_PLAY);
commandFilter.addAction(DownloadServiceImpl.CMD_TOGGLEPAUSE);
commandFilter.addAction(DownloadServiceImpl.CMD_PAUSE);
commandFilter.addAction(DownloadServiceImpl.CMD_STOP);
commandFilter.addAction(DownloadServiceImpl.CMD_PREVIOUS);
commandFilter.addAction(DownloadServiceImpl.CMD_NEXT);
downloadService.registerReceiver(intentReceiver, commandFilter);
deserializeDownloadQueue();
int instance = Util.getActiveServer(downloadService);
downloadService.setJukeboxEnabled(Util.getJukeboxEnabled(downloadService, instance));
new CacheCleaner(downloadService, downloadService).clean();
}
deserializeDownloadQueue();
public void onStart(Intent intent) {
if (intent != null && intent.getExtras() != null) {
KeyEvent event = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT);
if (event != null) {
handleKeyEvent(event);
}
}
}
new CacheCleaner(downloadService, downloadService).clean();
}
public void onDestroy() {
executorService.shutdown();
serializeDownloadQueueNow();
downloadService.clear(false);
downloadService.unregisterReceiver(ejectEventReceiver);
downloadService.unregisterReceiver(headsetEventReceiver);
downloadService.unregisterReceiver(intentReceiver);
public void onStart(Intent intent)
{
if (intent != null && intent.getExtras() != null)
{
KeyEvent event = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT);
if (event != null)
{
handleKeyEvent(event);
}
}
}
TelephonyManager telephonyManager = (TelephonyManager) downloadService.getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
}
public void onDestroy()
{
executorService.shutdown();
serializeDownloadQueueNow();
downloadService.clear(false);
downloadService.unregisterReceiver(ejectEventReceiver);
downloadService.unregisterReceiver(headsetEventReceiver);
downloadService.unregisterReceiver(intentReceiver);
public boolean isExternalStorageAvailable() {
return externalStorageAvailable;
}
TelephonyManager telephonyManager = (TelephonyManager) downloadService.getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
}
public void serializeDownloadQueue() {
if(!setup.get()) {
public boolean isExternalStorageAvailable()
{
return externalStorageAvailable;
}
public void serializeDownloadQueue()
{
if (!setup.get())
{
return;
}
new SerializeTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public void serializeDownloadQueueNow() {
List<DownloadFile> songs = new ArrayList<DownloadFile>(downloadService.getSongs());
new SerializeTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public void serializeDownloadQueueNow()
{
List<DownloadFile> songs = new ArrayList<DownloadFile>(downloadService.getSongs());
State state = new State();
for (DownloadFile downloadFile : songs) {
for (DownloadFile downloadFile : songs)
{
state.songs.add(downloadFile.getSong());
}
state.currentPlayingIndex = downloadService.getCurrentPlayingIndex();
@ -206,29 +246,36 @@ public class DownloadServiceLifecycleSupport {
Log.i(TAG, "Serialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition);
FileUtil.serialize(downloadService, state, FILENAME_DOWNLOADS_SER);
}
}
private void deserializeDownloadQueue() {
private void deserializeDownloadQueue()
{
new DeserializeTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void deserializeDownloadQueueNow() {
State state = FileUtil.deserialize(downloadService, FILENAME_DOWNLOADS_SER);
if (state == null) {
return;
}
Log.i(TAG, "Deserialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition);
downloadService.restore(state.songs, state.currentPlayingIndex, state.currentPlayingPosition, false, false);
// Work-around: Serialize again, as the restore() method creates a serialization without current playing info.
serializeDownloadQueue();
}
private void handleKeyEvent(KeyEvent event) {
if (event.getAction() != KeyEvent.ACTION_DOWN || event.getRepeatCount() > 0) {
return;
}
private void deserializeDownloadQueueNow()
{
State state = FileUtil.deserialize(downloadService, FILENAME_DOWNLOADS_SER);
if (state == null)
{
return;
}
Log.i(TAG, "Deserialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition);
downloadService.restore(state.songs, state.currentPlayingIndex, state.currentPlayingPosition, false, false);
switch (event.getKeyCode()) {
// Work-around: Serialize again, as the restore() method creates a serialization without current playing info.
serializeDownloadQueue();
}
private void handleKeyEvent(KeyEvent event)
{
if (event.getAction() != KeyEvent.ACTION_DOWN || event.getRepeatCount() > 0)
{
return;
}
switch (event.getKeyCode())
{
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
case KeyEvent.KEYCODE_HEADSETHOOK:
downloadService.togglePlayPause();
@ -237,7 +284,8 @@ public class DownloadServiceLifecycleSupport {
downloadService.previous();
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
if (downloadService.getCurrentPlayingIndex() < downloadService.size() - 1) {
if (downloadService.getCurrentPlayingIndex() < downloadService.size() - 1)
{
downloadService.next();
}
break;
@ -245,76 +293,95 @@ public class DownloadServiceLifecycleSupport {
downloadService.stop();
break;
case KeyEvent.KEYCODE_MEDIA_PLAY:
if(downloadService.getPlayerState() != PlayerState.STARTED) {
if (downloadService.getPlayerState() != PlayerState.STARTED)
{
downloadService.start();
}
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
downloadService.pause();
break;
default:
break;
}
}
default:
break;
}
}
/**
* Logic taken from packages/apps/Music. Will pause when an incoming
* call rings or if a call (incoming or outgoing) is connected.
*/
private class MyPhoneStateListener extends PhoneStateListener {
private boolean resumeAfterCall;
/**
* Logic taken from packages/apps/Music. Will pause when an incoming
* call rings or if a call (incoming or outgoing) is connected.
*/
private class MyPhoneStateListener extends PhoneStateListener
{
private boolean resumeAfterCall;
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
case TelephonyManager.CALL_STATE_OFFHOOK:
if (downloadService.getPlayerState() == PlayerState.STARTED && !downloadService.isJukeboxEnabled()) {
resumeAfterCall = true;
downloadService.pause();
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if (resumeAfterCall) {
resumeAfterCall = false;
downloadService.start();
}
break;
default:
break;
}
}
}
private static class State implements Serializable {
private static final long serialVersionUID = -6346438781062572270L;
private List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
private int currentPlayingIndex;
private int currentPlayingPosition;
}
private class SerializeTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
if(lock.tryLock()) {
try {
public void onCallStateChanged(int state, String incomingNumber)
{
switch (state)
{
case TelephonyManager.CALL_STATE_RINGING:
case TelephonyManager.CALL_STATE_OFFHOOK:
if (downloadService.getPlayerState() == PlayerState.STARTED && !downloadService.isJukeboxEnabled())
{
resumeAfterCall = true;
downloadService.pause();
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if (resumeAfterCall)
{
resumeAfterCall = false;
downloadService.start();
}
break;
default:
break;
}
}
}
private static class State implements Serializable
{
private static final long serialVersionUID = -6346438781062572270L;
private List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
private int currentPlayingIndex;
private int currentPlayingPosition;
}
private class SerializeTask extends AsyncTask<Void, Void, Void>
{
@Override
protected Void doInBackground(Void... params)
{
if (lock.tryLock())
{
try
{
serializeDownloadQueueNow();
} finally {
}
finally
{
lock.unlock();
}
}
return null;
}
}
private class DeserializeTask extends AsyncTask<Void, Void, Void> {
private class DeserializeTask extends AsyncTask<Void, Void, Void>
{
@Override
protected Void doInBackground(Void... params) {
try {
protected Void doInBackground(Void... params)
{
try
{
lock.lock();
deserializeDownloadQueueNow();
setup.set(true);
} finally {
}
finally
{
lock.unlock();
}
return null;

View File

@ -26,6 +26,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.JukeboxStatus;
import com.thejoshwa.ultrasonic.androidapp.domain.PlayerState;
@ -48,312 +49,383 @@ import java.util.concurrent.atomic.AtomicLong;
* @author Sindre Mehus
* @version $Id$
*/
public class JukeboxService {
public class JukeboxService
{
private static final String TAG = JukeboxService.class.getSimpleName();
private static final long STATUS_UPDATE_INTERVAL_SECONDS = 5L;
private static final String TAG = JukeboxService.class.getSimpleName();
private static final long STATUS_UPDATE_INTERVAL_SECONDS = 5L;
private final Handler handler = new Handler();
private final TaskQueue tasks = new TaskQueue();
private final DownloadServiceImpl downloadService;
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> statusUpdateFuture;
private final AtomicLong timeOfLastUpdate = new AtomicLong();
private JukeboxStatus jukeboxStatus;
private float gain = 0.5f;
private VolumeToast volumeToast;
private final Handler handler = new Handler();
private final TaskQueue tasks = new TaskQueue();
private final DownloadServiceImpl downloadService;
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> statusUpdateFuture;
private final AtomicLong timeOfLastUpdate = new AtomicLong();
private JukeboxStatus jukeboxStatus;
private float gain = 0.5f;
private VolumeToast volumeToast;
// TODO: Report warning if queue fills up.
// TODO: Create shutdown method?
// TODO: Disable repeat.
// TODO: Persist RC state?
// TODO: Minimize status updates.
// TODO: Report warning if queue fills up.
// TODO: Create shutdown method?
// TODO: Disable repeat.
// TODO: Persist RC state?
// TODO: Minimize status updates.
public JukeboxService(DownloadServiceImpl downloadService) {
this.downloadService = downloadService;
new Thread() {
@Override
public void run() {
processTasks();
}
}.start();
}
public JukeboxService(DownloadServiceImpl downloadService)
{
this.downloadService = downloadService;
new Thread()
{
@Override
public void run()
{
processTasks();
}
}.start();
}
private synchronized void startStatusUpdate() {
stopStatusUpdate();
Runnable updateTask = new Runnable() {
@Override
public void run() {
tasks.remove(GetStatus.class);
tasks.add(new GetStatus());
}
};
statusUpdateFuture = executorService.scheduleWithFixedDelay(updateTask, STATUS_UPDATE_INTERVAL_SECONDS,
STATUS_UPDATE_INTERVAL_SECONDS, TimeUnit.SECONDS);
}
private synchronized void startStatusUpdate()
{
stopStatusUpdate();
Runnable updateTask = new Runnable()
{
@Override
public void run()
{
tasks.remove(GetStatus.class);
tasks.add(new GetStatus());
}
};
statusUpdateFuture = executorService.scheduleWithFixedDelay(updateTask, STATUS_UPDATE_INTERVAL_SECONDS, STATUS_UPDATE_INTERVAL_SECONDS, TimeUnit.SECONDS);
}
private synchronized void stopStatusUpdate() {
if (statusUpdateFuture != null) {
statusUpdateFuture.cancel(false);
statusUpdateFuture = null;
}
}
private synchronized void stopStatusUpdate()
{
if (statusUpdateFuture != null)
{
statusUpdateFuture.cancel(false);
statusUpdateFuture = null;
}
}
private void processTasks() {
while (true) {
JukeboxTask task = null;
try {
if (!Util.isOffline(downloadService)) {
task = tasks.take();
JukeboxStatus status = task.execute();
onStatusUpdate(status);
}
} catch (Throwable x) {
onError(task, x);
}
}
}
private void processTasks()
{
while (true)
{
JukeboxTask task = null;
try
{
if (!Util.isOffline(downloadService))
{
task = tasks.take();
JukeboxStatus status = task.execute();
onStatusUpdate(status);
}
}
catch (Throwable x)
{
onError(task, x);
}
}
}
private void onStatusUpdate(JukeboxStatus jukeboxStatus) {
timeOfLastUpdate.set(System.currentTimeMillis());
this.jukeboxStatus = jukeboxStatus;
private void onStatusUpdate(JukeboxStatus jukeboxStatus)
{
timeOfLastUpdate.set(System.currentTimeMillis());
this.jukeboxStatus = jukeboxStatus;
// Track change?
Integer index = jukeboxStatus.getCurrentPlayingIndex();
if (index != null && index != -1 && index != downloadService.getCurrentPlayingIndex()) {
downloadService.setCurrentPlaying(index);
}
}
// Track change?
Integer index = jukeboxStatus.getCurrentPlayingIndex();
if (index != null && index != -1 && index != downloadService.getCurrentPlayingIndex())
{
downloadService.setCurrentPlaying(index);
}
}
private void onError(JukeboxTask task, Throwable x) {
if (x instanceof ServerTooOldException && !(task instanceof Stop)) {
disableJukeboxOnError(x, R.string.download_jukebox_server_too_old);
} else if (x instanceof OfflineException && !(task instanceof Stop)) {
disableJukeboxOnError(x, R.string.download_jukebox_offline);
} else if (x instanceof SubsonicRESTException && ((SubsonicRESTException) x).getCode() == 50 && !(task instanceof Stop)) {
disableJukeboxOnError(x, R.string.download_jukebox_not_authorized);
} else {
Log.e(TAG, "Failed to process jukebox task: " + x, x);
}
}
private void onError(JukeboxTask task, Throwable x)
{
if (x instanceof ServerTooOldException && !(task instanceof Stop))
{
disableJukeboxOnError(x, R.string.download_jukebox_server_too_old);
}
else if (x instanceof OfflineException && !(task instanceof Stop))
{
disableJukeboxOnError(x, R.string.download_jukebox_offline);
}
else if (x instanceof SubsonicRESTException && ((SubsonicRESTException) x).getCode() == 50 && !(task instanceof Stop))
{
disableJukeboxOnError(x, R.string.download_jukebox_not_authorized);
}
else
{
Log.e(TAG, "Failed to process jukebox task: " + x, x);
}
}
private void disableJukeboxOnError(Throwable x, final int resourceId) {
Log.w(TAG, x.toString());
handler.post(new Runnable() {
@Override
public void run() {
Util.toast(downloadService, resourceId, false);
}
});
downloadService.setJukeboxEnabled(false);
}
private void disableJukeboxOnError(Throwable x, final int resourceId)
{
Log.w(TAG, x.toString());
handler.post(new Runnable()
{
@Override
public void run()
{
Util.toast(downloadService, resourceId, false);
}
});
downloadService.setJukeboxEnabled(false);
}
public void updatePlaylist() {
tasks.remove(Skip.class);
tasks.remove(Stop.class);
tasks.remove(Start.class);
public void updatePlaylist()
{
tasks.remove(Skip.class);
tasks.remove(Stop.class);
tasks.remove(Start.class);
List<String> ids = new ArrayList<String>();
for (DownloadFile file : downloadService.getDownloads()) {
ids.add(file.getSong().getId());
}
tasks.add(new SetPlaylist(ids));
}
List<String> ids = new ArrayList<String>();
for (DownloadFile file : downloadService.getDownloads())
{
ids.add(file.getSong().getId());
}
tasks.add(new SetPlaylist(ids));
}
public void skip(final int index, final int offsetSeconds) {
tasks.remove(Skip.class);
tasks.remove(Stop.class);
tasks.remove(Start.class);
public void skip(final int index, final int offsetSeconds)
{
tasks.remove(Skip.class);
tasks.remove(Stop.class);
tasks.remove(Start.class);
startStatusUpdate();
if (jukeboxStatus != null) {
jukeboxStatus.setPositionSeconds(offsetSeconds);
}
tasks.add(new Skip(index, offsetSeconds));
downloadService.setPlayerState(PlayerState.STARTED);
}
startStatusUpdate();
public void stop() {
tasks.remove(Stop.class);
tasks.remove(Start.class);
if (jukeboxStatus != null)
{
jukeboxStatus.setPositionSeconds(offsetSeconds);
}
stopStatusUpdate();
tasks.add(new Stop());
}
tasks.add(new Skip(index, offsetSeconds));
downloadService.setPlayerState(PlayerState.STARTED);
}
public void start() {
tasks.remove(Stop.class);
tasks.remove(Start.class);
public void stop()
{
tasks.remove(Stop.class);
tasks.remove(Start.class);
startStatusUpdate();
tasks.add(new Start());
}
stopStatusUpdate();
tasks.add(new Stop());
}
public synchronized void adjustVolume(boolean up) {
float delta = up ? 0.05f : -0.05f;
gain += delta;
gain = Math.max(gain, 0.0f);
gain = Math.min(gain, 1.0f);
public void start()
{
tasks.remove(Stop.class);
tasks.remove(Start.class);
tasks.remove(SetGain.class);
tasks.add(new SetGain(gain));
startStatusUpdate();
tasks.add(new Start());
}
if (volumeToast == null) {
volumeToast = new VolumeToast(downloadService);
}
volumeToast.setVolume(gain);
}
public synchronized void adjustVolume(boolean up)
{
float delta = up ? 0.05f : -0.05f;
gain += delta;
gain = Math.max(gain, 0.0f);
gain = Math.min(gain, 1.0f);
private MusicService getMusicService() {
return MusicServiceFactory.getMusicService(downloadService);
}
tasks.remove(SetGain.class);
tasks.add(new SetGain(gain));
public int getPositionSeconds() {
if (jukeboxStatus == null || jukeboxStatus.getPositionSeconds() == null || timeOfLastUpdate.get() == 0) {
return 0;
}
if (volumeToast == null)
{
volumeToast = new VolumeToast(downloadService);
}
volumeToast.setVolume(gain);
}
if (jukeboxStatus.isPlaying()) {
int secondsSinceLastUpdate = (int) ((System.currentTimeMillis() - timeOfLastUpdate.get()) / 1000L);
return jukeboxStatus.getPositionSeconds() + secondsSinceLastUpdate;
}
private MusicService getMusicService()
{
return MusicServiceFactory.getMusicService(downloadService);
}
return jukeboxStatus.getPositionSeconds();
}
public int getPositionSeconds()
{
if (jukeboxStatus == null || jukeboxStatus.getPositionSeconds() == null || timeOfLastUpdate.get() == 0)
{
return 0;
}
public void setEnabled(boolean enabled) {
tasks.clear();
if (enabled) {
updatePlaylist();
}
stop();
downloadService.setPlayerState(PlayerState.IDLE);
}
if (jukeboxStatus.isPlaying())
{
int secondsSinceLastUpdate = (int) ((System.currentTimeMillis() - timeOfLastUpdate.get()) / 1000L);
return jukeboxStatus.getPositionSeconds() + secondsSinceLastUpdate;
}
private static class TaskQueue {
return jukeboxStatus.getPositionSeconds();
}
private final LinkedBlockingQueue<JukeboxTask> queue = new LinkedBlockingQueue<JukeboxTask>();
public void setEnabled(boolean enabled)
{
tasks.clear();
if (enabled)
{
updatePlaylist();
}
stop();
downloadService.setPlayerState(PlayerState.IDLE);
}
void add(JukeboxTask jukeboxTask) {
queue.add(jukeboxTask);
}
private static class TaskQueue
{
JukeboxTask take() throws InterruptedException {
return queue.take();
}
private final LinkedBlockingQueue<JukeboxTask> queue = new LinkedBlockingQueue<JukeboxTask>();
void remove(Class<? extends JukeboxTask> clazz) {
try {
Iterator<JukeboxTask> iterator = queue.iterator();
while (iterator.hasNext()) {
JukeboxTask task = iterator.next();
if (clazz.equals(task.getClass())) {
iterator.remove();
}
}
} catch (Throwable x) {
Log.w(TAG, "Failed to clean-up task queue.", x);
}
}
void add(JukeboxTask jukeboxTask)
{
queue.add(jukeboxTask);
}
void clear() {
queue.clear();
}
}
JukeboxTask take() throws InterruptedException
{
return queue.take();
}
private abstract class JukeboxTask {
void remove(Class<? extends JukeboxTask> clazz)
{
try
{
Iterator<JukeboxTask> iterator = queue.iterator();
while (iterator.hasNext())
{
JukeboxTask task = iterator.next();
if (clazz.equals(task.getClass()))
{
iterator.remove();
}
}
}
catch (Throwable x)
{
Log.w(TAG, "Failed to clean-up task queue.", x);
}
}
abstract JukeboxStatus execute() throws Exception;
void clear()
{
queue.clear();
}
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}
private abstract class JukeboxTask
{
private class GetStatus extends JukeboxTask {
@Override
JukeboxStatus execute() throws Exception {
return getMusicService().getJukeboxStatus(downloadService, null);
}
}
abstract JukeboxStatus execute() throws Exception;
private class SetPlaylist extends JukeboxTask {
@Override
public String toString()
{
return getClass().getSimpleName();
}
}
private final List<String> ids;
private class GetStatus extends JukeboxTask
{
@Override
JukeboxStatus execute() throws Exception
{
return getMusicService().getJukeboxStatus(downloadService, null);
}
}
SetPlaylist(List<String> ids) {
this.ids = ids;
}
private class SetPlaylist extends JukeboxTask
{
@Override
JukeboxStatus execute() throws Exception {
return getMusicService().updateJukeboxPlaylist(ids, downloadService, null);
}
}
private final List<String> ids;
private class Skip extends JukeboxTask {
private final int index;
private final int offsetSeconds;
SetPlaylist(List<String> ids)
{
this.ids = ids;
}
Skip(int index, int offsetSeconds) {
this.index = index;
this.offsetSeconds = offsetSeconds;
}
@Override
JukeboxStatus execute() throws Exception
{
return getMusicService().updateJukeboxPlaylist(ids, downloadService, null);
}
}
@Override
JukeboxStatus execute() throws Exception {
return getMusicService().skipJukebox(index, offsetSeconds, downloadService, null);
}
}
private class Skip extends JukeboxTask
{
private final int index;
private final int offsetSeconds;
private class Stop extends JukeboxTask {
@Override
JukeboxStatus execute() throws Exception {
return getMusicService().stopJukebox(downloadService, null);
}
}
Skip(int index, int offsetSeconds)
{
this.index = index;
this.offsetSeconds = offsetSeconds;
}
private class Start extends JukeboxTask {
@Override
JukeboxStatus execute() throws Exception {
return getMusicService().startJukebox(downloadService, null);
}
}
@Override
JukeboxStatus execute() throws Exception
{
return getMusicService().skipJukebox(index, offsetSeconds, downloadService, null);
}
}
private class SetGain extends JukeboxTask {
private class Stop extends JukeboxTask
{
@Override
JukeboxStatus execute() throws Exception
{
return getMusicService().stopJukebox(downloadService, null);
}
}
private final float gain;
private class Start extends JukeboxTask
{
@Override
JukeboxStatus execute() throws Exception
{
return getMusicService().startJukebox(downloadService, null);
}
}
private SetGain(float gain) {
this.gain = gain;
}
private class SetGain extends JukeboxTask
{
@Override
JukeboxStatus execute() throws Exception {
return getMusicService().setJukeboxGain(gain, downloadService, null);
}
}
private final float gain;
private static class VolumeToast extends Toast {
private SetGain(float gain)
{
this.gain = gain;
}
private final ProgressBar progressBar;
@Override
JukeboxStatus execute() throws Exception
{
return getMusicService().setJukeboxGain(gain, downloadService, null);
}
}
public VolumeToast(Context context) {
super(context);
setDuration(Toast.LENGTH_SHORT);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.jukebox_volume, null);
progressBar = (ProgressBar) view.findViewById(R.id.jukebox_volume_progress_bar);
setView(view);
setGravity(Gravity.TOP, 0, 0);
}
private static class VolumeToast extends Toast
{
public void setVolume(float volume) {
progressBar.setProgress(Math.round(100 * volume));
show();
}
}
private final ProgressBar progressBar;
public VolumeToast(Context context)
{
super(context);
setDuration(Toast.LENGTH_SHORT);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.jukebox_volume, null);
progressBar = (ProgressBar) view.findViewById(R.id.jukebox_volume_progress_bar);
setView(view);
setGravity(Gravity.TOP, 0, 0);
}
public void setVolume(float volume)
{
progressBar.setProgress(Math.round(100 * volume));
show();
}
}
}

View File

@ -27,91 +27,101 @@ import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import com.thejoshwa.ultrasonic.androidapp.util.FileUtil;
/**
* @author Sindre Mehus
*/
public class MediaStoreService {
public class MediaStoreService
{
private static final String TAG = MediaStoreService.class.getSimpleName();
private static final Uri ALBUM_ART_URI = Uri.parse("content://media/external/audio/albumart");
private static final String TAG = MediaStoreService.class.getSimpleName();
private static final Uri ALBUM_ART_URI = Uri.parse("content://media/external/audio/albumart");
private final Context context;
private final Context context;
public MediaStoreService(Context context) {
this.context = context;
}
public MediaStoreService(Context context)
{
this.context = context;
}
public void saveInMediaStore(DownloadFile downloadFile) {
MusicDirectory.Entry song = downloadFile.getSong();
File songFile = downloadFile.getCompleteFile();
public void saveInMediaStore(DownloadFile downloadFile)
{
MusicDirectory.Entry song = downloadFile.getSong();
File songFile = downloadFile.getCompleteFile();
// Delete existing row in case the song has been downloaded before.
deleteFromMediaStore(downloadFile);
// Delete existing row in case the song has been downloaded before.
deleteFromMediaStore(downloadFile);
ContentResolver contentResolver = context.getContentResolver();
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.TITLE, song.getTitle());
values.put(MediaStore.Audio.AudioColumns.ARTIST, song.getArtist());
values.put(MediaStore.Audio.AudioColumns.ALBUM, song.getAlbum());
values.put(MediaStore.Audio.AudioColumns.TRACK, song.getTrack());
values.put(MediaStore.Audio.AudioColumns.YEAR, song.getYear());
values.put(MediaStore.MediaColumns.DATA, songFile.getAbsolutePath());
values.put(MediaStore.MediaColumns.MIME_TYPE, song.getContentType());
values.put(MediaStore.Audio.AudioColumns.IS_MUSIC, 1);
ContentResolver contentResolver = context.getContentResolver();
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.TITLE, song.getTitle());
values.put(MediaStore.Audio.AudioColumns.ARTIST, song.getArtist());
values.put(MediaStore.Audio.AudioColumns.ALBUM, song.getAlbum());
values.put(MediaStore.Audio.AudioColumns.TRACK, song.getTrack());
values.put(MediaStore.Audio.AudioColumns.YEAR, song.getYear());
values.put(MediaStore.MediaColumns.DATA, songFile.getAbsolutePath());
values.put(MediaStore.MediaColumns.MIME_TYPE, song.getContentType());
values.put(MediaStore.Audio.AudioColumns.IS_MUSIC, 1);
Uri uri = contentResolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values);
Uri uri = contentResolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values);
if (uri != null) {
// Look up album, and add cover art if found.
Cursor cursor = contentResolver.query(uri, new String[]{MediaStore.Audio.AudioColumns.ALBUM_ID}, null, null, null);
if (uri != null)
{
// Look up album, and add cover art if found.
Cursor cursor = contentResolver.query(uri, new String[]{MediaStore.Audio.AudioColumns.ALBUM_ID}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
int albumId = cursor.getInt(0);
insertAlbumArt(albumId, downloadFile);
cursor.close();
}
}
}
if (cursor != null && cursor.moveToFirst())
{
int albumId = cursor.getInt(0);
insertAlbumArt(albumId, downloadFile);
cursor.close();
}
}
}
public void deleteFromMediaStore(DownloadFile downloadFile) {
ContentResolver contentResolver = context.getContentResolver();
MusicDirectory.Entry song = downloadFile.getSong();
File file = downloadFile.getCompleteFile();
public void deleteFromMediaStore(DownloadFile downloadFile)
{
ContentResolver contentResolver = context.getContentResolver();
MusicDirectory.Entry song = downloadFile.getSong();
File file = downloadFile.getCompleteFile();
int n = contentResolver.delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
MediaStore.Audio.AudioColumns.TITLE_KEY + "=? AND " +
MediaStore.MediaColumns.DATA + "=?",
new String[]{MediaStore.Audio.keyFor(song.getTitle()), file.getAbsolutePath()});
if (n > 0) {
Log.i(TAG, "Deleting media store row for " + song);
}
}
int n = contentResolver.delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MediaStore.Audio.AudioColumns.TITLE_KEY + "=? AND " +
MediaStore.MediaColumns.DATA + "=?", new String[]{MediaStore.Audio.keyFor(song.getTitle()), file.getAbsolutePath()});
if (n > 0)
{
Log.i(TAG, "Deleting media store row for " + song);
}
}
private void insertAlbumArt(int albumId, DownloadFile downloadFile) {
ContentResolver contentResolver = context.getContentResolver();
Uri uri = Uri.withAppendedPath(ALBUM_ART_URI, String.valueOf(albumId));
private void insertAlbumArt(int albumId, DownloadFile downloadFile)
{
ContentResolver contentResolver = context.getContentResolver();
Uri uri = Uri.withAppendedPath(ALBUM_ART_URI, String.valueOf(albumId));
if (uri == null) {
return;
}
if (uri == null)
{
return;
}
Cursor cursor = contentResolver.query(uri, null, null, null, null);
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor != null && !cursor.moveToFirst()) {
// No album art found, add it.
File albumArtFile = FileUtil.getAlbumArtFile(context, downloadFile.getSong());
if (albumArtFile.exists()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Audio.AlbumColumns.ALBUM_ID, albumId);
values.put(MediaStore.MediaColumns.DATA, albumArtFile.getPath());
contentResolver.insert(ALBUM_ART_URI, values);
Log.i(TAG, "Added album art: " + albumArtFile);
}
if (cursor != null && !cursor.moveToFirst())
{
// No album art found, add it.
File albumArtFile = FileUtil.getAlbumArtFile(context, downloadFile.getSong());
if (albumArtFile.exists())
{
ContentValues values = new ContentValues();
values.put(MediaStore.Audio.AlbumColumns.ALBUM_ID, albumId);
values.put(MediaStore.MediaColumns.DATA, albumArtFile.getPath());
contentResolver.insert(ALBUM_ART_URI, values);
Log.i(TAG, "Added album art: " + albumArtFile);
}
cursor.close();
}
}
cursor.close();
}
}
}

View File

@ -18,10 +18,6 @@
*/
package com.thejoshwa.ultrasonic.androidapp.service;
import java.util.List;
import org.apache.http.HttpResponse;
import android.content.Context;
import android.graphics.Bitmap;
@ -41,100 +37,105 @@ import com.thejoshwa.ultrasonic.androidapp.domain.Version;
import com.thejoshwa.ultrasonic.androidapp.util.CancellableTask;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import org.apache.http.HttpResponse;
import java.util.List;
/**
* @author Sindre Mehus
*/
public interface MusicService {
public interface MusicService
{
void ping(Context context, ProgressListener progressListener) throws Exception;
void ping(Context context, ProgressListener progressListener) throws Exception;
boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception;
boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception;
List<Genre> getGenres(Context context, ProgressListener progressListener) throws Exception;
void star(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception;
void unstar(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception;
List<Genre> getGenres(Context context, ProgressListener progressListener) throws Exception;
List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
Indexes getArtists(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
void star(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
void unstar(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception;
SearchResult search(SearchCriteria criteria, Context context, ProgressListener progressListener) throws Exception;
List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception;
List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception;
Indexes getArtists(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
SearchResult search(SearchCriteria criteria, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception;
List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception;
void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception;
void updatePlaylist(String id, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception;
void removeFromPlaylist(String id, List<Integer> toRemove, Context context, ProgressListener progressListener) throws Exception;
void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception;
Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception;
void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception;
Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getAlbumList2(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception;
void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getRandomSongs(int size, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception;
SearchResult getStarred(Context context, ProgressListener progressListener) throws Exception;
SearchResult getStarred2(Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception;
Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception;
MusicDirectory getAlbumList2(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception;
HttpResponse getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, CancellableTask task) throws Exception;
MusicDirectory getRandomSongs(int size, Context context, ProgressListener progressListener) throws Exception;
Version getLocalVersion(Context context) throws Exception;
MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception;
Version getLatestVersion(Context context, ProgressListener progressListener) throws Exception;
SearchResult getStarred(Context context, ProgressListener progressListener) throws Exception;
String getVideoUrl(Context context, String id, boolean useFlash) throws Exception;
SearchResult getStarred2(Context context, ProgressListener progressListener) throws Exception;
Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception;
HttpResponse getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, CancellableTask task) throws Exception;
Version getLocalVersion(Context context) throws Exception;
Version getLatestVersion(Context context, ProgressListener progressListener) throws Exception;
String getVideoUrl(Context context, String id, boolean useFlash) throws Exception;
String getVideoStreamUrl(int Bitrate, Context context, String id);
JukeboxStatus updateJukeboxPlaylist(List<String> ids, Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus updateJukeboxPlaylist(List<String> ids, Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus startJukebox(Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus startJukebox(Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception;
List<Share> getShares(Context context, ProgressListener progressListener) throws Exception;
List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception;
void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception;
List<Share> getShares(Context context, ProgressListener progressListener) throws Exception;
List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception;
void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception;
List<Bookmark> getBookmarks(Context context, ProgressListener progressListener) throws Exception;
void deleteBookmark(String id, Context context, ProgressListener progressListener) throws Exception;
void createBookmark(String id, int position, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getVideos(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
}

View File

@ -19,18 +19,20 @@
package com.thejoshwa.ultrasonic.androidapp.service;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.util.Util;
/**
* @author Sindre Mehus
* @version $Id$
*/
public class MusicServiceFactory {
public class MusicServiceFactory
{
private static final MusicService REST_MUSIC_SERVICE = new CachedMusicService(new RESTMusicService());
private static final MusicService OFFLINE_MUSIC_SERVICE = new OfflineMusicService();
private static final MusicService REST_MUSIC_SERVICE = new CachedMusicService(new RESTMusicService());
private static final MusicService OFFLINE_MUSIC_SERVICE = new OfflineMusicService();
public static MusicService getMusicService(Context context) {
return Util.isOffline(context) ? OFFLINE_MUSIC_SERVICE : REST_MUSIC_SERVICE;
}
public static MusicService getMusicService(Context context)
{
return Util.isOffline(context) ? OFFLINE_MUSIC_SERVICE : REST_MUSIC_SERVICE;
}
}

View File

@ -24,14 +24,12 @@ package com.thejoshwa.ultrasonic.androidapp.service;
* @author Sindre Mehus
* @version $Id$
*/
public class OfflineException extends Exception {
/**
*
*/
public class OfflineException extends Exception
{
private static final long serialVersionUID = -4479642294747429444L;
public OfflineException(String message) {
super(message);
}
public OfflineException(String message)
{
super(message);
}
}

View File

@ -2,6 +2,7 @@ package com.thejoshwa.ultrasonic.androidapp.service;
import android.content.Context;
import android.util.Log;
import com.thejoshwa.ultrasonic.androidapp.util.Util;
/**
@ -10,43 +11,59 @@ import com.thejoshwa.ultrasonic.androidapp.util.Util;
* @author Sindre Mehus
* @version $Id$
*/
public class Scrobbler {
public class Scrobbler
{
private static final String TAG = Scrobbler.class.getSimpleName();
private static final String TAG = Scrobbler.class.getSimpleName();
private String lastSubmission;
private String lastNowPlaying;
private String lastSubmission;
private String lastNowPlaying;
public void scrobble(final Context context, final DownloadFile song, final boolean submission) {
if (song == null || !Util.isScrobblingEnabled(context)) {
return;
}
final String id = song.getSong().getId();
public void scrobble(final Context context, final DownloadFile song, final boolean submission)
{
if (song == null || !Util.isScrobblingEnabled(context))
{
return;
}
// Avoid duplicate registrations.
if (submission && id.equals(lastSubmission)) {
return;
}
if (!submission && id.equals(lastNowPlaying)) {
return;
}
if (submission) {
lastSubmission = id;
} else {
lastNowPlaying = id;
}
final String id = song.getSong().getId();
new Thread("Scrobble " + song) {
@Override
public void run() {
MusicService service = MusicServiceFactory.getMusicService(context);
try {
service.scrobble(id, submission, context, null);
Log.i(TAG, "Scrobbled '" + (submission ? "submission" : "now playing") + "' for " + song);
} catch (Exception x) {
Log.i(TAG, "Failed to scrobble'" + (submission ? "submission" : "now playing") + "' for " + song, x);
}
}
}.start();
}
// Avoid duplicate registrations.
if (submission && id.equals(lastSubmission))
{
return;
}
if (!submission && id.equals(lastNowPlaying))
{
return;
}
if (submission)
{
lastSubmission = id;
}
else
{
lastNowPlaying = id;
}
new Thread(String.format("Scrobble %s", song))
{
@Override
public void run()
{
MusicService service = MusicServiceFactory.getMusicService(context);
try
{
service.scrobble(id, submission, context, null);
Log.i(TAG, String.format("Scrobbled '%s' for %s", submission ? "submission" : "now playing", song));
}
catch (Exception x)
{
Log.i(TAG, String.format("Failed to scrobble'%s' for %s", submission ? "submission" : "now playing", song), x);
}
}
}.start();
}
}

View File

@ -24,25 +24,25 @@ package com.thejoshwa.ultrasonic.androidapp.service;
* @author Sindre Mehus
* @version $Id$
*/
public class ServerTooOldException extends Exception {
/**
*
*/
public class ServerTooOldException extends Exception
{
private static final long serialVersionUID = -7955245839000220002L;
public ServerTooOldException(String text) {
super(createMessage(text));
}
public ServerTooOldException(String text)
{
super(createMessage(text));
}
private static String createMessage(String text) {
StringBuilder builder = new StringBuilder();
if (text != null) {
builder.append(text).append(" ");
}
private static String createMessage(String text)
{
StringBuilder builder = new StringBuilder();
builder.append("Subsonic server version is too old. Please upgrade.");
return builder.toString();
}
if (text != null)
{
builder.append(text).append(' ');
}
builder.append("Subsonic server version is too old. Please upgrade.");
return builder.toString();
}
}

View File

@ -18,126 +18,150 @@
*/
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import java.io.Reader;
import org.xmlpull.v1.XmlPullParser;
import android.content.Context;
import android.util.Xml;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.Version;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import com.thejoshwa.ultrasonic.androidapp.util.Util;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
/**
* @author Sindre Mehus
*/
public abstract class AbstractParser {
public abstract class AbstractParser
{
private final Context context;
private XmlPullParser parser;
private boolean rootElementFound;
private final Context context;
private XmlPullParser parser;
private boolean rootElementFound;
public AbstractParser(Context context) {
this.context = context;
}
public AbstractParser(Context context)
{
this.context = context;
}
protected Context getContext() {
return context;
}
protected Context getContext()
{
return context;
}
protected void handleError() throws Exception {
int code = getInteger("code");
String message;
switch (code) {
case 20:
message = context.getResources().getString(R.string.parser_upgrade_client);
break;
case 30:
message = context.getResources().getString(R.string.parser_upgrade_server);
break;
case 40:
message = context.getResources().getString(R.string.parser_not_authenticated);
break;
case 50:
message = context.getResources().getString(R.string.parser_not_authorized);
break;
default:
message = get("message");
break;
}
throw new SubsonicRESTException(code, message);
}
protected void handleError() throws Exception
{
int code = getInteger("code");
String message;
switch (code)
{
case 20:
message = context.getResources().getString(R.string.parser_upgrade_client);
break;
case 30:
message = context.getResources().getString(R.string.parser_upgrade_server);
break;
case 40:
message = context.getResources().getString(R.string.parser_not_authenticated);
break;
case 50:
message = context.getResources().getString(R.string.parser_not_authorized);
break;
default:
message = get("message");
break;
}
throw new SubsonicRESTException(code, message);
}
protected void updateProgress(ProgressListener progressListener, int messageId) {
if (progressListener != null) {
progressListener.updateProgress(messageId);
}
}
protected void updateProgress(ProgressListener progressListener, int messageId)
{
if (progressListener != null)
{
progressListener.updateProgress(messageId);
}
}
protected void updateProgress(ProgressListener progressListener, String message) {
if (progressListener != null) {
progressListener.updateProgress(message);
}
}
protected void updateProgress(ProgressListener progressListener, String message)
{
if (progressListener != null)
{
progressListener.updateProgress(message);
}
}
protected String getText() {
return parser.getText();
}
protected String getText()
{
return parser.getText();
}
protected String get(String name) {
return parser.getAttributeValue(null, name);
}
protected String get(String name)
{
return parser.getAttributeValue(null, name);
}
protected boolean getBoolean(String name) {
return "true".equals(get(name));
}
protected boolean getValueExists(String name) {
String value = get(name);
return value != null && !value.isEmpty();
}
protected boolean getBoolean(String name)
{
return "true".equals(get(name));
}
protected Integer getInteger(String name) {
String s = get(name);
return s == null ? null : Integer.valueOf(s);
}
protected boolean getValueExists(String name)
{
String value = get(name);
return value != null && !value.isEmpty();
}
protected Long getLong(String name) {
String s = get(name);
return s == null ? null : Long.valueOf(s);
}
protected Integer getInteger(String name)
{
String s = get(name);
return s == null ? null : Integer.valueOf(s);
}
protected Float getFloat(String name) {
String s = get(name);
return s == null ? null : Float.valueOf(s);
}
protected Long getLong(String name)
{
String s = get(name);
return s == null ? null : Long.valueOf(s);
}
protected void init(Reader reader) throws Exception {
parser = Xml.newPullParser();
parser.setInput(reader);
rootElementFound = false;
}
protected Float getFloat(String name)
{
String s = get(name);
return s == null ? null : Float.valueOf(s);
}
protected int nextParseEvent() throws Exception {
return parser.next();
}
protected void init(Reader reader) throws Exception
{
parser = Xml.newPullParser();
parser.setInput(reader);
rootElementFound = false;
}
protected String getElementName() {
String name = parser.getName();
if ("subsonic-response".equals(name)) {
rootElementFound = true;
String version = get("version");
if (version != null) {
Util.setServerRestVersion(context, new Version(version));
}
}
return name;
}
protected int nextParseEvent() throws Exception
{
return parser.next();
}
protected void validate() throws Exception {
if (!rootElementFound) {
throw new Exception(context.getResources().getString(R.string.background_task_parse_error));
}
}
protected String getElementName()
{
String name = parser.getName();
if ("subsonic-response".equals(name))
{
rootElementFound = true;
String version = get("version");
if (version != null)
{
Util.setServerRestVersion(context, new Version(version));
}
}
return name;
}
protected void validate() throws Exception
{
if (!rootElementFound)
{
throw new Exception(context.getResources().getString(R.string.background_task_parse_error));
}
}
}

View File

@ -19,9 +19,11 @@
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
@ -29,34 +31,41 @@ import java.io.Reader;
/**
* @author Sindre Mehus
*/
public class AlbumListParser extends MusicDirectoryEntryParser {
public class AlbumListParser extends MusicDirectoryEntryParser
{
public AlbumListParser(Context context)
{
super(context);
}
public AlbumListParser(Context context) {
super(context);
}
public MusicDirectory parse(Reader reader, ProgressListener progressListener, boolean useId3) throws Exception
{
public MusicDirectory parse(Reader reader, ProgressListener progressListener, boolean useId3) throws Exception {
updateProgress(progressListener, R.string.parser_reading);
init(reader);
updateProgress(progressListener, R.string.parser_reading);
init(reader);
MusicDirectory dir = new MusicDirectory();
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("album".equals(name))
{
dir.addChild(parseEntry("", useId3, 0));
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
MusicDirectory dir = new MusicDirectory();
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("album".equals(name)) {
dir.addChild(parseEntry("", useId3, 0));
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return dir;
}
return dir;
}
}

View File

@ -1,10 +1,13 @@
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.Bookmark;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
@ -12,48 +15,59 @@ import java.util.List;
/**
* @author Joshua Bahnsen
*/
public class BookmarkParser extends MusicDirectoryEntryParser {
public class BookmarkParser extends MusicDirectoryEntryParser
{
public BookmarkParser(Context context) {
super(context);
}
public BookmarkParser(Context context)
{
super(context);
}
public List<Bookmark> parse(Reader reader, ProgressListener progressListener) throws Exception {
public List<Bookmark> parse(Reader reader, ProgressListener progressListener) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
init(reader);
updateProgress(progressListener, R.string.parser_reading);
init(reader);
List<Bookmark> dir = new ArrayList<Bookmark>();
Bookmark bookmark = null;
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("bookmark".equals(name)) {
bookmark = new Bookmark();
bookmark.setChanged(get("changed"));
bookmark.setCreated(get("created"));
bookmark.setComment(get("comment"));
bookmark.setPosition(getInteger("position"));
bookmark.setUsername(get("username"));
} else if ("entry".equals(name)) {
if (bookmark != null) {
bookmark.setEntry(parseEntry(null, false, bookmark.getPosition()));
dir.add(bookmark);
}
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
List<Bookmark> dir = new ArrayList<Bookmark>();
Bookmark bookmark = null;
int eventType;
validate();
updateProgress(progressListener, R.string.parser_reading_done);
do
{
eventType = nextParseEvent();
return dir;
}
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("bookmark".equals(name))
{
bookmark = new Bookmark();
bookmark.setChanged(get("changed"));
bookmark.setCreated(get("created"));
bookmark.setComment(get("comment"));
bookmark.setPosition(getInteger("position"));
bookmark.setUsername(get("username"));
}
else if ("entry".equals(name))
{
if (bookmark != null)
{
bookmark.setEntry(parseEntry(null, false, bookmark.getPosition()));
dir.add(bookmark);
}
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return dir;
}
}

View File

@ -1,9 +1,11 @@
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.ChatMessage;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
@ -13,37 +15,45 @@ import java.util.List;
/**
* @author Joshua Bahnsen
*/
public class ChatMessageParser extends AbstractParser {
public class ChatMessageParser extends AbstractParser
{
public ChatMessageParser(Context context) {
super(context);
}
public ChatMessageParser(Context context)
{
super(context);
}
public List<ChatMessage> parse(Reader reader, ProgressListener progressListener) throws Exception {
updateProgress(progressListener, R.string.parser_reading);
init(reader);
List<ChatMessage> result = new ArrayList<ChatMessage>();
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("chatMessage".equals(name)) {
ChatMessage chatMessage = new ChatMessage();
chatMessage.setUsername(get("username"));
chatMessage.setTime(getLong("time"));
chatMessage.setMessage(get("message"));
result.add(chatMessage);
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
public List<ChatMessage> parse(Reader reader, ProgressListener progressListener) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
init(reader);
List<ChatMessage> result = new ArrayList<ChatMessage>();
int eventType;
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return result;
}
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("chatMessage".equals(name))
{
ChatMessage chatMessage = new ChatMessage();
chatMessage.setUsername(get("username"));
chatMessage.setTime(getLong("time"));
chatMessage.setMessage(get("message"));
result.add(chatMessage);
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return result;
}
}

View File

@ -19,6 +19,7 @@
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
@ -26,24 +27,29 @@ import java.io.Reader;
/**
* @author Sindre Mehus
*/
public class ErrorParser extends AbstractParser {
public class ErrorParser extends AbstractParser
{
public ErrorParser(Context context) {
super(context);
}
public ErrorParser(Context context)
{
super(context);
}
public void parse(Reader reader) throws Exception {
public void parse(Reader reader) throws Exception
{
init(reader);
init(reader);
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG && "error".equals(getElementName())) {
handleError();
}
} while (eventType != XmlPullParser.END_DOCUMENT);
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG && "error".equals(getElementName()))
{
handleError();
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
}
validate();
}
}

View File

@ -24,6 +24,7 @@ import android.util.Log;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.Genre;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.BufferedReader;
@ -32,95 +33,122 @@ import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
/**
* @author Joshua Bahnsen
*/
public class GenreParser extends AbstractParser {
public class GenreParser extends AbstractParser
{
private static final String TAG = GenreParser.class.getSimpleName();
public GenreParser(Context context) {
super(context);
}
private static final Pattern COMPILE = Pattern.compile("(?:&amp;)(amp;|lt;|gt;|#37;|apos;)");
private static final Pattern PATTERN = Pattern.compile("&(?!amp;|lt;|gt;|#37;|apos;)");
private static final Pattern COMPILE1 = Pattern.compile("%");
private static final Pattern COMPILE2 = Pattern.compile("'");
public List<Genre> parse(Reader reader, ProgressListener progressListener) throws Exception {
updateProgress(progressListener, R.string.parser_reading);
List<Genre> result = new ArrayList<Genre>();
StringReader sr = null;
try {
BufferedReader br = new BufferedReader(reader);
String xml = null;
String line;
while ((line = br.readLine()) != null) {
if (xml == null) {
xml = line;
} else {
xml += line;
}
}
br.close();
public GenreParser(Context context)
{
super(context);
}
// Replace possible unescaped XML characters
// No replacements for <> at this time
if (xml != null) {
// Replace double escaped ampersand (&amp;apos;)
xml = xml.replaceAll("(?:&amp;)(amp;|lt;|gt;|#37;|apos;)", "&$1");
public List<Genre> parse(Reader reader, ProgressListener progressListener) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
// Replace unescaped ampersand
xml = xml.replaceAll("&(?!amp;|lt;|gt;|#37;|apos;)", "&amp;");
List<Genre> result = new ArrayList<Genre>();
StringReader sr = null;
// Replace unescaped percent symbol
xml = xml.replaceAll("%", "&#37;");
try
{
BufferedReader br = new BufferedReader(reader);
String xml = null;
String line;
// Replace unescaped apostrophe
xml = xml.replaceAll("'", "&apos;");
}
while ((line = br.readLine()) != null)
{
if (xml == null)
{
xml = line;
}
else
{
xml += line;
}
}
br.close();
sr = new StringReader(xml);
} catch (IOException ioe) {
Log.e(TAG, "Error parsing Genre XML", ioe);
}
// Replace possible unescaped XML characters
// No replacements for <> at this time
if (xml != null)
{
// Replace double escaped ampersand (&amp;apos;)
xml = COMPILE.matcher(xml).replaceAll("&$1");
if (sr == null) {
Log.w(TAG, "Unable to parse Genre XML, returning empty list");
return result;
}
init(sr);
// Replace unescaped ampersand
xml = PATTERN.matcher(xml).replaceAll("&amp;");
Genre genre = null;
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("genre".equals(name)) {
genre = new Genre();
} else if ("error".equals(name)) {
handleError();
} else {
genre = null;
}
} else if (eventType == XmlPullParser.TEXT) {
if (genre != null) {
String value = getText();
// Replace unescaped percent symbol
xml = COMPILE1.matcher(xml).replaceAll("&#37;");
genre.setName(value);
genre.setIndex(value.substring(0, 1));
result.add(genre);
genre = null;
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
// Replace unescaped apostrophe
xml = COMPILE2.matcher(xml).replaceAll("&apos;");
}
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return result;
}
sr = new StringReader(xml);
}
catch (IOException ioe)
{
Log.e(TAG, "Error parsing Genre XML", ioe);
}
if (sr == null)
{
Log.w(TAG, "Unable to parse Genre XML, returning empty list");
return result;
}
init(sr);
Genre genre = null;
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("genre".equals(name))
{
genre = new Genre();
}
else if ("error".equals(name))
{
handleError();
}
else
{
genre = null;
}
}
else if (eventType == XmlPullParser.TEXT)
{
if (genre != null)
{
String value = getText();
genre.setName(value);
genre.setIndex(value.substring(0, 1));
result.add(genre);
genre = null;
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return result;
}
}

View File

@ -25,84 +25,102 @@ import java.util.ArrayList;
import org.xmlpull.v1.XmlPullParser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.Artist;
import com.thejoshwa.ultrasonic.androidapp.domain.Indexes;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import android.util.Log;
/**
* @author Sindre Mehus
*/
public class IndexesParser extends AbstractParser {
private static final String TAG = IndexesParser.class.getSimpleName();
public class IndexesParser extends AbstractParser
{
private static final String TAG = IndexesParser.class.getSimpleName();
public IndexesParser(Context context) {
super(context);
}
public IndexesParser(Context context)
{
super(context);
}
public Indexes parse(Reader reader, ProgressListener progressListener) throws Exception {
public Indexes parse(Reader reader, ProgressListener progressListener) throws Exception
{
long t0 = System.currentTimeMillis();
updateProgress(progressListener, R.string.parser_reading);
init(reader);
long t0 = System.currentTimeMillis();
updateProgress(progressListener, R.string.parser_reading);
init(reader);
List<Artist> artists = new ArrayList<Artist>();
List<Artist> shortcuts = new ArrayList<Artist>();
Long lastModified = null;
String ignoredArticles = null;
int eventType;
String index = "#";
boolean changed = false;
List<Artist> artists = new ArrayList<Artist>();
List<Artist> shortcuts = new ArrayList<Artist>();
Long lastModified = null;
String ignoredArticles = null;
int eventType;
String index = "#";
boolean changed = false;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("indexes".equals(name) || "artists".equals(name)) {
changed = true;
lastModified = getLong("lastModified");
ignoredArticles = get("ignoredArticles");
} else if ("index".equals(name)) {
index = get("name");
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("indexes".equals(name) || "artists".equals(name))
{
changed = true;
lastModified = getLong("lastModified");
ignoredArticles = get("ignoredArticles");
}
else if ("index".equals(name))
{
index = get("name");
} else if ("artist".equals(name)) {
Artist artist = new Artist();
artist.setId(get("id"));
artist.setName(get("name"));
artist.setCoverArt(get("coverArt"));
artist.setAlbumCount(getLong("albumCount"));
artist.setIndex(index);
artists.add(artist);
}
else if ("artist".equals(name))
{
Artist artist = new Artist();
artist.setId(get("id"));
artist.setName(get("name"));
artist.setCoverArt(get("coverArt"));
artist.setAlbumCount(getLong("albumCount"));
artist.setIndex(index);
artists.add(artist);
if (artists.size() % 10 == 0) {
String msg = getContext().getResources().getString(R.string.parser_artist_count, artists.size());
updateProgress(progressListener, msg);
}
} else if ("shortcut".equals(name)) {
Artist shortcut = new Artist();
shortcut.setId(get("id"));
shortcut.setName(get("name"));
shortcut.setIndex("*");
shortcuts.add(shortcut);
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
if (artists.size() % 10 == 0)
{
String msg = getContext().getResources().getString(R.string.parser_artist_count, artists.size());
updateProgress(progressListener, msg);
}
}
else if ("shortcut".equals(name))
{
Artist shortcut = new Artist();
shortcut.setId(get("id"));
shortcut.setName(get("name"));
shortcut.setIndex("*");
shortcuts.add(shortcut);
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
validate();
if (!changed) {
return null;
}
if (!changed)
{
return null;
}
long t1 = System.currentTimeMillis();
Log.d(TAG, "Got " + artists.size() + " artist(s) in " + (t1 - t0) + "ms.");
long t1 = System.currentTimeMillis();
Log.d(TAG, "Got " + artists.size() + " artist(s) in " + (t1 - t0) + "ms.");
String msg = getContext().getResources().getString(R.string.parser_artist_count, artists.size());
updateProgress(progressListener, msg);
String msg = getContext().getResources().getString(R.string.parser_artist_count, artists.size());
updateProgress(progressListener, msg);
return new Indexes(lastModified == null ? 0L : lastModified, shortcuts, artists);
}
return new Indexes(lastModified == null ? 0L : lastModified, shortcuts, artists);
}
}

View File

@ -18,45 +18,54 @@
*/
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import java.io.Reader;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.domain.JukeboxStatus;
import org.xmlpull.v1.XmlPullParser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.domain.JukeboxStatus;
import java.io.Reader;
/**
* @author Sindre Mehus
*/
public class JukeboxStatusParser extends AbstractParser {
public class JukeboxStatusParser extends AbstractParser
{
public JukeboxStatusParser(Context context) {
super(context);
}
public JukeboxStatusParser(Context context)
{
super(context);
}
public JukeboxStatus parse(Reader reader) throws Exception {
public JukeboxStatus parse(Reader reader) throws Exception
{
init(reader);
init(reader);
JukeboxStatus jukeboxStatus = new JukeboxStatus();
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("jukeboxPlaylist".equals(name) || "jukeboxStatus".equals(name)) {
jukeboxStatus.setPositionSeconds(getInteger("position"));
jukeboxStatus.setCurrentIndex(getInteger("currentIndex"));
jukeboxStatus.setPlaying(getBoolean("playing"));
jukeboxStatus.setGain(getFloat("gain"));
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
JukeboxStatus jukeboxStatus = new JukeboxStatus();
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("jukeboxPlaylist".equals(name) || "jukeboxStatus".equals(name))
{
jukeboxStatus.setPositionSeconds(getInteger("position"));
jukeboxStatus.setCurrentIndex(getInteger("currentIndex"));
jukeboxStatus.setPlaying(getBoolean("playing"));
jukeboxStatus.setGain(getFloat("gain"));
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
validate();
return jukeboxStatus;
}
return jukeboxStatus;
}
}

View File

@ -19,6 +19,7 @@
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
@ -29,34 +30,44 @@ import com.thejoshwa.ultrasonic.androidapp.domain.Version;
/**
* @author Sindre Mehus
*/
public class LicenseParser extends AbstractParser {
public class LicenseParser extends AbstractParser
{
public LicenseParser(Context context) {
super(context);
}
public LicenseParser(Context context)
{
super(context);
}
public ServerInfo parse(Reader reader) throws Exception {
public ServerInfo parse(Reader reader) throws Exception
{
init(reader);
init(reader);
ServerInfo serverInfo = new ServerInfo();
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("subsonic-response".equals(name)) {
serverInfo.setRestVersion(new Version(get("version")));
} else if ("license".equals(name)) {
serverInfo.setLicenseValid(getBoolean("valid"));
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
ServerInfo serverInfo = new ServerInfo();
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("subsonic-response".equals(name))
{
serverInfo.setRestVersion(new Version(get("version")));
}
else if ("license".equals(name))
{
serverInfo.setLicenseValid(getBoolean("valid"));
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
validate();
return serverInfo;
}
return serverInfo;
}
}

View File

@ -19,9 +19,11 @@
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.Lyrics;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
@ -29,37 +31,48 @@ import java.io.Reader;
/**
* @author Sindre Mehus
*/
public class LyricsParser extends AbstractParser {
public class LyricsParser extends AbstractParser
{
public LyricsParser(Context context) {
super(context);
}
public LyricsParser(Context context)
{
super(context);
}
public Lyrics parse(Reader reader, ProgressListener progressListener) throws Exception {
updateProgress(progressListener, R.string.parser_reading);
init(reader);
public Lyrics parse(Reader reader, ProgressListener progressListener) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
init(reader);
Lyrics lyrics = null;
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("lyrics".equals(name)) {
lyrics = new Lyrics();
lyrics.setArtist(get("artist"));
lyrics.setTitle(get("title"));
} else if ("error".equals(name)) {
handleError();
}
} else if (eventType == XmlPullParser.TEXT) {
if (lyrics != null && lyrics.getText() == null) {
lyrics.setText(getText());
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
Lyrics lyrics = null;
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("lyrics".equals(name))
{
lyrics = new Lyrics();
lyrics.setArtist(get("artist"));
lyrics.setTitle(get("title"));
}
else if ("error".equals(name))
{
handleError();
}
}
else if (eventType == XmlPullParser.TEXT)
{
if (lyrics != null && lyrics.getText() == null)
{
lyrics.setText(getText());
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
return lyrics;
}
validate();
return lyrics;
}
}

View File

@ -19,52 +19,59 @@
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import com.thejoshwa.ultrasonic.androidapp.util.Constants;
/**
* @author Sindre Mehus
*/
public class MusicDirectoryEntryParser extends AbstractParser {
public class MusicDirectoryEntryParser extends AbstractParser
{
public MusicDirectoryEntryParser(Context context) {
super(context);
}
public MusicDirectoryEntryParser(Context context)
{
super(context);
}
protected MusicDirectory.Entry parseEntry(String artist, boolean isAlbum, int bookmarkPosition) {
MusicDirectory.Entry entry = new MusicDirectory.Entry();
entry.setId(get("id"));
entry.setParent(get("parent"));
entry.setTitle(isAlbum ? get("name") : get("title"));
entry.setIsDirectory(getBoolean("isDir") || isAlbum);
entry.setCoverArt(get("coverArt"));
entry.setArtist(get("artist"));
entry.setArtistId(get("artistId"));
entry.setYear(getInteger("year"));
entry.setCreated(get("created"));
entry.setStarred(getValueExists(Constants.STARRED));
protected MusicDirectory.Entry parseEntry(String artist, boolean isAlbum, int bookmarkPosition)
{
MusicDirectory.Entry entry = new MusicDirectory.Entry();
entry.setId(get("id"));
entry.setParent(get("parent"));
entry.setTitle(isAlbum ? get("name") : get("title"));
entry.setIsDirectory(getBoolean("isDir") || isAlbum);
entry.setCoverArt(get("coverArt"));
entry.setArtist(get("artist"));
entry.setArtistId(get("artistId"));
entry.setYear(getInteger("year"));
entry.setCreated(get("created"));
entry.setStarred(getValueExists(Constants.STARRED));
if (!entry.isDirectory()) {
entry.setAlbum(get("album"));
entry.setAlbumId(get("albumId"));
entry.setTrack(getInteger("track"));
entry.setGenre(get("genre"));
entry.setContentType(get("contentType"));
entry.setSuffix(get("suffix"));
entry.setTranscodedContentType(get("transcodedContentType"));
entry.setTranscodedSuffix(get("transcodedSuffix"));
entry.setSize(getLong("size"));
entry.setDuration(getInteger("duration"));
entry.setBitRate(getInteger("bitRate"));
entry.setPath(get("path"));
entry.setIsVideo(getBoolean("isVideo"));
entry.setDiscNumber(getInteger("discNumber"));
entry.setType(get("type"));
entry.setBookmarkPosition(bookmarkPosition);
} else if(!"".equals(artist)) {
entry.setPath(artist + "/" + entry.getTitle());
if (!entry.isDirectory())
{
entry.setAlbum(get("album"));
entry.setAlbumId(get("albumId"));
entry.setTrack(getInteger("track"));
entry.setGenre(get("genre"));
entry.setContentType(get("contentType"));
entry.setSuffix(get("suffix"));
entry.setTranscodedContentType(get("transcodedContentType"));
entry.setTranscodedSuffix(get("transcodedSuffix"));
entry.setSize(getLong("size"));
entry.setDuration(getInteger("duration"));
entry.setBitRate(getInteger("bitRate"));
entry.setPath(get("path"));
entry.setIsVideo(getBoolean("isVideo"));
entry.setDiscNumber(getInteger("discNumber"));
entry.setType(get("type"));
entry.setBookmarkPosition(bookmarkPosition);
}
return entry;
}
else if (!"".equals(artist))
{
entry.setPath(String.format("%s/%s", artist, entry.getTitle()));
}
return entry;
}
}

View File

@ -20,54 +20,69 @@ package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import android.util.Log;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
/**
* @author Sindre Mehus
*/
public class MusicDirectoryParser extends MusicDirectoryEntryParser {
public class MusicDirectoryParser extends MusicDirectoryEntryParser
{
private static final String TAG = MusicDirectoryParser.class.getSimpleName();
private static final String TAG = MusicDirectoryParser.class.getSimpleName();
public MusicDirectoryParser(Context context) {
super(context);
}
public MusicDirectoryParser(Context context)
{
super(context);
}
public MusicDirectory parse(String artist, Reader reader, ProgressListener progressListener, boolean isAlbum) throws Exception {
public MusicDirectory parse(String artist, Reader reader, ProgressListener progressListener, boolean isAlbum) throws Exception
{
long t0 = System.currentTimeMillis();
updateProgress(progressListener, R.string.parser_reading);
init(reader);
long t0 = System.currentTimeMillis();
updateProgress(progressListener, R.string.parser_reading);
init(reader);
MusicDirectory dir = new MusicDirectory();
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("child".equals(name) || "song".equals(name) || "video".equals(name)) {
dir.addChild(parseEntry(artist, false, 0));
} else if ("album".equals(name) && !isAlbum) {
dir.addChild(parseEntry(artist, true, 0));
} else if ("directory".equals(name) || "artist".equals(name)) {
dir.setName(get("name"));
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
MusicDirectory dir = new MusicDirectory();
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
validate();
updateProgress(progressListener, R.string.parser_reading_done);
if ("child".equals(name) || "song".equals(name) || "video".equals(name))
{
dir.addChild(parseEntry(artist, false, 0));
}
else if ("album".equals(name) && !isAlbum)
{
dir.addChild(parseEntry(artist, true, 0));
}
else if ("directory".equals(name) || "artist".equals(name))
{
dir.setName(get("name"));
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
long t1 = System.currentTimeMillis();
Log.d(TAG, "Got music directory in " + (t1 - t0) + "ms.");
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return dir;
}
long t1 = System.currentTimeMillis();
Log.d(TAG, "Got music directory in " + (t1 - t0) + "ms.");
return dir;
}
}

View File

@ -25,6 +25,7 @@ import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicFolder;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
@ -32,37 +33,45 @@ import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
/**
* @author Sindre Mehus
*/
public class MusicFoldersParser extends AbstractParser {
public class MusicFoldersParser extends AbstractParser
{
public MusicFoldersParser(Context context) {
super(context);
}
public MusicFoldersParser(Context context)
{
super(context);
}
public List<MusicFolder> parse(Reader reader, ProgressListener progressListener) throws Exception {
public List<MusicFolder> parse(Reader reader, ProgressListener progressListener) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
init(reader);
updateProgress(progressListener, R.string.parser_reading);
init(reader);
List<MusicFolder> result = new ArrayList<MusicFolder>();
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String tag = getElementName();
if ("musicFolder".equals(tag)) {
String id = get("id");
String name = get("name");
result.add(new MusicFolder(id, name));
} else if ("error".equals(tag)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
List<MusicFolder> result = new ArrayList<MusicFolder>();
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String tag = getElementName();
if ("musicFolder".equals(tag))
{
String id = get("id");
String name = get("name");
result.add(new MusicFolder(id, name));
}
else if ("error".equals(tag))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return result;
}
return result;
}
}

View File

@ -19,9 +19,11 @@
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
@ -29,34 +31,42 @@ import java.io.Reader;
/**
* @author Sindre Mehus
*/
public class PlaylistParser extends MusicDirectoryEntryParser {
public class PlaylistParser extends MusicDirectoryEntryParser
{
public PlaylistParser(Context context) {
super(context);
}
public PlaylistParser(Context context)
{
super(context);
}
public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception {
updateProgress(progressListener, R.string.parser_reading);
init(reader);
public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
init(reader);
MusicDirectory dir = new MusicDirectory();
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("entry".equals(name)) {
dir.addChild(parseEntry("", false, 0));
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
MusicDirectory dir = new MusicDirectory();
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("entry".equals(name))
{
dir.addChild(parseEntry("", false, 0));
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return dir;
}
return dir;
}
}

View File

@ -19,6 +19,7 @@
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.Playlist;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
@ -33,42 +34,50 @@ import java.util.List;
/**
* @author Sindre Mehus
*/
public class PlaylistsParser extends AbstractParser {
public class PlaylistsParser extends AbstractParser
{
public PlaylistsParser(Context context) {
super(context);
}
public PlaylistsParser(Context context)
{
super(context);
}
public List<Playlist> parse(Reader reader, ProgressListener progressListener) throws Exception {
public List<Playlist> parse(Reader reader, ProgressListener progressListener) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
init(reader);
updateProgress(progressListener, R.string.parser_reading);
init(reader);
List<Playlist> result = new ArrayList<Playlist>();
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String tag = getElementName();
if ("playlist".equals(tag)) {
String id = get("id");
String name = get("name");
List<Playlist> result = new ArrayList<Playlist>();
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String tag = getElementName();
if ("playlist".equals(tag))
{
String id = get("id");
String name = get("name");
String owner = get("owner");
String comment = get("comment");
String songCount = get("songCount");
String created = get("created");
String pub = get("public");
result.add(new Playlist(id, name, owner, comment, songCount, created, pub));
} else if ("error".equals(tag)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
result.add(new Playlist(id, name, owner, comment, songCount, created, pub));
}
else if ("error".equals(tag))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return PlaylistAdapter.PlaylistComparator.sort(result);
}
return PlaylistAdapter.PlaylistComparator.sort(result);
}
}

View File

@ -19,9 +19,11 @@
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
@ -29,34 +31,42 @@ import java.io.Reader;
/**
* @author Sindre Mehus
*/
public class RandomSongsParser extends MusicDirectoryEntryParser {
public class RandomSongsParser extends MusicDirectoryEntryParser
{
public RandomSongsParser(Context context) {
super(context);
}
public RandomSongsParser(Context context)
{
super(context);
}
public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception {
updateProgress(progressListener, R.string.parser_reading);
init(reader);
public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
init(reader);
MusicDirectory dir = new MusicDirectory();
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("song".equals(name)) {
dir.addChild(parseEntry("", false, 0));
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
MusicDirectory dir = new MusicDirectory();
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("song".equals(name))
{
dir.addChild(parseEntry("", false, 0));
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return dir;
}
return dir;
}
}

View File

@ -19,11 +19,13 @@
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import com.thejoshwa.ultrasonic.androidapp.domain.SearchResult;
import com.thejoshwa.ultrasonic.androidapp.domain.Artist;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
@ -33,43 +35,55 @@ import java.util.ArrayList;
/**
* @author Sindre Mehus
*/
public class SearchResult2Parser extends MusicDirectoryEntryParser {
public class SearchResult2Parser extends MusicDirectoryEntryParser
{
public SearchResult2Parser(Context context) {
super(context);
}
public SearchResult2Parser(Context context)
{
super(context);
}
public SearchResult parse(Reader reader, ProgressListener progressListener, boolean useId3) throws Exception {
updateProgress(progressListener, R.string.parser_reading);
init(reader);
public SearchResult parse(Reader reader, ProgressListener progressListener, boolean useId3) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
init(reader);
List<Artist> artists = new ArrayList<Artist>();
List<MusicDirectory.Entry> albums = new ArrayList<MusicDirectory.Entry>();
List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("artist".equals(name)) {
Artist artist = new Artist();
artist.setId(get("id"));
artist.setName(get("name"));
artists.add(artist);
} else if ("album".equals(name)) {
albums.add(parseEntry("", useId3, 0));
} else if ("song".equals(name)) {
songs.add(parseEntry("", false, 0));
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
List<Artist> artists = new ArrayList<Artist>();
List<MusicDirectory.Entry> albums = new ArrayList<MusicDirectory.Entry>();
List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("artist".equals(name))
{
Artist artist = new Artist();
artist.setId(get("id"));
artist.setName(get("name"));
artists.add(artist);
}
else if ("album".equals(name))
{
albums.add(parseEntry("", useId3, 0));
}
else if ("song".equals(name))
{
songs.add(parseEntry("", false, 0));
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return new SearchResult(artists, albums, songs);
}
return new SearchResult(artists, albums, songs);
}
}

View File

@ -19,11 +19,13 @@
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import com.thejoshwa.ultrasonic.androidapp.domain.SearchResult;
import com.thejoshwa.ultrasonic.androidapp.domain.Artist;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
@ -34,34 +36,42 @@ import java.util.ArrayList;
/**
* @author Sindre Mehus
*/
public class SearchResultParser extends MusicDirectoryEntryParser {
public class SearchResultParser extends MusicDirectoryEntryParser
{
public SearchResultParser(Context context) {
super(context);
}
public SearchResultParser(Context context)
{
super(context);
}
public SearchResult parse(Reader reader, ProgressListener progressListener) throws Exception {
updateProgress(progressListener, R.string.parser_reading);
init(reader);
public SearchResult parse(Reader reader, ProgressListener progressListener) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
init(reader);
List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("match".equals(name)) {
songs.add(parseEntry("", false, 0));
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
int eventType;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("match".equals(name))
{
songs.add(parseEntry("", false, 0));
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return new SearchResult(Collections.<Artist>emptyList(), Collections.<MusicDirectory.Entry>emptyList(), songs);
}
return new SearchResult(Collections.<Artist>emptyList(), Collections.<MusicDirectory.Entry>emptyList(), songs);
}
}

View File

@ -1,10 +1,13 @@
package com.thejoshwa.ultrasonic.androidapp.service.parser;
import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.R;
import com.thejoshwa.ultrasonic.androidapp.domain.Share;
import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
@ -12,50 +15,61 @@ import java.util.List;
/**
* @author Joshua Bahnsen
*/
public class ShareParser extends MusicDirectoryEntryParser {
public class ShareParser extends MusicDirectoryEntryParser
{
public ShareParser(Context context) {
super(context);
}
public ShareParser(Context context)
{
super(context);
}
public List<Share> parse(Reader reader, ProgressListener progressListener) throws Exception {
public List<Share> parse(Reader reader, ProgressListener progressListener) throws Exception
{
updateProgress(progressListener, R.string.parser_reading);
init(reader);
updateProgress(progressListener, R.string.parser_reading);
init(reader);
List<Share> dir = new ArrayList<Share>();
Share share = null;
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("share".equals(name)) {
share = new Share();
share.setCreated(get("created"));
share.setDescription(get("description"));
share.setExpires(get("expires"));
share.setId(get("id"));
share.setLastVisited(get("lastVisited"));
share.setUrl(get("url"));
share.setUsername(get("username"));
share.setVisitCount(getLong("visitCount"));
} else if ("entry".equals(name)) {
if (share != null) {
share.addEntry(parseEntry(null, false, 0));
}
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
List<Share> dir = new ArrayList<Share>();
Share share = null;
int eventType;
validate();
updateProgress(progressListener, R.string.parser_reading_done);
do
{
eventType = nextParseEvent();
return dir;
}
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("share".equals(name))
{
share = new Share();
share.setCreated(get("created"));
share.setDescription(get("description"));
share.setExpires(get("expires"));
share.setId(get("id"));
share.setLastVisited(get("lastVisited"));
share.setUrl(get("url"));
share.setUsername(get("username"));
share.setVisitCount(getLong("visitCount"));
}
else if ("entry".equals(name))
{
if (share != null)
{
share.addEntry(parseEntry(null, false, 0));
}
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
updateProgress(progressListener, R.string.parser_reading_done);
return dir;
}
}

View File

@ -4,20 +4,23 @@ package com.thejoshwa.ultrasonic.androidapp.service.parser;
* @author Sindre Mehus
* @version $Id$
*/
public class SubsonicRESTException extends Exception {
public class SubsonicRESTException extends Exception
{
/**
*
/**
*
*/
private static final long serialVersionUID = 859440717343258203L;
private final int code;
public SubsonicRESTException(int code, String message) {
super(message);
this.code = code;
}
public SubsonicRESTException(int code, String message)
{
super(message);
this.code = code;
}
public int getCode() {
return code;
}
public int getCode()
{
return code;
}
}

View File

@ -28,20 +28,24 @@ import java.util.regex.Pattern;
/**
* @author Sindre Mehus
*/
public class VersionParser {
public class VersionParser
{
public Version parse(Reader reader) throws Exception {
public static Version parse(Reader reader) throws Exception
{
BufferedReader bufferedReader = new BufferedReader(reader);
Pattern pattern = Pattern.compile("SUBSONIC_ANDROID_VERSION_BEGIN(.*)SUBSONIC_ANDROID_VERSION_END");
String line = bufferedReader.readLine();
while (line != null) {
Matcher finalMatcher = pattern.matcher(line);
if (finalMatcher.find()) {
return new Version(finalMatcher.group(1));
}
line = bufferedReader.readLine();
}
return null;
}
BufferedReader bufferedReader = new BufferedReader(reader);
Pattern pattern = Pattern.compile("SUBSONIC_ANDROID_VERSION_BEGIN(.*)SUBSONIC_ANDROID_VERSION_END");
String line = bufferedReader.readLine();
while (line != null)
{
Matcher finalMatcher = pattern.matcher(line);
if (finalMatcher.find())
{
return new Version(finalMatcher.group(1));
}
line = bufferedReader.readLine();
}
return null;
}
}

View File

@ -67,7 +67,7 @@ import javax.net.ssl.X509TrustManager;
* server attempts to authenticate itself with a non-trusted certificate.
* <p>
* Use JDK keytool utility to import a trusted certificate and generate a trust-store file:
* <pre>
* <pre>
* keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
* </pre>
* <p>
@ -78,8 +78,8 @@ import javax.net.ssl.X509TrustManager;
* The following parameters can be used to customize the behavior of this
* class:
* <ul>
* <li>{@link org.apache.http.params.CoreConnectionPNames#CONNECTION_TIMEOUT}</li>
* <li>{@link org.apache.http.params.CoreConnectionPNames#SO_TIMEOUT}</li>
* <li>{@link org.apache.http.params.CoreConnectionPNames#CONNECTION_TIMEOUT}</li>
* <li>{@link org.apache.http.params.CoreConnectionPNames#SO_TIMEOUT}</li>
* </ul>
* <p>
* SSLSocketFactory will enable client authentication when supplied with
@ -92,245 +92,282 @@ import javax.net.ssl.X509TrustManager;
* <p>
* Use the following sequence of actions to generate a key-store file
* </p>
* <ul>
* <li>
* <p>
* Use JDK keytool utility to generate a new key
* <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre>
* For simplicity use the same password for the key as that of the key-store
* </p>
* </li>
* <li>
* <p>
* Issue a certificate signing request (CSR)
* <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre>
* </p>
* </li>
* <li>
* <p>
* Send the certificate request to the trusted Certificate Authority for signature.
* One may choose to act as her own CA and sign the certificate request using a PKI
* tool, such as OpenSSL.
* </p>
* </li>
* <li>
* <p>
* Import the trusted CA root certificate
* <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
* </p>
* </li>
* <li>
* <p>
* Import the PKCS#7 file containg the complete certificate chain
* <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>
* </p>
* </li>
* <li>
* <p>
* Verify the content the resultant keystore file
* <pre>keytool -list -v -keystore my.keystore</pre>
* </p>
* </li>
* </ul>
* <ul>
* <li>
* <p>
* Use JDK keytool utility to generate a new key
* <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre>
* For simplicity use the same password for the key as that of the key-store
* </p>
* </li>
* <li>
* <p>
* Issue a certificate signing request (CSR)
* <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre>
* </p>
* </li>
* <li>
* <p>
* Send the certificate request to the trusted Certificate Authority for signature.
* One may choose to act as her own CA and sign the certificate request using a PKI
* tool, such as OpenSSL.
* </p>
* </li>
* <li>
* <p>
* Import the trusted CA root certificate
* <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
* </p>
* </li>
* <li>
* <p>
* Import the PKCS#7 file containg the complete certificate chain
* <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>
* </p>
* </li>
* <li>
* <p>
* Verify the content the resultant keystore file
* <pre>keytool -list -v -keystore my.keystore</pre>
* </p>
* </li>
* </ul>
*
* @since 4.0
*/
public class SSLSocketFactory implements LayeredSocketFactory {
public class SSLSocketFactory implements LayeredSocketFactory
{
public static final String TLS = "TLS";
public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER = new AllowAllHostnameVerifier();
public static final String TLS = "TLS";
public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER = new AllowAllHostnameVerifier();
/**
* The default factory using the default JVM settings for secure connections.
*/
private final javax.net.ssl.SSLSocketFactory socketFactory;
private final HostNameResolver nameResolver;
private volatile X509HostnameVerifier hostnameVerifier;
/**
* The default factory using the default JVM settings for secure connections.
*/
private final javax.net.ssl.SSLSocketFactory socketFactory;
private final HostNameResolver nameResolver;
private volatile X509HostnameVerifier hostnameVerifier;
private static SSLContext createSSLContext(String algorithm, final KeyStore keystore, final String keyStorePassword, final SecureRandom random, final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, KeyManagementException {
if (algorithm == null) {
algorithm = TLS;
}
private static SSLContext createSSLContext(String algorithm, final KeyStore keystore, final String keyStorePassword, final SecureRandom random, final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, KeyManagementException
{
if (algorithm == null)
{
algorithm = TLS;
}
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keystore, keyStorePassword != null ? keyStorePassword.toCharArray() : null);
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keystore);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keystore, keyStorePassword != null ? keyStorePassword.toCharArray() : null);
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keystore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers != null && trustStrategy != null) {
for (int i = 0; i < trustManagers.length; i++) {
TrustManager tm = trustManagers[i];
if (trustManagers != null && trustStrategy != null)
{
for (int i = 0; i < trustManagers.length; i++)
{
TrustManager tm = trustManagers[i];
if (tm instanceof X509TrustManager) {
trustManagers[i] = new TrustManagerDecorator((X509TrustManager) tm, trustStrategy);
}
}
}
if (tm instanceof X509TrustManager)
{
trustManagers[i] = new TrustManagerDecorator((X509TrustManager) tm, trustStrategy);
}
}
}
SSLContext sslcontext = SSLContext.getInstance(algorithm);
sslcontext.init(keyManagers, trustManagers, random);
SSLContext sslcontext = SSLContext.getInstance(algorithm);
sslcontext.init(keyManagers, trustManagers, random);
return sslcontext;
}
return sslcontext;
}
/**
* @since 4.1
*/
public SSLSocketFactory(String algorithm, final KeyStore keystore, final String keyStorePassword, final SecureRandom random, final TrustStrategy trustStrategy, final X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
this(createSSLContext(algorithm, keystore, keyStorePassword, random, trustStrategy), hostnameVerifier);
}
/**
* @since 4.1
*/
public SSLSocketFactory(String algorithm, final KeyStore keystore, final String keyStorePassword, final SecureRandom random, final TrustStrategy trustStrategy, final X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
{
this(createSSLContext(algorithm, keystore, keyStorePassword, random, trustStrategy), hostnameVerifier);
}
/**
* @since 4.1
*/
public SSLSocketFactory(final TrustStrategy trustStrategy, final X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
this(TLS, null, null, null, trustStrategy, hostnameVerifier);
}
/**
* @since 4.1
*/
public SSLSocketFactory(final TrustStrategy trustStrategy, final X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
{
this(TLS, null, null, null, trustStrategy, hostnameVerifier);
}
/**
* @since 4.1
*/
public SSLSocketFactory(final SSLContext sslContext, final X509HostnameVerifier hostnameVerifier) {
super();
this.socketFactory = sslContext.getSocketFactory();
this.hostnameVerifier = hostnameVerifier;
this.nameResolver = null;
}
/**
* @since 4.1
*/
public SSLSocketFactory(final SSLContext sslContext, final X509HostnameVerifier hostnameVerifier)
{
super();
this.socketFactory = sslContext.getSocketFactory();
this.hostnameVerifier = hostnameVerifier;
this.nameResolver = null;
}
@SuppressWarnings("cast")
public Socket createSocket() throws IOException {
// the cast makes sure that the factory is working as expected
return this.socketFactory.createSocket();
}
@SuppressWarnings("cast")
public Socket createSocket() throws IOException
{
// the cast makes sure that the factory is working as expected
return this.socketFactory.createSocket();
}
/**
* @since 4.1
*/
public Socket connectSocket(final Socket sock, final InetSocketAddress remoteAddress, final InetSocketAddress localAddress, final HttpParams params) throws IOException {
if (remoteAddress == null) {
throw new IllegalArgumentException("Remote address may not be null");
}
/**
* @since 4.1
*/
public Socket connectSocket(final Socket sock, final InetSocketAddress remoteAddress, final InetSocketAddress localAddress, final HttpParams params) throws IOException
{
if (remoteAddress == null)
{
throw new IllegalArgumentException("Remote address may not be null");
}
if (params == null) {
throw new IllegalArgumentException("HTTP parameters may not be null");
}
if (params == null)
{
throw new IllegalArgumentException("HTTP parameters may not be null");
}
SSLSocket sslSocket = (SSLSocket) (sock != null ? sock : createSocket());
SSLSocket sslSocket = (SSLSocket) (sock != null ? sock : createSocket());
if (localAddress != null) {
// sslSocket.setReuseAddress(HttpConnectionParams.getSoReuseaddr(params));
sslSocket.bind(localAddress);
}
if (localAddress != null)
{
// sslSocket.setReuseAddress(HttpConnectionParams.getSoReuseaddr(params));
sslSocket.bind(localAddress);
}
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
try {
sslSocket.connect(remoteAddress, connTimeout);
} catch (SocketTimeoutException ex) {
throw new ConnectTimeoutException("Connect to " + remoteAddress.getHostName() + "/" + remoteAddress.getAddress() + " timed out");
}
try
{
sslSocket.connect(remoteAddress, connTimeout);
}
catch (SocketTimeoutException ex)
{
throw new ConnectTimeoutException(String.format("Connect to %s/%s timed out", remoteAddress.getHostName(), remoteAddress.getAddress()));
}
sslSocket.setSoTimeout(soTimeout);
sslSocket.setSoTimeout(soTimeout);
if (this.hostnameVerifier != null) {
try {
this.hostnameVerifier.verify(remoteAddress.getHostName(), sslSocket);
// verifyHostName() didn't blowup - good!
} catch (IOException iox) {
// close the socket before re-throwing the exception
try { sslSocket.close(); } catch (Exception x) { /*ignore*/ }
throw iox;
}
}
if (this.hostnameVerifier != null)
{
try
{
this.hostnameVerifier.verify(remoteAddress.getHostName(), sslSocket);
// verifyHostName() didn't blowup - good!
}
catch (IOException iox)
{
// close the socket before re-throwing the exception
try
{
sslSocket.close();
}
catch (Exception x)
{ /*ignore*/ }
throw iox;
}
}
return sslSocket;
}
return sslSocket;
}
/**
* Checks whether a socket connection is secure.
* This factory creates TLS/SSL socket connections
* which, by default, are considered secure.
* <br/>
* Derived classes may override this method to perform
* runtime checks, for example based on the cypher suite.
*
* @param sock the connected socket
*
* @return <code>true</code>
*
* @throws IllegalArgumentException if the argument is invalid
*/
public boolean isSecure(final Socket sock) throws IllegalArgumentException {
if (sock == null) {
throw new IllegalArgumentException("Socket may not be null");
}
/**
* Checks whether a socket connection is secure.
* This factory creates TLS/SSL socket connections
* which, by default, are considered secure.
* <br/>
* Derived classes may override this method to perform
* runtime checks, for example based on the cypher suite.
*
* @param sock the connected socket
* @return <code>true</code>
* @throws IllegalArgumentException if the argument is invalid
*/
public boolean isSecure(final Socket sock) throws IllegalArgumentException
{
if (sock == null)
{
throw new IllegalArgumentException("Socket may not be null");
}
// This instanceof check is in line with createSocket() above.
if (!(sock instanceof SSLSocket)) {
throw new IllegalArgumentException("Socket not created by this factory");
}
// This instanceof check is in line with createSocket() above.
if (!(sock instanceof SSLSocket))
{
throw new IllegalArgumentException("Socket not created by this factory");
}
// This check is performed last since it calls the argument object.
if (sock.isClosed()) {
throw new IllegalArgumentException("Socket is closed");
}
// This check is performed last since it calls the argument object.
if (sock.isClosed())
{
throw new IllegalArgumentException("Socket is closed");
}
return true;
}
return true;
}
/**
* @since 4.1
*/
public Socket createLayeredSocket(final Socket socket, final String host, final int port, final boolean autoClose) throws IOException {
SSLSocket sslSocket = (SSLSocket) this.socketFactory.createSocket(socket, host, port, autoClose);
/**
* @since 4.1
*/
public Socket createLayeredSocket(final Socket socket, final String host, final int port, final boolean autoClose) throws IOException
{
SSLSocket sslSocket = (SSLSocket) this.socketFactory.createSocket(socket, host, port, autoClose);
if (this.hostnameVerifier != null) {
this.hostnameVerifier.verify(host, sslSocket);
}
if (this.hostnameVerifier != null)
{
this.hostnameVerifier.verify(host, sslSocket);
}
// verifyHostName() didn't blowup - good!
return sslSocket;
}
// verifyHostName() didn't blowup - good!
return sslSocket;
}
/**
* @deprecated Use {@link #connectSocket(Socket, InetSocketAddress, InetSocketAddress, HttpParams)}
*/
@Deprecated
public Socket connectSocket(final Socket socket, final String host, int port, final InetAddress localAddress, int localPort, final HttpParams params) throws IOException {
InetSocketAddress local = null;
/**
* @deprecated Use {@link #connectSocket(Socket, InetSocketAddress, InetSocketAddress, HttpParams)}
*/
@Deprecated
public Socket connectSocket(final Socket socket, final String host, int port, final InetAddress localAddress, int localPort, final HttpParams params) throws IOException
{
InetSocketAddress local = null;
if (localAddress != null || localPort > 0) {
// we need to bind explicitly
if (localPort < 0) {
localPort = 0; // indicates "any"
}
if (localAddress != null || localPort > 0)
{
// we need to bind explicitly
if (localPort < 0)
{
localPort = 0; // indicates "any"
}
local = new InetSocketAddress(localAddress, localPort);
}
local = new InetSocketAddress(localAddress, localPort);
}
InetAddress remoteAddress;
InetAddress remoteAddress;
if (this.nameResolver != null) {
remoteAddress = this.nameResolver.resolve(host);
} else {
remoteAddress = InetAddress.getByName(host);
}
if (this.nameResolver != null)
{
remoteAddress = this.nameResolver.resolve(host);
}
else
{
remoteAddress = InetAddress.getByName(host);
}
InetSocketAddress remote = new InetSocketAddress(remoteAddress, port);
InetSocketAddress remote = new InetSocketAddress(remoteAddress, port);
return connectSocket(socket, remote, local, params);
}
return connectSocket(socket, remote, local, params);
}
/**
* @deprecated Use {@link #createLayeredSocket(Socket, String, int, boolean)}
*/
@Deprecated
public Socket createSocket(final Socket socket, final String host, int port, boolean autoClose) throws IOException {
return createLayeredSocket(socket, host, port, autoClose);
}
/**
* @deprecated Use {@link #createLayeredSocket(Socket, String, int, boolean)}
*/
@Deprecated
public Socket createSocket(final Socket socket, final String host, int port, boolean autoClose) throws IOException
{
return createLayeredSocket(socket, host, port, autoClose);
}
}

View File

@ -34,28 +34,37 @@ import javax.net.ssl.X509TrustManager;
/**
* @since 4.1
*/
class TrustManagerDecorator implements X509TrustManager {
class TrustManagerDecorator implements X509TrustManager
{
private final X509TrustManager trustManager;
private final TrustStrategy trustStrategy;
private final X509TrustManager trustManager;
private final TrustStrategy trustStrategy;
TrustManagerDecorator(final X509TrustManager trustManager, final TrustStrategy trustStrategy) {
super();
this.trustManager = trustManager;
this.trustStrategy = trustStrategy;
}
TrustManagerDecorator(final X509TrustManager trustManager, final TrustStrategy trustStrategy)
{
super();
this.trustManager = trustManager;
this.trustStrategy = trustStrategy;
}
public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
this.trustManager.checkClientTrusted(chain, authType);
}
@Override
public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException
{
this.trustManager.checkClientTrusted(chain, authType);
}
public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
if (!this.trustStrategy.isTrusted(chain, authType)) {
this.trustManager.checkServerTrusted(chain, authType);
}
}
@Override
public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException
{
if (!this.trustStrategy.isTrusted(chain, authType))
{
this.trustManager.checkServerTrusted(chain, authType);
}
}
public X509Certificate[] getAcceptedIssuers() {
return this.trustManager.getAcceptedIssuers();
}
@Override
public X509Certificate[] getAcceptedIssuers()
{
return this.trustManager.getAcceptedIssuers();
}
}

View File

@ -35,10 +35,12 @@ import java.security.cert.X509Certificate;
*
* @since 4.1
*/
public class TrustSelfSignedStrategy implements TrustStrategy {
public boolean isTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
return true;
}
public class TrustSelfSignedStrategy implements TrustStrategy
{
@Override
public boolean isTrusted(final X509Certificate[] chain, final String authType) throws CertificateException
{
return true;
}
}

View File

@ -36,22 +36,23 @@ import java.security.cert.X509Certificate;
*
* @since 4.1
*/
public interface TrustStrategy {
public interface TrustStrategy
{
/**
* Determines whether the certificate chain can be trusted without consulting the trust manager
* configured in the actual SSL context. This method can be used to override the standard JSSE
* certificate verification process.
* <p>
* Please note that, if this method returns <code>false</code>, the trust manager configured
* in the actual SSL context can still clear the certificate as trusted.
*
* @param chain the peer certificate chain
* @param authType the authentication type based on the client certificate
* @return <code>true</code> if the certificate can be trusted without verification by
* the trust manager, <code>false</code> otherwise.
* @throws CertificateException thrown if the certificate is not trusted or invalid.
*/
boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException;
/**
* Determines whether the certificate chain can be trusted without consulting the trust manager
* configured in the actual SSL context. This method can be used to override the standard JSSE
* certificate verification process.
* <p/>
* Please note that, if this method returns <code>false</code>, the trust manager configured
* in the actual SSL context can still clear the certificate as trusted.
*
* @param chain the peer certificate chain
* @param authType the authentication type based on the client certificate
* @return <code>true</code> if the certificate can be trusted without verification by
* the trust manager, <code>false</code> otherwise.
* @throws CertificateException thrown if the certificate is not trusted or invalid.
*/
boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException;
}

View File

@ -5,81 +5,97 @@ import android.content.Context;
import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class AlbumHeader {
private boolean isAllVideo;
private long totalDuration;
private Set<String> artists;
private Set<String> grandParents;
private Set<String> genres;
public class AlbumHeader
{
private boolean isAllVideo;
private long totalDuration;
private Set<String> artists;
private Set<String> grandParents;
private Set<String> genres;
public boolean getIsAllVideo() {
return isAllVideo;
}
public boolean getIsAllVideo()
{
return isAllVideo;
}
public long getTotalDuration() {
return totalDuration;
}
public long getTotalDuration()
{
return totalDuration;
}
public Set<String> getArtists () {
return artists;
}
public Set<String> getArtists()
{
return artists;
}
public Set<String> getGrandParents () {
return this.grandParents;
}
public Set<String> getGrandParents()
{
return this.grandParents;
}
public Set<String> getGenres () {
return this.genres;
}
public Set<String> getGenres()
{
return this.genres;
}
public AlbumHeader() {
this.artists = new HashSet<String>();
this.grandParents = new HashSet<String>();
this.genres = new HashSet<String>();
this.isAllVideo = true;
this.totalDuration = 0;
}
public AlbumHeader()
{
this.artists = new HashSet<String>();
this.grandParents = new HashSet<String>();
this.genres = new HashSet<String>();
this.isAllVideo = true;
this.totalDuration = 0;
}
public static AlbumHeader processEntries(Context context, List<MusicDirectory.Entry> entries) {
AlbumHeader albumHeader = new AlbumHeader();
public static AlbumHeader processEntries(Context context, Iterable<MusicDirectory.Entry> entries)
{
AlbumHeader albumHeader = new AlbumHeader();
for (MusicDirectory.Entry entry : entries) {
if (!entry.isVideo()) {
albumHeader.isAllVideo = false;
}
for (MusicDirectory.Entry entry : entries)
{
if (!entry.isVideo())
{
albumHeader.isAllVideo = false;
}
if (!entry.isDirectory()) {
if (Util.shouldUseFolderForArtistName(context)) {
albumHeader.processGrandParents(entry);
}
if (!entry.isDirectory())
{
if (Util.shouldUseFolderForArtistName(context))
{
albumHeader.processGrandParents(entry);
}
if (entry.getArtist() != null) {
Integer duration = entry.getDuration();
if (entry.getArtist() != null)
{
Integer duration = entry.getDuration();
if (duration != null) {
albumHeader.totalDuration += duration;
}
if (duration != null)
{
albumHeader.totalDuration += duration;
}
albumHeader.artists.add(entry.getArtist());
}
albumHeader.artists.add(entry.getArtist());
}
if (entry.getGenre() != null) {
albumHeader.genres.add(entry.getGenre());
}
}
}
if (entry.getGenre() != null)
{
albumHeader.genres.add(entry.getGenre());
}
}
}
return albumHeader;
}
return albumHeader;
}
private void processGrandParents(MusicDirectory.Entry entry) {
String grandParent = Util.getGrandparent(entry.getPath());
private void processGrandParents(MusicDirectory.Entry entry)
{
String grandParent = Util.getGrandparent(entry.getPath());
if (grandParent != null) {
this.grandParents.add(grandParent);
}
}
if (grandParent != null)
{
this.grandParents.add(grandParent);
}
}
}

View File

@ -18,79 +18,92 @@
*/
package com.thejoshwa.ultrasonic.androidapp.util;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.xmlpull.v1.XmlPullParserException;
import android.app.Activity;
import android.os.Handler;
import android.util.Log;
import com.thejoshwa.ultrasonic.androidapp.R;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* @author Sindre Mehus
*/
public abstract class BackgroundTask<T> implements ProgressListener {
public abstract class BackgroundTask<T> implements ProgressListener
{
private static final String TAG = BackgroundTask.class.getSimpleName();
private final Activity activity;
private final Handler handler;
private static final String TAG = BackgroundTask.class.getSimpleName();
private final Activity activity;
private final Handler handler;
public BackgroundTask(Activity activity) {
this.activity = activity;
handler = new Handler();
}
public BackgroundTask(Activity activity)
{
this.activity = activity;
handler = new Handler();
}
protected Activity getActivity() {
return activity;
}
protected Activity getActivity()
{
return activity;
}
protected Handler getHandler() {
return handler;
}
protected Handler getHandler()
{
return handler;
}
public abstract void execute();
public abstract void execute();
protected abstract T doInBackground() throws Throwable;
protected abstract T doInBackground() throws Throwable;
protected abstract void done(T result);
protected abstract void done(T result);
protected void error(Throwable error) {
Log.w(TAG, "Got exception: " + error, error);
new ErrorDialog(activity, getErrorMessage(error), true);
}
protected void error(Throwable error)
{
Log.w(TAG, String.format("Got exception: %s", error), error);
new ErrorDialog(activity, getErrorMessage(error), true);
}
protected String getErrorMessage(Throwable error) {
protected String getErrorMessage(Throwable error)
{
if (error instanceof IOException && !Util.isNetworkConnected(activity)) {
return activity.getResources().getString(R.string.background_task_no_network);
}
if (error instanceof IOException && !Util.isNetworkConnected(activity))
{
return activity.getResources().getString(R.string.background_task_no_network);
}
if (error instanceof FileNotFoundException) {
return activity.getResources().getString(R.string.background_task_not_found);
}
if (error instanceof FileNotFoundException)
{
return activity.getResources().getString(R.string.background_task_not_found);
}
if (error instanceof IOException) {
return activity.getResources().getString(R.string.background_task_network_error);
}
if (error instanceof IOException)
{
return activity.getResources().getString(R.string.background_task_network_error);
}
if (error instanceof XmlPullParserException) {
return activity.getResources().getString(R.string.background_task_parse_error);
}
if (error instanceof XmlPullParserException)
{
return activity.getResources().getString(R.string.background_task_parse_error);
}
String message = error.getMessage();
if (message != null) {
return message;
}
return error.getClass().getSimpleName();
}
String message = error.getMessage();
if (message != null)
{
return message;
}
return error.getClass().getSimpleName();
}
@Override
public abstract void updateProgress(final String message);
@Override
public abstract void updateProgress(final String message);
@Override
public void updateProgress(int messageId) {
updateProgress(activity.getResources().getString(messageId));
}
@Override
public void updateProgress(int messageId)
{
updateProgress(activity.getResources().getString(messageId));
}
}

View File

@ -1,7 +1,17 @@
package com.thejoshwa.ultrasonic.androidapp.util;
import android.content.Context;
import android.os.AsyncTask;
import android.os.StatFs;
import android.util.Log;
import com.thejoshwa.ultrasonic.androidapp.domain.Playlist;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadFile;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadService;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
@ -9,172 +19,202 @@ import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import android.content.Context;
import android.util.Log;
import android.os.AsyncTask;
import android.os.StatFs;
import com.thejoshwa.ultrasonic.androidapp.domain.Playlist;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadFile;
import com.thejoshwa.ultrasonic.androidapp.service.DownloadService;
/**
* @author Sindre Mehus
* @version $Id$
*/
public class CacheCleaner {
public class CacheCleaner
{
private static final String TAG = CacheCleaner.class.getSimpleName();
private static final String TAG = CacheCleaner.class.getSimpleName();
private static final long MIN_FREE_SPACE = 500 * 1024L * 1024L;
private final Context context;
private final DownloadService downloadService;
private final Context context;
private final DownloadService downloadService;
public CacheCleaner(Context context, DownloadService downloadService) {
this.context = context;
this.downloadService = downloadService;
}
public void clean() {
new BackgroundCleanup().execute();
}
public void cleanSpace() {
new BackgroundSpaceCleanup().execute();
public CacheCleaner(Context context, DownloadService downloadService)
{
this.context = context;
this.downloadService = downloadService;
}
public void cleanPlaylists(List<Playlist> playlists) {
public void clean()
{
new BackgroundCleanup().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public void cleanSpace()
{
new BackgroundSpaceCleanup().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public void cleanPlaylists(List<Playlist> playlists)
{
new BackgroundPlaylistsCleanup().execute(playlists);
}
private void deleteEmptyDirs(List<File> dirs, Set<File> undeletable) {
for (File dir : dirs) {
if (undeletable.contains(dir)) {
continue;
}
private static void deleteEmptyDirs(Iterable<File> dirs, Collection<File> undeletable)
{
for (File dir : dirs)
{
if (undeletable.contains(dir))
{
continue;
}
File[] children = dir.listFiles();
File[] children = dir.listFiles();
if (children != null) {
// No songs left in the folder
if (children.length == 1 && children[0].getPath().equals(FileUtil.getAlbumArtFile(dir).getPath())) {
Util.delete(FileUtil.getAlbumArtFile(dir));
children = dir.listFiles();
}
if (children != null)
{
// No songs left in the folder
if (children.length == 1 && children[0].getPath().equals(FileUtil.getAlbumArtFile(dir).getPath()))
{
Util.delete(FileUtil.getAlbumArtFile(dir));
children = dir.listFiles();
}
// Delete empty directory
if (children != null && children.length == 0) {
Util.delete(dir);
}
}
}
}
private long getMinimumDelete(List<File> files) {
if(files.size() == 0) {
// Delete empty directory
if (children != null && children.length == 0)
{
Util.delete(dir);
}
}
}
}
private long getMinimumDelete(List<File> files)
{
if (files.size() == 0)
{
return 0L;
}
long cacheSizeBytes = Util.getCacheSizeMB(context) * 1024L * 1024L;
long bytesUsedBySubsonic = 0L;
for (File file : files) {
bytesUsedBySubsonic += file.length();
}
long bytesUsedBySubsonic = 0L;
for (File file : files)
{
bytesUsedBySubsonic += file.length();
}
// Ensure that file system is not more than 95% full.
StatFs stat = new StatFs(files.get(0).getPath());
long bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize();
long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
long bytesUsedFs = bytesTotalFs - bytesAvailableFs;
long minFsAvailability = bytesTotalFs - MIN_FREE_SPACE;
StatFs stat = new StatFs(files.get(0).getPath());
long bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize();
long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
long bytesUsedFs = bytesTotalFs - bytesAvailableFs;
long minFsAvailability = bytesTotalFs - MIN_FREE_SPACE;
long bytesToDeleteCacheLimit = Math.max(bytesUsedBySubsonic - cacheSizeBytes, 0L);
long bytesToDeleteFsLimit = Math.max(bytesUsedFs - minFsAvailability, 0L);
long bytesToDelete = Math.max(bytesToDeleteCacheLimit, bytesToDeleteFsLimit);
long bytesToDeleteCacheLimit = Math.max(bytesUsedBySubsonic - cacheSizeBytes, 0L);
long bytesToDeleteFsLimit = Math.max(bytesUsedFs - minFsAvailability, 0L);
long bytesToDelete = Math.max(bytesToDeleteCacheLimit, bytesToDeleteFsLimit);
Log.i(TAG, String.format("File system : %s of %s available", Util.formatBytes(bytesAvailableFs), Util.formatBytes(bytesTotalFs)));
Log.i(TAG, String.format("Cache limit : %s", Util.formatBytes(cacheSizeBytes)));
Log.i(TAG, String.format("Cache size before : %s", Util.formatBytes(bytesUsedBySubsonic)));
Log.i(TAG, String.format("Minimum to delete : %s", Util.formatBytes(bytesToDelete)));
Log.i(TAG, "File system : " + Util.formatBytes(bytesAvailableFs) + " of " + Util.formatBytes(bytesTotalFs) + " available");
Log.i(TAG, "Cache limit : " + Util.formatBytes(cacheSizeBytes));
Log.i(TAG, "Cache size before : " + Util.formatBytes(bytesUsedBySubsonic));
Log.i(TAG, "Minimum to delete : " + Util.formatBytes(bytesToDelete));
return bytesToDelete;
}
private void deleteFiles(List<File> files, Set<File> undeletable, long bytesToDelete, boolean deletePartials) {
if (files.isEmpty()) {
return;
}
private static void deleteFiles(Collection<File> files, Collection<File> undeletable, long bytesToDelete, boolean deletePartials)
{
if (files.isEmpty())
{
return;
}
long bytesDeleted = 0L;
for (File file : files) {
if(!deletePartials && bytesDeleted > bytesToDelete) break;
long bytesDeleted = 0L;
for (File file : files)
{
if (!deletePartials && bytesDeleted > bytesToDelete) break;
if (bytesToDelete > bytesDeleted || (deletePartials && (file.getName().endsWith(".partial") || file.getName().contains(".partial.")))) {
if (!undeletable.contains(file) && !file.getName().equals(Constants.ALBUM_ART_FILE)) {
long size = file.length();
if (Util.delete(file)) {
bytesDeleted += size;
}
}
}
}
if (bytesToDelete > bytesDeleted || (deletePartials && (file.getName().endsWith(".partial") || file.getName().contains(".partial."))))
{
if (!undeletable.contains(file) && !file.getName().equals(Constants.ALBUM_ART_FILE))
{
long size = file.length();
if (Util.delete(file))
{
bytesDeleted += size;
}
}
}
}
Log.i(TAG, "Deleted : " + Util.formatBytes(bytesDeleted));
}
Log.i(TAG, String.format("Deleted : %s", Util.formatBytes(bytesDeleted)));
}
private void findCandidatesForDeletion(File file, List<File> files, List<File> dirs) {
if (file.isFile()) {
String name = file.getName();
boolean isCacheFile = name.endsWith(".partial") || name.contains(".partial.") || name.endsWith(".complete") || name.contains(".complete.");
if (isCacheFile) {
files.add(file);
}
} else {
// Depth-first
for (File child : FileUtil.listFiles(file)) {
findCandidatesForDeletion(child, files, dirs);
}
dirs.add(file);
}
}
private static void findCandidatesForDeletion(File file, List<File> files, List<File> dirs)
{
if (file.isFile())
{
String name = file.getName();
boolean isCacheFile = name.endsWith(".partial") || name.contains(".partial.") || name.endsWith(".complete") || name.contains(".complete.");
if (isCacheFile)
{
files.add(file);
}
}
else
{
// Depth-first
for (File child : FileUtil.listFiles(file))
{
findCandidatesForDeletion(child, files, dirs);
}
dirs.add(file);
}
}
private void sortByAscendingModificationTime(List<File> files) {
Collections.sort(files, new Comparator<File>() {
@Override
public int compare(File a, File b) {
if (a.lastModified() < b.lastModified()) {
return -1;
}
if (a.lastModified() > b.lastModified()) {
return 1;
}
return 0;
}
});
}
private static void sortByAscendingModificationTime(List<File> files)
{
Collections.sort(files, new Comparator<File>()
{
@Override
public int compare(File a, File b)
{
if (a.lastModified() < b.lastModified())
{
return -1;
}
private Set<File> findUndeletableFiles() {
Set<File> undeletable = new HashSet<File>(5);
if (a.lastModified() > b.lastModified())
{
return 1;
}
for (DownloadFile downloadFile : downloadService.getDownloads()) {
undeletable.add(downloadFile.getPartialFile());
undeletable.add(downloadFile.getCompleteFile());
}
return 0;
}
});
}
undeletable.add(FileUtil.getMusicDirectory(context));
return undeletable;
}
private Set<File> findUndeletableFiles()
{
Set<File> undeletable = new HashSet<File>(5);
private class BackgroundCleanup extends AsyncTask<Void, Void, Void> {
for (DownloadFile downloadFile : downloadService.getDownloads())
{
undeletable.add(downloadFile.getPartialFile());
undeletable.add(downloadFile.getCompleteFile());
}
undeletable.add(FileUtil.getMusicDirectory(context));
return undeletable;
}
private class BackgroundCleanup extends AsyncTask<Void, Void, Void>
{
@Override
protected Void doInBackground(Void... params) {
if (downloadService == null) {
protected Void doInBackground(Void... params)
{
if (downloadService == null)
{
Log.e(TAG, "DownloadService not set. Aborting cache cleaning.");
return null;
}
try {
try
{
List<File> files = new ArrayList<File>();
List<File> dirs = new ArrayList<File>();
@ -185,7 +225,9 @@ public class CacheCleaner {
deleteFiles(files, undeletable, getMinimumDelete(files), true);
deleteEmptyDirs(dirs, undeletable);
} catch (RuntimeException x) {
}
catch (RuntimeException x)
{
Log.e(TAG, "Error in cache cleaning.", x);
}
@ -193,26 +235,33 @@ public class CacheCleaner {
}
}
private class BackgroundSpaceCleanup extends AsyncTask<Void, Void, Void> {
private class BackgroundSpaceCleanup extends AsyncTask<Void, Void, Void>
{
@Override
protected Void doInBackground(Void... params) {
if (downloadService == null) {
protected Void doInBackground(Void... params)
{
if (downloadService == null)
{
Log.e(TAG, "DownloadService not set. Aborting cache cleaning.");
return null;
}
try {
try
{
List<File> files = new ArrayList<File>();
List<File> dirs = new ArrayList<File>();
findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, dirs);
long bytesToDelete = getMinimumDelete(files);
if(bytesToDelete > 0L) {
if (bytesToDelete > 0L)
{
sortByAscendingModificationTime(files);
Set<File> undeletable = findUndeletableFiles();
deleteFiles(files, undeletable, bytesToDelete, false);
}
} catch (RuntimeException x) {
}
catch (RuntimeException x)
{
Log.e(TAG, "Error in cache cleaning.", x);
}
@ -220,21 +269,28 @@ public class CacheCleaner {
}
}
private class BackgroundPlaylistsCleanup extends AsyncTask<List<Playlist>, Void, Void> {
private class BackgroundPlaylistsCleanup extends AsyncTask<List<Playlist>, Void, Void>
{
@Override
protected Void doInBackground(List<Playlist>... params) {
try {
protected Void doInBackground(List<Playlist>... params)
{
try
{
String server = Util.getServerName(context);
SortedSet<File> playlistFiles = FileUtil.listFiles(FileUtil.getPlaylistDirectory(server));
List<Playlist> playlists = params[0];
for (Playlist playlist : playlists) {
for (Playlist playlist : playlists)
{
playlistFiles.remove(FileUtil.getPlaylistFile(server, playlist.getName()));
}
for(File playlist : playlistFiles) {
for (File playlist : playlistFiles)
{
playlist.delete();
}
} catch (RuntimeException x) {
}
catch (RuntimeException x)
{
Log.e(TAG, "Error in playlist cache cleaning.", x);
}

Some files were not shown because too many files have changed in this diff Show More