aboutsummaryrefslogtreecommitdiff
path: root/subsonic-android/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'subsonic-android/src/net')
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/DownloadActivity.java874
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/EqualizerActivity.java181
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/HelpActivity.java117
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/LyricsActivity.java72
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/MainActivity.java258
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/PlayVideoActivity.java147
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/QueryReceiverActivity.java56
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SearchActivity.java368
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SelectAlbumActivity.java568
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SelectArtistActivity.java228
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SelectPlaylistActivity.java141
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SettingsActivity.java297
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SubsonicTabActivity.java382
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/VoiceQueryReceiverActivity.java59
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/audiofx/EqualizerController.java138
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/audiofx/VisualizerController.java90
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Artist.java60
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Indexes.java50
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/JukeboxStatus.java63
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Lyrics.java55
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/MusicDirectory.java259
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/MusicFolder.java46
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/PlayerState.java34
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Playlist.java56
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/RepeatMode.java28
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/SearchCritera.java55
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/SearchResult.java51
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/ServerInfo.java46
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Version.java142
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/provider/SearchSuggestionProvider.java36
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/provider/SubsonicAppWidgetProvider.java238
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/receiver/BluetoothIntentReceiver.java53
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/receiver/MediaButtonIntentReceiver.java50
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/CachedMusicService.java237
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadFile.java323
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadService.java112
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadServiceImpl.java930
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadServiceLifecycleSupport.java271
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/JukeboxService.java356
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/MediaStoreService.java109
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/MusicService.java91
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/MusicServiceFactory.java36
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/OfflineException.java32
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/OfflineMusicService.java273
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/RESTMusicService.java785
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/Scrobbler.java52
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ServerTooOldException.java51
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/AbstractParser.java138
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/AlbumListParser.java62
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/ErrorParser.java49
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/IndexesParser.java104
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/JukeboxStatusParser.java62
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/LicenseParser.java62
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/LyricsParser.java65
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/MusicDirectoryEntryParser.java59
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/MusicDirectoryParser.java71
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/MusicFoldersParser.java69
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/PlaylistParser.java62
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/PlaylistsParser.java67
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/RandomSongsParser.java62
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/SearchResult2Parser.java75
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/SearchResultParser.java67
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/SubsonicRESTException.java19
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/VersionParser.java47
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/SSLSocketFactory.java497
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/TrustManagerDecorator.java65
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/TrustSelfSignedStrategy.java44
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/TrustStrategy.java57
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/AlbumView.java55
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ArtistAdapter.java78
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/BackgroundTask.java96
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/CacheCleaner.java171
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/CancellableTask.java87
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/Constants.java91
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/EntryAdapter.java71
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ErrorDialog.java61
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/FileUtil.java311
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/HorizontalSlider.java141
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ImageLoader.java252
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/LRUCache.java102
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/MergeAdapter.java290
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ModalBackgroundTask.java139
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/MyViewFlipper.java53
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/Pair.java54
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/PlaylistAdapter.java99
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ProgressListener.java27
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SackOfViewsAdapter.java181
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ShufflePlayBuffer.java109
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SilentBackgroundTask.java67
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SimpleServiceBinder.java37
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SongView.java178
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/TabActivityBackgroundTask.java67
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/TimeLimitedCache.java55
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/util/Util.java829
-rw-r--r--subsonic-android/src/net/sourceforge/subsonic/androidapp/view/VisualizerView.java132
95 files changed, 0 insertions, 14592 deletions
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/DownloadActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/DownloadActivity.java
deleted file mode 100644
index 68144481..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/DownloadActivity.java
+++ /dev/null
@@ -1,874 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.activity;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.graphics.Color;
-import android.graphics.Typeface;
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.ContextMenu;
-import android.view.Display;
-import android.view.GestureDetector;
-import android.view.GestureDetector.OnGestureListener;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.animation.AnimationUtils;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.ViewFlipper;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.domain.PlayerState;
-import net.sourceforge.subsonic.androidapp.domain.RepeatMode;
-import net.sourceforge.subsonic.androidapp.service.DownloadFile;
-import net.sourceforge.subsonic.androidapp.service.DownloadService;
-import net.sourceforge.subsonic.androidapp.service.MusicService;
-import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.HorizontalSlider;
-import net.sourceforge.subsonic.androidapp.util.SilentBackgroundTask;
-import net.sourceforge.subsonic.androidapp.util.SongView;
-import net.sourceforge.subsonic.androidapp.util.Util;
-import net.sourceforge.subsonic.androidapp.view.VisualizerView;
-
-import static net.sourceforge.subsonic.androidapp.domain.PlayerState.*;
-
-public class DownloadActivity extends SubsonicTabActivity implements OnGestureListener {
-
- private static final int DIALOG_SAVE_PLAYLIST = 100;
- private static final int PERCENTAGE_OF_SCREEN_FOR_SWIPE = 5;
- private static final int COLOR_BUTTON_ENABLED = Color.rgb(129, 201, 54);
- private static final int COLOR_BUTTON_DISABLED = Color.rgb(164, 166, 158);
-
- private ViewFlipper playlistFlipper;
- private ViewFlipper buttonBarFlipper;
- private TextView emptyTextView;
- private TextView songTitleTextView;
- private TextView albumTextView;
- private TextView artistTextView;
- private ImageView albumArtImageView;
- private ListView playlistView;
- private TextView positionTextView;
- private TextView durationTextView;
- private TextView statusTextView;
- private HorizontalSlider progressBar;
- private View previousButton;
- private View nextButton;
- private View pauseButton;
- private View stopButton;
- private View startButton;
- private View shuffleButton;
- private ImageButton repeatButton;
- private Button equalizerButton;
- private Button visualizerButton;
- private Button jukeboxButton;
- private View toggleListButton;
- private ScheduledExecutorService executorService;
- private DownloadFile currentPlaying;
- private long currentRevision;
- private EditText playlistNameView;
- private GestureDetector gestureScanner;
- private int swipeDistance;
- private int swipeVelocity;
- private VisualizerView visualizerView;
-
- /**
- * Called when the activity is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.download);
-
- WindowManager w = getWindowManager();
- Display d = w.getDefaultDisplay();
- swipeDistance = (d.getWidth() + d.getHeight()) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100;
- swipeVelocity = (d.getWidth() + d.getHeight()) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100;
- gestureScanner = new GestureDetector(this);
-
- playlistFlipper = (ViewFlipper) findViewById(R.id.download_playlist_flipper);
- buttonBarFlipper = (ViewFlipper) findViewById(R.id.download_button_bar_flipper);
- emptyTextView = (TextView) findViewById(R.id.download_empty);
- songTitleTextView = (TextView) findViewById(R.id.download_song_title);
- albumTextView = (TextView) findViewById(R.id.download_album);
- artistTextView = (TextView) findViewById(R.id.download_artist);
- albumArtImageView = (ImageView) findViewById(R.id.download_album_art_image);
- positionTextView = (TextView) findViewById(R.id.download_position);
- durationTextView = (TextView) findViewById(R.id.download_duration);
- statusTextView = (TextView) findViewById(R.id.download_status);
- progressBar = (HorizontalSlider) findViewById(R.id.download_progress_bar);
- playlistView = (ListView) findViewById(R.id.download_list);
- previousButton = findViewById(R.id.download_previous);
- nextButton = findViewById(R.id.download_next);
- pauseButton = findViewById(R.id.download_pause);
- stopButton = findViewById(R.id.download_stop);
- startButton = findViewById(R.id.download_start);
- shuffleButton = findViewById(R.id.download_shuffle);
- repeatButton = (ImageButton) findViewById(R.id.download_repeat);
- equalizerButton = (Button) findViewById(R.id.download_equalizer);
- visualizerButton = (Button) findViewById(R.id.download_visualizer);
- jukeboxButton = (Button) findViewById(R.id.download_jukebox);
- LinearLayout visualizerViewLayout = (LinearLayout) findViewById(R.id.download_visualizer_view_layout);
-
- toggleListButton = findViewById(R.id.download_toggle_list);
-
- View.OnTouchListener touchListener = new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent me) {
- return gestureScanner.onTouchEvent(me);
- }
- };
- previousButton.setOnTouchListener(touchListener);
- nextButton.setOnTouchListener(touchListener);
- pauseButton.setOnTouchListener(touchListener);
- stopButton.setOnTouchListener(touchListener);
- startButton.setOnTouchListener(touchListener);
- equalizerButton.setOnTouchListener(touchListener);
- visualizerButton.setOnTouchListener(touchListener);
- jukeboxButton.setOnTouchListener(touchListener);
- buttonBarFlipper.setOnTouchListener(touchListener);
- emptyTextView.setOnTouchListener(touchListener);
- albumArtImageView.setOnTouchListener(touchListener);
-
- albumArtImageView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- toggleFullscreenAlbumArt();
- }
- });
-
- previousButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- warnIfNetworkOrStorageUnavailable();
- getDownloadService().previous();
- onCurrentChanged();
- onProgressChanged();
- }
- });
-
- nextButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- warnIfNetworkOrStorageUnavailable();
- if (getDownloadService().getCurrentPlayingIndex() < getDownloadService().size() - 1) {
- getDownloadService().next();
- onCurrentChanged();
- onProgressChanged();
- }
- }
- });
-
- pauseButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- getDownloadService().pause();
- onCurrentChanged();
- onProgressChanged();
- }
- });
-
- stopButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- getDownloadService().reset();
- onCurrentChanged();
- onProgressChanged();
- }
- });
-
- startButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- warnIfNetworkOrStorageUnavailable();
- start();
- onCurrentChanged();
- onProgressChanged();
- }
- });
-
- shuffleButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- getDownloadService().shuffle();
- Util.toast(DownloadActivity.this, R.string.download_menu_shuffle_notification);
- }
- });
-
- repeatButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- RepeatMode repeatMode = getDownloadService().getRepeatMode().next();
- getDownloadService().setRepeatMode(repeatMode);
- onDownloadListChanged();
- switch (repeatMode) {
- case OFF:
- Util.toast(DownloadActivity.this, R.string.download_repeat_off);
- break;
- case ALL:
- Util.toast(DownloadActivity.this, R.string.download_repeat_all);
- break;
- case SINGLE:
- Util.toast(DownloadActivity.this, R.string.download_repeat_single);
- break;
- default:
- break;
- }
- }
- });
-
- equalizerButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- startActivity(new Intent(DownloadActivity.this, EqualizerActivity.class));
- }
- });
-
- visualizerButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- boolean active = !visualizerView.isActive();
- visualizerView.setActive(active);
- getDownloadService().setShowVisualization(visualizerView.isActive());
- updateButtons();
- Util.toast(DownloadActivity.this, active ? R.string.download_visualizer_on : R.string.download_visualizer_off);
- }
- });
-
- jukeboxButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- boolean jukeboxEnabled = !getDownloadService().isJukeboxEnabled();
- getDownloadService().setJukeboxEnabled(jukeboxEnabled);
- updateButtons();
- Util.toast(DownloadActivity.this, jukeboxEnabled ? R.string.download_jukebox_on : R.string.download_jukebox_off, false);
- }
- });
-
- toggleListButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- toggleFullscreenAlbumArt();
- }
- });
-
- progressBar.setOnSliderChangeListener(new HorizontalSlider.OnSliderChangeListener() {
- @Override
- public void onSliderChanged(View view, int position, boolean inProgress) {
- Util.toast(DownloadActivity.this, Util.formatDuration(position / 1000), true);
- if (!inProgress) {
- getDownloadService().seekTo(position);
- onProgressChanged();
- }
- }
- });
- playlistView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- warnIfNetworkOrStorageUnavailable();
- getDownloadService().play(position);
- onCurrentChanged();
- onProgressChanged();
- }
- });
-
- registerForContextMenu(playlistView);
-
- DownloadService downloadService = getDownloadService();
- if (downloadService != null && getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, false)) {
- warnIfNetworkOrStorageUnavailable();
- downloadService.setShufflePlayEnabled(true);
- }
-
- boolean visualizerAvailable = downloadService != null && downloadService.getVisualizerController() != null;
- boolean equalizerAvailable = downloadService != null && downloadService.getEqualizerController() != null;
-
- if (!equalizerAvailable) {
- equalizerButton.setVisibility(View.GONE);
- }
- if (!visualizerAvailable) {
- visualizerButton.setVisibility(View.GONE);
- } else {
- visualizerView = new VisualizerView(this);
- visualizerViewLayout.addView(visualizerView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
-
- visualizerView.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View view, MotionEvent motionEvent) {
- visualizerView.setActive(!visualizerView.isActive());
- getDownloadService().setShowVisualization(visualizerView.isActive());
- updateButtons();
- return true;
- }
- });
- }
-
- // TODO: Extract to utility method and cache.
- Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/Storopia.ttf");
- equalizerButton.setTypeface(typeface);
- visualizerButton.setTypeface(typeface);
- jukeboxButton.setTypeface(typeface);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- final Handler handler = new Handler();
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- handler.post(new Runnable() {
- @Override
- public void run() {
- update();
- }
- });
- }
- };
-
- executorService = Executors.newSingleThreadScheduledExecutor();
- executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS);
-
- DownloadService downloadService = getDownloadService();
- if (downloadService == null || downloadService.getCurrentPlaying() == null) {
- playlistFlipper.setDisplayedChild(1);
- buttonBarFlipper.setDisplayedChild(1);
- }
-
- onDownloadListChanged();
- onCurrentChanged();
- onProgressChanged();
- scrollToCurrent();
- if (downloadService != null && downloadService.getKeepScreenOn()) {
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- } else {
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
-
- if (visualizerView != null) {
- visualizerView.setActive(downloadService != null && downloadService.getShowVisualization());
- }
-
- updateButtons();
- }
-
- private void updateButtons() {
- boolean eqEnabled = getDownloadService() != null && getDownloadService().getEqualizerController() != null &&
- getDownloadService().getEqualizerController().isEnabled();
- equalizerButton.setTextColor(eqEnabled ? COLOR_BUTTON_ENABLED : COLOR_BUTTON_DISABLED);
-
- if (visualizerView != null) {
- visualizerButton.setTextColor(visualizerView.isActive() ? COLOR_BUTTON_ENABLED : COLOR_BUTTON_DISABLED);
- }
-
- boolean jukeboxEnabled = getDownloadService() != null && getDownloadService().isJukeboxEnabled();
- jukeboxButton.setTextColor(jukeboxEnabled ? COLOR_BUTTON_ENABLED : COLOR_BUTTON_DISABLED);
- }
-
- // Scroll to current playing/downloading.
- private void scrollToCurrent() {
- if (getDownloadService() == null) {
- return;
- }
-
- for (int i = 0; i < playlistView.getAdapter().getCount(); i++) {
- if (currentPlaying == playlistView.getItemAtPosition(i)) {
- playlistView.setSelectionFromTop(i, 40);
- return;
- }
- }
- DownloadFile currentDownloading = getDownloadService().getCurrentDownloading();
- for (int i = 0; i < playlistView.getAdapter().getCount(); i++) {
- if (currentDownloading == playlistView.getItemAtPosition(i)) {
- playlistView.setSelectionFromTop(i, 40);
- return;
- }
- }
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- executorService.shutdown();
- if (visualizerView != null) {
- visualizerView.setActive(false);
- }
- }
-
- @Override
- protected Dialog onCreateDialog(int id) {
- if (id == DIALOG_SAVE_PLAYLIST) {
- AlertDialog.Builder builder;
-
- LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
- final View layout = inflater.inflate(R.layout.save_playlist, (ViewGroup) findViewById(R.id.save_playlist_root));
- playlistNameView = (EditText) layout.findViewById(R.id.save_playlist_name);
-
- builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.download_playlist_title);
- builder.setMessage(R.string.download_playlist_name);
- builder.setPositiveButton(R.string.common_save, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- savePlaylistInBackground(String.valueOf(playlistNameView.getText()));
- }
- });
- builder.setNegativeButton(R.string.common_cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
- builder.setView(layout);
- builder.setCancelable(true);
-
- return builder.create();
- } else {
- return super.onCreateDialog(id);
- }
- }
-
- @Override
- protected void onPrepareDialog(int id, Dialog dialog) {
- if (id == DIALOG_SAVE_PLAYLIST) {
- String playlistName = getDownloadService().getSuggestedPlaylistName();
- if (playlistName != null) {
- playlistNameView.setText(playlistName);
- } else {
- DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
- playlistNameView.setText(dateFormat.format(new Date()));
- }
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.nowplaying, menu);
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- MenuItem savePlaylist = menu.findItem(R.id.menu_save_playlist);
- boolean savePlaylistEnabled = !Util.isOffline(this);
- savePlaylist.setEnabled(savePlaylistEnabled);
- savePlaylist.setVisible(savePlaylistEnabled);
- MenuItem screenOption = menu.findItem(R.id.menu_screen_on_off);
- if (getDownloadService().getKeepScreenOn()) {
- screenOption.setTitle(R.string.download_menu_screen_off);
- } else {
- screenOption.setTitle(R.string.download_menu_screen_on);
- }
- return super.onPrepareOptionsMenu(menu);
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
- if (view == playlistView) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
- DownloadFile downloadFile = (DownloadFile) playlistView.getItemAtPosition(info.position);
-
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.nowplaying_context, menu);
-
- if (downloadFile.getSong().getParent() == null) {
- menu.findItem(R.id.menu_show_album).setVisible(false);
- }
- if (Util.isOffline(this)) {
- menu.findItem(R.id.menu_lyrics).setVisible(false);
- menu.findItem(R.id.menu_save_playlist).setVisible(false);
- }
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- DownloadFile downloadFile = (DownloadFile) playlistView.getItemAtPosition(info.position);
- return menuItemSelected(menuItem.getItemId(), downloadFile) || super.onContextItemSelected(menuItem);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem menuItem) {
- return menuItemSelected(menuItem.getItemId(), null) || super.onOptionsItemSelected(menuItem);
- }
-
- private boolean menuItemSelected(int menuItemId, DownloadFile song) {
- switch (menuItemId) {
- case R.id.menu_show_album:
- Intent intent = new Intent(this, SelectAlbumActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, song.getSong().getParent());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, song.getSong().getAlbum());
- Util.startActivityWithoutTransition(this, intent);
- return true;
- case R.id.menu_lyrics:
- intent = new Intent(this, LyricsActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ARTIST, song.getSong().getArtist());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_TITLE, song.getSong().getTitle());
- Util.startActivityWithoutTransition(this, intent);
- return true;
- case R.id.menu_remove:
- getDownloadService().remove(song);
- onDownloadListChanged();
- return true;
- case R.id.menu_remove_all:
- getDownloadService().setShufflePlayEnabled(false);
- getDownloadService().clear();
- onDownloadListChanged();
- return true;
- case R.id.menu_screen_on_off:
- if (getDownloadService().getKeepScreenOn()) {
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- getDownloadService().setKeepScreenOn(false);
- } else {
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- getDownloadService().setKeepScreenOn(true);
- }
- return true;
- case R.id.menu_shuffle:
- getDownloadService().shuffle();
- Util.toast(this, R.string.download_menu_shuffle_notification);
- return true;
- case R.id.menu_save_playlist:
- showDialog(DIALOG_SAVE_PLAYLIST);
- return true;
- default:
- return false;
- }
- }
-
- private void update() {
- if (getDownloadService() == null) {
- return;
- }
-
- if (currentRevision != getDownloadService().getDownloadListUpdateRevision()) {
- onDownloadListChanged();
- }
-
- if (currentPlaying != getDownloadService().getCurrentPlaying()) {
- onCurrentChanged();
- }
-
- onProgressChanged();
- }
-
- private void savePlaylistInBackground(final String playlistName) {
- Util.toast(DownloadActivity.this, getResources().getString(R.string.download_playlist_saving, playlistName));
- getDownloadService().setSuggestedPlaylistName(playlistName);
- new SilentBackgroundTask<Void>(this) {
- @Override
- protected Void doInBackground() throws Throwable {
- List<MusicDirectory.Entry> entries = new LinkedList<MusicDirectory.Entry>();
- for (DownloadFile downloadFile : getDownloadService().getDownloads()) {
- entries.add(downloadFile.getSong());
- }
- MusicService musicService = MusicServiceFactory.getMusicService(DownloadActivity.this);
- musicService.createPlaylist(null, playlistName, entries, DownloadActivity.this, null);
- return null;
- }
-
- @Override
- protected void done(Void result) {
- Util.toast(DownloadActivity.this, R.string.download_playlist_done);
- }
-
- @Override
- protected void error(Throwable error) {
- String msg = getResources().getString(R.string.download_playlist_error) + " " + getErrorMessage(error);
- Util.toast(DownloadActivity.this, msg);
- }
- }.execute();
- }
-
- private void toggleFullscreenAlbumArt() {
- scrollToCurrent();
- if (playlistFlipper.getDisplayedChild() == 1) {
- playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_down_in));
- playlistFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_down_out));
- playlistFlipper.setDisplayedChild(0);
- buttonBarFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_down_in));
- buttonBarFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_down_out));
- buttonBarFlipper.setDisplayedChild(0);
-
-
- } else {
- playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_up_in));
- playlistFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_up_out));
- playlistFlipper.setDisplayedChild(1);
- buttonBarFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_up_in));
- buttonBarFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_up_out));
- buttonBarFlipper.setDisplayedChild(1);
- }
- }
-
- private void start() {
- DownloadService service = getDownloadService();
- PlayerState state = service.getPlayerState();
- if (state == PAUSED || state == COMPLETED) {
- service.start();
- } else if (state == STOPPED || state == IDLE) {
- warnIfNetworkOrStorageUnavailable();
- int current = service.getCurrentPlayingIndex();
- // TODO: Use play() method.
- if (current == -1) {
- service.play(0);
- } else {
- service.play(current);
- }
- }
- }
-
- private void onDownloadListChanged() {
- DownloadService downloadService = getDownloadService();
- if (downloadService == null) {
- return;
- }
-
- List<DownloadFile> list = downloadService.getDownloads();
-
- playlistView.setAdapter(new SongListAdapter(list));
- emptyTextView.setVisibility(list.isEmpty() ? View.VISIBLE : View.GONE);
- currentRevision = downloadService.getDownloadListUpdateRevision();
-
- switch (downloadService.getRepeatMode()) {
- case OFF:
- repeatButton.setImageResource(R.drawable.media_repeat_off);
- break;
- case ALL:
- repeatButton.setImageResource(R.drawable.media_repeat_all);
- break;
- case SINGLE:
- repeatButton.setImageResource(R.drawable.media_repeat_single);
- break;
- default:
- break;
- }
- }
-
- private void onCurrentChanged() {
- if (getDownloadService() == null) {
- return;
- }
-
- currentPlaying = getDownloadService().getCurrentPlaying();
- if (currentPlaying != null) {
- MusicDirectory.Entry song = currentPlaying.getSong();
- songTitleTextView.setText(song.getTitle());
- albumTextView.setText(song.getAlbum());
- artistTextView.setText(song.getArtist());
- getImageLoader().loadImage(albumArtImageView, song, true, true);
- } else {
- songTitleTextView.setText(null);
- albumTextView.setText(null);
- artistTextView.setText(null);
- getImageLoader().loadImage(albumArtImageView, null, true, false);
- }
- }
-
- private void onProgressChanged() {
- if (getDownloadService() == null) {
- return;
- }
-
- if (currentPlaying != null) {
-
- int millisPlayed = Math.max(0, getDownloadService().getPlayerPosition());
- Integer duration = getDownloadService().getPlayerDuration();
- int millisTotal = duration == null ? 0 : duration;
-
- positionTextView.setText(Util.formatDuration(millisPlayed / 1000));
- durationTextView.setText(Util.formatDuration(millisTotal / 1000));
- progressBar.setMax(millisTotal == 0 ? 100 : millisTotal); // Work-around for apparent bug.
- progressBar.setProgress(millisPlayed);
- progressBar.setSlidingEnabled(currentPlaying.isCompleteFileAvailable() || getDownloadService().isJukeboxEnabled());
- } else {
- positionTextView.setText("0:00");
- durationTextView.setText("-:--");
- progressBar.setProgress(0);
- progressBar.setSlidingEnabled(false);
- }
-
- PlayerState playerState = getDownloadService().getPlayerState();
-
- switch (playerState) {
- case DOWNLOADING:
- long bytes = currentPlaying.getPartialFile().length();
- statusTextView.setText(getResources().getString(R.string.download_playerstate_downloading, Util.formatLocalizedBytes(bytes, this)));
- break;
- case PREPARING:
- statusTextView.setText(R.string.download_playerstate_buffering);
- break;
- case STARTED:
- if (getDownloadService().isShufflePlayEnabled()) {
- statusTextView.setText(R.string.download_playerstate_playing_shuffle);
- } else {
- statusTextView.setText(null);
- }
- break;
- default:
- statusTextView.setText(null);
- break;
- }
-
- switch (playerState) {
- case STARTED:
- pauseButton.setVisibility(View.VISIBLE);
- stopButton.setVisibility(View.GONE);
- startButton.setVisibility(View.GONE);
- break;
- case DOWNLOADING:
- case PREPARING:
- pauseButton.setVisibility(View.GONE);
- stopButton.setVisibility(View.VISIBLE);
- startButton.setVisibility(View.GONE);
- break;
- default:
- pauseButton.setVisibility(View.GONE);
- stopButton.setVisibility(View.GONE);
- startButton.setVisibility(View.VISIBLE);
- break;
- }
-
- jukeboxButton.setTextColor(getDownloadService().isJukeboxEnabled() ? COLOR_BUTTON_ENABLED : COLOR_BUTTON_DISABLED);
- }
-
- private class SongListAdapter extends ArrayAdapter<DownloadFile> {
- public SongListAdapter(List<DownloadFile> entries) {
- super(DownloadActivity.this, android.R.layout.simple_list_item_1, entries);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- SongView view;
- if (convertView != null && convertView instanceof SongView) {
- view = (SongView) convertView;
- } else {
- view = new SongView(DownloadActivity.this);
- }
- DownloadFile downloadFile = getItem(position);
- view.setSong(downloadFile.getSong(), false);
- return view;
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent me) {
- return gestureScanner.onTouchEvent(me);
- }
-
- @Override
- public boolean onDown(MotionEvent me) {
- return false;
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
-
- DownloadService downloadService = getDownloadService();
- if (downloadService == null) {
- return false;
- }
-
- // Right to Left swipe
- if (e1.getX() - e2.getX() > swipeDistance && Math.abs(velocityX) > swipeVelocity) {
- warnIfNetworkOrStorageUnavailable();
- if (downloadService.getCurrentPlayingIndex() < downloadService.size() - 1) {
- downloadService.next();
- onCurrentChanged();
- onProgressChanged();
- }
- return true;
- }
-
- // Left to Right swipe
- if (e2.getX() - e1.getX() > swipeDistance && Math.abs(velocityX) > swipeVelocity) {
- warnIfNetworkOrStorageUnavailable();
- downloadService.previous();
- onCurrentChanged();
- onProgressChanged();
- return true;
- }
-
- // Top to Bottom swipe
- if (e2.getY() - e1.getY() > swipeDistance && Math.abs(velocityY) > swipeVelocity) {
- warnIfNetworkOrStorageUnavailable();
- downloadService.seekTo(downloadService.getPlayerPosition() + 30000);
- onProgressChanged();
- return true;
- }
-
- // Bottom to Top swipe
- if (e1.getY() - e2.getY() > swipeDistance && Math.abs(velocityY) > swipeVelocity) {
- warnIfNetworkOrStorageUnavailable();
- downloadService.seekTo(downloadService.getPlayerPosition() - 8000);
- onProgressChanged();
- return true;
- }
-
- return false;
- }
-
- @Override
- public void onLongPress(MotionEvent e) {
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- return false;
- }
-
- @Override
- public void onShowPress(MotionEvent e) {
- }
-
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- return false;
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/EqualizerActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/EqualizerActivity.java
deleted file mode 100644
index daf6193e..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/EqualizerActivity.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2011 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.activity;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import android.app.Activity;
-import android.media.audiofx.Equalizer;
-import android.os.Bundle;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.LinearLayout;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.audiofx.EqualizerController;
-import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
-
-/**
- * Equalizer controls.
- *
- * @author Sindre Mehus
- * @version $Id$
- */
-public class EqualizerActivity extends Activity {
-
- private static final int MENU_GROUP_PRESET = 100;
-
- 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();
-
- initEqualizer();
-
- 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);
- }
- });
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- equalizerController.saveSettings();
- }
-
- @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;
- }
-
- 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;
- }
-
- private void setEqualizerEnabled(boolean enabled) {
- equalizer.setEnabled(enabled);
- 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);
- }
- }
-
- private void initEqualizer() {
- LinearLayout layout = (LinearLayout) findViewById(R.id.equalizer_layout);
-
- final short minEQLevel = equalizer.getBandLevelRange()[0];
- final short maxEQLevel = equalizer.getBandLevelRange()[1];
-
- for (short i = 0; i < equalizer.getNumberOfBands(); i++) {
- final short band = i;
-
- View bandBar = LayoutInflater.from(this).inflate(R.layout.equalizer_bar, null);
- TextView 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);
-
- freqTextView.setText((equalizer.getCenterFreq(band) / 1000) + " Hz");
-
- bars.put(band, bar);
- bar.setMax(maxEQLevel - minEQLevel);
- short level = equalizer.getBandLevel(band);
- bar.setProgress(level - minEQLevel);
- bar.setEnabled(equalizer.getEnabled());
- updateLevelText(levelTextView, level);
-
- 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 onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
- layout.addView(bandBar);
- }
- }
-
- private void updateLevelText(TextView levelTextView, short level) {
- levelTextView.setText((level > 0 ? "+" : "") + level / 100 + " dB");
- }
-
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/HelpActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/HelpActivity.java
deleted file mode 100644
index 4b2eb63b..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/HelpActivity.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-
-package net.sourceforge.subsonic.androidapp.activity;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.Window;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.Button;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-/**
- * An HTML-based help screen with Back and Done buttons at the bottom.
- *
- * @author Sindre Mehus
- */
-public final class HelpActivity extends Activity {
-
- private WebView webView;
- private Button backButton;
-
- @Override
- protected void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
-
- setContentView(R.layout.help);
-
- 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 = (Button) findViewById(R.id.help_back);
- backButton.setOnClickListener(new Button.OnClickListener() {
- @Override
- public void onClick(View view) {
- webView.goBack();
- }
- });
-
- Button doneButton = (Button) findViewById(R.id.help_close);
- doneButton.setOnClickListener(new Button.OnClickListener() {
- @Override
- public void onClick(View view) {
- finish();
- }
- });
- }
-
- @Override
- public void onResume() {
- super.onResume();
- }
-
- @Override
- protected void onSaveInstanceState(Bundle state) {
- webView.saveState(state);
- }
-
- @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 final class HelpClient extends WebViewClient {
- @Override
- public void onLoadResource(WebView webView, String url) {
- setProgressBarIndeterminateVisibility(true);
- setTitle(getResources().getString(R.string.help_loading));
- super.onLoadResource(webView, url);
- }
-
- @Override
- public void onPageFinished(WebView view, String url) {
- setProgressBarIndeterminateVisibility(false);
- setTitle(view.getTitle());
- backButton.setEnabled(view.canGoBack());
- }
-
- @Override
- public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
- Util.toast(HelpActivity.this, description);
- }
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/LyricsActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/LyricsActivity.java
deleted file mode 100644
index 0ec75e2c..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/LyricsActivity.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-
-package net.sourceforge.subsonic.androidapp.activity;
-
-import android.os.Bundle;
-import android.widget.TextView;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.Lyrics;
-import net.sourceforge.subsonic.androidapp.service.MusicService;
-import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
-import net.sourceforge.subsonic.androidapp.util.BackgroundTask;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.TabActivityBackgroundTask;
-
-/**
- * Displays song lyrics.
- *
- * @author Sindre Mehus
- */
-public final class LyricsActivity extends SubsonicTabActivity {
-
- @Override
- protected void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- setContentView(R.layout.lyrics);
- load();
- }
-
- private void load() {
- BackgroundTask<Lyrics> task = new TabActivityBackgroundTask<Lyrics>(this) {
- @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();
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/MainActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/MainActivity.java
deleted file mode 100644
index c63a391b..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/MainActivity.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-
-package net.sourceforge.subsonic.androidapp.activity;
-
-import java.util.Arrays;
-
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.service.DownloadService;
-import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.MergeAdapter;
-import net.sourceforge.subsonic.androidapp.util.Util;
-import net.sourceforge.subsonic.androidapp.util.FileUtil;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ImageButton;
-import android.widget.ListView;
-import android.widget.TextView;
-
-public class MainActivity extends SubsonicTabActivity {
-
- private static final int MENU_GROUP_SERVER = 10;
- 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_OFFLINE = 104;
-
- private String theme;
-
- private static boolean infoDialogDisplayed;
-
- /**
- * Called when the activity is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) {
- exit();
- }
- setContentView(R.layout.main);
-
- loadSettings();
-
- 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 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 albumsRecentButton = buttons.findViewById(R.id.main_albums_recent);
- final View albumsFrequentButton = buttons.findViewById(R.id.main_albums_frequent);
-
- final View dummyView = findViewById(R.id.main_dummy);
-
- int instance = Util.getActiveServer(this);
- String name = Util.getServerName(this, instance);
- serverTextView.setText(name);
-
- ListView list = (ListView) findViewById(R.id.main_list);
-
- MergeAdapter adapter = new MergeAdapter();
- adapter.addViews(Arrays.asList(serverButton), true);
- if (!Util.isOffline(this)) {
- adapter.addView(albumsTitle, false);
- adapter.addViews(Arrays.asList(albumsNewestButton, albumsRandomButton, albumsHighestButton, albumsRecentButton, albumsFrequentButton), 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");
- } else if (view == albumsRandomButton) {
- showAlbumList("random");
- } else if (view == albumsHighestButton) {
- showAlbumList("highest");
- } else if (view == albumsRecentButton) {
- showAlbumList("recent");
- } else if (view == albumsFrequentButton) {
- showAlbumList("frequent");
- }
- }
- });
-
- // Title: Subsonic
- setTitle(R.string.common_appname);
-
- // Button 1: shuffle
- ImageButton actionShuffleButton = (ImageButton)findViewById(R.id.action_button_1);
- actionShuffleButton.setImageResource(R.drawable.action_shuffle);
- actionShuffleButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(MainActivity.this, DownloadActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
- Util.startActivityWithoutTransition(MainActivity.this, intent);
- }
- });
-
- // Button 2: search
- ImageButton actionSearchButton = (ImageButton)findViewById(R.id.action_button_2);
- actionSearchButton.setImageResource(R.drawable.action_search);
- actionSearchButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(MainActivity.this, SearchActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, true);
- Util.startActivityWithoutTransition(MainActivity.this, intent);
- }
- });
-
- // Remember the current theme.
- theme = Util.getTheme(this);
-
- showInfoDialog();
- }
-
- private void loadSettings() {
- PreferenceManager.setDefaultValues(this, R.xml.settings, false);
- SharedPreferences prefs = Util.getPreferences(this);
- if (!prefs.contains(Constants.PREFERENCES_KEY_CACHE_LOCATION)) {
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory().getPath());
- editor.commit();
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- // Restart activity if theme has changed.
- if (theme != null && !theme.equals(Util.getTheme(this))) {
- restart();
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
-
- MenuItem menuItem1 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_1, MENU_ITEM_SERVER_1, Util.getServerName(this, 1));
- MenuItem menuItem2 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_2, MENU_ITEM_SERVER_2, Util.getServerName(this, 2));
- MenuItem menuItem3 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_3, MENU_ITEM_SERVER_3, Util.getServerName(this, 3));
- MenuItem menuItem4 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_OFFLINE, MENU_ITEM_OFFLINE, Util.getServerName(this, 0));
- menu.setGroupCheckable(MENU_GROUP_SERVER, true, true);
- menu.setHeaderTitle(R.string.main_select_server);
-
- switch (Util.getActiveServer(this)) {
- case 0:
- menuItem4.setChecked(true);
- break;
- case 1:
- menuItem1.setChecked(true);
- break;
- case 2:
- menuItem2.setChecked(true);
- break;
- case 3:
- menuItem3.setChecked(true);
- break;
- }
- }
-
- @Override
- public boolean onContextItemSelected(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;
- default:
- return super.onContextItemSelected(menuItem);
- }
-
- // Restart activity
- restart();
- return true;
- }
-
- private void setActiveServer(int instance) {
- if (Util.getActiveServer(this) != instance) {
- DownloadService service = getDownloadService();
- if (service != null) {
- service.clearIncomplete();
- }
- Util.setActiveServer(this, instance);
- }
- }
-
- private void restart() {
- Intent intent = new Intent(this, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- Util.startActivityWithoutTransition(this, intent);
- }
-
- private void exit() {
- stopService(new Intent(this, DownloadServiceImpl.class));
- finish();
- }
-
- private void showInfoDialog() {
- if (!infoDialogDisplayed) {
- infoDialogDisplayed = true;
- if (Util.getRestUrl(this, null).contains("demo.subsonic.org")) {
- Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text);
- }
- }
- }
-
- private void showAlbumList(String type) {
- 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_SIZE, 20);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
- Util.startActivityWithoutTransition(this, intent);
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/PlayVideoActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/PlayVideoActivity.java
deleted file mode 100644
index ea332ca0..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/PlayVideoActivity.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-
-package net.sourceforge.subsonic.androidapp.activity;
-
-import java.lang.reflect.Method;
-
-import android.app.Activity;
-import android.graphics.Bitmap;
-import android.media.AudioManager;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.Window;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-/**
- * Plays videos in a web page.
- *
- * @author Sindre Mehus
- */
-public final class PlayVideoActivity extends Activity {
-
- private static final String TAG = PlayVideoActivity.class.getSimpleName();
- private WebView webView;
-
- @Override
- protected void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- getWindow().requestFeature(Window.FEATURE_NO_TITLE);
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
-
- setContentView(R.layout.play_video);
-
- webView = (WebView) findViewById(R.id.play_video_contents);
- webView.getSettings().setJavaScriptEnabled(true);
- webView.getSettings().setPluginsEnabled(true);
- webView.getSettings().setAllowFileAccess(true);
- webView.getSettings().setSupportZoom(true);
- webView.getSettings().setBuiltInZoomControls(true);
-
- webView.setWebViewClient(new Client());
- if (bundle != null) {
- webView.restoreState(bundle);
- } else {
- webView.loadUrl(getVideoUrl());
- }
-
- // Show warning if Flash plugin is not installed.
- if (isFlashPluginInstalled()) {
- Util.toast(this, R.string.play_video_loading, false);
- } else {
- Util.toast(this, R.string.play_video_noplugin, false);
- }
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- callHiddenWebViewMethod("onPause");
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- callHiddenWebViewMethod("onResume");
- }
-
- private String getVideoUrl() {
- String id = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ID);
- return MusicServiceFactory.getMusicService(this).getVideoUrl(this, id);
- }
-
- @Override
- protected void onSaveInstanceState(Bundle state) {
- webView.saveState(state);
- }
-
- private void callHiddenWebViewMethod(String name){
- if( webView != null ){
- try {
- Method method = WebView.class.getMethod(name);
- method.invoke(webView);
- } catch (Throwable x) {
- Log.e(TAG, "Failed to invoke " + name, x);
- }
- }
- }
-
- private boolean isFlashPluginInstalled() {
- try {
- PackageInfo packageInfo = getPackageManager().getPackageInfo("com.adobe.flashplayer", 0);
- return packageInfo != null;
- } catch (PackageManager.NameNotFoundException x) {
- return false;
- }
- }
-
- private final class Client extends WebViewClient {
-
- @Override
- public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
- Util.toast(PlayVideoActivity.this, description);
- Log.e(TAG, "Error: " + description);
- }
-
- @Override
- public void onLoadResource(WebView view, String url) {
- super.onLoadResource(view, url);
- Log.d(TAG, "onLoadResource: " + url);
- }
-
- @Override
- public void onPageStarted(WebView view, String url, Bitmap favicon) {
- super.onPageStarted(view, url, favicon);
- Log.d(TAG, "onPageStarted: " + url);
- }
-
- @Override
- public void onPageFinished(WebView view, String url) {
- super.onPageFinished(view, url);
- Log.d(TAG, "onPageFinished: " + url);
- }
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/QueryReceiverActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/QueryReceiverActivity.java
deleted file mode 100644
index 35b5ccaf..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/QueryReceiverActivity.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-
-package net.sourceforge.subsonic.androidapp.activity;
-
-import android.app.Activity;
-import android.app.SearchManager;
-import android.content.Intent;
-import android.os.Bundle;
-import android.provider.SearchRecentSuggestions;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.Util;
-import net.sourceforge.subsonic.androidapp.provider.SearchSuggestionProvider;
-
-/**
- * Receives search queries and forwards to the SelectAlbumActivity.
- *
- * @author Sindre Mehus
- */
-public class QueryReceiverActivity extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- String query = getIntent().getStringExtra(SearchManager.QUERY);
-
- 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);
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SearchActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SearchActivity.java
deleted file mode 100644
index 73b787a0..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SearchActivity.java
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-
-package net.sourceforge.subsonic.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.widget.AdapterView;
-import android.widget.ImageButton;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.net.Uri;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.Artist;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.domain.SearchCritera;
-import net.sourceforge.subsonic.androidapp.domain.SearchResult;
-import net.sourceforge.subsonic.androidapp.service.MusicService;
-import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
-import net.sourceforge.subsonic.androidapp.service.DownloadService;
-import net.sourceforge.subsonic.androidapp.util.ArtistAdapter;
-import net.sourceforge.subsonic.androidapp.util.BackgroundTask;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.EntryAdapter;
-import net.sourceforge.subsonic.androidapp.util.MergeAdapter;
-import net.sourceforge.subsonic.androidapp.util.TabActivityBackgroundTask;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-/**
- * Performs searches and displays the matching artists, albums and songs.
- *
- * @author Sindre Mehus
- */
-public class SearchActivity extends SubsonicTabActivity {
-
- private static final int DEFAULT_ARTISTS = 3;
- private static final int DEFAULT_ALBUMS = 5;
- private static final int DEFAULT_SONGS = 10;
-
- private static final int MAX_ARTISTS = 10;
- private static final int MAX_ALBUMS = 20;
- private static final int MAX_SONGS = 25;
- 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);
-
- setTitle(R.string.search_title);
-
- View buttons = LayoutInflater.from(this).inflate(R.layout.search_buttons, null);
-
- artistsHeading = buttons.findViewById(R.id.search_artists);
- albumsHeading = buttons.findViewById(R.id.search_albums);
- songsHeading = buttons.findViewById(R.id.search_songs);
-
- 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);
-
- list = (ListView) findViewById(R.id.search_list);
-
- 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);
- }
-
- }
- }
- }
- });
- registerForContextMenu(list);
-
- // Button 1: gone
- findViewById(R.id.action_button_1).setVisibility(View.GONE);
-
- // Button 2: search
- final ImageButton actionSearchButton = (ImageButton)findViewById(R.id.action_button_2);
- actionSearchButton.setImageResource(R.drawable.action_search);
- actionSearchButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onSearchRequested();
- }
- });
-
- onNewIntent(getIntent());
- }
-
- @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();
- }
- }
-
- @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);
-
- boolean isArtist = selectedItem instanceof Artist;
- boolean isAlbum = selectedItem instanceof MusicDirectory.Entry && ((MusicDirectory.Entry) selectedItem).isDirectory();
- boolean isSong = selectedItem instanceof MusicDirectory.Entry && (!((MusicDirectory.Entry) selectedItem).isDirectory())
- && (!((MusicDirectory.Entry) selectedItem).isVideo());
-
- if (isArtist || isAlbum) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.select_album_context, menu);
- } else if (isSong) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.select_song_context, menu);
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- Object selectedItem = list.getItemAtPosition(info.position);
-
- Artist artist = selectedItem instanceof Artist ? (Artist) selectedItem : null;
- MusicDirectory.Entry entry = selectedItem instanceof MusicDirectory.Entry ? (MusicDirectory.Entry) selectedItem : null;
- String id = artist != null ? artist.getId() : entry.getId();
-
- switch (menuItem.getItemId()) {
- case R.id.album_menu_play_now:
- downloadRecursively(id, false, false, true);
- break;
- case R.id.album_menu_play_last:
- downloadRecursively(id, false, true, false);
- break;
- case R.id.album_menu_pin:
- downloadRecursively(id, true, true, false);
- break;
- case R.id.song_menu_play_now:
- onSongSelected(entry, false, false, true, false);
- break;
- case R.id.song_menu_play_next:
- onSongSelected(entry, false, true, false, true);
- break;
- case R.id.song_menu_play_last:
- onSongSelected(entry, false, true, false, false);
- break;
- default:
- return super.onContextItemSelected(menuItem);
- }
-
- return true;
- }
-
- private void search(final String query, final boolean autoplay) {
- BackgroundTask<SearchResult> task = new TabActivityBackgroundTask<SearchResult>(this) {
- @Override
- protected SearchResult doInBackground() throws Throwable {
- SearchCritera criteria = new SearchCritera(query, MAX_ARTISTS, MAX_ALBUMS, MAX_SONGS);
- MusicService service = MusicServiceFactory.getMusicService(SearchActivity.this);
- return service.search(criteria, SearchActivity.this, this);
- }
-
- @Override
- protected void done(SearchResult result) {
- searchResult = result;
- populateList();
- if (autoplay) {
- autoplay();
- }
-
- }
- };
- task.execute();
- }
-
- private void populateList() {
- mergeAdapter = new MergeAdapter();
- mergeAdapter.addView(searchButton, true);
-
- 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);
- }
- }
-
- 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);
- }
- }
-
- 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);
- }
- }
-
- boolean empty = searchResult.getArtists().isEmpty() && searchResult.getAlbums().isEmpty() && searchResult.getSongs().isEmpty();
- searchButton.setText(empty ? R.string.search_no_match : R.string.search_search);
- }
-
- list.setAdapter(mergeAdapter);
- }
-
- private void expandArtists() {
- artistAdapter.clear();
- for (Artist artist : searchResult.getArtists()) {
- artistAdapter.add(artist);
- }
- artistAdapter.notifyDataSetChanged();
- mergeAdapter.removeAdapter(moreArtistsAdapter);
- mergeAdapter.notifyDataSetChanged();
- }
-
- private void expandAlbums() {
- albumAdapter.clear();
- 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_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) {
- downloadService.clear();
- }
- downloadService.download(Arrays.asList(song), save, false, playNext);
- 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) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(MusicServiceFactory.getMusicService(this).getVideoUrl(this, entry.getId())));
- startActivity(intent);
- }
-
- 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);
- }
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SelectAlbumActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SelectAlbumActivity.java
deleted file mode 100644
index 070bed0b..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SelectAlbumActivity.java
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.activity;
-
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.Button;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.ListView;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.service.DownloadFile;
-import net.sourceforge.subsonic.androidapp.service.MusicService;
-import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.EntryAdapter;
-import net.sourceforge.subsonic.androidapp.util.Pair;
-import net.sourceforge.subsonic.androidapp.util.TabActivityBackgroundTask;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class SelectAlbumActivity extends SubsonicTabActivity {
-
- private static final String TAG = SelectAlbumActivity.class.getSimpleName();
-
- private ListView entryList;
- private View footer;
- private View emptyView;
- private Button selectButton;
- private Button playNowButton;
- private Button playLastButton;
- private Button pinButton;
- private Button unpinButton;
- private Button deleteButton;
- private Button moreButton;
- private ImageView coverArtView;
- private boolean licenseValid;
- private ImageButton playAllButton;
-
- /**
- * Called when the activity is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.select_album);
-
- entryList = (ListView) findViewById(R.id.select_album_entries);
-
- footer = LayoutInflater.from(this).inflate(R.layout.select_album_footer, entryList, false);
- entryList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- entryList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (position >= 0) {
- MusicDirectory.Entry entry = (MusicDirectory.Entry) parent.getItemAtPosition(position);
- if (entry.isDirectory()) {
- Intent intent = new Intent(SelectAlbumActivity.this, SelectAlbumActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, entry.getId());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, entry.getTitle());
- Util.startActivityWithoutTransition(SelectAlbumActivity.this, intent);
- } else if (entry.isVideo()) {
- playVideo(entry);
- } else {
- enableButtons();
- }
- }
- }
- });
-
- coverArtView = (ImageView) findViewById(R.id.actionbar_home_icon);
- selectButton = (Button) findViewById(R.id.select_album_select);
- playNowButton = (Button) findViewById(R.id.select_album_play_now);
- playLastButton = (Button) findViewById(R.id.select_album_play_last);
- pinButton = (Button) footer.findViewById(R.id.select_album_pin);
- unpinButton = (Button) footer.findViewById(R.id.select_album_unpin);
- unpinButton = (Button) footer.findViewById(R.id.select_album_unpin);
- deleteButton = (Button) footer.findViewById(R.id.select_album_delete);
- moreButton = (Button) footer.findViewById(R.id.select_album_more);
- emptyView = findViewById(R.id.select_album_empty);
-
- selectButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- selectAllOrNone();
- }
- });
- playNowButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- download(false, false, true, false);
- selectAll(false, false);
- }
- });
- playLastButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- download(true, false, false, false);
- selectAll(false, false);
- }
- });
- pinButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- download(true, true, false, false);
- selectAll(false, false);
- }
- });
- unpinButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- unpin();
- selectAll(false, false);
- }
- });
- deleteButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- delete();
- selectAll(false, false);
- }
- });
-
- registerForContextMenu(entryList);
-
- enableButtons();
-
- String id = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ID);
- String name = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_NAME);
- String playlistId = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID);
- String playlistName = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME);
- String albumListType = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE);
- int albumListSize = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0);
- int albumListOffset = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
-
- if (playlistId != null) {
- getPlaylist(playlistId, playlistName);
- } else if (albumListType != null) {
- getAlbumList(albumListType, albumListSize, albumListOffset);
- } else {
- getMusicDirectory(id, name);
- }
-
- // Button 1: play all
- playAllButton = (ImageButton) findViewById(R.id.action_button_1);
- playAllButton.setImageResource(R.drawable.action_play_all);
- playAllButton.setVisibility(View.GONE);
- playAllButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- playAll();
- }
- });
-
- // Button 2: refresh
- ImageButton refreshButton = (ImageButton) findViewById(R.id.action_button_2);
- refreshButton.setImageResource(R.drawable.action_refresh);
- refreshButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- refresh();
- }
- });
- }
-
- private void playAll() {
- boolean hasSubFolders = false;
- for (int i = 0; i < entryList.getCount(); i++) {
- MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(i);
- if (entry != null && entry.isDirectory()) {
- hasSubFolders = true;
- break;
- }
- }
-
- String id = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ID);
- if (hasSubFolders && id != null) {
- downloadRecursively(id, false, false, true);
- } else {
- selectAll(true, false);
- download(false, false, true, false);
- selectAll(false, false);
- }
- }
-
- private void refresh() {
- finish();
- Intent intent = getIntent();
- intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
- Util.startActivityWithoutTransition(this, intent);
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
- AdapterView.AdapterContextMenuInfo info =
- (AdapterView.AdapterContextMenuInfo) menuInfo;
-
- MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(info.position);
-
- if (entry.isDirectory()) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.select_album_context, menu);
- } else {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.select_song_context, menu);
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(info.position);
- List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(10);
- songs.add((MusicDirectory.Entry) entryList.getItemAtPosition(info.position));
- switch (menuItem.getItemId()) {
- case R.id.album_menu_play_now:
- downloadRecursively(entry.getId(), false, false, true);
- break;
- case R.id.album_menu_play_last:
- downloadRecursively(entry.getId(), false, true, false);
- break;
- case R.id.album_menu_pin:
- downloadRecursively(entry.getId(), true, true, false);
- break;
- case R.id.song_menu_play_now:
- getDownloadService().download(songs, false, true, true);
- break;
- case R.id.song_menu_play_next:
- getDownloadService().download(songs, false, false, true);
- break;
- case R.id.song_menu_play_last:
- getDownloadService().download(songs, false, false, false);
- break;
- default:
- return super.onContextItemSelected(menuItem);
- }
- return true;
- }
-
- private void getMusicDirectory(final String id, String name) {
- setTitle(name);
-
- new LoadTask() {
- @Override
- protected MusicDirectory load(MusicService service) throws Exception {
- boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false);
- return service.getMusicDirectory(id, refresh, SelectAlbumActivity.this, this);
- }
- }.execute();
- }
-
- private void getPlaylist(final String playlistId, final String playlistName) {
- setTitle(playlistName);
-
- new LoadTask() {
- @Override
- protected MusicDirectory load(MusicService service) throws Exception {
- return service.getPlaylist(playlistId, playlistName, SelectAlbumActivity.this, this);
- }
- }.execute();
- }
-
- private void getAlbumList(final String albumListType, final int size, final int offset) {
-
- if ("newest".equals(albumListType)) {
- setTitle(R.string.main_albums_newest);
- } else if ("random".equals(albumListType)) {
- setTitle(R.string.main_albums_random);
- } else if ("highest".equals(albumListType)) {
- setTitle(R.string.main_albums_highest);
- } else if ("recent".equals(albumListType)) {
- setTitle(R.string.main_albums_recent);
- } else if ("frequent".equals(albumListType)) {
- setTitle(R.string.main_albums_frequent);
- }
-
- new LoadTask() {
- @Override
- protected MusicDirectory load(MusicService service) throws Exception {
- return service.getAlbumList(albumListType, size, offset, SelectAlbumActivity.this, this);
- }
-
- @Override
- protected void done(Pair<MusicDirectory, Boolean> result) {
- if (!result.getFirst().getChildren().isEmpty()) {
- pinButton.setVisibility(View.GONE);
- unpinButton.setVisibility(View.GONE);
- deleteButton.setVisibility(View.GONE);
- moreButton.setVisibility(View.VISIBLE);
- entryList.addFooterView(footer);
-
- moreButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(SelectAlbumActivity.this, SelectAlbumActivity.class);
- String type = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE);
- int size = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0);
- int offset = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0) + size;
-
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, size);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, offset);
- Util.startActivityWithoutTransition(SelectAlbumActivity.this, intent);
- }
- });
- }
- super.done(result);
- }
- }.execute();
- }
-
- private void selectAllOrNone() {
- boolean someUnselected = false;
- int count = entryList.getCount();
- for (int i = 0; i < count; i++) {
- if (!entryList.isItemChecked(i) && entryList.getItemAtPosition(i) instanceof MusicDirectory.Entry) {
- someUnselected = true;
- break;
- }
- }
- selectAll(someUnselected, true);
- }
-
- private void selectAll(boolean selected, boolean toast) {
- int count = entryList.getCount();
- int selectedCount = 0;
- for (int i = 0; i < count; i++) {
- MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(i);
- if (entry != null && !entry.isDirectory() && !entry.isVideo()) {
- entryList.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();
- boolean enabled = !selection.isEmpty();
- boolean unpinEnabled = false;
- boolean deleteEnabled = false;
-
- for (MusicDirectory.Entry song : selection) {
- DownloadFile downloadFile = getDownloadService().forSong(song);
- if (downloadFile.isCompleteFileAvailable()) {
- deleteEnabled = true;
- }
- if (downloadFile.isSaved()) {
- unpinEnabled = true;
- }
- }
-
- playNowButton.setEnabled(enabled);
- playLastButton.setEnabled(enabled);
- pinButton.setEnabled(enabled && !Util.isOffline(this));
- unpinButton.setEnabled(unpinEnabled);
- deleteButton.setEnabled(deleteEnabled);
- }
-
- private List<MusicDirectory.Entry> getSelectedSongs() {
- List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(10);
- int count = entryList.getCount();
- for (int i = 0; i < count; i++) {
- if (entryList.isItemChecked(i)) {
- songs.add((MusicDirectory.Entry) entryList.getItemAtPosition(i));
- }
- }
- return songs;
- }
-
- private void download(final boolean append, final boolean save, final boolean autoplay, final boolean playNext) {
- if (getDownloadService() == null) {
- return;
- }
-
- final List<MusicDirectory.Entry> songs = getSelectedSongs();
- Runnable onValid = new Runnable() {
- @Override
- public void run() {
- if (!append) {
- getDownloadService().clear();
- }
-
- warnIfNetworkOrStorageUnavailable();
- getDownloadService().download(songs, save, autoplay, playNext);
- String playlistName = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME);
- if (playlistName != null) {
- getDownloadService().setSuggestedPlaylistName(playlistName);
- }
- if (autoplay) {
- Util.startActivityWithoutTransition(SelectAlbumActivity.this, DownloadActivity.class);
- } else if (save) {
- Util.toast(SelectAlbumActivity.this,
- getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size()));
- } else if (append) {
- Util.toast(SelectAlbumActivity.this,
- getResources().getQuantityString(R.plurals.select_album_n_songs_added, songs.size(), songs.size()));
- }
- }
- };
-
- checkLicenseAndTrialPeriod(onValid);
- }
-
- private void delete() {
- if (getDownloadService() != null) {
- getDownloadService().delete(getSelectedSongs());
- }
- }
-
- private void unpin() {
- if (getDownloadService() != null) {
- getDownloadService().unpin(getSelectedSongs());
- }
- }
-
- private void playVideo(MusicDirectory.Entry entry) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(MusicServiceFactory.getMusicService(this).getVideoUrl(this, entry.getId())));
-
- startActivity(intent);
- }
-
- private void checkLicenseAndTrialPeriod(Runnable onValid) {
- if (licenseValid) {
- onValid.run();
- return;
- }
-
- int trialDaysLeft = Util.getRemainingTrialDays(this);
- Log.i(TAG, trialDaysLeft + " trial days left.");
-
- if (trialDaysLeft == 0) {
- showDonationDialog(trialDaysLeft, null);
- } else if (trialDaysLeft < Constants.FREE_TRIAL_DAYS / 2) {
- showDonationDialog(trialDaysLeft, onValid);
- } else {
- Util.toast(this, getResources().getString(R.string.select_album_not_licensed, trialDaysLeft));
- onValid.run();
- }
- }
-
- private void showDonationDialog(int trialDaysLeft, final Runnable onValid) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setIcon(android.R.drawable.ic_dialog_info);
-
- if (trialDaysLeft == 0) {
- builder.setTitle(R.string.select_album_donate_dialog_0_trial_days_left);
- } else {
- builder.setTitle(getResources().getQuantityString(R.plurals.select_album_donate_dialog_n_trial_days_left,
- trialDaysLeft, trialDaysLeft));
- }
-
- builder.setMessage(R.string.select_album_donate_dialog_message);
-
- builder.setPositiveButton(R.string.select_album_donate_dialog_now,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.DONATION_URL)));
- }
- });
-
- builder.setNegativeButton(R.string.select_album_donate_dialog_later,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- dialogInterface.dismiss();
- if (onValid != null) {
- onValid.run();
- }
- }
- });
-
- builder.create().show();
- }
-
- private abstract class LoadTask extends TabActivityBackgroundTask<Pair<MusicDirectory, Boolean>> {
-
- public LoadTask() {
- super(SelectAlbumActivity.this);
- }
-
- protected abstract MusicDirectory load(MusicService service) throws Exception;
-
- @Override
- protected Pair<MusicDirectory, Boolean> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(SelectAlbumActivity.this);
- MusicDirectory dir = load(musicService);
- boolean valid = musicService.isLicenseValid(SelectAlbumActivity.this, this);
- return new Pair<MusicDirectory, Boolean>(dir, valid);
- }
-
- @Override
- protected void done(Pair<MusicDirectory, Boolean> result) {
- List<MusicDirectory.Entry> entries = result.getFirst().getChildren();
-
- int songCount = 0;
- for (MusicDirectory.Entry entry : entries) {
- if (!entry.isDirectory()) {
- songCount++;
- }
- }
-
- if (songCount > 0) {
- getImageLoader().loadImage(coverArtView, entries.get(0), false, true);
- entryList.addFooterView(footer);
- selectButton.setVisibility(View.VISIBLE);
- playNowButton.setVisibility(View.VISIBLE);
- playLastButton.setVisibility(View.VISIBLE);
- }
-
- boolean isAlbumList = getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE);
-
- emptyView.setVisibility(entries.isEmpty() ? View.VISIBLE : View.GONE);
- playAllButton.setVisibility(isAlbumList || entries.isEmpty() ? View.GONE : View.VISIBLE);
- entryList.setAdapter(new EntryAdapter(SelectAlbumActivity.this, getImageLoader(), entries, true));
- licenseValid = result.getSecond();
-
- boolean playAll = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false);
- if (playAll && songCount > 0) {
- playAll();
- }
- }
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SelectArtistActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SelectArtistActivity.java
deleted file mode 100644
index 959066ab..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SelectArtistActivity.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-
-package net.sourceforge.subsonic.androidapp.activity;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ImageButton;
-import android.widget.ListView;
-import android.widget.TextView;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.Artist;
-import net.sourceforge.subsonic.androidapp.domain.Indexes;
-import net.sourceforge.subsonic.androidapp.domain.MusicFolder;
-import net.sourceforge.subsonic.androidapp.service.MusicService;
-import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
-import net.sourceforge.subsonic.androidapp.util.ArtistAdapter;
-import net.sourceforge.subsonic.androidapp.util.BackgroundTask;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.TabActivityBackgroundTask;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class SelectArtistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener {
-
- private static final int MENU_GROUP_MUSIC_FOLDER = 10;
-
- private ListView artistList;
- 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);
-
- artistList = (ListView) findViewById(R.id.select_artist_list);
- artistList.setOnItemClickListener(this);
-
- folderButton = LayoutInflater.from(this).inflate(R.layout.select_artist_header, artistList, false);
- folderName = (TextView) folderButton.findViewById(R.id.select_artist_folder_2);
-
- if (!Util.isOffline(this)) {
- artistList.addHeaderView(folderButton);
- }
-
- registerForContextMenu(artistList);
-
- setTitle(Util.isOffline(this) ? R.string.music_library_label_offline : R.string.music_library_label);
-
- // Button 1: shuffle
- ImageButton shuffleButton = (ImageButton) findViewById(R.id.action_button_1);
- shuffleButton.setImageResource(R.drawable.action_shuffle);
- shuffleButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(SelectArtistActivity.this, DownloadActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
- Util.startActivityWithoutTransition(SelectArtistActivity.this, intent);
- }
- });
-
- // Button 2: refresh
- ImageButton refreshButton = (ImageButton) findViewById(R.id.action_button_2);
- refreshButton.setImageResource(R.drawable.action_refresh);
- refreshButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- refresh();
- }
- });
-
- musicFolders = null;
- load();
- }
-
- private void refresh() {
- finish();
- Intent intent = getIntent();
- intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
- Util.startActivityWithoutTransition(this, intent);
- }
-
- private void selectFolder() {
- folderButton.showContextMenu();
- }
-
- private void load() {
- BackgroundTask<Indexes> task = new TabActivityBackgroundTask<Indexes>(this) {
- @Override
- protected Indexes doInBackground() throws Throwable {
- boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false);
- MusicService musicService = MusicServiceFactory.getMusicService(SelectArtistActivity.this);
- if (!Util.isOffline(SelectArtistActivity.this)) {
- musicFolders = musicService.getMusicFolders(refresh, SelectArtistActivity.this, this);
- }
- String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this);
- return musicService.getIndexes(musicFolderId, refresh, SelectArtistActivity.this, this);
- }
-
- @Override
- protected void done(Indexes result) {
- List<Artist> artists = new ArrayList<Artist>(result.getShortcuts().size() + result.getArtists().size());
- artists.addAll(result.getShortcuts());
- artists.addAll(result.getArtists());
- artistList.setAdapter(new ArtistAdapter(SelectArtistActivity.this, artists));
-
- // Display selected music folder
- if (musicFolders != null) {
- String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this);
- if (musicFolderId == null) {
- folderName.setText(R.string.select_artist_all_folders);
- } else {
- for (MusicFolder musicFolder : musicFolders) {
- if (musicFolder.getId().equals(musicFolderId)) {
- folderName.setText(musicFolder.getName());
- 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);
- 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);
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
-
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
-
- if (artistList.getItemAtPosition(info.position) instanceof Artist) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.select_artist_context, menu);
- } else if (info.position == 0) {
- 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);
- }
- }
- }
- menu.setGroupCheckable(MENU_GROUP_MUSIC_FOLDER, true, true);
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
-
- Artist artist = (Artist) artistList.getItemAtPosition(info.position);
-
- if (artist != null) {
- switch (menuItem.getItemId()) {
- case R.id.artist_menu_play_now:
- downloadRecursively(artist.getId(), false, false, true);
- break;
- case R.id.artist_menu_play_last:
- downloadRecursively(artist.getId(), false, true, false);
- break;
- case R.id.artist_menu_pin:
- downloadRecursively(artist.getId(), true, true, false);
- break;
- default:
- return super.onContextItemSelected(menuItem);
- }
- } else if (info.position == 0) {
- 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();
- }
-
- return true;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SelectPlaylistActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SelectPlaylistActivity.java
deleted file mode 100644
index 253124b5..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SelectPlaylistActivity.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-
-package net.sourceforge.subsonic.androidapp.activity;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.ContextMenu;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ImageButton;
-import android.widget.ListView;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.Playlist;
-import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
-import net.sourceforge.subsonic.androidapp.service.MusicService;
-import net.sourceforge.subsonic.androidapp.util.BackgroundTask;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.PlaylistAdapter;
-import net.sourceforge.subsonic.androidapp.util.TabActivityBackgroundTask;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-import java.util.List;
-
-public class SelectPlaylistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener {
-
- private static final int MENU_ITEM_PLAY_ALL = 1;
-
- private ListView list;
- private View emptyTextView;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.select_playlist);
-
- list = (ListView) findViewById(R.id.select_playlist_list);
- emptyTextView = findViewById(R.id.select_playlist_empty);
- list.setOnItemClickListener(this);
- registerForContextMenu(list);
-
- // Title: Playlists
- setTitle(R.string.playlist_label);
-
- // Button 1: gone
- ImageButton searchButton = (ImageButton)findViewById(R.id.action_button_1);
- searchButton.setVisibility(View.GONE);
-
- // Button 2: refresh
- ImageButton refreshButton = (ImageButton) findViewById(R.id.action_button_2);
- refreshButton.setImageResource(R.drawable.action_refresh);
- refreshButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- refresh();
- }
- });
-
- load();
- }
-
- 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) {
- @Override
- protected List<Playlist> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(SelectPlaylistActivity.this);
- boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false);
- return musicService.getPlaylists(refresh, SelectPlaylistActivity.this, this);
- }
-
- @Override
- protected void done(List<Playlist> result) {
- list.setAdapter(new PlaylistAdapter(SelectPlaylistActivity.this, PlaylistAdapter.PlaylistComparator.sort(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);
- menu.add(Menu.NONE, MENU_ITEM_PLAY_ALL, MENU_ITEM_PLAY_ALL, R.string.common_play_now);
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
- Playlist playlist = (Playlist) list.getItemAtPosition(info.position);
-
- switch (menuItem.getItemId()) {
- case MENU_ITEM_PLAY_ALL:
- 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());
- intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
- Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent);
- break;
- default:
- return super.onContextItemSelected(menuItem);
- }
- return true;
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-
- 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);
- }
-
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SettingsActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SettingsActivity.java
deleted file mode 100644
index f726a2af..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SettingsActivity.java
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.activity;
-
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.preference.EditTextPreference;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.PreferenceActivity;
-import android.preference.PreferenceScreen;
-import android.provider.SearchRecentSuggestions;
-import android.util.Log;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.provider.SearchSuggestionProvider;
-import net.sourceforge.subsonic.androidapp.service.DownloadService;
-import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
-import net.sourceforge.subsonic.androidapp.service.MusicService;
-import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.ErrorDialog;
-import net.sourceforge.subsonic.androidapp.util.FileUtil;
-import net.sourceforge.subsonic.androidapp.util.ModalBackgroundTask;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-import java.io.File;
-import java.net.URL;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-public class SettingsActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
-
- private static final String TAG = SettingsActivity.class.getSimpleName();
- private final Map<String, ServerSettings> serverSettings = new LinkedHashMap<String, ServerSettings>();
- private boolean testingConnection;
- private ListPreference theme;
- private ListPreference maxBitrateWifi;
- private ListPreference maxBitrateMobile;
- private ListPreference cacheSize;
- private EditTextPreference cacheLocation;
- private ListPreference preloadCount;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.settings);
-
- theme = (ListPreference) findPreference(Constants.PREFERENCES_KEY_THEME);
- maxBitrateWifi = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI);
- maxBitrateMobile = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE);
- cacheSize = (ListPreference) findPreference(Constants.PREFERENCES_KEY_CACHE_SIZE);
- cacheLocation = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_CACHE_LOCATION);
- preloadCount = (ListPreference) findPreference(Constants.PREFERENCES_KEY_PRELOAD_COUNT);
-
- findPreference("testConnection1").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- testConnection(1);
- return false;
- }
- });
-
- findPreference("testConnection2").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- testConnection(2);
- return false;
- }
- });
-
- findPreference("testConnection3").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- testConnection(3);
- return false;
- }
- });
-
- findPreference("clearSearchHistory").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- SearchRecentSuggestions suggestions = new SearchRecentSuggestions(SettingsActivity.this, SearchSuggestionProvider.AUTHORITY, SearchSuggestionProvider.MODE);
- suggestions.clearHistory();
- Util.toast(SettingsActivity.this, R.string.settings_search_history_cleared);
- return false;
- }
- });
-
- for (int i = 1; i <= 3; i++) {
- String instance = String.valueOf(i);
- serverSettings.put(instance, new ServerSettings(instance));
- }
-
- SharedPreferences prefs = Util.getPreferences(this);
- prefs.registerOnSharedPreferenceChangeListener(this);
-
- update();
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
-
- SharedPreferences prefs = Util.getPreferences(this);
- prefs.unregisterOnSharedPreferenceChangeListener(this);
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- Log.d(TAG, "Preference changed: " + key);
- update();
-
- if (Constants.PREFERENCES_KEY_HIDE_MEDIA.equals(key)) {
- setHideMedia(sharedPreferences.getBoolean(key, false));
- }
- else if (Constants.PREFERENCES_KEY_MEDIA_BUTTONS.equals(key)) {
- setMediaButtonsEnabled(sharedPreferences.getBoolean(key, true));
- }
- else if (Constants.PREFERENCES_KEY_CACHE_LOCATION.equals(key)) {
- setCacheLocation(sharedPreferences.getString(key, ""));
- }
- }
-
- private void update() {
- if (testingConnection) {
- return;
- }
-
- theme.setSummary(theme.getEntry());
- maxBitrateWifi.setSummary(maxBitrateWifi.getEntry());
- maxBitrateMobile.setSummary(maxBitrateMobile.getEntry());
- cacheSize.setSummary(cacheSize.getEntry());
- cacheLocation.setSummary(cacheLocation.getText());
- preloadCount.setSummary(preloadCount.getEntry());
- for (ServerSettings ss : serverSettings.values()) {
- ss.update();
- }
- }
-
- private void setHideMedia(boolean hide) {
- File nomediaDir = new File(FileUtil.getSubsonicDirectory(), ".nomedia");
- if (hide && !nomediaDir.exists()) {
- if (!nomediaDir.mkdir()) {
- Log.w(TAG, "Failed to create " + nomediaDir);
- }
- } else if (nomediaDir.exists()) {
- if (!nomediaDir.delete()) {
- Log.w(TAG, "Failed to delete " + nomediaDir);
- }
- }
- Util.toast(this, R.string.settings_hide_media_toast, false);
- }
-
- private void setMediaButtonsEnabled(boolean enabled) {
- if (enabled) {
- Util.registerMediaButtonEventReceiver(this);
- } else {
- Util.unregisterMediaButtonEventReceiver(this);
- }
- }
-
- private void setCacheLocation(String path) {
- File dir = new File(path);
- if (!FileUtil.ensureDirectoryExistsAndIsReadWritable(dir)) {
- Util.toast(this, R.string.settings_cache_location_error, false);
-
- // Reset it to the default.
- String defaultPath = FileUtil.getDefaultMusicDirectory().getPath();
- if (!defaultPath.equals(path)) {
- SharedPreferences prefs = Util.getPreferences(this);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, defaultPath);
- editor.commit();
- cacheLocation.setSummary(defaultPath);
- cacheLocation.setText(defaultPath);
- }
-
- // Clear download queue.
- DownloadService downloadService = DownloadServiceImpl.getInstance();
- downloadService.clear();
- }
- }
-
- private void testConnection(final int instance) {
- ModalBackgroundTask<Boolean> task = new ModalBackgroundTask<Boolean>(this, false) {
- private int previousInstance;
-
- @Override
- protected Boolean doInBackground() throws Throwable {
- updateProgress(R.string.settings_testing_connection);
-
- previousInstance = Util.getActiveServer(SettingsActivity.this);
- testingConnection = true;
- Util.setActiveServer(SettingsActivity.this, instance);
- try {
- MusicService musicService = MusicServiceFactory.getMusicService(SettingsActivity.this);
- musicService.ping(SettingsActivity.this, this);
- return musicService.isLicenseValid(SettingsActivity.this, null);
- } finally {
- Util.setActiveServer(SettingsActivity.this, previousInstance);
- testingConnection = false;
- }
- }
-
- @Override
- protected void done(Boolean licenseValid) {
- if (licenseValid) {
- Util.toast(SettingsActivity.this, R.string.settings_testing_ok);
- } else {
- Util.toast(SettingsActivity.this, R.string.settings_testing_unlicensed);
- }
- }
-
- @Override
- protected void cancel() {
- super.cancel();
- Util.setActiveServer(SettingsActivity.this, previousInstance);
- }
-
- @Override
- protected void error(Throwable error) {
- Log.w(TAG, error.toString(), error);
- new ErrorDialog(SettingsActivity.this, getResources().getString(R.string.settings_connection_failure) +
- " " + getErrorMessage(error), false);
- }
- };
- task.execute();
- }
-
- private class ServerSettings {
- private EditTextPreference serverName;
- private EditTextPreference serverUrl;
- private EditTextPreference username;
- private PreferenceScreen screen;
-
- private ServerSettings(String instance) {
-
- screen = (PreferenceScreen) findPreference("server" + instance);
- serverName = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_SERVER_NAME + instance);
- serverUrl = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_SERVER_URL + instance);
- username = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_USERNAME + instance);
-
- serverUrl.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object value) {
- try {
- String url = (String) value;
- new URL(url);
- if (!url.equals(url.trim()) || url.contains("@")) {
- throw new Exception();
- }
- } catch (Exception x) {
- new ErrorDialog(SettingsActivity.this, R.string.settings_invalid_url, false);
- return false;
- }
- return true;
- }
- });
-
- username.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object value) {
- String username = (String) value;
- if (username == null || !username.equals(username.trim())) {
- new ErrorDialog(SettingsActivity.this, R.string.settings_invalid_username, false);
- return false;
- }
- return true;
- }
- });
- }
-
- public void update() {
- serverName.setSummary(serverName.getText());
- serverUrl.setSummary(serverUrl.getText());
- username.setSummary(username.getText());
- screen.setSummary(serverUrl.getText());
- screen.setTitle(serverName.getText());
- }
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SubsonicTabActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SubsonicTabActivity.java
deleted file mode 100644
index f75e39fc..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/SubsonicTabActivity.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.activity;
-
-import java.io.File;
-import java.io.PrintWriter;
-import java.util.LinkedList;
-import java.util.List;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.graphics.Typeface;
-import android.media.AudioManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Environment;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.widget.TextView;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.service.DownloadService;
-import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
-import net.sourceforge.subsonic.androidapp.service.MusicService;
-import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.ImageLoader;
-import net.sourceforge.subsonic.androidapp.util.ModalBackgroundTask;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-/**
- * @author Sindre Mehus
- */
-public class SubsonicTabActivity extends Activity {
-
- private static final String TAG = SubsonicTabActivity.class.getSimpleName();
- private static ImageLoader IMAGE_LOADER;
-
- private boolean destroyed;
- private View homeButton;
- private View musicButton;
- private View searchButton;
- private View playlistButton;
- private View nowPlayingButton;
-
- @Override
- protected void onCreate(Bundle bundle) {
- setUncaughtExceptionHandler();
- applyTheme();
- super.onCreate(bundle);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- startService(new Intent(this, DownloadServiceImpl.class));
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
- }
-
- @Override
- protected void onPostCreate(Bundle bundle) {
- super.onPostCreate(bundle);
-
- homeButton = findViewById(R.id.button_bar_home);
- homeButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(SubsonicTabActivity.this, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
- }
- });
-
- musicButton = findViewById(R.id.button_bar_music);
- musicButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(SubsonicTabActivity.this, SelectArtistActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
- }
- });
-
- searchButton = findViewById(R.id.button_bar_search);
- searchButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(SubsonicTabActivity.this, SearchActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, true);
- Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
- }
- });
-
- playlistButton = findViewById(R.id.button_bar_playlists);
- playlistButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(SubsonicTabActivity.this, SelectPlaylistActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
- }
- });
-
- nowPlayingButton = findViewById(R.id.button_bar_now_playing);
- nowPlayingButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Util.startActivityWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class);
- }
- });
-
- if (this instanceof MainActivity) {
- homeButton.setEnabled(false);
- } else if (this instanceof SelectAlbumActivity || this instanceof SelectArtistActivity) {
- musicButton.setEnabled(false);
- } else if (this instanceof SearchActivity) {
- searchButton.setEnabled(false);
- } else if (this instanceof SelectPlaylistActivity) {
- playlistButton.setEnabled(false);
- } else if (this instanceof DownloadActivity || this instanceof LyricsActivity) {
- nowPlayingButton.setEnabled(false);
- }
-
- updateButtonVisibility();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- Util.registerMediaButtonEventReceiver(this);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.main, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
-
- case R.id.menu_exit:
- Intent 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);
- return true;
-
- case R.id.menu_settings:
- startActivity(new Intent(this, SettingsActivity.class));
- return true;
-
- case R.id.menu_help:
- startActivity(new Intent(this, HelpActivity.class));
- return true;
- }
-
- return false;
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- destroyed = true;
- getImageLoader().clear();
- }
-
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- boolean isVolumeDown = keyCode == KeyEvent.KEYCODE_VOLUME_DOWN;
- boolean isVolumeUp = keyCode == KeyEvent.KEYCODE_VOLUME_UP;
- boolean isVolumeAdjust = isVolumeDown || isVolumeUp;
- boolean isJukebox = getDownloadService() != null && getDownloadService().isJukeboxEnabled();
-
- if (isVolumeAdjust && isJukebox) {
- getDownloadService().adjustJukeboxVolume(isVolumeUp);
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- public void finish() {
- super.finish();
- Util.disablePendingTransition(this);
- }
-
- @Override
- public void setTitle(CharSequence title) {
- super.setTitle(title);
-
- // Set the font of title in the action bar.
- TextView text = (TextView) findViewById(R.id.actionbar_title_text);
- Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/Storopia.ttf");
- text.setTypeface(typeface);
-
- text.setText(title);
- }
-
- @Override
- public void setTitle(int titleId) {
- setTitle(getString(titleId));
- }
-
- private void applyTheme() {
- String theme = Util.getTheme(this);
- if ("dark".equals(theme)) {
- setTheme(android.R.style.Theme);
- } else if ("light".equals(theme)) {
- setTheme(android.R.style.Theme_Light);
- }
- }
-
- public boolean isDestroyed() {
- return destroyed;
- }
-
- private void updateButtonVisibility() {
- int visibility = Util.isOffline(this) ? View.GONE : View.VISIBLE;
- searchButton.setVisibility(visibility);
- }
-
- public void setProgressVisible(boolean visible) {
- View view = findViewById(R.id.tab_progress);
- if (view != null) {
- view.setVisibility(visible ? View.VISIBLE : View.GONE);
- }
- }
-
- public void updateProgress(String message) {
- TextView view = (TextView) findViewById(R.id.tab_progress_message);
- if (view != null) {
- view.setText(message);
- }
- }
-
- public DownloadService getDownloadService() {
- // If service is not available, request it to start and wait for it.
- for (int i = 0; i < 5; i++) {
- DownloadService downloadService = DownloadServiceImpl.getInstance();
- if (downloadService != null) {
- return downloadService;
- }
- Log.w(TAG, "DownloadService not running. Attempting to start it.");
- startService(new Intent(this, DownloadServiceImpl.class));
- Util.sleepQuietly(50L);
- }
- return DownloadServiceImpl.getInstance();
- }
-
- protected void warnIfNetworkOrStorageUnavailable() {
- if (!Util.isExternalStoragePresent()) {
- Util.toast(this, R.string.select_album_no_sdcard);
- } else if (!Util.isOffline(this) && !Util.isNetworkConnected(this)) {
- Util.toast(this, R.string.select_album_no_network);
- }
- }
-
- protected synchronized ImageLoader getImageLoader() {
- if (IMAGE_LOADER == null) {
- IMAGE_LOADER = new ImageLoader(this);
- }
- return IMAGE_LOADER;
- }
-
- protected void downloadRecursively(final String id, final boolean save, final boolean append, final boolean autoplay) {
- ModalBackgroundTask<List<MusicDirectory.Entry>> task = new ModalBackgroundTask<List<MusicDirectory.Entry>>(this, false) {
-
- private static final int MAX_SONGS = 500;
-
- @Override
- protected List<MusicDirectory.Entry> doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
- MusicDirectory root = musicService.getMusicDirectory(id, false, SubsonicTabActivity.this, this);
- List<MusicDirectory.Entry> songs = new LinkedList<MusicDirectory.Entry>();
- getSongsRecursively(root, songs);
- return songs;
- }
-
- private void getSongsRecursively(MusicDirectory parent, List<MusicDirectory.Entry> songs) throws Exception {
- if (songs.size() > MAX_SONGS) {
- return;
- }
-
- for (MusicDirectory.Entry song : parent.getChildren(false, true)) {
- if (!song.isVideo()) {
- songs.add(song);
- }
- }
- for (MusicDirectory.Entry dir : parent.getChildren(true, false)) {
- MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
- getSongsRecursively(musicService.getMusicDirectory(dir.getId(), false, SubsonicTabActivity.this, this), songs);
- }
- }
-
- @Override
- protected void done(List<MusicDirectory.Entry> songs) {
- DownloadService downloadService = getDownloadService();
- if (!songs.isEmpty() && downloadService != null) {
- if (!append) {
- downloadService.clear();
- }
- warnIfNetworkOrStorageUnavailable();
- downloadService.download(songs, save, autoplay, false);
- Util.startActivityWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class);
- }
- }
- };
-
- task.execute();
- }
-
- private void setUncaughtExceptionHandler() {
- Thread.UncaughtExceptionHandler handler = Thread.getDefaultUncaughtExceptionHandler();
- if (!(handler instanceof SubsonicUncaughtExceptionHandler)) {
- Thread.setDefaultUncaughtExceptionHandler(new SubsonicUncaughtExceptionHandler(this));
- }
- }
-
- /**
- * Logs the stack trace of uncaught exceptions to a file on the SD card.
- */
- private static class SubsonicUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
-
- private final Thread.UncaughtExceptionHandler defaultHandler;
- private final Context context;
-
- private SubsonicUncaughtExceptionHandler(Context context) {
- this.context = context;
- defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
- }
-
- @Override
- public void uncaughtException(Thread thread, Throwable throwable) {
- File file = null;
- PrintWriter printWriter = null;
- try {
-
- PackageInfo packageInfo = context.getPackageManager().getPackageInfo("net.sourceforge.subsonic.androidapp", 0);
- file = new File(Environment.getExternalStorageDirectory(), "subsonic-stacktrace.txt");
- printWriter = new PrintWriter(file);
- printWriter.println("Android API level: " + Build.VERSION.SDK);
- printWriter.println("Subsonic version name: " + packageInfo.versionName);
- printWriter.println("Subsonic version code: " + packageInfo.versionCode);
- printWriter.println();
- throwable.printStackTrace(printWriter);
- Log.i(TAG, "Stack trace written to " + file);
- } catch (Throwable x) {
- Log.e(TAG, "Failed to write stack trace to " + file, x);
- } finally {
- Util.close(printWriter);
- if (defaultHandler != null) {
- defaultHandler.uncaughtException(thread, throwable);
- }
-
- }
- }
- }
-}
-
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/VoiceQueryReceiverActivity.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/VoiceQueryReceiverActivity.java
deleted file mode 100644
index 205c2fe7..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/activity/VoiceQueryReceiverActivity.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-
-package net.sourceforge.subsonic.androidapp.activity;
-
-import android.app.Activity;
-import android.app.SearchManager;
-import android.content.Intent;
-import android.os.Bundle;
-import android.provider.SearchRecentSuggestions;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.Util;
-import net.sourceforge.subsonic.androidapp.provider.SearchSuggestionProvider;
-
-/**
- * Receives voice search queries and forwards to the SearchActivity.
- *
- * http://android-developers.blogspot.com/2010/09/supporting-new-music-voice-action.html
- *
- * @author Sindre Mehus
- */
-public class VoiceQueryReceiverActivity extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- String query = getIntent().getStringExtra(SearchManager.QUERY);
-
- 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);
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/audiofx/EqualizerController.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/audiofx/EqualizerController.java
deleted file mode 100644
index 77a270ed..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/audiofx/EqualizerController.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2011 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.audiofx;
-
-import java.io.Serializable;
-
-import android.content.Context;
-import android.media.MediaPlayer;
-import android.media.audiofx.Equalizer;
-import android.util.Log;
-import net.sourceforge.subsonic.androidapp.util.FileUtil;
-
-/**
- * Backward-compatible wrapper for {@link Equalizer}, which is API Level 9.
- *
- * @author Sindre Mehus
- * @version $Id$
- */
-public class EqualizerController {
-
- private static final String TAG = EqualizerController.class.getSimpleName();
-
- private final Context context;
- private Equalizer equalizer;
-
- // 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.
- }
-
- public EqualizerController(Context context, MediaPlayer mediaPlayer) {
- this.context = context;
- try {
- equalizer = new Equalizer(0, mediaPlayer.getAudioSessionId());
- } catch (Throwable x) {
- 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 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);
- }
- }
-
- public boolean isAvailable() {
- return equalizer != null;
- }
-
- public boolean isEnabled() {
- return isAvailable() && equalizer.getEnabled();
- }
-
- public void release() {
- if (isAvailable()) {
- equalizer.release();
- }
- }
-
- public Equalizer getEqualizer() {
- return equalizer;
- }
-
- private static class EqualizerSettings implements Serializable {
-
- private final short[] bandLevels;
- 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 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);
- }
- }
-}
-
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/audiofx/VisualizerController.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/audiofx/VisualizerController.java
deleted file mode 100644
index 9a211b58..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/audiofx/VisualizerController.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2011 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.audiofx;
-
-import android.content.Context;
-import android.media.MediaPlayer;
-import android.media.audiofx.Visualizer;
-import android.util.Log;
-
-/**
- * Backward-compatible wrapper for {@link Visualizer}, which is API Level 9.
- *
- * @author Sindre Mehus
- * @version $Id$
- */
-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 final Context context;
- private Visualizer visualizer;
-
- // 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.
- }
-
- public VisualizerController(Context context, MediaPlayer mediaPlayer) {
- this.context = context;
- try {
- visualizer = new Visualizer(mediaPlayer.getAudioSessionId());
- } 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);
- }
- }
-
- public boolean isAvailable() {
- return visualizer != null;
- }
-
- public boolean isEnabled() {
- return isAvailable() && visualizer.getEnabled();
- }
-
- public void release() {
- if (isAvailable()) {
- visualizer.release();
- }
- }
-
- public Visualizer getVisualizer() {
- return visualizer;
- }
-}
-
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Artist.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Artist.java
deleted file mode 100644
index fce7b628..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Artist.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.domain;
-
-import java.io.Serializable;
-
-/**
- * @author Sindre Mehus
- */
-public class Artist implements Serializable {
-
- private String id;
- private String name;
- private String index;
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getName() {
- 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;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Indexes.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Indexes.java
deleted file mode 100644
index f16861be..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Indexes.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.domain;
-
-import java.util.List;
-import java.io.Serializable;
-
-/**
- * @author Sindre Mehus
- */
-public class Indexes implements Serializable {
-
- private final long lastModified;
- private final List<Artist> shortcuts;
- private final List<Artist> artists;
-
- public Indexes(long lastModified, List<Artist> shortcuts, List<Artist> artists) {
- this.lastModified = lastModified;
- this.shortcuts = shortcuts;
- this.artists = artists;
- }
-
- public long getLastModified() {
- return lastModified;
- }
-
- public List<Artist> getShortcuts() {
- return shortcuts;
- }
-
- public List<Artist> getArtists() {
- return artists;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/JukeboxStatus.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/JukeboxStatus.java
deleted file mode 100644
index 53a901ad..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/JukeboxStatus.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.domain;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public class JukeboxStatus {
-
- private Integer positionSeconds;
- private Integer currentPlayingIndex;
- private Float gain;
- private boolean playing;
-
- public Integer getPositionSeconds() {
- return positionSeconds;
- }
-
- public void setPositionSeconds(Integer positionSeconds) {
- this.positionSeconds = positionSeconds;
- }
-
- public Integer getCurrentPlayingIndex() {
- return currentPlayingIndex;
- }
-
- public void setCurrentIndex(Integer currentPlayingIndex) {
- this.currentPlayingIndex = currentPlayingIndex;
- }
-
- public boolean isPlaying() {
- return playing;
- }
-
- public void setPlaying(boolean playing) {
- this.playing = playing;
- }
-
- public Float getGain() {
- return gain;
- }
-
- public void setGain(float gain) {
- this.gain = gain;
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Lyrics.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Lyrics.java
deleted file mode 100644
index c1a4c7c0..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Lyrics.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2010 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.domain;
-
-/**
- * Song lyrics.
- *
- * @author Sindre Mehus
- */
-public class Lyrics {
-
- private String artist;
- private String title;
- private String text;
-
- public String getArtist() {
- return artist;
- }
-
- public void setArtist(String artist) {
- this.artist = artist;
- }
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public String getText() {
- return text;
- }
-
- public void setText(String text) {
- this.text = text;
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/MusicDirectory.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/MusicDirectory.java
deleted file mode 100644
index 4d4d265b..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/MusicDirectory.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.domain;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.io.Serializable;
-
-/**
- * @author Sindre Mehus
- */
-public class MusicDirectory {
-
- private String name;
- private final List<Entry> children = new ArrayList<Entry>();
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public void addChild(Entry child) {
- children.add(child);
- }
-
- public List<Entry> getChildren() {
- return getChildren(true, true);
- }
-
- 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;
- }
-
- public static class Entry implements Serializable {
- private String id;
- private String parent;
- private boolean directory;
- private String title;
- private String album;
- private String artist;
- 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 Integer duration;
- private Integer bitRate;
- private String path;
- private boolean video;
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getParent() {
- return parent;
- }
-
- public void setParent(String parent) {
- this.parent = parent;
- }
-
- public boolean isDirectory() {
- return directory;
- }
-
- public void setDirectory(boolean directory) {
- this.directory = directory;
- }
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public String getAlbum() {
- return album;
- }
-
- public void setAlbum(String album) {
- this.album = album;
- }
-
- public String getArtist() {
- return artist;
- }
-
- public void setArtist(String artist) {
- this.artist = artist;
- }
-
- public Integer getTrack() {
- return track;
- }
-
- public void setTrack(Integer track) {
- this.track = track;
- }
-
- public Integer getYear() {
- return year;
- }
-
- public void setYear(Integer year) {
- this.year = year;
- }
-
- public String getGenre() {
- return genre;
- }
-
- public void setGenre(String genre) {
- this.genre = genre;
- }
-
- public String getContentType() {
- return contentType;
- }
-
- public void setContentType(String contentType) {
- this.contentType = contentType;
- }
-
- public String getSuffix() {
- return suffix;
- }
-
- public void setSuffix(String suffix) {
- this.suffix = suffix;
- }
-
- public String getTranscodedContentType() {
- return transcodedContentType;
- }
-
- public void setTranscodedContentType(String transcodedContentType) {
- this.transcodedContentType = transcodedContentType;
- }
-
- public String getTranscodedSuffix() {
- return transcodedSuffix;
- }
-
- public void setTranscodedSuffix(String transcodedSuffix) {
- this.transcodedSuffix = transcodedSuffix;
- }
-
- public Long getSize() {
- return size;
- }
-
- public void setSize(Long size) {
- this.size = size;
- }
-
- public Integer getDuration() {
- return duration;
- }
-
- public void setDuration(Integer duration) {
- this.duration = duration;
- }
-
- public Integer getBitRate() {
- return bitRate;
- }
-
- 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 video;
- }
-
- public void setVideo(boolean video) {
- this.video = video;
- }
-
- @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);
- }
-
- @Override
- public int hashCode() {
- return id.hashCode();
- }
-
- @Override
- public String toString() {
- return title;
- }
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/MusicFolder.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/MusicFolder.java
deleted file mode 100644
index 595f2b5e..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/MusicFolder.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.domain;
-
-import java.io.Serializable;
-
-/**
- * Represents a top level directory in which music or other media is stored.
- *
- * @author Sindre Mehus
- * @version $Id$
- */
-public class MusicFolder implements Serializable {
-
- private final String id;
- private final String name;
-
- public MusicFolder(String id, String name) {
- this.id = id;
- this.name = name;
- }
-
- public String getId() {
- return id;
- }
-
- public String getName() {
- return name;
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/PlayerState.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/PlayerState.java
deleted file mode 100644
index 0e13159b..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/PlayerState.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.domain;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public enum PlayerState {
- IDLE,
- DOWNLOADING,
- PREPARING,
- PREPARED,
- STARTED,
- STOPPED,
- PAUSED,
- COMPLETED
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Playlist.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Playlist.java
deleted file mode 100644
index 8bb29f76..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Playlist.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.domain;
-
-import java.io.Serializable;
-
-/**
- * @author Sindre Mehus
- */
-public class Playlist implements Serializable {
-
- private String id;
- private String name;
-
- public Playlist(String id, String name) {
- this.id = id;
- this.name = name;
- }
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- @Override
- public String toString() {
- return name;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/RepeatMode.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/RepeatMode.java
deleted file mode 100644
index be2ad061..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/RepeatMode.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package net.sourceforge.subsonic.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 abstract RepeatMode next();
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/SearchCritera.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/SearchCritera.java
deleted file mode 100644
index 8f944b1a..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/SearchCritera.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.domain;
-
-/**
- * The criteria for a music search.
- *
- * @author Sindre Mehus
- */
-public class SearchCritera {
-
- 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 String getQuery() {
- return query;
- }
-
- public int getArtistCount() {
- return artistCount;
- }
-
- public int getAlbumCount() {
- return albumCount;
- }
-
- public int getSongCount() {
- return songCount;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/SearchResult.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/SearchResult.java
deleted file mode 100644
index 54c91628..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/SearchResult.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.domain;
-
-import java.util.List;
-
-/**
- * The result of a search. Contains matching artists, albums and songs.
- *
- * @author Sindre Mehus
- */
-public class SearchResult {
-
- 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 List<Artist> getArtists() {
- return artists;
- }
-
- public List<MusicDirectory.Entry> getAlbums() {
- return albums;
- }
-
- public List<MusicDirectory.Entry> getSongs() {
- return songs;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/ServerInfo.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/ServerInfo.java
deleted file mode 100644
index 9212c585..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/ServerInfo.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2010 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.domain;
-
-/**
- * Information about the Subsonic server.
- *
- * @author Sindre Mehus
- */
-public class ServerInfo {
-
- private boolean isLicenseValid;
- private Version restVersion;
-
- public boolean isLicenseValid() {
- return isLicenseValid;
- }
-
- public void setLicenseValid(boolean licenseValid) {
- isLicenseValid = licenseValid;
- }
-
- public Version getRestVersion() {
- return restVersion;
- }
-
- public void setRestVersion(Version restVersion) {
- this.restVersion = restVersion;
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Version.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Version.java
deleted file mode 100644
index bd1643b5..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/domain/Version.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.domain;
-
-/**
- * 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;
-
- /**
- * 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]);
-
- 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 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;
-
- final Version version = (Version) o;
-
- if (beta != version.beta) return false;
- if (bugfix != version.bugfix) return false;
- if (major != version.major) return false;
- return 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 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();
- }
-
- /**
- * 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 (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;
-
- if (thisBeta < otherBeta) {
- return -1;
- } else if (thisBeta > otherBeta) {
- return 1;
- }
-
- return 0;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/provider/SearchSuggestionProvider.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/provider/SearchSuggestionProvider.java
deleted file mode 100644
index d3ba4f5c..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/provider/SearchSuggestionProvider.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2010 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.provider;
-
-import android.content.SearchRecentSuggestionsProvider;
-
-/**
- * Provides search suggestions based on recent searches.
- *
- * @author Sindre Mehus
- */
-public class SearchSuggestionProvider extends SearchRecentSuggestionsProvider {
-
- public static final String AUTHORITY = SearchSuggestionProvider.class.getName();
- public static final int MODE = DATABASE_MODE_QUERIES;
-
- public SearchSuggestionProvider() {
- setupSuggestions(AUTHORITY, MODE);
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/provider/SubsonicAppWidgetProvider.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/provider/SubsonicAppWidgetProvider.java
deleted file mode 100644
index dba3bdcd..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/provider/SubsonicAppWidgetProvider.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2010 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.provider;
-
-import android.app.PendingIntent;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProvider;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.os.Environment;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.widget.RemoteViews;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.activity.DownloadActivity;
-import net.sourceforge.subsonic.androidapp.activity.MainActivity;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.service.DownloadService;
-import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
-import net.sourceforge.subsonic.androidapp.util.FileUtil;
-
-/**
- * Simple widget to show currently playing album art along
- * with play/pause and next track buttons.
- * <p/>
- * Based on source code from the stock Android Music app.
- *
- * @author Sindre Mehus
- */
-public class SubsonicAppWidgetProvider extends AppWidgetProvider {
-
- private static SubsonicAppWidgetProvider instance;
- private static final String TAG = SubsonicAppWidgetProvider.class.getSimpleName();
-
- public static synchronized SubsonicAppWidgetProvider getInstance() {
- if (instance == null) {
- instance = new SubsonicAppWidgetProvider();
- }
- return instance;
- }
-
- @Override
- public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
- defaultAppWidget(context, appWidgetIds);
- }
-
- /**
- * Initialize given widgets to default state, where we launch Subsonic 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(), R.layout.appwidget);
-
- 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);
- 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) {
- if (hasInstances(context)) {
- performUpdate(context, service, null, playing);
- }
- }
-
- /**
- * Check against {@link AppWidgetManager} if there are any instances of this widget.
- */
- private boolean hasInstances(Context context) {
- AppWidgetManager manager = AppWidgetManager.getInstance(context);
- int[] appWidgetIds = manager.getAppWidgetIds(new ComponentName(context, getClass()));
- return (appWidgetIds.length > 0);
- }
-
- /**
- * Update all active widget instances by pushing changes
- */
- private void performUpdate(Context context, DownloadService service, int[] appWidgetIds, boolean playing) {
- final Resources res = context.getResources();
- final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget);
-
- MusicDirectory.Entry currentPlaying = service.getCurrentPlaying() == null ? null : service.getCurrentPlaying().getSong();
- String title = currentPlaying == null ? null : currentPlaying.getTitle();
- CharSequence artist = currentPlaying == null ? null : currentPlaying.getArtist();
- CharSequence errorState = 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);
- }
-
- if (errorState != null) {
- // Show error state to user
- views.setTextViewText(R.id.title,null);
- views.setTextViewText(R.id.artist, errorState);
- 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);
- }
-
- // Set correct drawable for pause state
- if (playing) {
- views.setImageViewResource(R.id.control_play, R.drawable.ic_appwidget_music_pause);
- } else {
- views.setImageViewResource(R.id.control_play, R.drawable.ic_appwidget_music_play);
- }
-
- // Set the cover art
- try {
- int size = context.getResources().getDrawable(R.drawable.appwidget_art_default).getIntrinsicHeight();
- Bitmap bitmap = currentPlaying == null ? null : FileUtil.getAlbumArtBitmap(context, currentPlaying, size);
-
- if (bitmap == null) {
- // Set default cover art
- views.setImageViewResource(R.id.appwidget_coverart, R.drawable.appwidget_art_unknown);
- } 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_unknown);
- }
-
- // Link actions buttons to intents
- linkButtons(context, views, currentPlaying != null);
-
- pushUpdate(context, appWidgetIds, views);
- }
-
- /**
- * Round the corners of a bitmap for the cover art image
- */
- private static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
- Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
- Canvas canvas = new Canvas(output);
-
- final int color = 0xff424242;
- final Paint paint = new Paint();
- final float roundPx = 10;
-
- // Add extra width to the rect so the right side wont be rounded.
- final Rect rect = new Rect(0, 0, bitmap.getWidth() + (int) roundPx, bitmap.getHeight());
- final RectF rectF = new RectF(rect);
-
- paint.setAntiAlias(true);
- canvas.drawARGB(0, 0, 0, 0);
- paint.setColor(color);
- canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
-
- paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
- canvas.drawBitmap(bitmap, rect, rect, paint);
-
- return output;
- }
-
- /**
- * 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) {
-
- 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);
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/receiver/BluetoothIntentReceiver.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/receiver/BluetoothIntentReceiver.java
deleted file mode 100644
index 6bf17ac2..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/receiver/BluetoothIntentReceiver.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2010 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.receiver;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-/**
- * Request media button focus when connected to Bluetooth A2DP.
- *
- * @author Sindre Mehus
- */
-public class BluetoothIntentReceiver extends BroadcastReceiver {
-
- private static final String TAG = BluetoothIntentReceiver.class.getSimpleName();
-
- @Override
- public void onReceive(Context context, Intent intent) {
- int state = intent.getIntExtra("android.bluetooth.a2dp.extra.SINK_STATE", -1);
- Log.i(TAG, "android.bluetooth.a2dp.extra.SINK_STATE, state = " + state);
- boolean connected = state == 2; // android.bluetooth.BluetoothA2dp.STATE_CONNECTED
- if (connected) {
- Log.i(TAG, "Connected to Bluetooth A2DP, requesting media button focus.");
- Util.registerMediaButtonEventReceiver(context);
- }
-
- boolean disconnected = state == 0; // android.bluetooth.BluetoothA2dp.STATE_DISCONNECTED
- if (disconnected) {
- Log.i(TAG, "Disconnected from Bluetooth A2DP, requesting pause.");
- context.sendBroadcast(new Intent(DownloadServiceImpl.CMD_PAUSE));
- }
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/receiver/MediaButtonIntentReceiver.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/receiver/MediaButtonIntentReceiver.java
deleted file mode 100644
index 5287d933..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/receiver/MediaButtonIntentReceiver.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2010 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.receiver;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-import android.view.KeyEvent;
-import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
-
-/**
- * @author Sindre Mehus
- */
-public class MediaButtonIntentReceiver extends BroadcastReceiver {
-
- private static final String TAG = MediaButtonIntentReceiver.class.getSimpleName();
-
- @Override
- public void onReceive(Context context, Intent intent) {
- KeyEvent event = (KeyEvent) intent.getExtras().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);
-
- try {
- abortBroadcast();
- } catch (Exception x) {
- // Ignored.
- }
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/CachedMusicService.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/CachedMusicService.java
deleted file mode 100644
index 14aed954..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/CachedMusicService.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service;
-
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.http.HttpResponse;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import net.sourceforge.subsonic.androidapp.domain.Indexes;
-import net.sourceforge.subsonic.androidapp.domain.JukeboxStatus;
-import net.sourceforge.subsonic.androidapp.domain.Lyrics;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.domain.MusicFolder;
-import net.sourceforge.subsonic.androidapp.domain.Playlist;
-import net.sourceforge.subsonic.androidapp.domain.SearchCritera;
-import net.sourceforge.subsonic.androidapp.domain.SearchResult;
-import net.sourceforge.subsonic.androidapp.domain.Version;
-import net.sourceforge.subsonic.androidapp.util.CancellableTask;
-import net.sourceforge.subsonic.androidapp.util.LRUCache;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-import net.sourceforge.subsonic.androidapp.util.TimeLimitedCache;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-/**
- * @author Sindre Mehus
- */
-public class CachedMusicService implements MusicService {
-
- private static final int MUSIC_DIR_CACHE_SIZE = 20;
- private static final int TTL_MUSIC_DIR = 5 * 60; // Five minutes
-
- private final MusicService musicService;
- private final LRUCache<String, TimeLimitedCache<MusicDirectory>> cachedMusicDirectories;
- 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<List<Playlist>> cachedPlaylists = new TimeLimitedCache<List<Playlist>>(60, TimeUnit.SECONDS);
- private final TimeLimitedCache<List<MusicFolder>> cachedMusicFolders = new TimeLimitedCache<List<MusicFolder>>(10 * 3600, TimeUnit.SECONDS);
- private String restUrl;
-
- public CachedMusicService(MusicService musicService) {
- this.musicService = musicService;
- cachedMusicDirectories = new LRUCache<String, TimeLimitedCache<MusicDirectory>>(MUSIC_DIR_CACHE_SIZE);
- }
-
- @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 MusicDirectory getMusicDirectory(String id, 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, refresh, context, progressListener);
- cache = new TimeLimitedCache<MusicDirectory>(TTL_MUSIC_DIR, TimeUnit.SECONDS);
- cache.set(dir);
- cachedMusicDirectories.put(id, cache);
- }
- return dir;
- }
-
- @Override
- public SearchResult search(SearchCritera 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 {
- musicService.createPlaylist(id, name, entries, 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 getRandomSongs(int size, Context context, ProgressListener progressListener) throws Exception {
- return musicService.getRandomSongs(size, context, progressListener);
- }
-
- @Override
- public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, ProgressListener progressListener) throws Exception {
- return musicService.getCoverArt(context, entry, size, saveToFile, 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) {
- return musicService.getVideoUrl(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;
- }
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadFile.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadFile.java
deleted file mode 100644
index 46373afe..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadFile.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.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.os.PowerManager;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.util.CancellableTask;
-import net.sourceforge.subsonic.androidapp.util.FileUtil;
-import net.sourceforge.subsonic.androidapp.util.Util;
-import net.sourceforge.subsonic.androidapp.util.CacheCleaner;
-
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-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 final MediaStoreService mediaStoreService;
- private CancellableTask downloadTask;
- private boolean save;
- private boolean failed;
- private int bitRate;
-
- 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()) +
- "." + bitRate + ".partial." + FileUtil.getExtension(saveFile.getName()));
- completeFile = new File(saveFile.getParent(), FileUtil.getBaseName(saveFile.getName()) +
- ".complete." + FileUtil.getExtension(saveFile.getName()));
- mediaStoreService = new MediaStoreService(context);
- }
-
- public MusicDirectory.Entry getSong() {
- return song;
- }
-
- /**
- * Returns the effective bit rate.
- */
- public int getBitRate() {
- if (bitRate > 0) {
- return bitRate;
- }
- return song.getBitRate() == null ? 160 : song.getBitRate();
- }
-
- public synchronized void download() {
- FileUtil.createDirectoryForParent(saveFile);
- failed = false;
- downloadTask = new DownloadTask();
- downloadTask.start();
- }
-
- public synchronized void cancelDownload() {
- if (downloadTask != null) {
- downloadTask.cancel();
- }
- }
-
- public File getCompleteFile() {
- if (saveFile.exists()) {
- return saveFile;
- }
-
- if (completeFile.exists()) {
- return completeFile;
- }
-
- return saveFile;
- }
-
- public File getPartialFile() {
- return partialFile;
- }
-
- public boolean isSaved() {
- return saveFile.exists();
- }
-
- public synchronized boolean isCompleteFileAvailable() {
- return saveFile.exists() || completeFile.exists();
- }
-
- public synchronized boolean isWorkDone() {
- return saveFile.exists() || (completeFile.exists() && !save);
- }
-
- public synchronized boolean isDownloading() {
- return downloadTask != null && downloadTask.isRunning();
- }
-
- public synchronized boolean isDownloadCancelled() {
- return downloadTask != null && downloadTask.isCancelled();
- }
-
- public boolean shouldSave() {
- return save;
- }
-
- public boolean isFailed() {
- return failed;
- }
-
- public void delete() {
- cancelDownload();
- Util.delete(partialFile);
- Util.delete(completeFile);
- Util.delete(saveFile);
- mediaStoreService.deleteFromMediaStore(this);
- }
-
- public void unpin() {
- if (saveFile.exists()) {
- saveFile.renameTo(completeFile);
- }
- }
-
- public boolean cleanup() {
- boolean ok = true;
- 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 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);
- }
- }
- }
-
- @Override
- public String toString() {
- return "DownloadFile (" + song + ")";
- }
-
- private class DownloadTask extends CancellableTask {
-
- @Override
- public void execute() {
-
- InputStream in = null;
- FileOutputStream out = null;
- PowerManager.WakeLock wakeLock = 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);
- }
-
- if (saveFile.exists()) {
- Log.i(TAG, saveFile + " already exists. Skipping.");
- return;
- }
- if (completeFile.exists()) {
- if (save) {
- Util.atomicCopy(completeFile, saveFile);
- } else {
- Log.i(TAG, completeFile + " already exists. Skipping.");
- }
- return;
- }
-
- MusicService musicService = MusicServiceFactory.getMusicService(context);
-
- // Attempt partial HTTP GET, appending to the file if it exists.
- HttpResponse response = musicService.getDownloadInputStream(context, song, partialFile.length(), bitRate, DownloadTask.this);
- 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");
- }
-
- out = new FileOutputStream(partialFile, partial);
- long n = copy(in, out);
- Log.i(TAG, "Downloaded " + n + " bytes to " + partialFile);
- out.flush();
- out.close();
-
- if (isCancelled()) {
- throw new Exception("Download of '" + song + "' was cancelled");
- }
-
- downloadAndSaveCoverArt(musicService);
-
- if (save) {
- Util.atomicCopy(partialFile, saveFile);
- mediaStoreService.saveInMediaStore(DownloadFile.this);
- } else {
- Util.atomicCopy(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);
- }
-
- } finally {
- Util.close(in);
- Util.close(out);
- if (wakeLock != null) {
- wakeLock.release();
- Log.i(TAG, "Released wake lock " + wakeLock);
- }
- new CacheCleaner(context, DownloadServiceImpl.getInstance()).clean();
- }
- }
-
- @Override
- public String toString() {
- return "DownloadTask (" + song + ")";
- }
-
- private void downloadAndSaveCoverArt(MusicService musicService) throws Exception {
- try {
- if (song.getCoverArt() != null) {
- DisplayMetrics metrics = context.getResources().getDisplayMetrics();
- int size = Math.min(metrics.widthPixels, metrics.heightPixels);
- musicService.getCoverArt(context, song, size, 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 {
-
- // 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();
-
- byte[] buffer = new byte[1024 * 16];
- long count = 0;
- int n;
- long lastLog = System.currentTimeMillis();
-
- 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, "Downloaded " + Util.formatBytes(count) + " of " + song);
- lastLog = now;
- }
- }
- return count;
- }
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadService.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadService.java
deleted file mode 100644
index b136bdbc..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadService.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service;
-
-import java.util.List;
-
-import net.sourceforge.subsonic.androidapp.audiofx.EqualizerController;
-import net.sourceforge.subsonic.androidapp.audiofx.VisualizerController;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.domain.PlayerState;
-import net.sourceforge.subsonic.androidapp.domain.RepeatMode;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public interface DownloadService {
-
- void download(List<MusicDirectory.Entry> songs, boolean save, boolean autoplay, boolean playNext);
-
- void setShufflePlayEnabled(boolean enabled);
-
- boolean isShufflePlayEnabled();
-
- void shuffle();
-
- RepeatMode getRepeatMode();
-
- void setRepeatMode(RepeatMode repeatMode);
-
- boolean getKeepScreenOn();
-
- void setKeepScreenOn(boolean screenOn);
-
- boolean getShowVisualization();
-
- void setShowVisualization(boolean showVisualization);
-
- void clear();
-
- void clearIncomplete();
-
- int size();
-
- void remove(DownloadFile downloadFile);
-
- List<DownloadFile> getDownloads();
-
- int getCurrentPlayingIndex();
-
- DownloadFile getCurrentPlaying();
-
- DownloadFile getCurrentDownloading();
-
- void play(int index);
-
- void seekTo(int position);
-
- void previous();
-
- void next();
-
- void pause();
-
- void start();
-
- void reset();
-
- PlayerState getPlayerState();
-
- int getPlayerPosition();
-
- int getPlayerDuration();
-
- void delete(List<MusicDirectory.Entry> songs);
-
- void unpin(List<MusicDirectory.Entry> songs);
-
- DownloadFile forSong(MusicDirectory.Entry song);
-
- long getDownloadListUpdateRevision();
-
- void setSuggestedPlaylistName(String name);
-
- String getSuggestedPlaylistName();
-
- EqualizerController getEqualizerController();
-
- VisualizerController getVisualizerController();
-
- boolean isJukeboxEnabled();
-
- void setJukeboxEnabled(boolean b);
-
- void adjustJukeboxVolume(boolean up);
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadServiceImpl.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadServiceImpl.java
deleted file mode 100644
index 2e668fea..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadServiceImpl.java
+++ /dev/null
@@ -1,930 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service;
-
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.media.AudioManager;
-import android.media.MediaPlayer;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.PowerManager;
-import android.util.Log;
-import net.sourceforge.subsonic.androidapp.audiofx.EqualizerController;
-import net.sourceforge.subsonic.androidapp.audiofx.VisualizerController;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.domain.PlayerState;
-import net.sourceforge.subsonic.androidapp.domain.RepeatMode;
-import net.sourceforge.subsonic.androidapp.util.CancellableTask;
-import net.sourceforge.subsonic.androidapp.util.LRUCache;
-import net.sourceforge.subsonic.androidapp.util.ShufflePlayBuffer;
-import net.sourceforge.subsonic.androidapp.util.SimpleServiceBinder;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-import static net.sourceforge.subsonic.androidapp.domain.PlayerState.*;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public class DownloadServiceImpl extends Service implements DownloadService {
-
- private static final String TAG = DownloadServiceImpl.class.getSimpleName();
-
- public static final String CMD_PLAY = "net.sourceforge.subsonic.androidapp.CMD_PLAY";
- public static final String CMD_TOGGLEPAUSE = "net.sourceforge.subsonic.androidapp.CMD_TOGGLEPAUSE";
- public static final String CMD_PAUSE = "net.sourceforge.subsonic.androidapp.CMD_PAUSE";
- public static final String CMD_STOP = "net.sourceforge.subsonic.androidapp.CMD_STOP";
- public static final String CMD_PREVIOUS = "net.sourceforge.subsonic.androidapp.CMD_PREVIOUS";
- public static final String CMD_NEXT = "net.sourceforge.subsonic.androidapp.CMD_NEXT";
-
- private final IBinder binder = new SimpleServiceBinder<DownloadService>(this);
- private MediaPlayer mediaPlayer;
- private final List<DownloadFile> downloadList = new ArrayList<DownloadFile>();
- private final Handler handler = new Handler();
- private final DownloadServiceLifecycleSupport lifecycleSupport = new DownloadServiceLifecycleSupport(this);
- private final ShufflePlayBuffer shufflePlayBuffer = new ShufflePlayBuffer(this);
-
- private final LRUCache<MusicDirectory.Entry, DownloadFile> downloadFileCache = new LRUCache<MusicDirectory.Entry, DownloadFile>(100);
- private final List<DownloadFile> cleanupCandidates = new ArrayList<DownloadFile>();
- private final Scrobbler scrobbler = new Scrobbler();
- private final JukeboxService jukeboxService = new JukeboxService(this);
- private DownloadFile currentPlaying;
- private DownloadFile currentDownloading;
- private CancellableTask bufferTask;
- private PlayerState playerState = IDLE;
- private boolean shufflePlay;
- private long revision;
- private static DownloadService instance;
- private String suggestedPlaylistName;
- private PowerManager.WakeLock wakeLock;
- private boolean keepScreenOn = false;
-
- private static boolean equalizerAvailable;
- private static boolean visualizerAvailable;
- private EqualizerController equalizerController;
- private VisualizerController visualizerController;
- private boolean showVisualization;
- private boolean jukeboxEnabled;
-
- static {
- try {
- EqualizerController.checkAvailable();
- equalizerAvailable = true;
- } catch (Throwable t) {
- equalizerAvailable = false;
- }
- }
- static {
- try {
- VisualizerController.checkAvailable();
- visualizerAvailable = true;
- } catch (Throwable t) {
- visualizerAvailable = false;
- }
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- mediaPlayer = new MediaPlayer();
- mediaPlayer.setWakeMode(this, PowerManager.PARTIAL_WAKE_LOCK);
-
- mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
- @Override
- public boolean onError(MediaPlayer mediaPlayer, int what, int more) {
- handleError(new Exception("MediaPlayer error: " + what + " (" + more + ")"));
- return false;
- }
- });
-
- if (equalizerAvailable) {
- equalizerController = new EqualizerController(this, mediaPlayer);
- if (!equalizerController.isAvailable()) {
- equalizerController = null;
- } else {
- equalizerController.loadSettings();
- }
- }
- if (visualizerAvailable) {
- visualizerController = new VisualizerController(this, mediaPlayer);
- if (!visualizerController.isAvailable()) {
- visualizerController = null;
- }
- }
-
- PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
- wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName());
- wakeLock.setReferenceCounted(false);
-
- instance = this;
- lifecycleSupport.onCreate();
- }
-
- @Override
- public void onStart(Intent intent, int startId) {
- super.onStart(intent, startId);
- lifecycleSupport.onStart(intent);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- lifecycleSupport.onDestroy();
- mediaPlayer.release();
- shufflePlayBuffer.shutdown();
- if (equalizerController != null) {
- equalizerController.release();
- }
- if (visualizerController != null) {
- visualizerController.release();
- }
-
- instance = null;
- }
-
- public static DownloadService getInstance() {
- return instance;
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return binder;
- }
-
- @Override
- public synchronized void download(List<MusicDirectory.Entry> songs, boolean save, boolean autoplay, boolean playNext) {
- shufflePlay = false;
- int offset = 1;
-
- if (songs.isEmpty()) {
- return;
- }
- if (playNext) {
- if (autoplay && getCurrentPlayingIndex() >= 0) {
- offset = 0;
- }
- for (MusicDirectory.Entry song : songs) {
- DownloadFile downloadFile = new DownloadFile(this, song, save);
- downloadList.add(getCurrentPlayingIndex() + offset, downloadFile);
- offset++;
- }
- revision++;
- } else {
- for (MusicDirectory.Entry song : songs) {
- DownloadFile downloadFile = new DownloadFile(this, song, save);
- downloadList.add(downloadFile);
- }
- revision++;
- }
- updateJukeboxPlaylist();
-
- if (autoplay) {
- play(0);
- } else {
- if (currentPlaying == null) {
- currentPlaying = downloadList.get(0);
- }
- checkDownloads();
- }
- lifecycleSupport.serializeDownloadQueue();
- }
-
- private void updateJukeboxPlaylist() {
- if (jukeboxEnabled) {
- jukeboxService.updatePlaylist();
- }
- }
-
- public void restore(List<MusicDirectory.Entry> songs, int currentPlayingIndex, int currentPlayingPosition) {
- download(songs, false, false, false);
- if (currentPlayingIndex != -1) {
- play(currentPlayingIndex, false);
- if (currentPlaying.isCompleteFileAvailable()) {
- doPlay(currentPlaying, currentPlayingPosition, false);
- }
- }
- }
-
- @Override
- public synchronized void setShufflePlayEnabled(boolean enabled) {
- if (shufflePlay == enabled) {
- return;
- }
-
- shufflePlay = enabled;
- if (shufflePlay) {
- clear();
- checkDownloads();
- }
- }
-
- @Override
- public synchronized boolean isShufflePlayEnabled() {
- return shufflePlay;
- }
-
- @Override
- public synchronized void shuffle() {
- Collections.shuffle(downloadList);
- if (currentPlaying != null) {
- downloadList.remove(getCurrentPlayingIndex());
- downloadList.add(0, currentPlaying);
- }
- revision++;
- lifecycleSupport.serializeDownloadQueue();
- updateJukeboxPlaylist();
- }
-
- @Override
- public RepeatMode getRepeatMode() {
- return Util.getRepeatMode(this);
- }
-
- @Override
- public void setRepeatMode(RepeatMode repeatMode) {
- Util.setRepeatMode(this, repeatMode);
- }
-
- @Override
- public boolean getKeepScreenOn() {
- return keepScreenOn;
- }
-
- @Override
- public void setKeepScreenOn(boolean keepScreenOn) {
- this.keepScreenOn = keepScreenOn;
- }
-
- @Override
- public boolean getShowVisualization() {
- return showVisualization;
- }
-
- @Override
- public void setShowVisualization(boolean showVisualization) {
- this.showVisualization = showVisualization;
- }
-
- @Override
- public synchronized DownloadFile forSong(MusicDirectory.Entry song) {
- for (DownloadFile downloadFile : downloadList) {
- if (downloadFile.getSong().equals(song)) {
- return downloadFile;
- }
- }
-
- DownloadFile downloadFile = downloadFileCache.get(song);
- if (downloadFile == null) {
- downloadFile = new DownloadFile(this, song, false);
- downloadFileCache.put(song, downloadFile);
- }
- return downloadFile;
- }
-
- @Override
- public synchronized void clear() {
- clear(true);
- }
-
- @Override
- public synchronized void clearIncomplete() {
- reset();
- Iterator<DownloadFile> iterator = downloadList.iterator();
- while (iterator.hasNext()) {
- DownloadFile downloadFile = iterator.next();
- if (!downloadFile.isCompleteFileAvailable()) {
- iterator.remove();
- }
- }
- lifecycleSupport.serializeDownloadQueue();
- updateJukeboxPlaylist();
- }
-
- @Override
- public synchronized int size() {
- return downloadList.size();
- }
-
- public synchronized void clear(boolean serialize) {
- reset();
- downloadList.clear();
- revision++;
- if (currentDownloading != null) {
- currentDownloading.cancelDownload();
- currentDownloading = null;
- }
- setCurrentPlaying(null, false);
-
- if (serialize) {
- lifecycleSupport.serializeDownloadQueue();
- }
- updateJukeboxPlaylist();
- }
-
- @Override
- public synchronized void remove(DownloadFile downloadFile) {
- if (downloadFile == currentDownloading) {
- currentDownloading.cancelDownload();
- currentDownloading = null;
- }
- if (downloadFile == currentPlaying) {
- reset();
- setCurrentPlaying(null, false);
- }
- downloadList.remove(downloadFile);
- revision++;
- lifecycleSupport.serializeDownloadQueue();
- updateJukeboxPlaylist();
- }
-
- @Override
- public synchronized void delete(List<MusicDirectory.Entry> songs) {
- for (MusicDirectory.Entry song : songs) {
- forSong(song).delete();
- }
- }
-
- @Override
- public synchronized void unpin(List<MusicDirectory.Entry> songs) {
- for (MusicDirectory.Entry song : songs) {
- forSong(song).unpin();
- }
- }
-
- synchronized void setCurrentPlaying(int currentPlayingIndex, boolean showNotification) {
- try {
- setCurrentPlaying(downloadList.get(currentPlayingIndex), showNotification);
- } catch (IndexOutOfBoundsException x) {
- // Ignored
- }
- }
-
- synchronized void setCurrentPlaying(DownloadFile currentPlaying, boolean showNotification) {
- this.currentPlaying = currentPlaying;
-
- if (currentPlaying != null) {
- Util.broadcastNewTrackInfo(this, currentPlaying.getSong());
- } else {
- Util.broadcastNewTrackInfo(this, null);
- }
-
- if (currentPlaying != null && showNotification) {
- Util.showPlayingNotification(this, this, handler, currentPlaying.getSong());
- } else {
- Util.hidePlayingNotification(this, this, handler);
- }
- }
-
- @Override
- public synchronized int getCurrentPlayingIndex() {
- return downloadList.indexOf(currentPlaying);
- }
-
- @Override
- public DownloadFile getCurrentPlaying() {
- return currentPlaying;
- }
-
- @Override
- public DownloadFile getCurrentDownloading() {
- return currentDownloading;
- }
-
- @Override
- public synchronized List<DownloadFile> getDownloads() {
- return new ArrayList<DownloadFile>(downloadList);
- }
-
- /** Plays either the current song (resume) or the first/next one in queue. */
- public synchronized void play()
- {
- int current = getCurrentPlayingIndex();
- if (current == -1) {
- play(0);
- } else {
- play(current);
- }
- }
-
- @Override
- public synchronized void play(int index) {
- play(index, true);
- }
-
- private synchronized void play(int index, boolean start) {
- if (index < 0 || index >= size()) {
- reset();
- setCurrentPlaying(null, false);
- } else {
- setCurrentPlaying(index, start);
- checkDownloads();
- if (start) {
- if (jukeboxEnabled) {
- jukeboxService.skip(getCurrentPlayingIndex(), 0);
- setPlayerState(STARTED);
- } else {
- bufferAndPlay();
- }
- }
- }
- }
-
- /** Plays or resumes the playback, depending on the current player state. */
- public synchronized void togglePlayPause()
- {
- if (playerState == PAUSED || playerState == COMPLETED) {
- start();
- } else if (playerState == STOPPED || playerState == IDLE) {
- play();
- } else if (playerState == STARTED) {
- pause();
- }
- }
-
- @Override
- public synchronized void seekTo(int position) {
- try {
- if (jukeboxEnabled) {
- jukeboxService.skip(getCurrentPlayingIndex(), position / 1000);
- } else {
- mediaPlayer.seekTo(position);
- }
- } catch (Exception x) {
- handleError(x);
- }
- }
-
- @Override
- public synchronized void previous() {
- int index = getCurrentPlayingIndex();
- if (index == -1) {
- return;
- }
-
- // Restart song if played more than five seconds.
- if (getPlayerPosition() > 5000 || index == 0) {
- play(index);
- } else {
- play(index - 1);
- }
- }
-
- @Override
- public synchronized void next() {
- int index = getCurrentPlayingIndex();
- if (index != -1) {
- play(index + 1);
- }
- }
-
- private void onSongCompleted() {
- int index = getCurrentPlayingIndex();
- if (index != -1) {
- switch (getRepeatMode()) {
- case OFF:
- play(index + 1);
- break;
- case ALL:
- play((index + 1) % size());
- break;
- case SINGLE:
- play(index);
- break;
- default:
- break;
- }
- }
- }
-
- @Override
- public synchronized void pause() {
- try {
- if (playerState == STARTED) {
- if (jukeboxEnabled) {
- jukeboxService.stop();
- } else {
- mediaPlayer.pause();
- }
- setPlayerState(PAUSED);
- }
- } catch (Exception x) {
- handleError(x);
- }
- }
-
- @Override
- public synchronized void start() {
- try {
- if (jukeboxEnabled) {
- jukeboxService.start();
- } else {
- mediaPlayer.start();
- }
- setPlayerState(STARTED);
- } catch (Exception x) {
- handleError(x);
- }
- }
-
- @Override
- public synchronized void reset() {
- if (bufferTask != null) {
- bufferTask.cancel();
- }
- try {
- mediaPlayer.reset();
- setPlayerState(IDLE);
- } catch (Exception x) {
- handleError(x);
- }
- }
-
- @Override
- public synchronized int getPlayerPosition() {
- try {
- if (playerState == IDLE || playerState == DOWNLOADING || playerState == PREPARING) {
- return 0;
- }
- if (jukeboxEnabled) {
- return jukeboxService.getPositionSeconds() * 1000;
- } else {
- return mediaPlayer.getCurrentPosition();
- }
- } catch (Exception x) {
- handleError(x);
- return 0;
- }
- }
-
- @Override
- public synchronized int getPlayerDuration() {
- if (currentPlaying != null) {
- Integer duration = currentPlaying.getSong().getDuration();
- if (duration != null) {
- return duration * 1000;
- }
- }
- if (playerState != IDLE && playerState != DOWNLOADING && playerState != PlayerState.PREPARING) {
- try {
- return mediaPlayer.getDuration();
- } catch (Exception x) {
- handleError(x);
- }
- }
- return 0;
- }
-
- @Override
- public PlayerState getPlayerState() {
- return playerState;
- }
-
- synchronized void setPlayerState(PlayerState playerState) {
- Log.i(TAG, this.playerState.name() + " -> " + playerState.name() + " (" + currentPlaying + ")");
-
- if (playerState == PAUSED) {
- lifecycleSupport.serializeDownloadQueue();
- }
-
- boolean show = this.playerState == PAUSED && playerState == PlayerState.STARTED;
- boolean hide = this.playerState == STARTED && playerState == PlayerState.PAUSED;
- Util.broadcastPlaybackStatusChange(this, playerState);
-
- this.playerState = playerState;
- if (show) {
- Util.showPlayingNotification(this, this, handler, currentPlaying.getSong());
- } else if (hide) {
- Util.hidePlayingNotification(this, this, handler);
- }
-
- if (playerState == STARTED) {
- scrobbler.scrobble(this, currentPlaying, false);
- } else if (playerState == COMPLETED) {
- scrobbler.scrobble(this, currentPlaying, true);
- }
- }
-
- @Override
- public void setSuggestedPlaylistName(String name) {
- this.suggestedPlaylistName = name;
- }
-
- @Override
- public String getSuggestedPlaylistName() {
- return suggestedPlaylistName;
- }
-
- @Override
- public EqualizerController getEqualizerController() {
- return equalizerController;
- }
-
- @Override
- public VisualizerController getVisualizerController() {
- return visualizerController;
- }
-
- @Override
- public boolean isJukeboxEnabled() {
- return jukeboxEnabled;
- }
-
- @Override
- public void setJukeboxEnabled(boolean jukeboxEnabled) {
- this.jukeboxEnabled = jukeboxEnabled;
- jukeboxService.setEnabled(jukeboxEnabled);
- if (jukeboxEnabled) {
- reset();
-
- // Cancel current download, if necessary.
- if (currentDownloading != null) {
- currentDownloading.cancelDownload();
- }
- }
- }
-
- @Override
- public void adjustJukeboxVolume(boolean up) {
- jukeboxService.adjustVolume(up);
- }
-
- private synchronized void bufferAndPlay() {
- reset();
-
- bufferTask = new BufferTask(currentPlaying, 0);
- bufferTask.start();
- }
-
- private synchronized void doPlay(final DownloadFile downloadFile, int position, boolean start) {
- try {
- final File file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile();
- downloadFile.updateModificationDate();
- mediaPlayer.setOnCompletionListener(null);
- mediaPlayer.reset();
- setPlayerState(IDLE);
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- mediaPlayer.setDataSource(file.getPath());
- setPlayerState(PREPARING);
- mediaPlayer.prepare();
- setPlayerState(PREPARED);
-
- mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
- @Override
- public void onCompletion(MediaPlayer mediaPlayer) {
-
- // Acquire a temporary wakelock, since when we return from
- // this callback the MediaPlayer will release its wakelock
- // and allow the device to go to sleep.
- wakeLock.acquire(60000);
-
- setPlayerState(COMPLETED);
-
- // If COMPLETED and not playing partial file, we are *really" finished
- // with the song and can move on to the next.
- if (!file.equals(downloadFile.getPartialFile())) {
- onSongCompleted();
- return;
- }
-
- // If file is not completely downloaded, restart the playback from the current position.
- int pos = mediaPlayer.getCurrentPosition();
- synchronized (DownloadServiceImpl.this) {
-
- // Work-around for apparent bug on certain phones: If close (less than ten seconds) to the end
- // of the song, skip to the next rather than restarting it.
- Integer duration = downloadFile.getSong().getDuration() == null ? null : downloadFile.getSong().getDuration() * 1000;
- if (duration != null) {
- if (Math.abs(duration - pos) < 10000) {
- Log.i(TAG, "Skipping restart from " + pos + " of " + duration);
- onSongCompleted();
- return;
- }
- }
-
- Log.i(TAG, "Requesting restart from " + pos + " of " + duration);
- reset();
- bufferTask = new BufferTask(downloadFile, pos);
- bufferTask.start();
- }
- }
- });
-
- if (position != 0) {
- Log.i(TAG, "Restarting player from position " + position);
- mediaPlayer.seekTo(position);
- }
-
- if (start) {
- mediaPlayer.start();
- setPlayerState(STARTED);
- } else {
- setPlayerState(PAUSED);
- }
- lifecycleSupport.serializeDownloadQueue();
-
- } catch (Exception x) {
- handleError(x);
- }
- }
-
- private void handleError(Exception x) {
- Log.w(TAG, "Media player error: " + x, x);
- mediaPlayer.reset();
- setPlayerState(IDLE);
- }
-
- protected synchronized void checkDownloads() {
-
- if (!Util.isExternalStoragePresent() || !lifecycleSupport.isExternalStorageAvailable()) {
- return;
- }
-
- if (shufflePlay) {
- checkShufflePlay();
- }
-
- if (jukeboxEnabled || !Util.isNetworkConnected(this)) {
- return;
- }
-
- if (downloadList.isEmpty()) {
- return;
- }
-
- // Need to download current playing?
- if (currentPlaying != null &&
- currentPlaying != currentDownloading &&
- !currentPlaying.isCompleteFileAvailable()) {
-
- // Cancel current download, if necessary.
- if (currentDownloading != null) {
- currentDownloading.cancelDownload();
- }
-
- currentDownloading = currentPlaying;
- currentDownloading.download();
- cleanupCandidates.add(currentDownloading);
- }
-
- // Find a suitable target for download.
- else if (currentDownloading == null || currentDownloading.isWorkDone() || currentDownloading.isFailed()) {
-
- int n = size();
- if (n == 0) {
- return;
- }
-
- int preloaded = 0;
-
- int start = currentPlaying == null ? 0 : getCurrentPlayingIndex();
- int i = start;
- do {
- DownloadFile downloadFile = downloadList.get(i);
- if (!downloadFile.isWorkDone()) {
- if (downloadFile.shouldSave() || preloaded < Util.getPreloadCount(this)) {
- currentDownloading = downloadFile;
- currentDownloading.download();
- cleanupCandidates.add(currentDownloading);
- break;
- }
- } else if (currentPlaying != downloadFile) {
- preloaded++;
- }
-
- i = (i + 1) % n;
- } while (i != start);
- }
-
- // Delete obsolete .partial and .complete files.
- cleanup();
- }
-
- private synchronized void checkShufflePlay() {
-
- final int listSize = 20;
- boolean wasEmpty = downloadList.isEmpty();
-
- long revisionBefore = revision;
-
- // First, ensure that list is at least 20 songs long.
- int size = size();
- if (size < listSize) {
- for (MusicDirectory.Entry song : shufflePlayBuffer.get(listSize - size)) {
- DownloadFile downloadFile = new DownloadFile(this, song, false);
- downloadList.add(downloadFile);
- revision++;
- }
- }
-
- int currIndex = currentPlaying == null ? 0 : getCurrentPlayingIndex();
-
- // Only shift playlist if playing song #5 or later.
- if (currIndex > 4) {
- int songsToShift = currIndex - 2;
- for (MusicDirectory.Entry song : shufflePlayBuffer.get(songsToShift)) {
- downloadList.add(new DownloadFile(this, song, false));
- downloadList.get(0).cancelDownload();
- downloadList.remove(0);
- revision++;
- }
- }
-
- if (revisionBefore != revision) {
- updateJukeboxPlaylist();
- }
-
- if (wasEmpty && !downloadList.isEmpty()) {
- play(0);
- }
- }
-
- public long getDownloadListUpdateRevision() {
- return revision;
- }
-
- private synchronized void cleanup() {
- Iterator<DownloadFile> iterator = cleanupCandidates.iterator();
- while (iterator.hasNext()) {
- DownloadFile downloadFile = iterator.next();
- if (downloadFile != currentPlaying && downloadFile != currentDownloading) {
- if (downloadFile.cleanup()) {
- iterator.remove();
- }
- }
- }
- }
-
- private class BufferTask extends CancellableTask {
-
- private static final int BUFFER_LENGTH_SECONDS = 5;
-
- private final DownloadFile downloadFile;
- private final int position;
- private final long expectedFileSize;
- private final File partialFile;
-
- public BufferTask(DownloadFile downloadFile, int position) {
- this.downloadFile = downloadFile;
- this.position = position;
- partialFile = downloadFile.getPartialFile();
-
- // Calculate roughly how many bytes BUFFER_LENGTH_SECONDS corresponds to.
- int bitRate = downloadFile.getBitRate();
- long byteCount = Math.max(100000, bitRate * 1024 / 8 * BUFFER_LENGTH_SECONDS);
-
- // Find out how large the file should grow before resuming playback.
- expectedFileSize = partialFile.length() + byteCount;
- }
-
- @Override
- public void execute() {
- setPlayerState(DOWNLOADING);
-
- while (!bufferComplete()) {
- Util.sleepQuietly(1000L);
- if (isCancelled()) {
- return;
- }
- }
- doPlay(downloadFile, position, true);
- }
-
- private boolean bufferComplete() {
- boolean completeFileAvailable = downloadFile.isCompleteFileAvailable();
- long size = partialFile.length();
-
- Log.i(TAG, "Buffering " + partialFile + " (" + size + "/" + expectedFileSize + ", " + completeFileAvailable + ")");
- return completeFileAvailable || size >= expectedFileSize;
- }
-
- @Override
- public String toString() {
- return "BufferTask (" + downloadFile + ")";
- }
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadServiceLifecycleSupport.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadServiceLifecycleSupport.java
deleted file mode 100644
index f6076059..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/DownloadServiceLifecycleSupport.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.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 android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.telephony.PhoneStateListener;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.view.KeyEvent;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.domain.PlayerState;
-import net.sourceforge.subsonic.androidapp.util.CacheCleaner;
-import net.sourceforge.subsonic.androidapp.util.FileUtil;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-/**
- * @author Sindre Mehus
- */
-public class DownloadServiceLifecycleSupport {
-
- 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;
-
- /**
- * 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 void onCreate() {
- Runnable downloadChecker = new Runnable() {
- @Override
- public void run() {
- try {
- downloadService.checkDownloads();
- } catch (Throwable x) {
- Log.e(TAG, "checkDownloads() failed.", x);
- }
- }
- };
-
- executorService = Executors.newScheduledThreadPool(2);
- 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) {
- downloadService.pause();
- }
- }
- };
- 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);
-
- // 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);
-
- // 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();
-
- new CacheCleaner(downloadService, downloadService).clean();
- }
-
- 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);
- }
- }
- }
-
- public void onDestroy() {
- executorService.shutdown();
- serializeDownloadQueue();
- downloadService.clear(false);
- downloadService.unregisterReceiver(ejectEventReceiver);
- downloadService.unregisterReceiver(headsetEventReceiver);
- downloadService.unregisterReceiver(intentReceiver);
-
- TelephonyManager telephonyManager = (TelephonyManager) downloadService.getSystemService(Context.TELEPHONY_SERVICE);
- telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
- }
-
- public boolean isExternalStorageAvailable() {
- return externalStorageAvailable;
- }
-
- public void serializeDownloadQueue() {
- State state = new State();
- for (DownloadFile downloadFile : downloadService.getDownloads()) {
- state.songs.add(downloadFile.getSong());
- }
- state.currentPlayingIndex = downloadService.getCurrentPlayingIndex();
- state.currentPlayingPosition = downloadService.getPlayerPosition();
-
- Log.i(TAG, "Serialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition);
- FileUtil.serialize(downloadService, state, FILENAME_DOWNLOADS_SER);
- }
-
- private void deserializeDownloadQueue() {
- 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);
-
- // 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();
- break;
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- downloadService.previous();
- break;
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- if (downloadService.getCurrentPlayingIndex() < downloadService.size() - 1) {
- downloadService.next();
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_STOP:
- downloadService.reset();
- break;
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- downloadService.start();
- break;
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- downloadService.pause();
- 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;
-
- @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) {
- 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;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/JukeboxService.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/JukeboxService.java
deleted file mode 100644
index e3145f4e..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/JukeboxService.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service;
-
-import android.content.Context;
-import android.os.Handler;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ProgressBar;
-import android.widget.Toast;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.JukeboxStatus;
-import net.sourceforge.subsonic.androidapp.domain.PlayerState;
-import net.sourceforge.subsonic.androidapp.service.parser.SubsonicRESTException;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * Provides an asynchronous interface to the remote jukebox on the Subsonic server.
- *
- * @author Sindre Mehus
- * @version $Id$
- */
-public class JukeboxService {
-
- 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;
-
- // 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();
- }
-
- 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 void processTasks() {
- while (true) {
- JukeboxTask task = null;
- try {
- 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;
-
- // Track change?
- Integer index = jukeboxStatus.getCurrentPlayingIndex();
- if (index != null && index != -1 && index != downloadService.getCurrentPlayingIndex()) {
- downloadService.setCurrentPlaying(index, true);
- }
- }
-
- 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);
- }
-
- 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));
- }
-
- 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);
- }
-
- public void stop() {
- tasks.remove(Stop.class);
- tasks.remove(Start.class);
-
- stopStatusUpdate();
- tasks.add(new Stop());
- }
-
- public void start() {
- tasks.remove(Stop.class);
- tasks.remove(Start.class);
-
- startStatusUpdate();
- tasks.add(new Start());
- }
-
- public synchronized void adjustVolume(boolean up) {
- float delta = up ? 0.1f : -0.1f;
- gain += delta;
- gain = Math.max(gain, 0.0f);
- gain = Math.min(gain, 1.0f);
-
- tasks.remove(SetGain.class);
- tasks.add(new SetGain(gain));
-
- if (volumeToast == null) {
- volumeToast = new VolumeToast(downloadService);
- }
- volumeToast.setVolume(gain);
- }
-
- private MusicService getMusicService() {
- return MusicServiceFactory.getMusicService(downloadService);
- }
-
- public int getPositionSeconds() {
- if (jukeboxStatus == null || jukeboxStatus.getPositionSeconds() == null || timeOfLastUpdate.get() == 0) {
- return 0;
- }
-
- if (jukeboxStatus.isPlaying()) {
- int secondsSinceLastUpdate = (int) ((System.currentTimeMillis() - timeOfLastUpdate.get()) / 1000L);
- return jukeboxStatus.getPositionSeconds() + secondsSinceLastUpdate;
- }
-
- return jukeboxStatus.getPositionSeconds();
- }
-
- public void setEnabled(boolean enabled) {
- tasks.clear();
- if (enabled) {
- updatePlaylist();
- }
- stop();
- downloadService.setPlayerState(PlayerState.IDLE);
- }
-
- private static class TaskQueue {
-
- private final LinkedBlockingQueue<JukeboxTask> queue = new LinkedBlockingQueue<JukeboxTask>();
-
- void add(JukeboxTask jukeboxTask) {
- queue.add(jukeboxTask);
- }
-
- JukeboxTask take() throws InterruptedException {
- return queue.take();
- }
-
- 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 clear() {
- queue.clear();
- }
- }
-
- private abstract class JukeboxTask {
-
- abstract JukeboxStatus execute() throws Exception;
-
- @Override
- public String toString() {
- return getClass().getSimpleName();
- }
- }
-
- private class GetStatus extends JukeboxTask {
- @Override
- JukeboxStatus execute() throws Exception {
- return getMusicService().getJukeboxStatus(downloadService, null);
- }
- }
-
- private class SetPlaylist extends JukeboxTask {
-
- private final List<String> ids;
-
- SetPlaylist(List<String> ids) {
- this.ids = ids;
- }
-
- @Override
- JukeboxStatus execute() throws Exception {
- return getMusicService().updateJukeboxPlaylist(ids, downloadService, null);
- }
- }
-
- private class Skip extends JukeboxTask {
- private final int index;
- private final int offsetSeconds;
-
- Skip(int index, int offsetSeconds) {
- this.index = index;
- this.offsetSeconds = offsetSeconds;
- }
-
- @Override
- JukeboxStatus execute() throws Exception {
- return getMusicService().skipJukebox(index, offsetSeconds, downloadService, null);
- }
- }
-
- private class Stop extends JukeboxTask {
- @Override
- JukeboxStatus execute() throws Exception {
- return getMusicService().stopJukebox(downloadService, null);
- }
- }
-
- private class Start extends JukeboxTask {
- @Override
- JukeboxStatus execute() throws Exception {
- return getMusicService().startJukebox(downloadService, null);
- }
- }
-
- private class SetGain extends JukeboxTask {
-
- private final float gain;
-
- private SetGain(float gain) {
- this.gain = gain;
- }
-
- @Override
- JukeboxStatus execute() throws Exception {
- return getMusicService().setJukeboxGain(gain, downloadService, null);
- }
- }
-
- private static class VolumeToast extends Toast {
-
- 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();
- }
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/MediaStoreService.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/MediaStoreService.java
deleted file mode 100644
index 775fa3f5..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/MediaStoreService.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service;
-
-import java.io.File;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.MediaStore;
-import android.util.Log;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.util.FileUtil;
-
-/**
- * @author Sindre Mehus
- */
-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 final Context context;
-
- public MediaStoreService(Context context) {
- this.context = context;
- }
-
- 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);
-
- 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);
-
- // 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.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();
-
- 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();
-
- Cursor cursor = contentResolver.query(Uri.withAppendedPath(ALBUM_ART_URI, String.valueOf(albumId)), null, null, null, null);
- if (!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();
- }
-
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/MusicService.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/MusicService.java
deleted file mode 100644
index cb0c5709..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/MusicService.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service;
-
-import java.util.List;
-
-import org.apache.http.HttpResponse;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import net.sourceforge.subsonic.androidapp.domain.Indexes;
-import net.sourceforge.subsonic.androidapp.domain.JukeboxStatus;
-import net.sourceforge.subsonic.androidapp.domain.Lyrics;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.domain.MusicFolder;
-import net.sourceforge.subsonic.androidapp.domain.Playlist;
-import net.sourceforge.subsonic.androidapp.domain.SearchCritera;
-import net.sourceforge.subsonic.androidapp.domain.SearchResult;
-import net.sourceforge.subsonic.androidapp.domain.Version;
-import net.sourceforge.subsonic.androidapp.util.CancellableTask;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-
-/**
- * @author Sindre Mehus
- */
-public interface MusicService {
-
- void ping(Context context, ProgressListener progressListener) throws Exception;
-
- boolean isLicenseValid(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;
-
- MusicDirectory getMusicDirectory(String id, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
-
- SearchResult search(SearchCritera 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;
-
- Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception;
-
- void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception;
-
- MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception;
-
- MusicDirectory getRandomSongs(int size, Context context, ProgressListener progressListener) throws Exception;
-
- Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, 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);
-
- JukeboxStatus updateJukeboxPlaylist(List<String> ids, 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 startJukebox(Context context, ProgressListener progressListener) throws Exception;
-
- JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception;
-
- JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception;
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/MusicServiceFactory.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/MusicServiceFactory.java
deleted file mode 100644
index 552d1d32..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/MusicServiceFactory.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service;
-
-import android.content.Context;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public class MusicServiceFactory {
-
- 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;
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/OfflineException.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/OfflineException.java
deleted file mode 100644
index 49c000bf..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/OfflineException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service;
-
-/**
- * Thrown by service methods that are not available in offline mode.
- *
- * @author Sindre Mehus
- * @version $Id$
- */
-public class OfflineException extends Exception {
-
- public OfflineException(String message) {
- super(message);
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/OfflineMusicService.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/OfflineMusicService.java
deleted file mode 100644
index 79fee6d2..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/OfflineMusicService.java
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.io.Reader;
-import java.io.FileReader;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Random;
-import java.util.Set;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import net.sourceforge.subsonic.androidapp.domain.Artist;
-import net.sourceforge.subsonic.androidapp.domain.Indexes;
-import net.sourceforge.subsonic.androidapp.domain.JukeboxStatus;
-import net.sourceforge.subsonic.androidapp.domain.Lyrics;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.domain.MusicFolder;
-import net.sourceforge.subsonic.androidapp.domain.Playlist;
-import net.sourceforge.subsonic.androidapp.domain.SearchCritera;
-import net.sourceforge.subsonic.androidapp.domain.SearchResult;
-import net.sourceforge.subsonic.androidapp.service.parser.PlaylistParser;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.FileUtil;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-/**
- * @author Sindre Mehus
- */
-public class OfflineMusicService extends RESTMusicService {
-
- @Override
- public boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception {
- return true;
- }
-
- @Override
- public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
- List<Artist> artists = new ArrayList<Artist>();
- File root = FileUtil.getMusicDirectory(context);
- for (File file : FileUtil.listFiles(root)) {
- if (file.isDirectory()) {
- Artist artist = new Artist();
- artist.setId(file.getPath());
- artist.setIndex(file.getName().substring(0, 1));
- artist.setName(file.getName());
- artists.add(artist);
- }
- }
- return new Indexes(0L, Collections.<Artist>emptyList(), artists);
- }
-
- @Override
- public MusicDirectory getMusicDirectory(String id, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
- File dir = new File(id);
- MusicDirectory result = new MusicDirectory();
- result.setName(dir.getName());
-
- Set<String> names = new HashSet<String>();
-
- for (File file : FileUtil.listMusicFiles(dir)) {
- String name = getName(file);
- if (name != null & !names.contains(name)) {
- names.add(name);
- result.addChild(createEntry(context, file, name));
- }
- }
- return result;
- }
-
- private String getName(File file) {
- String name = file.getName();
- if (file.isDirectory()) {
- return name;
- }
-
- if (name.endsWith(".partial") || name.contains(".partial.") || name.equals(Constants.ALBUM_ART_FILE)) {
- return null;
- }
-
- name = name.replace(".complete", "");
- return FileUtil.getBaseName(name);
- }
-
- private MusicDirectory.Entry createEntry(Context context, File file, String name) {
- MusicDirectory.Entry entry = new MusicDirectory.Entry();
- entry.setDirectory(file.isDirectory());
- entry.setId(file.getPath());
- entry.setParent(file.getParent());
- entry.setSize(file.length());
- String root = FileUtil.getMusicDirectory(context).getPath();
- entry.setPath(file.getPath().replaceFirst("^" + root + "/" , ""));
- if (file.isFile()) {
- entry.setArtist(file.getParentFile().getParentFile().getName());
- entry.setAlbum(file.getParentFile().getName());
- }
- entry.setTitle(name);
- entry.setSuffix(FileUtil.getExtension(file.getName().replace(".complete", "")));
-
- File albumArt = FileUtil.getAlbumArtFile(context, entry);
- if (albumArt.exists()) {
- entry.setCoverArt(albumArt.getPath());
- }
- return entry;
- }
-
- @Override
- public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, ProgressListener progressListener) throws Exception {
- InputStream in = new FileInputStream(entry.getCoverArt());
- try {
- byte[] bytes = Util.toByteArray(in);
- Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
- return Bitmap.createScaledBitmap(bitmap, size, size, true);
- } finally {
- Util.close(in);
- }
- }
-
- @Override
- public List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
- throw new OfflineException("Music folders not available in offline mode");
- }
-
- @Override
- public SearchResult search(SearchCritera criteria, Context context, ProgressListener progressListener) throws Exception {
- throw new OfflineException("Search not available in offline mode");
- }
-
- @Override
- public List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
- List<Playlist> playlists = new ArrayList<Playlist>();
- File root = FileUtil.getPlaylistDirectory();
- for (File file : FileUtil.listFiles(root)) {
- Playlist playlist = new Playlist(file.getName(), file.getName());
- playlists.add(playlist);
- }
- return playlists;
- }
-
- @Override
- public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception {
- DownloadService downloadService = DownloadServiceImpl.getInstance();
- if (downloadService == null) {
- return new MusicDirectory();
- }
-
- Reader reader = null;
- try {
- reader = new FileReader(FileUtil.getPlaylistFile(name));
- MusicDirectory fullList = new PlaylistParser(context).parse(reader, progressListener);
- MusicDirectory playlist = new MusicDirectory();
- for(MusicDirectory.Entry song: fullList.getChildren()) {
- DownloadFile downloadFile = downloadService.forSong(song);
- File completeFile = downloadFile.getCompleteFile();
- if(completeFile.exists()) {
- playlist.addChild(song);
- }
- }
- return playlist;
- } finally {
- Util.close(reader);
- }
- }
-
- @Override
- public void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception {
- throw new OfflineException("Playlists not available in offline mode");
- }
-
- @Override
- public Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception {
- throw new OfflineException("Lyrics not available in offline mode");
- }
-
- @Override
- public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception {
- throw new OfflineException("Scrobbling not available in offline mode");
- }
-
- @Override
- public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception {
- throw new OfflineException("Album lists not available in offline mode");
- }
-
- @Override
- public String getVideoUrl(Context context, String id) {
- return null;
- }
-
- @Override
- public JukeboxStatus updateJukeboxPlaylist(List<String> ids, Context context, ProgressListener progressListener) throws Exception {
- throw new OfflineException("Jukebox not available in offline mode");
- }
-
- @Override
- public JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception {
- throw new OfflineException("Jukebox not available in offline mode");
- }
-
- @Override
- public JukeboxStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception {
- throw new OfflineException("Jukebox not available in offline mode");
- }
-
- @Override
- public JukeboxStatus startJukebox(Context context, ProgressListener progressListener) throws Exception {
- throw new OfflineException("Jukebox not available in offline mode");
- }
-
- @Override
- public JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception {
- throw new OfflineException("Jukebox not available in offline mode");
- }
-
- @Override
- public JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception {
- throw new OfflineException("Jukebox not available in offline mode");
- }
-
- @Override
- public MusicDirectory getRandomSongs(int size, Context context, ProgressListener progressListener) throws Exception {
- File root = FileUtil.getMusicDirectory(context);
- List<File> children = new LinkedList<File>();
- listFilesRecursively(root, children);
- MusicDirectory result = new MusicDirectory();
-
- if (children.isEmpty()) {
- return result;
- }
- Random random = new Random();
- for (int i = 0; i < size; i++) {
- File file = children.get(random.nextInt(children.size()));
- result.addChild(createEntry(context, file, getName(file)));
- }
-
- return result;
- }
-
- private void listFilesRecursively(File parent, List<File> children) {
- for (File file : FileUtil.listMusicFiles(parent)) {
- if (file.isFile()) {
- children.add(file);
- } else {
- listFilesRecursively(file, children);
- }
- }
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/RESTMusicService.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/RESTMusicService.java
deleted file mode 100644
index a939feef..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/RESTMusicService.java
+++ /dev/null
@@ -1,785 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.FileReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpResponse;
-import org.apache.http.NameValuePair;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.entity.UrlEncodedFormEntity;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.conn.params.ConnManagerParams;
-import org.apache.http.conn.params.ConnPerRouteBean;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.conn.scheme.SocketFactory;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
-import org.apache.http.message.BasicHeader;
-import org.apache.http.message.BasicNameValuePair;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.protocol.BasicHttpContext;
-import org.apache.http.protocol.ExecutionContext;
-import org.apache.http.protocol.HttpContext;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.pm.PackageInfo;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.util.Log;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.Indexes;
-import net.sourceforge.subsonic.androidapp.domain.JukeboxStatus;
-import net.sourceforge.subsonic.androidapp.domain.Lyrics;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.domain.MusicFolder;
-import net.sourceforge.subsonic.androidapp.domain.Playlist;
-import net.sourceforge.subsonic.androidapp.domain.SearchCritera;
-import net.sourceforge.subsonic.androidapp.domain.SearchResult;
-import net.sourceforge.subsonic.androidapp.domain.ServerInfo;
-import net.sourceforge.subsonic.androidapp.domain.Version;
-import net.sourceforge.subsonic.androidapp.service.parser.AlbumListParser;
-import net.sourceforge.subsonic.androidapp.service.parser.ErrorParser;
-import net.sourceforge.subsonic.androidapp.service.parser.IndexesParser;
-import net.sourceforge.subsonic.androidapp.service.parser.JukeboxStatusParser;
-import net.sourceforge.subsonic.androidapp.service.parser.LicenseParser;
-import net.sourceforge.subsonic.androidapp.service.parser.LyricsParser;
-import net.sourceforge.subsonic.androidapp.service.parser.MusicDirectoryParser;
-import net.sourceforge.subsonic.androidapp.service.parser.MusicFoldersParser;
-import net.sourceforge.subsonic.androidapp.service.parser.PlaylistParser;
-import net.sourceforge.subsonic.androidapp.service.parser.PlaylistsParser;
-import net.sourceforge.subsonic.androidapp.service.parser.RandomSongsParser;
-import net.sourceforge.subsonic.androidapp.service.parser.SearchResult2Parser;
-import net.sourceforge.subsonic.androidapp.service.parser.SearchResultParser;
-import net.sourceforge.subsonic.androidapp.service.parser.VersionParser;
-import net.sourceforge.subsonic.androidapp.service.ssl.SSLSocketFactory;
-import net.sourceforge.subsonic.androidapp.service.ssl.TrustSelfSignedStrategy;
-import net.sourceforge.subsonic.androidapp.util.CancellableTask;
-import net.sourceforge.subsonic.androidapp.util.Constants;
-import net.sourceforge.subsonic.androidapp.util.FileUtil;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-/**
- * @author Sindre Mehus
- */
-public class RESTMusicService implements MusicService {
-
- private static final String TAG = RESTMusicService.class.getSimpleName();
-
- private static final int SOCKET_CONNECT_TIMEOUT = 10 * 1000;
- private static final int SOCKET_READ_TIMEOUT_DEFAULT = 10 * 1000;
- private static final int SOCKET_READ_TIMEOUT_DOWNLOAD = 30 * 1000;
- private static final int SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS = 60 * 1000;
- private static final int SOCKET_READ_TIMEOUT_GET_PLAYLIST = 60 * 1000;
-
- // Allow 20 seconds extra timeout per MB offset.
- private static final double TIMEOUT_MILLIS_PER_OFFSET_BYTE = 20000.0 / 1000000.0;
-
- /**
- * URL from which to fetch latest versions.
- */
- private static final String VERSION_URL = "http://subsonic.org/backend/version.view";
-
- private static final int HTTP_REQUEST_MAX_ATTEMPTS = 5;
- private static final long REDIRECTION_CHECK_INTERVAL_MILLIS = 60L * 60L * 1000L;
-
- private final DefaultHttpClient httpClient;
- private long redirectionLastChecked;
- private int redirectionNetworkType = -1;
- private String redirectFrom;
- private String redirectTo;
- private final ThreadSafeClientConnManager connManager;
-
- public RESTMusicService() {
-
- // Create and initialize default HTTP parameters
- HttpParams params = new BasicHttpParams();
- ConnManagerParams.setMaxTotalConnections(params, 20);
- ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(20));
- HttpConnectionParams.setConnectionTimeout(params, SOCKET_CONNECT_TIMEOUT);
- HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_DEFAULT);
-
- // Turn off stale checking. Our connections break all the time anyway,
- // and it's not worth it to pay the penalty of checking every time.
- HttpConnectionParams.setStaleCheckingEnabled(params, false);
-
- // Create and initialize scheme registry
- SchemeRegistry schemeRegistry = new SchemeRegistry();
- schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- schemeRegistry.register(new Scheme("https", createSSLSocketFactory(), 443));
-
- // Create an HttpClient with the ThreadSafeClientConnManager.
- // This connection manager must be used if more than one thread will
- // be using the HttpClient.
- connManager = new ThreadSafeClientConnManager(params, schemeRegistry);
- httpClient = new DefaultHttpClient(connManager, params);
- }
-
- private SocketFactory createSSLSocketFactory() {
- try {
- return new SSLSocketFactory(new TrustSelfSignedStrategy(), SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
- } catch (Throwable x) {
- Log.e(TAG, "Failed to create custom SSL socket factory, using default.", x);
- return org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory();
- }
- }
-
- @Override
- public void ping(Context context, ProgressListener progressListener) throws Exception {
- Reader reader = getReader(context, progressListener, "ping", null);
- try {
- new ErrorParser(context).parse(reader);
- } finally {
- Util.close(reader);
- }
- }
-
- @Override
- public boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception {
- Reader reader = getReader(context, progressListener, "getLicense", null);
- try {
- ServerInfo serverInfo = new LicenseParser(context).parse(reader);
- return serverInfo.isLicenseValid();
- } finally {
- Util.close(reader);
- }
- }
-
- public List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
- List<MusicFolder> cachedMusicFolders = readCachedMusicFolders(context);
- if (cachedMusicFolders != null && !refresh) {
- return cachedMusicFolders;
- }
-
- Reader reader = getReader(context, progressListener, "getMusicFolders", null);
- try {
- List<MusicFolder> musicFolders = new MusicFoldersParser(context).parse(reader, progressListener);
- writeCachedMusicFolders(context, musicFolders);
- return musicFolders;
- } finally {
- Util.close(reader);
- }
- }
-
- @Override
- public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
- Indexes cachedIndexes = readCachedIndexes(context, musicFolderId);
- if (cachedIndexes != null && !refresh) {
- return cachedIndexes;
- }
-
- long lastModified = cachedIndexes == null ? 0L : cachedIndexes.getLastModified();
-
- List<String> parameterNames = new ArrayList<String>();
- List<Object> parameterValues = new ArrayList<Object>();
-
- parameterNames.add("ifModifiedSince");
- parameterValues.add(lastModified);
-
- if (musicFolderId != null) {
- parameterNames.add("musicFolderId");
- parameterValues.add(musicFolderId);
- }
-
- Reader reader = getReader(context, progressListener, "getIndexes", null, parameterNames, parameterValues);
- try {
- Indexes indexes = new IndexesParser(context).parse(reader, progressListener);
- if (indexes != null) {
- writeCachedIndexes(context, indexes, musicFolderId);
- return indexes;
- }
- return cachedIndexes;
- } finally {
- Util.close(reader);
- }
- }
-
- private Indexes readCachedIndexes(Context context, String musicFolderId) {
- String filename = getCachedIndexesFilename(context, musicFolderId);
- return FileUtil.deserialize(context, filename);
- }
-
- private void writeCachedIndexes(Context context, Indexes indexes, String musicFolderId) {
- String filename = getCachedIndexesFilename(context, musicFolderId);
- FileUtil.serialize(context, indexes, filename);
- }
-
- private String getCachedIndexesFilename(Context context, String musicFolderId) {
- String s = Util.getRestUrl(context, null) + musicFolderId;
- return "indexes-" + Math.abs(s.hashCode()) + ".ser";
- }
-
- private ArrayList<MusicFolder> readCachedMusicFolders(Context context) {
- String filename = getCachedMusicFoldersFilename(context);
- return FileUtil.deserialize(context, filename);
- }
-
- private void writeCachedMusicFolders(Context context, List<MusicFolder> musicFolders) {
- String filename = getCachedMusicFoldersFilename(context);
- FileUtil.serialize(context, new ArrayList<MusicFolder>(musicFolders), filename);
- }
-
- private String getCachedMusicFoldersFilename(Context context) {
- String s = Util.getRestUrl(context, null);
- return "musicFolders-" + Math.abs(s.hashCode()) + ".ser";
- }
-
- @Override
- public MusicDirectory getMusicDirectory(String id, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
- Reader reader = getReader(context, progressListener, "getMusicDirectory", null, "id", id);
- try {
- return new MusicDirectoryParser(context).parse(reader, progressListener);
- } finally {
- Util.close(reader);
- }
- }
-
- @Override
- public SearchResult search(SearchCritera critera, Context context, ProgressListener progressListener) throws Exception {
- try {
- return searchNew(critera, context, progressListener);
- } catch (ServerTooOldException x) {
- // Ensure backward compatibility with REST 1.3.
- return searchOld(critera, context, progressListener);
- }
- }
-
- /**
- * Search using the "search" REST method.
- */
- private SearchResult searchOld(SearchCritera critera, Context context, ProgressListener progressListener) throws Exception {
- List<String> parameterNames = Arrays.asList("any", "songCount");
- List<Object> parameterValues = Arrays.<Object>asList(critera.getQuery(), critera.getSongCount());
- Reader reader = getReader(context, progressListener, "search", null, parameterNames, parameterValues);
- try {
- return new SearchResultParser(context).parse(reader, progressListener);
- } finally {
- Util.close(reader);
- }
- }
-
- /**
- * Search using the "search2" REST method, available in 1.4.0 and later.
- */
- private SearchResult searchNew(SearchCritera critera, Context context, ProgressListener progressListener) throws Exception {
- checkServerVersion(context, "1.4", null);
-
- List<String> parameterNames = Arrays.asList("query", "artistCount", "albumCount", "songCount");
- List<Object> parameterValues = Arrays.<Object>asList(critera.getQuery(), critera.getArtistCount(),
- critera.getAlbumCount(), critera.getSongCount());
- Reader reader = getReader(context, progressListener, "search2", null, parameterNames, parameterValues);
- try {
- return new SearchResult2Parser(context).parse(reader, progressListener);
- } finally {
- Util.close(reader);
- }
- }
-
- @Override
- public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception {
- HttpParams params = new BasicHttpParams();
- HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_PLAYLIST);
-
- Reader reader = getReader(context, progressListener, "getPlaylist", params, "id", id);
- OutputStreamWriter out = null;
- try {
- out = new OutputStreamWriter(new FileOutputStream(FileUtil.getPlaylistFile(name)));
-
- char[] buff = new char[256];
- int n;
- while((n = reader.read(buff)) >= 0) {
- out.write(buff, 0, n);
- }
- } finally {
- Util.close(out);
- Util.close(reader);
- }
-
- try {
- reader = new FileReader(FileUtil.getPlaylistFile(name));
- return new PlaylistParser(context).parse(reader, progressListener);
- } finally {
- Util.close(reader);
- }
- }
-
- @Override
- public List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
- Reader reader = getReader(context, progressListener, "getPlaylists", null);
- try {
- return new PlaylistsParser(context).parse(reader, progressListener);
- } finally {
- Util.close(reader);
- }
- }
-
- @Override
- public void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception {
- List<String> parameterNames = new LinkedList<String>();
- List<Object> parameterValues = new LinkedList<Object>();
-
- if (id != null) {
- parameterNames.add("playlistId");
- parameterValues.add(id);
- }
- if (name != null) {
- parameterNames.add("name");
- parameterValues.add(name);
- }
- for (MusicDirectory.Entry entry : entries) {
- parameterNames.add("songId");
- parameterValues.add(entry.getId());
- }
-
- Reader reader = getReader(context, progressListener, "createPlaylist", null, parameterNames, parameterValues);
- try {
- new ErrorParser(context).parse(reader);
- } finally {
- Util.close(reader);
- }
- }
-
- @Override
- public Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception {
- Reader reader = getReader(context, progressListener, "getLyrics", null, Arrays.asList("artist", "title"), Arrays.<Object>asList(artist, title));
- try {
- return new LyricsParser(context).parse(reader, progressListener);
- } finally {
- Util.close(reader);
- }
- }
-
- @Override
- public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception {
- checkServerVersion(context, "1.5", "Scrobbling not supported.");
- Reader reader = getReader(context, progressListener, "scrobble", null, Arrays.asList("id", "submission"), Arrays.<Object>asList(id, submission));
- try {
- new ErrorParser(context).parse(reader);
- } finally {
- Util.close(reader);
- }
- }
-
- @Override
- public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception {
- Reader reader = getReader(context, progressListener, "getAlbumList",
- null, Arrays.asList("type", "size", "offset"), Arrays.<Object>asList(type, size, offset));
- try {
- return new AlbumListParser(context).parse(reader, progressListener);
- } finally {
- Util.close(reader);
- }
- }
-
- @Override
- public MusicDirectory getRandomSongs(int size, Context context, ProgressListener progressListener) throws Exception {
- HttpParams params = new BasicHttpParams();
- HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS);
-
- Reader reader = getReader(context, progressListener, "getRandomSongs", params, "size", size);
- try {
- return new RandomSongsParser(context).parse(reader, progressListener);
- } finally {
- Util.close(reader);
- }
- }
-
- @Override
- public Version getLocalVersion(Context context) throws Exception {
- PackageInfo packageInfo = context.getPackageManager().getPackageInfo("net.sourceforge.subsonic.androidapp", 0);
- return new Version(packageInfo.versionName);
- }
-
- @Override
- public Version getLatestVersion(Context context, ProgressListener progressListener) throws Exception {
- Reader reader = getReaderForURL(context, VERSION_URL, null, null, null, progressListener);
- try {
- return new VersionParser().parse(reader);
- } finally {
- Util.close(reader);
- }
- }
-
- private void checkServerVersion(Context context, String version, String text) throws ServerTooOldException {
- Version serverVersion = Util.getServerRestVersion(context);
- Version requiredVersion = new Version(version);
- boolean ok = serverVersion == null || serverVersion.compareTo(requiredVersion) >= 0;
-
- if (!ok) {
- throw new ServerTooOldException(text, serverVersion, requiredVersion);
- }
- }
-
- @Override
- public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, ProgressListener progressListener) throws Exception {
-
- // Synchronize on the entry so that we don't download concurrently for the same song.
- synchronized (entry) {
-
- // Use cached file, if existing.
- Bitmap bitmap = FileUtil.getAlbumArtBitmap(context, entry, size);
- if (bitmap != null) {
- return bitmap;
- }
-
- String url = Util.getRestUrl(context, "getCoverArt");
-
- InputStream in = null;
- try {
- List<String> parameterNames = Arrays.asList("id", "size");
- List<Object> parameterValues = Arrays.<Object>asList(entry.getCoverArt(), size);
- HttpEntity entity = getEntityForURL(context, url, null, parameterNames, parameterValues, progressListener);
- in = entity.getContent();
-
- // If content type is XML, an error occured. Get it.
- String contentType = Util.getContentType(entity);
- if (contentType != null && contentType.startsWith("text/xml")) {
- new ErrorParser(context).parse(new InputStreamReader(in, Constants.UTF_8));
- return null; // Never reached.
- }
-
- byte[] bytes = Util.toByteArray(in);
-
- if (saveToFile) {
- OutputStream out = null;
- try {
- out = new FileOutputStream(FileUtil.getAlbumArtFile(context, entry));
- out.write(bytes);
- } finally {
- Util.close(out);
- }
- }
-
- return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
-
- } finally {
- Util.close(in);
- }
- }
- }
-
- @Override
- public HttpResponse getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, CancellableTask task) throws Exception {
-
- String url = Util.getRestUrl(context, "stream");
-
- // Set socket read timeout. Note: The timeout increases as the offset gets larger. This is
- // to avoid the thrashing effect seen when offset is combined with transcoding/downsampling on the server.
- // In that case, the server uses a long time before sending any data, causing the client to time out.
- HttpParams params = new BasicHttpParams();
- int timeout = (int) (SOCKET_READ_TIMEOUT_DOWNLOAD + offset * TIMEOUT_MILLIS_PER_OFFSET_BYTE);
- HttpConnectionParams.setSoTimeout(params, timeout);
-
- // Add "Range" header if offset is given.
- List<Header> headers = new ArrayList<Header>();
- if (offset > 0) {
- headers.add(new BasicHeader("Range", "bytes=" + offset + "-"));
- }
- List<String> parameterNames = Arrays.asList("id", "maxBitRate");
- List<Object> parameterValues = Arrays.<Object>asList(song.getId(), maxBitrate);
- HttpResponse response = getResponseForURL(context, url, params, parameterNames, parameterValues, headers, null, task);
-
- // If content type is XML, an error occurred. Get it.
- String contentType = Util.getContentType(response.getEntity());
- if (contentType != null && contentType.startsWith("text/xml")) {
- InputStream in = response.getEntity().getContent();
- try {
- new ErrorParser(context).parse(new InputStreamReader(in, Constants.UTF_8));
- } finally {
- Util.close(in);
- }
- }
-
- return response;
- }
-
- @Override
- public String getVideoUrl(Context context, String id) {
- StringBuilder builder = new StringBuilder(Util.getRestUrl(context, "videoPlayer"));
- builder.append("&id=").append(id);
- builder.append("&maxBitRate=500");
- builder.append("&autoplay=true");
-
- String url = rewriteUrlWithRedirect(context, builder.toString());
- Log.i(TAG, "Using video URL: " + url);
- return url;
- }
-
- @Override
- public JukeboxStatus updateJukeboxPlaylist(List<String> ids, Context context, ProgressListener progressListener) throws Exception {
- int n = ids.size();
- List<String> parameterNames = new ArrayList<String>(n + 1);
- parameterNames.add("action");
- for (int i = 0; i < n; i++) {
- parameterNames.add("id");
- }
- List<Object> parameterValues = new ArrayList<Object>();
- parameterValues.add("set");
- parameterValues.addAll(ids);
-
- return executeJukeboxCommand(context, progressListener, parameterNames, parameterValues);
- }
-
- @Override
- public JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception {
- List<String> parameterNames = Arrays.asList("action", "index", "offset");
- List<Object> parameterValues = Arrays.<Object>asList("skip", index, offsetSeconds);
- return executeJukeboxCommand(context, progressListener, parameterNames, parameterValues);
- }
-
- @Override
- public JukeboxStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception {
- return executeJukeboxCommand(context, progressListener, Arrays.asList("action"), Arrays.<Object>asList("stop"));
- }
-
- @Override
- public JukeboxStatus startJukebox(Context context, ProgressListener progressListener) throws Exception {
- return executeJukeboxCommand(context, progressListener, Arrays.asList("action"), Arrays.<Object>asList("start"));
- }
-
- @Override
- public JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception {
- return executeJukeboxCommand(context, progressListener, Arrays.asList("action"), Arrays.<Object>asList("status"));
- }
-
- @Override
- public JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception {
- List<String> parameterNames = Arrays.asList("action", "gain");
- List<Object> parameterValues = Arrays.<Object>asList("setGain", gain);
- return executeJukeboxCommand(context, progressListener, parameterNames, parameterValues);
-
- }
-
- private JukeboxStatus executeJukeboxCommand(Context context, ProgressListener progressListener, List<String> parameterNames, List<Object> parameterValues) throws Exception {
- checkServerVersion(context, "1.7", "Jukebox not supported.");
- Reader reader = getReader(context, progressListener, "jukeboxControl", null, parameterNames, parameterValues);
- try {
- return new JukeboxStatusParser(context).parse(reader);
- } finally {
- Util.close(reader);
- }
- }
-
- private Reader getReader(Context context, ProgressListener progressListener, String method, HttpParams requestParams) throws Exception {
- return getReader(context, progressListener, method, requestParams, Collections.<String>emptyList(), Collections.emptyList());
- }
-
- private Reader getReader(Context context, ProgressListener progressListener, String method,
- HttpParams requestParams, String parameterName, Object parameterValue) throws Exception {
- return getReader(context, progressListener, method, requestParams, Arrays.asList(parameterName), Arrays.<Object>asList(parameterValue));
- }
-
- private Reader getReader(Context context, ProgressListener progressListener, String method,
- HttpParams requestParams, List<String> parameterNames, List<Object> parameterValues) throws Exception {
-
- if (progressListener != null) {
- progressListener.updateProgress(R.string.service_connecting);
- }
-
- String url = Util.getRestUrl(context, method);
- return getReaderForURL(context, url, requestParams, parameterNames, parameterValues, progressListener);
- }
-
- private Reader getReaderForURL(Context context, String url, HttpParams requestParams, List<String> parameterNames,
- List<Object> parameterValues, ProgressListener progressListener) throws Exception {
- HttpEntity entity = getEntityForURL(context, url, requestParams, parameterNames, parameterValues, progressListener);
- if (entity == null) {
- throw new RuntimeException("No entity received for URL " + url);
- }
-
- InputStream in = entity.getContent();
- return new InputStreamReader(in, Constants.UTF_8);
- }
-
- private HttpEntity getEntityForURL(Context context, String url, HttpParams requestParams, List<String> parameterNames,
- List<Object> parameterValues, ProgressListener progressListener) throws Exception {
- return getResponseForURL(context, url, requestParams, parameterNames, parameterValues, null, progressListener, null).getEntity();
- }
-
- private HttpResponse getResponseForURL(Context context, String url, HttpParams requestParams,
- List<String> parameterNames, List<Object> parameterValues,
- List<Header> headers, ProgressListener progressListener, CancellableTask task) throws Exception {
- Log.d(TAG, "Connections in pool: " + connManager.getConnectionsInPool());
-
- // If not too many parameters, extract them to the URL rather than relying on the HTTP POST request being
- // received intact. Remember, HTTP POST requests are converted to GET requests during HTTP redirects, thus
- // loosing its entity.
- if (parameterNames != null && parameterNames.size() < 10) {
- StringBuilder builder = new StringBuilder(url);
- for (int i = 0; i < parameterNames.size(); i++) {
- builder.append("&").append(parameterNames.get(i)).append("=");
- builder.append(URLEncoder.encode(String.valueOf(parameterValues.get(i)), "UTF-8"));
- }
- url = builder.toString();
- parameterNames = null;
- parameterValues = null;
- }
-
- String rewrittenUrl = rewriteUrlWithRedirect(context, url);
- return executeWithRetry(context, rewrittenUrl, url, requestParams, parameterNames, parameterValues, headers, progressListener, task);
- }
-
- private HttpResponse executeWithRetry(Context context, String url, String originalUrl, HttpParams requestParams,
- List<String> parameterNames, List<Object> parameterValues,
- List<Header> headers, ProgressListener progressListener, CancellableTask task) throws IOException {
- Log.i(TAG, "Using URL " + url);
-
- final AtomicReference<Boolean> cancelled = new AtomicReference<Boolean>(false);
- int attempts = 0;
- while (true) {
- attempts++;
- HttpContext httpContext = new BasicHttpContext();
- final HttpPost request = new HttpPost(url);
-
- if (task != null) {
- // Attempt to abort the HTTP request if the task is cancelled.
- task.setOnCancelListener(new CancellableTask.OnCancelListener() {
- @Override
- public void onCancel() {
- cancelled.set(true);
- request.abort();
- }
- });
- }
-
- if (parameterNames != null) {
- List<NameValuePair> params = new ArrayList<NameValuePair>();
- for (int i = 0; i < parameterNames.size(); i++) {
- params.add(new BasicNameValuePair(parameterNames.get(i), String.valueOf(parameterValues.get(i))));
- }
- request.setEntity(new UrlEncodedFormEntity(params, Constants.UTF_8));
- }
-
- if (requestParams != null) {
- request.setParams(requestParams);
- Log.d(TAG, "Socket read timeout: " + HttpConnectionParams.getSoTimeout(requestParams) + " ms.");
- }
-
- if (headers != null) {
- for (Header header : headers) {
- request.addHeader(header);
- }
- }
-
- // Set credentials to get through apache proxies that require authentication.
- SharedPreferences prefs = Util.getPreferences(context);
- int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
- String username = prefs.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null);
- String password = prefs.getString(Constants.PREFERENCES_KEY_PASSWORD + instance, null);
- httpClient.getCredentialsProvider().setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
- new UsernamePasswordCredentials(username, password));
-
- try {
- HttpResponse response = httpClient.execute(request, httpContext);
- detectRedirect(originalUrl, context, httpContext);
- return response;
- } catch (IOException x) {
- request.abort();
- if (attempts >= HTTP_REQUEST_MAX_ATTEMPTS || cancelled.get()) {
- throw x;
- }
- if (progressListener != null) {
- String msg = context.getResources().getString(R.string.music_service_retry, attempts, HTTP_REQUEST_MAX_ATTEMPTS - 1);
- progressListener.updateProgress(msg);
- }
- Log.w(TAG, "Got IOException (" + attempts + "), will retry", x);
- increaseTimeouts(requestParams);
- Util.sleepQuietly(2000L);
- }
- }
- }
-
- private void increaseTimeouts(HttpParams requestParams) {
- if (requestParams != null) {
- int connectTimeout = HttpConnectionParams.getConnectionTimeout(requestParams);
- if (connectTimeout != 0) {
- HttpConnectionParams.setConnectionTimeout(requestParams, (int) (connectTimeout * 1.3F));
- }
- int readTimeout = HttpConnectionParams.getSoTimeout(requestParams);
- if (readTimeout != 0) {
- HttpConnectionParams.setSoTimeout(requestParams, (int) (readTimeout * 1.5F));
- }
- }
- }
-
- private void detectRedirect(String originalUrl, Context context, HttpContext httpContext) {
- HttpUriRequest request = (HttpUriRequest) httpContext.getAttribute(ExecutionContext.HTTP_REQUEST);
- HttpHost host = (HttpHost) httpContext.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
- String redirectedUrl = host.toURI() + request.getURI();
-
- redirectFrom = originalUrl.substring(0, originalUrl.indexOf("/rest/"));
- redirectTo = redirectedUrl.substring(0, redirectedUrl.indexOf("/rest/"));
-
- Log.i(TAG, redirectFrom + " redirects to " + redirectTo);
- redirectionLastChecked = System.currentTimeMillis();
- redirectionNetworkType = getCurrentNetworkType(context);
- }
-
- private String rewriteUrlWithRedirect(Context context, String url) {
-
- // Only cache for a certain time.
- if (System.currentTimeMillis() - redirectionLastChecked > REDIRECTION_CHECK_INTERVAL_MILLIS) {
- return url;
- }
-
- // Ignore cache if network type has changed.
- if (redirectionNetworkType != getCurrentNetworkType(context)) {
- return url;
- }
-
- if (redirectFrom == null || redirectTo == null) {
- return url;
- }
-
- return url.replace(redirectFrom, redirectTo);
- }
-
- private int getCurrentNetworkType(Context context) {
- ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = manager.getActiveNetworkInfo();
- return networkInfo == null ? -1 : networkInfo.getType();
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/Scrobbler.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/Scrobbler.java
deleted file mode 100644
index ce121a4b..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/Scrobbler.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package net.sourceforge.subsonic.androidapp.service;
-
-import android.content.Context;
-import android.util.Log;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-/**
- * Scrobbles played songs to Last.fm.
- *
- * @author Sindre Mehus
- * @version $Id$
- */
-public class Scrobbler {
-
- private static final String TAG = Scrobbler.class.getSimpleName();
-
- 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();
-
- // Avoid duplicate registrations.
- if (submission && id.equals(lastSubmission)) {
- return;
- }
- if (!submission && id.equals(lastNowPlaying)) {
- return;
- }
- if (submission) {
- lastSubmission = id;
- } else {
- lastNowPlaying = id;
- }
-
- 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();
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ServerTooOldException.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ServerTooOldException.java
deleted file mode 100644
index 9d433385..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ServerTooOldException.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service;
-
-import net.sourceforge.subsonic.androidapp.domain.Version;
-
-/**
- * Thrown if the REST API version implemented by the server is too old.
- *
- * @author Sindre Mehus
- * @version $Id$
- */
-public class ServerTooOldException extends Exception {
-
- private final String text;
- private final Version serverVersion;
- private final Version requiredVersion;
-
- public ServerTooOldException(String text, Version serverVersion, Version requiredVersion) {
- this.text = text;
- this.serverVersion = serverVersion;
- this.requiredVersion = requiredVersion;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- if (text != null) {
- builder.append(text).append(" ");
- }
- builder.append("Server API version too old. ");
- builder.append("Requires ").append(requiredVersion).append(" but is ").append(serverVersion).append(".");
- return builder.toString();
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/AbstractParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/AbstractParser.java
deleted file mode 100644
index 4ddff7e9..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/AbstractParser.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import java.io.Reader;
-
-import org.xmlpull.v1.XmlPullParser;
-
-import android.content.Context;
-import android.util.Xml;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.Version;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-import net.sourceforge.subsonic.androidapp.util.Util;
-
-/**
- * @author Sindre Mehus
- */
-public abstract class AbstractParser {
-
- private final Context context;
- private XmlPullParser parser;
- private boolean rootElementFound;
-
- public AbstractParser(Context context) {
- this.context = 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 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 String getText() {
- return parser.getText();
- }
-
- protected String get(String name) {
- return parser.getAttributeValue(null, name);
- }
-
- 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 Long getLong(String name) {
- String s = get(name);
- return s == null ? null : Long.valueOf(s);
- }
-
- protected Float getFloat(String name) {
- String s = get(name);
- return s == null ? null : Float.valueOf(s);
- }
-
- protected void init(Reader reader) throws Exception {
- parser = Xml.newPullParser();
- parser.setInput(reader);
- rootElementFound = false;
- }
-
- protected int nextParseEvent() throws Exception {
- return parser.next();
- }
-
- 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));
- }
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/AlbumListParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/AlbumListParser.java
deleted file mode 100644
index 298ef114..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/AlbumListParser.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import android.content.Context;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.Reader;
-
-/**
- * @author Sindre Mehus
- */
-public class AlbumListParser extends MusicDirectoryEntryParser {
-
- public AlbumListParser(Context context) {
- super(context);
- }
-
- 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 ("album".equals(name)) {
- dir.addChild(parseEntry());
- } else if ("error".equals(name)) {
- handleError();
- }
- }
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- validate();
- updateProgress(progressListener, R.string.parser_reading_done);
-
- return dir;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/ErrorParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/ErrorParser.java
deleted file mode 100644
index b2c61c5b..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/ErrorParser.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import android.content.Context;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.Reader;
-
-/**
- * @author Sindre Mehus
- */
-public class ErrorParser extends AbstractParser {
-
- public ErrorParser(Context context) {
- super(context);
- }
-
- public void parse(Reader reader) throws Exception {
-
- init(reader);
-
- int eventType;
- do {
- eventType = nextParseEvent();
- if (eventType == XmlPullParser.START_TAG && "error".equals(getElementName())) {
- handleError();
- }
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- validate();
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/IndexesParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/IndexesParser.java
deleted file mode 100644
index 83ef3e77..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/IndexesParser.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import java.io.Reader;
-import java.util.List;
-import java.util.ArrayList;
-
-import org.xmlpull.v1.XmlPullParser;
-
-import android.content.Context;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.Artist;
-import net.sourceforge.subsonic.androidapp.domain.Indexes;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-import android.util.Log;
-
-/**
- * @author Sindre Mehus
- */
-public class IndexesParser extends AbstractParser {
- private static final String TAG = IndexesParser.class.getSimpleName();
-
- public IndexesParser(Context context) {
- super(context);
- }
-
- public Indexes parse(Reader reader, ProgressListener progressListener) throws Exception {
-
- 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;
- int eventType;
- String index = "#";
- boolean changed = false;
-
- do {
- eventType = nextParseEvent();
- if (eventType == XmlPullParser.START_TAG) {
- String name = getElementName();
- if ("indexes".equals(name)) {
- changed = true;
- lastModified = getLong("lastModified");
- } 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.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);
-
- validate();
-
- if (!changed) {
- return null;
- }
-
- 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);
-
- return new Indexes(lastModified == null ? 0L : lastModified, shortcuts, artists);
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/JukeboxStatusParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/JukeboxStatusParser.java
deleted file mode 100644
index 2a61508d..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/JukeboxStatusParser.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import java.io.Reader;
-
-import org.xmlpull.v1.XmlPullParser;
-
-import android.content.Context;
-import net.sourceforge.subsonic.androidapp.domain.JukeboxStatus;
-
-/**
- * @author Sindre Mehus
- */
-public class JukeboxStatusParser extends AbstractParser {
-
- public JukeboxStatusParser(Context context) {
- super(context);
- }
-
- public JukeboxStatus parse(Reader reader) throws Exception {
-
- 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);
-
- validate();
-
- return jukeboxStatus;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/LicenseParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/LicenseParser.java
deleted file mode 100644
index 636c3e6e..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/LicenseParser.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import android.content.Context;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.Reader;
-
-import net.sourceforge.subsonic.androidapp.domain.ServerInfo;
-import net.sourceforge.subsonic.androidapp.domain.Version;
-
-/**
- * @author Sindre Mehus
- */
-public class LicenseParser extends AbstractParser {
-
- public LicenseParser(Context context) {
- super(context);
- }
-
- public ServerInfo parse(Reader reader) throws Exception {
-
- 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);
-
- validate();
-
- return serverInfo;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/LyricsParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/LyricsParser.java
deleted file mode 100644
index 698fb4b8..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/LyricsParser.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2010 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import android.content.Context;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.Lyrics;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.Reader;
-
-/**
- * @author Sindre Mehus
- */
-public class LyricsParser extends AbstractParser {
-
- public LyricsParser(Context context) {
- super(context);
- }
-
- 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);
-
- validate();
- return lyrics;
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/MusicDirectoryEntryParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/MusicDirectoryEntryParser.java
deleted file mode 100644
index 3da90613..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/MusicDirectoryEntryParser.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import android.content.Context;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-
-/**
- * @author Sindre Mehus
- */
-public class MusicDirectoryEntryParser extends AbstractParser {
-
- public MusicDirectoryEntryParser(Context context) {
- super(context);
- }
-
- protected MusicDirectory.Entry parseEntry() {
- MusicDirectory.Entry entry = new MusicDirectory.Entry();
- entry.setId(get("id"));
- entry.setParent(get("parent"));
- entry.setTitle(get("title"));
- entry.setDirectory(getBoolean("isDir"));
- entry.setCoverArt(get("coverArt"));
- entry.setArtist(get("artist"));
-
- if (!entry.isDirectory()) {
- entry.setAlbum(get("album"));
- entry.setTrack(getInteger("track"));
- entry.setYear(getInteger("year"));
- 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.setVideo(getBoolean("isVideo"));
- }
- return entry;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/MusicDirectoryParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/MusicDirectoryParser.java
deleted file mode 100644
index b818fc3d..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/MusicDirectoryParser.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import android.content.Context;
-import android.util.Log;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.Reader;
-
-/**
- * @author Sindre Mehus
- */
-public class MusicDirectoryParser extends MusicDirectoryEntryParser {
-
- private static final String TAG = MusicDirectoryParser.class.getSimpleName();
-
- public MusicDirectoryParser(Context context) {
- super(context);
- }
-
- public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception {
-
- 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)) {
- dir.addChild(parseEntry());
- } else if ("directory".equals(name)) {
- dir.setName(get("name"));
- } else if ("error".equals(name)) {
- handleError();
- }
- }
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- validate();
- updateProgress(progressListener, R.string.parser_reading_done);
-
- long t1 = System.currentTimeMillis();
- Log.d(TAG, "Got music directory in " + (t1 - t0) + "ms.");
-
- return dir;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/MusicFoldersParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/MusicFoldersParser.java
deleted file mode 100644
index 35057bd9..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/MusicFoldersParser.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.xmlpull.v1.XmlPullParser;
-
-import android.content.Context;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.MusicFolder;
-import net.sourceforge.subsonic.androidapp.domain.Playlist;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-
-/**
- * @author Sindre Mehus
- */
-public class MusicFoldersParser extends AbstractParser {
-
- public MusicFoldersParser(Context context) {
- super(context);
- }
-
- public List<MusicFolder> parse(Reader reader, ProgressListener progressListener) throws Exception {
-
- 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);
-
- validate();
- updateProgress(progressListener, R.string.parser_reading_done);
-
- return result;
- }
-
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/PlaylistParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/PlaylistParser.java
deleted file mode 100644
index ee829639..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/PlaylistParser.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import android.content.Context;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.Reader;
-
-/**
- * @author Sindre Mehus
- */
-public class PlaylistParser extends MusicDirectoryEntryParser {
-
- public PlaylistParser(Context context) {
- super(context);
- }
-
- 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());
- } else if ("error".equals(name)) {
- handleError();
- }
- }
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- validate();
- updateProgress(progressListener, R.string.parser_reading_done);
-
- return dir;
- }
-
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/PlaylistsParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/PlaylistsParser.java
deleted file mode 100644
index c1b88b8c..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/PlaylistsParser.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import android.content.Context;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.Playlist;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author Sindre Mehus
- */
-public class PlaylistsParser extends AbstractParser {
-
- public PlaylistsParser(Context context) {
- super(context);
- }
-
- public List<Playlist> parse(Reader reader, ProgressListener progressListener) throws Exception {
-
- 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");
- result.add(new Playlist(id, name));
- } else if ("error".equals(tag)) {
- handleError();
- }
- }
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- validate();
- updateProgress(progressListener, R.string.parser_reading_done);
-
- return result;
- }
-
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/RandomSongsParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/RandomSongsParser.java
deleted file mode 100644
index 0bf422b7..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/RandomSongsParser.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import android.content.Context;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.Reader;
-
-/**
- * @author Sindre Mehus
- */
-public class RandomSongsParser extends MusicDirectoryEntryParser {
-
- public RandomSongsParser(Context context) {
- super(context);
- }
-
- 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());
- } else if ("error".equals(name)) {
- handleError();
- }
- }
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- validate();
- updateProgress(progressListener, R.string.parser_reading_done);
-
- return dir;
- }
-
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/SearchResult2Parser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/SearchResult2Parser.java
deleted file mode 100644
index 01052f25..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/SearchResult2Parser.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import android.content.Context;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.domain.SearchResult;
-import net.sourceforge.subsonic.androidapp.domain.Artist;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.Reader;
-import java.util.List;
-import java.util.ArrayList;
-
-/**
- * @author Sindre Mehus
- */
-public class SearchResult2Parser extends MusicDirectoryEntryParser {
-
- public SearchResult2Parser(Context context) {
- super(context);
- }
-
- public SearchResult parse(Reader reader, ProgressListener progressListener) 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());
- } else if ("song".equals(name)) {
- songs.add(parseEntry());
- } else if ("error".equals(name)) {
- handleError();
- }
- }
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- validate();
- updateProgress(progressListener, R.string.parser_reading_done);
-
- return new SearchResult(artists, albums, songs);
- }
-
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/SearchResultParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/SearchResultParser.java
deleted file mode 100644
index c38b077f..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/SearchResultParser.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import android.content.Context;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.domain.SearchResult;
-import net.sourceforge.subsonic.androidapp.domain.Artist;
-import net.sourceforge.subsonic.androidapp.util.ProgressListener;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.Reader;
-import java.util.Collections;
-import java.util.List;
-import java.util.ArrayList;
-
-/**
- * @author Sindre Mehus
- */
-public class SearchResultParser extends MusicDirectoryEntryParser {
-
- public SearchResultParser(Context context) {
- super(context);
- }
-
- 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());
- } else if ("error".equals(name)) {
- handleError();
- }
- }
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- validate();
- updateProgress(progressListener, R.string.parser_reading_done);
-
- return new SearchResult(Collections.<Artist>emptyList(), Collections.<MusicDirectory.Entry>emptyList(), songs);
- }
-
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/SubsonicRESTException.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/SubsonicRESTException.java
deleted file mode 100644
index b46b6f22..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/SubsonicRESTException.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public class SubsonicRESTException extends Exception {
-
- private final int code;
-
- public SubsonicRESTException(int code, String message) {
- super(message);
- this.code = code;
- }
-
- public int getCode() {
- return code;
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/VersionParser.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/VersionParser.java
deleted file mode 100644
index b8a05531..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/parser/VersionParser.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.service.parser;
-
-import net.sourceforge.subsonic.androidapp.domain.Version;
-
-import java.io.BufferedReader;
-import java.io.Reader;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * @author Sindre Mehus
- */
-public class VersionParser {
-
- public 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;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/SSLSocketFactory.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/SSLSocketFactory.java
deleted file mode 100644
index 0e146650..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/SSLSocketFactory.java
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package net.sourceforge.subsonic.androidapp.service.ssl;
-
-import org.apache.http.conn.ConnectTimeoutException;
-import org.apache.http.conn.scheme.HostNameResolver;
-import org.apache.http.conn.scheme.LayeredSocketFactory;
-import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
-import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
-import org.apache.http.conn.ssl.StrictHostnameVerifier;
-import org.apache.http.conn.ssl.X509HostnameVerifier;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketTimeoutException;
-import java.net.UnknownHostException;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.UnrecoverableKeyException;
-
-/**
- * Layered socket factory for TLS/SSL connections.
- * <p>
- * SSLSocketFactory can be used to validate the identity of the HTTPS server against a list of
- * trusted certificates and to authenticate to the HTTPS server using a private key.
- * <p>
- * SSLSocketFactory will enable server authentication when supplied with
- * a {@link KeyStore trust-store} file containing one or several trusted certificates. The client
- * secure socket will reject the connection during the SSL session handshake if the target HTTPS
- * 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>
- * keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
- * </pre>
- * <p>
- * In special cases the standard trust verification process can be bypassed by using a custom
- * {@link TrustStrategy}. This interface is primarily intended for allowing self-signed
- * certificates to be accepted as trusted without having to add them to the trust-store file.
- * <p>
- * 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>
- * </ul>
- * <p>
- * SSLSocketFactory will enable client authentication when supplied with
- * a {@link KeyStore key-store} file containing a private key/public certificate
- * pair. The client secure socket will use the private key to authenticate
- * itself to the target HTTPS server during the SSL session handshake if
- * requested to do so by the server.
- * The target HTTPS server will in its turn verify the certificate presented
- * by the client in order to establish client's authenticity
- * <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>
- *
- * @since 4.0
- */
-public class SSLSocketFactory implements LayeredSocketFactory {
-
- public static final String TLS = "TLS";
- public static final String SSL = "SSL";
- public static final String SSLV2 = "SSLv2";
-
- public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER
- = new AllowAllHostnameVerifier();
-
- public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
- = new BrowserCompatHostnameVerifier();
-
- public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER
- = new StrictHostnameVerifier();
-
- /**
- * The default factory using the default JVM settings for secure connections.
- */
- private static final SSLSocketFactory DEFAULT_FACTORY = new SSLSocketFactory();
-
- /**
- * Gets the default factory, which uses the default JVM settings for secure
- * connections.
- *
- * @return the default factory
- */
- public static SSLSocketFactory getSocketFactory() {
- return DEFAULT_FACTORY;
- }
-
- private final javax.net.ssl.SSLSocketFactory socketfactory;
- private final HostNameResolver nameResolver;
- // TODO: make final
- private volatile X509HostnameVerifier hostnameVerifier;
-
- private static SSLContext createSSLContext(
- String algorithm,
- final KeyStore keystore,
- final String keystorePassword,
- final KeyStore truststore,
- final SecureRandom random,
- final TrustStrategy trustStrategy)
- throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, KeyManagementException {
- if (algorithm == null) {
- algorithm = TLS;
- }
- KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
- KeyManagerFactory.getDefaultAlgorithm());
- kmfactory.init(keystore, keystorePassword != null ? keystorePassword.toCharArray(): null);
- KeyManager[] keymanagers = kmfactory.getKeyManagers();
- TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
- TrustManagerFactory.getDefaultAlgorithm());
- tmfactory.init(keystore);
- TrustManager[] trustmanagers = tmfactory.getTrustManagers();
- 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);
- }
- }
- }
-
- SSLContext sslcontext = SSLContext.getInstance(algorithm);
- sslcontext.init(keymanagers, trustmanagers, random);
- return sslcontext;
- }
-
- /**
- * @deprecated Use {@link #SSLSocketFactory(String, KeyStore, String, KeyStore, SecureRandom, X509HostnameVerifier)}
- */
- @Deprecated
- public SSLSocketFactory(
- final String algorithm,
- final KeyStore keystore,
- final String keystorePassword,
- final KeyStore truststore,
- final SecureRandom random,
- final HostNameResolver nameResolver)
- throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
- this(createSSLContext(
- algorithm, keystore, keystorePassword, truststore, random, null),
- nameResolver);
- }
-
- /**
- * @since 4.1
- */
- public SSLSocketFactory(
- String algorithm,
- final KeyStore keystore,
- final String keystorePassword,
- final KeyStore truststore,
- final SecureRandom random,
- final X509HostnameVerifier hostnameVerifier)
- throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
- this(createSSLContext(
- algorithm, keystore, keystorePassword, truststore, random, null),
- hostnameVerifier);
- }
-
- /**
- * @since 4.1
- */
- public SSLSocketFactory(
- String algorithm,
- final KeyStore keystore,
- final String keystorePassword,
- final KeyStore truststore,
- final SecureRandom random,
- final TrustStrategy trustStrategy,
- final X509HostnameVerifier hostnameVerifier)
- throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
- this(createSSLContext(
- algorithm, keystore, keystorePassword, truststore, random, trustStrategy),
- hostnameVerifier);
- }
-
- public SSLSocketFactory(
- final KeyStore keystore,
- final String keystorePassword,
- final KeyStore truststore)
- throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
- this(TLS, keystore, keystorePassword, truststore, null, null, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
- }
-
- public SSLSocketFactory(
- final KeyStore keystore,
- final String keystorePassword)
- throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException{
- this(TLS, keystore, keystorePassword, null, null, null, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
- }
-
- public SSLSocketFactory(
- final KeyStore truststore)
- throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
- this(TLS, null, null, truststore, null, null, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
- }
-
- /**
- * @since 4.1
- */
- public SSLSocketFactory(
- final TrustStrategy trustStrategy,
- final X509HostnameVerifier hostnameVerifier)
- throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
- this(TLS, null, null, null, null, trustStrategy, hostnameVerifier);
- }
-
- /**
- * @since 4.1
- */
- public SSLSocketFactory(
- final TrustStrategy trustStrategy)
- throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
- this(TLS, null, null, null, null, trustStrategy, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
- }
-
- public SSLSocketFactory(final SSLContext sslContext) {
- this(sslContext, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
- }
-
- /**
- * @deprecated Use {@link #SSLSocketFactory(SSLContext)}
- */
- @Deprecated
- public SSLSocketFactory(
- final SSLContext sslContext, final HostNameResolver nameResolver) {
- super();
- this.socketfactory = sslContext.getSocketFactory();
- this.hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
- this.nameResolver = nameResolver;
- }
-
- /**
- * @since 4.1
- */
- public SSLSocketFactory(
- final SSLContext sslContext, final X509HostnameVerifier hostnameVerifier) {
- super();
- this.socketfactory = sslContext.getSocketFactory();
- this.hostnameVerifier = hostnameVerifier;
- this.nameResolver = null;
- }
-
- private SSLSocketFactory() {
- super();
- this.socketfactory = HttpsURLConnection.getDefaultSSLSocketFactory();
- this.hostnameVerifier = null;
- this.nameResolver = null;
- }
-
- /**
- * @param params Optional parameters. Parameters passed to this method will have no effect.
- * This method will create a unconnected instance of {@link Socket} class
- * using {@link javax.net.ssl.SSLSocketFactory#createSocket()} method.
- * @since 4.1
- */
- @SuppressWarnings("cast")
- public Socket createSocket(final HttpParams params) throws IOException {
- // the cast makes sure that the factory is working as expected
- return (SSLSocket) this.socketfactory.createSocket();
- }
-
- @SuppressWarnings("cast")
- public Socket createSocket() throws IOException {
- // the cast makes sure that the factory is working as expected
- return (SSLSocket) this.socketfactory.createSocket();
- }
-
- /**
- * @since 4.1
- */
- public Socket connectSocket(
- final Socket sock,
- final InetSocketAddress remoteAddress,
- final InetSocketAddress localAddress,
- final HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException {
- if (remoteAddress == null) {
- throw new IllegalArgumentException("Remote address may not be null");
- }
- if (params == null) {
- throw new IllegalArgumentException("HTTP parameters may not be null");
- }
- SSLSocket sslsock = (SSLSocket) (sock != null ? sock : createSocket());
- if (localAddress != null) {
-// sslsock.setReuseAddress(HttpConnectionParams.getSoReuseaddr(params));
- sslsock.bind(localAddress);
- }
-
- int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
- int soTimeout = HttpConnectionParams.getSoTimeout(params);
-
- try {
- sslsock.connect(remoteAddress, connTimeout);
- } catch (SocketTimeoutException ex) {
- throw new ConnectTimeoutException("Connect to " + remoteAddress.getHostName() + "/"
- + remoteAddress.getAddress() + " timed out");
- }
- sslsock.setSoTimeout(soTimeout);
- if (this.hostnameVerifier != null) {
- try {
- this.hostnameVerifier.verify(remoteAddress.getHostName(), sslsock);
- // verifyHostName() didn't blowup - good!
- } catch (IOException iox) {
- // close the socket before re-throwing the exception
- try { sslsock.close(); } catch (Exception x) { /*ignore*/ }
- throw iox;
- }
- }
- return sslsock;
- }
-
-
- /**
- * 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 check is performed last since it calls the argument object.
- if (sock.isClosed()) {
- throw new IllegalArgumentException("Socket is closed");
- }
- return true;
- }
-
- /**
- * @since 4.1
- */
- public Socket createLayeredSocket(
- final Socket socket,
- final String host,
- final int port,
- final boolean autoClose) throws IOException, UnknownHostException {
- SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(
- socket,
- host,
- port,
- autoClose
- );
- if (this.hostnameVerifier != null) {
- this.hostnameVerifier.verify(host, sslSocket);
- }
- // verifyHostName() didn't blowup - good!
- return sslSocket;
- }
-
- @Deprecated
- public void setHostnameVerifier(X509HostnameVerifier hostnameVerifier) {
- if ( hostnameVerifier == null ) {
- throw new IllegalArgumentException("Hostname verifier may not be null");
- }
- this.hostnameVerifier = hostnameVerifier;
- }
-
- public X509HostnameVerifier getHostnameVerifier() {
- return this.hostnameVerifier;
- }
-
- /**
- * @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, UnknownHostException, ConnectTimeoutException {
- InetSocketAddress local = null;
- if (localAddress != null || localPort > 0) {
- // we need to bind explicitly
- if (localPort < 0) {
- localPort = 0; // indicates "any"
- }
- local = new InetSocketAddress(localAddress, localPort);
- }
- InetAddress remoteAddress;
- if (this.nameResolver != null) {
- remoteAddress = this.nameResolver.resolve(host);
- } else {
- remoteAddress = InetAddress.getByName(host);
- }
- InetSocketAddress remote = new InetSocketAddress(remoteAddress, port);
- 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, UnknownHostException {
- return createLayeredSocket(socket, host, port, autoClose);
- }
-
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/TrustManagerDecorator.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/TrustManagerDecorator.java
deleted file mode 100644
index 41d98249..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/TrustManagerDecorator.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-package net.sourceforge.subsonic.androidapp.service.ssl;
-
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-import javax.net.ssl.X509TrustManager;
-
-
-/**
- * @since 4.1
- */
-class TrustManagerDecorator implements X509TrustManager {
-
- private final X509TrustManager trustManager;
- private final 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);
- }
-
- 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();
- }
-
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/TrustSelfSignedStrategy.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/TrustSelfSignedStrategy.java
deleted file mode 100644
index 4fdaaba2..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/TrustSelfSignedStrategy.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-package net.sourceforge.subsonic.androidapp.service.ssl;
-
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-/**
- * A trust strategy that accepts self-signed certificates as trusted. Verification of all other
- * certificates is done by the trust manager configured in the SSL context.
- *
- * @since 4.1
- */
-public class TrustSelfSignedStrategy implements TrustStrategy {
-
- public boolean isTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
- return true;
- }
-
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/TrustStrategy.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/TrustStrategy.java
deleted file mode 100644
index 3cf75b68..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/service/ssl/TrustStrategy.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-package net.sourceforge.subsonic.androidapp.service.ssl;
-
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-/**
- * A strategy to establish trustworthiness of certificates without consulting the trust manager
- * configured in the actual SSL context. This interface can be used to override the standard
- * JSSE certificate verification process.
- *
- * @since 4.1
- */
-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;
-
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/AlbumView.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/AlbumView.java
deleted file mode 100644
index a4dd3acd..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/AlbumView.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-
-/**
- * Used to display albums in a {@code ListView}.
- *
- * @author Sindre Mehus
- */
-public class AlbumView extends LinearLayout {
-
- private TextView titleView;
- private TextView artistView;
- private View coverArtView;
-
- public AlbumView(Context context) {
- super(context);
- LayoutInflater.from(context).inflate(R.layout.album_list_item, this, true);
-
- titleView = (TextView) findViewById(R.id.album_title);
- artistView = (TextView) findViewById(R.id.album_artist);
- coverArtView = findViewById(R.id.album_coverart);
- }
-
- public void setAlbum(MusicDirectory.Entry album, ImageLoader imageLoader) {
- titleView.setText(album.getTitle());
- artistView.setText(album.getArtist());
- artistView.setVisibility(album.getArtist() == null ? View.GONE : View.VISIBLE);
- imageLoader.loadImage(coverArtView, album, false, true);
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ArtistAdapter.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ArtistAdapter.java
deleted file mode 100644
index 98ed3c9b..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ArtistAdapter.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2010 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import net.sourceforge.subsonic.androidapp.domain.Artist;
-import net.sourceforge.subsonic.androidapp.R;
-import android.widget.ArrayAdapter;
-import android.widget.SectionIndexer;
-import android.content.Context;
-
-import java.util.List;
-import java.util.Set;
-import java.util.LinkedHashSet;
-import java.util.ArrayList;
-
-/**
- * @author Sindre Mehus
-*/
-public class ArtistAdapter extends ArrayAdapter<Artist> implements SectionIndexer {
-
- // Both arrays are indexed by section ID.
- private final Object[] sections;
- private final Integer[] positions;
-
- public ArtistAdapter(Context context, List<Artist> artists) {
- super(context, R.layout.artist_list_item, artists);
-
- Set<String> sectionSet = new LinkedHashSet<String>(30);
- List<Integer> positionList = new ArrayList<Integer>(30);
- for (int i = 0; i < artists.size(); i++) {
- Artist artist = artists.get(i);
- String index = artist.getIndex();
- if (!sectionSet.contains(index)) {
- sectionSet.add(index);
- positionList.add(i);
- }
- }
- sections = sectionSet.toArray(new Object[sectionSet.size()]);
- positions = positionList.toArray(new Integer[positionList.size()]);
- }
-
- @Override
- public Object[] getSections() {
- return sections;
- }
-
- @Override
- public int getPositionForSection(int section) {
- section = Math.min(section, positions.length - 1);
- return positions[section];
- }
-
- @Override
- public int getSectionForPosition(int pos) {
- for (int i = 0; i < sections.length - 1; i++) {
- if (pos < positions[i + 1]) {
- return i;
- }
- }
- return sections.length - 1;
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/BackgroundTask.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/BackgroundTask.java
deleted file mode 100644
index 1db2fdc1..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/BackgroundTask.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.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 net.sourceforge.subsonic.androidapp.R;
-
-/**
- * @author Sindre Mehus
- */
-public abstract class BackgroundTask<T> implements ProgressListener {
-
- 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();
- }
-
- protected Activity getActivity() {
- return activity;
- }
-
- protected Handler getHandler() {
- return handler;
- }
-
- public abstract void execute();
-
- protected abstract T doInBackground() throws Throwable;
-
- 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 String getErrorMessage(Throwable error) {
-
- 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 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);
- }
-
- String message = error.getMessage();
- if (message != null) {
- return message;
- }
- return error.getClass().getSimpleName();
- }
-
- @Override
- public abstract void updateProgress(final String message);
-
- @Override
- public void updateProgress(int messageId) {
- updateProgress(activity.getResources().getString(messageId));
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/CacheCleaner.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/CacheCleaner.java
deleted file mode 100644
index 46459571..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/CacheCleaner.java
+++ /dev/null
@@ -1,171 +0,0 @@
-package net.sourceforge.subsonic.androidapp.util;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import android.content.Context;
-import android.util.Log;
-import android.os.StatFs;
-import net.sourceforge.subsonic.androidapp.service.DownloadFile;
-import net.sourceforge.subsonic.androidapp.service.DownloadService;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public class CacheCleaner {
-
- private static final String TAG = CacheCleaner.class.getSimpleName();
- private static final double MAX_FILE_SYSTEM_USAGE = 0.95;
-
- private final Context context;
- private final DownloadService downloadService;
-
- public CacheCleaner(Context context, DownloadService downloadService) {
- this.context = context;
- this.downloadService = downloadService;
- }
-
- public void clean() {
-
- Log.i(TAG, "Starting cache cleaning.");
-
- if (downloadService == null) {
- Log.e(TAG, "DownloadService not set. Aborting cache cleaning.");
- return;
- }
-
- try {
-
- List<File> files = new ArrayList<File>();
- List<File> dirs = new ArrayList<File>();
-
- findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, dirs);
- sortByAscendingModificationTime(files);
-
- Set<File> undeletable = findUndeletableFiles();
-
- deleteFiles(files, undeletable);
- deleteEmptyDirs(dirs, undeletable);
- Log.i(TAG, "Completed cache cleaning.");
-
- } catch (RuntimeException x) {
- Log.e(TAG, "Error in cache cleaning.", x);
- }
- }
-
- private void deleteEmptyDirs(List<File> dirs, Set<File> undeletable) {
- for (File dir : dirs) {
- if (undeletable.contains(dir)) {
- continue;
- }
-
- File[] children = dir.listFiles();
-
- // Delete empty directory and associated album artwork.
- if (children.length == 0) {
- Util.delete(dir);
- Util.delete(FileUtil.getAlbumArtFile(dir));
- }
- }
- }
-
- private void deleteFiles(List<File> files, Set<File> undeletable) {
-
- if (files.isEmpty()) {
- return;
- }
-
- long cacheSizeBytes = Util.getCacheSizeMB(context) * 1024L * 1024L;
-
- 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 = Math.round(MAX_FILE_SYSTEM_USAGE * (double) bytesTotalFs);
-
- long bytesToDeleteCacheLimit = Math.max(bytesUsedBySubsonic - cacheSizeBytes, 0L);
- long bytesToDeleteFsLimit = Math.max(bytesUsedFs - minFsAvailability, 0L);
- long bytesToDelete = Math.max(bytesToDeleteCacheLimit, bytesToDeleteFsLimit);
-
- 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));
-
- long bytesDeleted = 0L;
- for (File file : files) {
-
- if (file.getName().equals(Constants.ALBUM_ART_FILE)) {
- // Move artwork to new folder.
- file.renameTo(FileUtil.getAlbumArtFile(file.getParentFile()));
-
- } else if (bytesToDelete > bytesDeleted || file.getName().endsWith(".partial") || file.getName().contains(".partial.")) {
- if (!undeletable.contains(file)) {
- long size = file.length();
- if (Util.delete(file)) {
- bytesDeleted += size;
- }
- }
- }
- }
-
- Log.i(TAG, "Deleted : " + Util.formatBytes(bytesDeleted));
- Log.i(TAG, "Cache size after : " + Util.formatBytes(bytesUsedBySubsonic - 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.");
- boolean isAlbumArtFile = name.equals(Constants.ALBUM_ART_FILE);
- if (isCacheFile || isAlbumArtFile) {
- 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 Set<File> findUndeletableFiles() {
- Set<File> undeletable = new HashSet<File>(5);
-
- for (DownloadFile downloadFile : downloadService.getDownloads()) {
- undeletable.add(downloadFile.getPartialFile());
- undeletable.add(downloadFile.getCompleteFile());
- }
-
- undeletable.add(FileUtil.getMusicDirectory(context));
- return undeletable;
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/CancellableTask.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/CancellableTask.java
deleted file mode 100644
index 9c8b06e1..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/CancellableTask.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-import android.util.Log;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public abstract class CancellableTask {
-
- private static final String TAG = CancellableTask.class.getSimpleName();
-
- private final AtomicBoolean running = new AtomicBoolean(false);
- private final AtomicBoolean cancelled = new AtomicBoolean(false);
- private final AtomicReference<Thread> thread = new AtomicReference<Thread>();
- private final AtomicReference<OnCancelListener> cancelListener = new AtomicReference<OnCancelListener>();
-
- public void cancel() {
- Log.d(TAG, "Cancelling " + CancellableTask.this);
- cancelled.set(true);
-
- OnCancelListener listener = cancelListener.get();
- if (listener != null) {
- try {
- listener.onCancel();
- } catch (Throwable x) {
- Log.w(TAG, "Error when invoking OnCancelListener.", x);
- }
- }
- }
-
- public boolean isCancelled() {
- return cancelled.get();
- }
-
- public void setOnCancelListener(OnCancelListener listener) {
- cancelListener.set(listener);
- }
-
- public boolean isRunning() {
- return running.get();
- }
-
- public abstract void execute();
-
- public void start() {
- thread.set(new Thread() {
- @Override
- public void run() {
- running.set(true);
- Log.d(TAG, "Starting thread for " + CancellableTask.this);
- try {
- execute();
- } finally {
- running.set(false);
- Log.d(TAG, "Stopping thread for " + CancellableTask.this);
- }
- }
- });
- thread.get().start();
- }
-
- public static interface OnCancelListener {
- void onCancel();
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/Constants.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/Constants.java
deleted file mode 100644
index bebe49ce..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/Constants.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public final class Constants {
-
- // Character encoding used throughout.
- public static final String UTF_8 = "UTF-8";
-
- // REST protocol version and client ID.
- // Note: Keep it as low as possible to maintain compatibility with older servers.
- public static final String REST_PROTOCOL_VERSION = "1.2.0";
- public static final String REST_CLIENT_ID = "android";
-
- // Names for intent extras.
- public static final String INTENT_EXTRA_NAME_ID = "subsonic.id";
- public static final String INTENT_EXTRA_NAME_NAME = "subsonic.name";
- public static final String INTENT_EXTRA_NAME_ARTIST = "subsonic.artist";
- public static final String INTENT_EXTRA_NAME_TITLE = "subsonic.title";
- public static final String INTENT_EXTRA_NAME_AUTOPLAY = "subsonic.playall";
- public static final String INTENT_EXTRA_NAME_ERROR = "subsonic.error";
- public static final String INTENT_EXTRA_NAME_QUERY = "subsonic.query";
- public static final String INTENT_EXTRA_NAME_PLAYLIST_ID = "subsonic.playlist.id";
- public static final String INTENT_EXTRA_NAME_PLAYLIST_NAME = "subsonic.playlist.name";
- public static final String INTENT_EXTRA_NAME_ALBUM_LIST_TYPE = "subsonic.albumlisttype";
- public static final String INTENT_EXTRA_NAME_ALBUM_LIST_SIZE = "subsonic.albumlistsize";
- public static final String INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET = "subsonic.albumlistoffset";
- public static final String INTENT_EXTRA_NAME_SHUFFLE = "subsonic.shuffle";
- public static final String INTENT_EXTRA_NAME_REFRESH = "subsonic.refresh";
- public static final String INTENT_EXTRA_REQUEST_SEARCH = "subsonic.requestsearch";
- public static final String INTENT_EXTRA_NAME_EXIT = "subsonic.exit" ;
-
- // Notification IDs.
- public static final int NOTIFICATION_ID_PLAYING = 100;
- public static final int NOTIFICATION_ID_ERROR = 101;
-
- // Preferences keys.
- public static final String PREFERENCES_KEY_SERVER_INSTANCE = "serverInstanceId";
- public static final String PREFERENCES_KEY_SERVER_NAME = "serverName";
- public static final String PREFERENCES_KEY_SERVER_URL = "serverUrl";
- public static final String PREFERENCES_KEY_MUSIC_FOLDER_ID = "musicFolderId";
- public static final String PREFERENCES_KEY_USERNAME = "username";
- public static final String PREFERENCES_KEY_PASSWORD = "password";
- public static final String PREFERENCES_KEY_INSTALL_TIME = "installTime";
- public static final String PREFERENCES_KEY_THEME = "theme";
- public static final String PREFERENCES_KEY_MAX_BITRATE_WIFI = "maxBitrateWifi";
- public static final String PREFERENCES_KEY_MAX_BITRATE_MOBILE = "maxBitrateMobile";
- public static final String PREFERENCES_KEY_CACHE_SIZE = "cacheSize";
- public static final String PREFERENCES_KEY_CACHE_LOCATION = "cacheLocation";
- public static final String PREFERENCES_KEY_PRELOAD_COUNT = "preloadCount";
- public static final String PREFERENCES_KEY_HIDE_MEDIA = "hideMedia";
- public static final String PREFERENCES_KEY_MEDIA_BUTTONS = "mediaButtons";
- public static final String PREFERENCES_KEY_SCREEN_LIT_ON_DOWNLOAD = "screenLitOnDownload";
- public static final String PREFERENCES_KEY_SCROBBLE = "scrobble";
- public static final String PREFERENCES_KEY_REPEAT_MODE = "repeatMode";
- public static final String PREFERENCES_KEY_WIFI_REQUIRED_FOR_DOWNLOAD = "wifiRequiredForDownload";
-
- // Name of the preferences file.
- public static final String PREFERENCES_FILE_NAME = "net.sourceforge.subsonic.androidapp_preferences";
-
- // Number of free trial days for non-licensed servers.
- public static final int FREE_TRIAL_DAYS = 30;
-
- // URL for project donations.
- public static final String DONATION_URL = "http://subsonic.org/pages/android-donation.jsp";
-
- public static final String ALBUM_ART_FILE = "folder.jpeg";
-
- private Constants() {
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/EntryAdapter.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/EntryAdapter.java
deleted file mode 100644
index 1b4d72cf..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/EntryAdapter.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2010 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import java.util.List;
-
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import net.sourceforge.subsonic.androidapp.activity.SubsonicTabActivity;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-
-/**
- * @author Sindre Mehus
- */
-public class EntryAdapter extends ArrayAdapter<MusicDirectory.Entry> {
-
- private final SubsonicTabActivity activity;
- private final ImageLoader imageLoader;
- private final boolean checkable;
-
- public EntryAdapter(SubsonicTabActivity activity, ImageLoader imageLoader, List<MusicDirectory.Entry> entries, boolean checkable) {
- super(activity, android.R.layout.simple_list_item_1, entries);
- this.activity = activity;
- this.imageLoader = imageLoader;
- this.checkable = checkable;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- MusicDirectory.Entry entry = getItem(position);
-
- if (entry.isDirectory()) {
- AlbumView view;
- // TODO: Reuse AlbumView objects once cover art loading is working.
-// if (convertView != null && convertView instanceof AlbumView) {
-// view = (AlbumView) convertView;
-// } else {
- view = new AlbumView(activity);
-// }
- view.setAlbum(entry, imageLoader);
- return view;
-
- } else {
- SongView view;
- if (convertView != null && convertView instanceof SongView) {
- view = (SongView) convertView;
- } else {
- view = new SongView(activity);
- }
- view.setSong(entry, checkable);
- return view;
- }
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ErrorDialog.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ErrorDialog.java
deleted file mode 100644
index b1c51573..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ErrorDialog.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import net.sourceforge.subsonic.androidapp.R;
-
-/**
- * @author Sindre Mehus
- */
-public class ErrorDialog {
-
- public ErrorDialog(Activity activity, int messageId, boolean finishActivityOnCancel) {
- this(activity, activity.getResources().getString(messageId), finishActivityOnCancel);
- }
-
- public ErrorDialog(final Activity activity, String message, final boolean finishActivityOnClose) {
-
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setIcon(android.R.drawable.ic_dialog_alert);
- builder.setTitle(R.string.error_label);
- builder.setMessage(message);
- builder.setCancelable(true);
- builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialogInterface) {
- if (finishActivityOnClose) {
- activity.finish();
- }
- }
- });
- builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- if (finishActivityOnClose) {
- activity.finish();
- }
- }
- });
-
- builder.create().show();
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/FileUtil.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/FileUtil.java
deleted file mode 100644
index 88d10d3e..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/FileUtil.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.util.Arrays;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import java.util.Iterator;
-import java.util.List;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Environment;
-import android.util.Log;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-
-/**
- * @author Sindre Mehus
- */
-public class FileUtil {
-
- private static final String TAG = FileUtil.class.getSimpleName();
- private static final String[] FILE_SYSTEM_UNSAFE = {"/", "\\", "..", ":", "\"", "?", "*", "<", ">"};
- private static final String[] FILE_SYSTEM_UNSAFE_DIR = {"\\", "..", ":", "\"", "?", "*", "<", ">"};
- private static final List<String> MUSIC_FILE_EXTENSIONS = Arrays.asList("mp3", "ogg", "aac", "flac", "m4a", "wav", "wma");
- private static final File DEFAULT_MUSIC_DIR = createDirectory("music");
-
- public static File getSongFile(Context context, MusicDirectory.Entry song) {
- File dir = getAlbumDirectory(context, song);
-
- StringBuilder fileName = new StringBuilder();
- Integer track = song.getTrack();
- if (track != null) {
- if (track < 10) {
- fileName.append("0");
- }
- fileName.append(track).append("-");
- }
-
- fileName.append(fileSystemSafe(song.getTitle())).append(".");
-
- if (song.getTranscodedSuffix() != null) {
- fileName.append(song.getTranscodedSuffix());
- } else {
- fileName.append(song.getSuffix());
- }
-
- return new File(dir, fileName.toString());
- }
-
- public static File getPlaylistFile(String id) {
- File playlistDir = getPlaylistDirectory();
- return new File(playlistDir, id);
- }
- public static File getPlaylistDirectory() {
- File playlistDir = new File(getSubsonicDirectory(), "playlists");
- ensureDirectoryExistsAndIsReadWritable(playlistDir);
- return playlistDir;
- }
-
- public static File getAlbumArtFile(Context context, MusicDirectory.Entry entry) {
- File albumDir = getAlbumDirectory(context, entry);
- return getAlbumArtFile(albumDir);
- }
-
- public static File getAlbumArtFile(File albumDir) {
- File albumArtDir = getAlbumArtDirectory();
- return new File(albumArtDir, Util.md5Hex(albumDir.getPath()) + ".jpeg");
- }
-
- public static Bitmap getAlbumArtBitmap(Context context, MusicDirectory.Entry entry, int size) {
- File albumArtFile = getAlbumArtFile(context, entry);
- if (albumArtFile.exists()) {
- Bitmap bitmap = BitmapFactory.decodeFile(albumArtFile.getPath());
- return bitmap == null ? null : Bitmap.createScaledBitmap(bitmap, size, size, true);
- }
- return null;
- }
-
- public static File getAlbumArtDirectory() {
- File albumArtDir = new File(getSubsonicDirectory(), "artwork");
- ensureDirectoryExistsAndIsReadWritable(albumArtDir);
- ensureDirectoryExistsAndIsReadWritable(new File(albumArtDir, ".nomedia"));
- return albumArtDir;
- }
-
- private static File getAlbumDirectory(Context context, MusicDirectory.Entry entry) {
- File dir;
- if (entry.getPath() != null) {
- File f = new File(fileSystemSafeDir(entry.getPath()));
- dir = new File(getMusicDirectory(context).getPath() + "/" + (entry.isDirectory() ? f.getPath() : f.getParent()));
- } else {
- String artist = fileSystemSafe(entry.getArtist());
- String album = fileSystemSafe(entry.getAlbum());
- dir = new File(getMusicDirectory(context).getPath() + "/" + artist + "/" + album);
- }
- return dir;
- }
-
- public static void createDirectoryForParent(File file) {
- File dir = file.getParentFile();
- if (!dir.exists()) {
- if (!dir.mkdirs()) {
- Log.e(TAG, "Failed to create directory " + dir);
- }
- }
- }
-
- private static File createDirectory(String name) {
- File dir = new File(getSubsonicDirectory(), name);
- if (!dir.exists() && !dir.mkdirs()) {
- Log.e(TAG, "Failed to create " + name);
- }
- return dir;
- }
-
- public static File getSubsonicDirectory() {
- return new File(Environment.getExternalStorageDirectory(), "subsonic");
- }
-
- public static File getDefaultMusicDirectory() {
- return DEFAULT_MUSIC_DIR;
- }
-
- public static File getMusicDirectory(Context context) {
- String path = Util.getPreferences(context).getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, DEFAULT_MUSIC_DIR.getPath());
- File dir = new File(path);
- return ensureDirectoryExistsAndIsReadWritable(dir) ? dir : getDefaultMusicDirectory();
- }
-
- public static boolean ensureDirectoryExistsAndIsReadWritable(File dir) {
- if (dir == null) {
- return false;
- }
-
- if (dir.exists()) {
- if (!dir.isDirectory()) {
- Log.w(TAG, dir + " exists but is not a directory.");
- return false;
- }
- } else {
- if (dir.mkdirs()) {
- Log.i(TAG, "Created directory " + dir);
- } else {
- Log.w(TAG, "Failed to create directory " + dir);
- return false;
- }
- }
-
- if (!dir.canRead()) {
- Log.w(TAG, "No read permission for directory " + dir);
- return false;
- }
-
- if (!dir.canWrite()) {
- Log.w(TAG, "No write permission for directory " + dir);
- return false;
- }
- return true;
- }
-
- /**
- * Makes a given filename safe by replacing special characters like slashes ("/" and "\")
- * with dashes ("-").
- *
- * @param filename The filename in question.
- * @return The filename with special characters replaced by hyphens.
- */
- private static String fileSystemSafe(String filename) {
- if (filename == null || filename.trim().length() == 0) {
- return "unnamed";
- }
-
- for (String s : FILE_SYSTEM_UNSAFE) {
- filename = filename.replace(s, "-");
- }
- return filename;
- }
-
- /**
- * Makes a given filename safe by replacing special characters like colons (":")
- * with dashes ("-").
- *
- * @param path The path of the directory in question.
- * @return The the directory name with special characters replaced by hyphens.
- */
- private static String fileSystemSafeDir(String path) {
- if (path == null || path.trim().length() == 0) {
- return "";
- }
-
- for (String s : FILE_SYSTEM_UNSAFE_DIR) {
- path = path.replace(s, "-");
- }
- return path;
- }
-
- /**
- * Similar to {@link File#listFiles()}, but returns a sorted set.
- * Never returns {@code null}, instead a warning is logged, and an empty set is returned.
- */
- public static SortedSet<File> listFiles(File dir) {
- File[] files = dir.listFiles();
- if (files == null) {
- Log.w(TAG, "Failed to list children for " + dir.getPath());
- return new TreeSet<File>();
- }
-
- return new TreeSet<File>(Arrays.asList(files));
- }
-
- public static SortedSet<File> listMusicFiles(File dir) {
- SortedSet<File> files = listFiles(dir);
- Iterator<File> iterator = files.iterator();
- while (iterator.hasNext()) {
- File file = iterator.next();
- if (!file.isDirectory() && !isMusicFile(file)) {
- iterator.remove();
- }
- }
- return files;
- }
-
- private static boolean isMusicFile(File file) {
- String extension = getExtension(file.getName());
- return MUSIC_FILE_EXTENSIONS.contains(extension);
- }
-
- /**
- * Returns the extension (the substring after the last dot) of the given file. The dot
- * is not included in the returned extension.
- *
- * @param name The filename in question.
- * @return The extension, or an empty string if no extension is found.
- */
- public static String getExtension(String name) {
- int index = name.lastIndexOf('.');
- return index == -1 ? "" : name.substring(index + 1).toLowerCase();
- }
-
- /**
- * Returns the base name (the substring before the last dot) of the given file. The dot
- * is not included in the returned basename.
- *
- * @param name The filename in question.
- * @return The base name, or an empty string if no basename is found.
- */
- public static String getBaseName(String name) {
- int index = name.lastIndexOf('.');
- return index == -1 ? name : name.substring(0, index);
- }
-
- public static <T extends Serializable> boolean serialize(Context context, T obj, String fileName) {
- File file = new File(context.getCacheDir(), fileName);
- ObjectOutputStream out = null;
- try {
- out = new ObjectOutputStream(new FileOutputStream(file));
- out.writeObject(obj);
- Log.i(TAG, "Serialized object to " + file);
- return true;
- } catch (Throwable x) {
- Log.w(TAG, "Failed to serialize object to " + file);
- return false;
- } finally {
- Util.close(out);
- }
- }
-
- public static <T extends Serializable> T deserialize(Context context, String fileName) {
- File file = new File(context.getCacheDir(), fileName);
- if (!file.exists() || !file.isFile()) {
- return null;
- }
-
- ObjectInputStream in = null;
- try {
- in = new ObjectInputStream(new FileInputStream(file));
- T result = (T) in.readObject();
- Log.i(TAG, "Deserialized object from " + file);
- return result;
- } catch (Throwable x) {
- Log.w(TAG, "Failed to deserialize object from " + file, x);
- return null;
- } finally {
- Util.close(in);
- }
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/HorizontalSlider.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/HorizontalSlider.java
deleted file mode 100644
index 6a79a0a0..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/HorizontalSlider.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ProgressBar;
-import net.sourceforge.subsonic.androidapp.R;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public class HorizontalSlider extends ProgressBar {
-
- private final Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.slider_knob);
- private boolean slidingEnabled;
- private OnSliderChangeListener listener;
- private static final int PADDING = 2;
- private boolean sliding;
- private int sliderPosition;
- private int startPosition;
-
- public interface OnSliderChangeListener {
- void onSliderChanged(View view, int position, boolean inProgress);
- }
-
- public HorizontalSlider(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- public HorizontalSlider(Context context, AttributeSet attrs) {
- super(context, attrs, android.R.attr.progressBarStyleHorizontal);
- }
-
- public HorizontalSlider(Context context) {
- super(context);
- }
-
- public void setSlidingEnabled(boolean slidingEnabled) {
- if (this.slidingEnabled != slidingEnabled) {
- this.slidingEnabled = slidingEnabled;
- invalidate();
- }
- }
-
- public boolean isSlidingEnabled() {
- return slidingEnabled;
- }
-
- public void setOnSliderChangeListener(OnSliderChangeListener listener) {
- this.listener = listener;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- int max = getMax();
- if (!slidingEnabled || max == 0) {
- return;
- }
-
- int paddingLeft = getPaddingLeft();
- int paddingRight = getPaddingRight();
- int paddingTop = getPaddingTop();
- int paddingBottom = getPaddingBottom();
-
- int w = getWidth() - paddingLeft - paddingRight;
- int h = getHeight() - paddingTop - paddingBottom;
- int position = sliding ? sliderPosition : getProgress();
-
- int bitmapWidth = bitmap.getWidth();
- int bitmapHeight = bitmap.getWidth();
- float x = paddingLeft + w * ((float) position / max) - bitmapWidth / 2.0F;
- x = Math.max(x, paddingLeft);
- x = Math.min(x, paddingLeft + w - bitmapWidth);
- float y = paddingTop + h / 2.0F - bitmapHeight / 2.0F;
-
- canvas.drawBitmap(bitmap, x, y, null);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!slidingEnabled) {
- return false;
- }
-
- int action = event.getAction();
-
- if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) {
-
- if (action == MotionEvent.ACTION_DOWN) {
- sliding = true;
- startPosition = getProgress();
- }
-
- float x = event.getX() - PADDING;
- float width = getWidth() - 2 * PADDING;
- sliderPosition = Math.round((float) getMax() * (x / width));
- sliderPosition = Math.max(sliderPosition, 0);
-
- setProgress(Math.min(startPosition, sliderPosition));
- setSecondaryProgress(Math.max(startPosition, sliderPosition));
- if (listener != null) {
- listener.onSliderChanged(this, sliderPosition, true);
- }
-
- } else if (action == MotionEvent.ACTION_UP) {
- sliding = false;
- setProgress(sliderPosition);
- setSecondaryProgress(0);
- if (listener != null) {
- listener.onSliderChanged(this, sliderPosition, false);
- }
- }
-
- return true;
- }
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ImageLoader.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ImageLoader.java
deleted file mode 100644
index 5cbd8c9f..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ImageLoader.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.LinearGradient;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Shader;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.TransitionDrawable;
-import android.os.Handler;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.service.MusicService;
-import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/**
- * Asynchronous loading of images, with caching.
- * <p/>
- * There should normally be only one instance of this class.
- *
- * @author Sindre Mehus
- */
-public class ImageLoader implements Runnable {
-
- private static final String TAG = ImageLoader.class.getSimpleName();
- private static final int CONCURRENCY = 5;
-
- private final LRUCache<String, Drawable> cache = new LRUCache<String, Drawable>(100);
- private final BlockingQueue<Task> queue;
- private final int imageSizeDefault;
- private final int imageSizeLarge;
- private Drawable largeUnknownImage;
-
- public ImageLoader(Context context) {
- queue = new LinkedBlockingQueue<Task>(500);
-
- // Determine the density-dependent image sizes.
- imageSizeDefault = context.getResources().getDrawable(R.drawable.unknown_album).getIntrinsicHeight();
- DisplayMetrics metrics = context.getResources().getDisplayMetrics();
- imageSizeLarge = (int) Math.round(Math.min(metrics.widthPixels, metrics.heightPixels) * 0.6);
-
- for (int i = 0; i < CONCURRENCY; i++) {
- new Thread(this, "ImageLoader").start();
- }
-
- createLargeUnknownImage(context);
- }
-
- private void createLargeUnknownImage(Context context) {
- BitmapDrawable drawable = (BitmapDrawable) context.getResources().getDrawable(R.drawable.unknown_album_large);
- Bitmap bitmap = Bitmap.createScaledBitmap(drawable.getBitmap(), imageSizeLarge, imageSizeLarge, true);
- bitmap = createReflection(bitmap);
- largeUnknownImage = Util.createDrawableFromBitmap(context, bitmap);
- }
-
- public void loadImage(View view, MusicDirectory.Entry entry, boolean large, boolean crossfade) {
- if (entry == null || entry.getCoverArt() == null) {
- setUnknownImage(view, large);
- return;
- }
-
- int size = large ? imageSizeLarge : imageSizeDefault;
- Drawable drawable = cache.get(getKey(entry.getCoverArt(), size));
- if (drawable != null) {
- setImage(view, drawable, large);
- return;
- }
-
- if (!large) {
- setUnknownImage(view, large);
- }
- queue.offer(new Task(view, entry, size, large, large, crossfade));
- }
-
- private String getKey(String coverArtId, int size) {
- return coverArtId + size;
- }
-
- private void setImage(View view, Drawable drawable, boolean crossfade) {
- if (view instanceof TextView) {
- // Cross-fading is not implemented for TextView since it's not in use. It would be easy to add it, though.
- TextView textView = (TextView) view;
- textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
- } else if (view instanceof ImageView) {
- ImageView imageView = (ImageView) view;
- if (crossfade) {
-
- Drawable existingDrawable = imageView.getDrawable();
- if (existingDrawable == null) {
- Bitmap emptyImage = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
- existingDrawable = new BitmapDrawable(emptyImage);
- }
-
- Drawable[] layers = new Drawable[]{existingDrawable, drawable};
-
- TransitionDrawable transitionDrawable = new TransitionDrawable(layers);
- imageView.setImageDrawable(transitionDrawable);
- transitionDrawable.startTransition(250);
- } else {
- imageView.setImageDrawable(drawable);
- }
- }
- }
-
- private void setUnknownImage(View view, boolean large) {
- if (large) {
- setImage(view, largeUnknownImage, false);
- } else {
- if (view instanceof TextView) {
- ((TextView) view).setCompoundDrawablesWithIntrinsicBounds(R.drawable.unknown_album, 0, 0, 0);
- } else if (view instanceof ImageView) {
- ((ImageView) view).setImageResource(R.drawable.unknown_album);
- }
- }
- }
-
- public void clear() {
- queue.clear();
- }
-
- @Override
- public void run() {
- while (true) {
- try {
- Task task = queue.take();
- task.execute();
- } catch (Throwable x) {
- Log.e(TAG, "Unexpected exception in ImageLoader.", x);
- }
- }
- }
-
- private Bitmap createReflection(Bitmap originalImage) {
-
- int width = originalImage.getWidth();
- int height = originalImage.getHeight();
-
- // The gap we want between the reflection and the original image
- final int reflectionGap = 4;
-
- // This will not scale but will flip on the Y axis
- Matrix matrix = new Matrix();
- matrix.preScale(1, -1);
-
- // Create a Bitmap with the flip matix applied to it.
- // We only want the bottom half of the image
- Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, height / 2, width, height / 2, matrix, false);
-
- // Create a new bitmap with same width but taller to fit reflection
- Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + height / 2), Bitmap.Config.ARGB_8888);
-
- // Create a new Canvas with the bitmap that's big enough for
- // the image plus gap plus reflection
- Canvas canvas = new Canvas(bitmapWithReflection);
-
- // Draw in the original image
- canvas.drawBitmap(originalImage, 0, 0, null);
-
- // Draw in the gap
- Paint defaultPaint = new Paint();
- canvas.drawRect(0, height, width, height + reflectionGap, defaultPaint);
-
- // Draw in the reflection
- canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);
-
- // Create a shader that is a linear gradient that covers the reflection
- Paint paint = new Paint();
- LinearGradient shader = new LinearGradient(0, originalImage.getHeight(), 0,
- bitmapWithReflection.getHeight() + reflectionGap, 0x70000000, 0xff000000,
- Shader.TileMode.CLAMP);
-
- // Set the paint to use this shader (linear gradient)
- paint.setShader(shader);
-
- // Draw a rectangle using the paint with our linear gradient
- canvas.drawRect(0, height, width, bitmapWithReflection.getHeight() + reflectionGap, paint);
-
- return bitmapWithReflection;
- }
-
- private class Task {
- private final View view;
- private final MusicDirectory.Entry entry;
- private final Handler handler;
- private final int size;
- private final boolean reflection;
- private final boolean saveToFile;
- private final boolean crossfade;
-
- public Task(View view, MusicDirectory.Entry entry, int size, boolean reflection, boolean saveToFile, boolean crossfade) {
- this.view = view;
- this.entry = entry;
- this.size = size;
- this.reflection = reflection;
- this.saveToFile = saveToFile;
- this.crossfade = crossfade;
- handler = new Handler();
- }
-
- public void execute() {
- try {
- MusicService musicService = MusicServiceFactory.getMusicService(view.getContext());
- Bitmap bitmap = musicService.getCoverArt(view.getContext(), entry, size, saveToFile, null);
-
- if (reflection) {
- bitmap = createReflection(bitmap);
- }
-
- final Drawable drawable = Util.createDrawableFromBitmap(view.getContext(), bitmap);
- cache.put(getKey(entry.getCoverArt(), size), drawable);
-
- handler.post(new Runnable() {
- @Override
- public void run() {
- setImage(view, drawable, crossfade);
- }
- });
- } catch (Throwable x) {
- Log.e(TAG, "Failed to download album art.", x);
- }
- }
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/LRUCache.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/LRUCache.java
deleted file mode 100644
index f6145fb7..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/LRUCache.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import java.lang.ref.SoftReference;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * @author Sindre Mehus
- */
-public class LRUCache<K,V>{
-
- private final int capacity;
- private final Map<K, TimestampedValue> map;
-
- public LRUCache(int capacity) {
- map = new HashMap<K, TimestampedValue>(capacity);
- this.capacity = capacity;
- }
-
- public synchronized V get(K key) {
- TimestampedValue value = map.get(key);
-
- V result = null;
- if (value != null) {
- value.updateTimestamp();
- result = value.getValue();
- }
-
- return result;
- }
-
- public synchronized void put(K key, V value) {
- if (map.size() >= capacity) {
- removeOldest();
- }
- map.put(key, new TimestampedValue(value));
- }
-
- public void clear() {
- map.clear();
- }
-
- private void removeOldest() {
- K oldestKey = null;
- long oldestTimestamp = Long.MAX_VALUE;
-
- for (Map.Entry<K, TimestampedValue> entry : map.entrySet()) {
- K key = entry.getKey();
- TimestampedValue value = entry.getValue();
- if (value.getTimestamp() < oldestTimestamp) {
- oldestTimestamp = value.getTimestamp();
- oldestKey = key;
- }
- }
-
- if (oldestKey != null) {
- map.remove(oldestKey);
- }
- }
-
- private final class TimestampedValue {
-
- private final SoftReference<V> value;
- private long timestamp;
-
- public TimestampedValue(V value) {
- this.value = new SoftReference<V>(value);
- updateTimestamp();
- }
-
- public V getValue() {
- return value.get();
- }
-
- public long getTimestamp() {
- return timestamp;
- }
-
- public void updateTimestamp() {
- timestamp = System.currentTimeMillis();
- }
- }
-
-} \ No newline at end of file
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/MergeAdapter.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/MergeAdapter.java
deleted file mode 100644
index 97dbc125..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/MergeAdapter.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/***
- Copyright (c) 2008-2009 CommonsWare, LLC
- Portions (c) 2009 Google, Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License"); you may
- not use this file except in compliance with the License. You may obtain
- a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-package net.sourceforge.subsonic.androidapp.util;
-
-import android.database.DataSetObserver;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ListAdapter;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Arrays;
-
-/**
- * Adapter that merges multiple child adapters and views
- * into a single contiguous whole.
- * <p/>
- * Adapters used as pieces within MergeAdapter must
- * have view type IDs monotonically increasing from 0. Ideally,
- * adapters also have distinct ranges for their row ids, as
- * returned by getItemId().
- */
-public class MergeAdapter extends BaseAdapter {
-
- private final CascadeDataSetObserver observer = new CascadeDataSetObserver();
- private final ArrayList<ListAdapter> pieces = new ArrayList<ListAdapter>();
-
- /**
- * Stock constructor, simply chaining to the superclass.
- */
- public MergeAdapter() {
- super();
- }
-
- /**
- * Adds a new adapter to the roster of things to appear
- * in the aggregate list.
- *
- * @param adapter Source for row views for this section
- */
- public void addAdapter(ListAdapter adapter) {
- pieces.add(adapter);
- adapter.registerDataSetObserver(observer);
- }
-
- public void removeAdapter(ListAdapter adapter) {
- adapter.unregisterDataSetObserver(observer);
- pieces.remove(adapter);
- }
-
- /**
- * Adds a new View to the roster of things to appear
- * in the aggregate list.
- *
- * @param view Single view to add
- */
- public ListAdapter addView(View view) {
- return addView(view, false);
- }
-
- /**
- * Adds a new View to the roster of things to appear
- * in the aggregate list.
- *
- * @param view Single view to add
- * @param enabled false if views are disabled, true if enabled
- */
- public ListAdapter addView(View view, boolean enabled) {
- return addViews(Arrays.asList(view), enabled);
- }
-
- /**
- * Adds a list of views to the roster of things to appear
- * in the aggregate list.
- *
- * @param views List of views to add
- */
- public ListAdapter addViews(List<View> views) {
- return addViews(views, false);
- }
-
- /**
- * Adds a list of views to the roster of things to appear
- * in the aggregate list.
- *
- * @param views List of views to add
- * @param enabled false if views are disabled, true if enabled
- */
- public ListAdapter addViews(List<View> views, boolean enabled) {
- ListAdapter adapter = enabled ? new EnabledSackAdapter(views) : new SackOfViewsAdapter(views);
- addAdapter(adapter);
- return adapter;
- }
-
- /**
- * Get the data item associated with the specified
- * position in the data set.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public Object getItem(int position) {
- for (ListAdapter piece : pieces) {
- int size = piece.getCount();
-
- if (position < size) {
- return (piece.getItem(position));
- }
-
- position -= size;
- }
-
- return (null);
- }
-
- /**
- * How many items are in the data set represented by this
- * Adapter.
- */
- @Override
- public int getCount() {
- int total = 0;
-
- for (ListAdapter piece : pieces) {
- total += piece.getCount();
- }
-
- return (total);
- }
-
- /**
- * Returns the number of types of Views that will be
- * created by getView().
- */
- @Override
- public int getViewTypeCount() {
- int total = 0;
-
- for (ListAdapter piece : pieces) {
- total += piece.getViewTypeCount();
- }
-
- return (Math.max(total, 1)); // needed for setListAdapter() before content add'
- }
-
- /**
- * Get the type of View that will be created by getView()
- * for the specified item.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public int getItemViewType(int position) {
- int typeOffset = 0;
- int result = -1;
-
- for (ListAdapter piece : pieces) {
- int size = piece.getCount();
-
- if (position < size) {
- result = typeOffset + piece.getItemViewType(position);
- break;
- }
-
- position -= size;
- typeOffset += piece.getViewTypeCount();
- }
-
- return (result);
- }
-
- /**
- * Are all items in this ListAdapter enabled? If yes it
- * means all items are selectable and clickable.
- */
- @Override
- public boolean areAllItemsEnabled() {
- return (false);
- }
-
- /**
- * Returns true if the item at the specified position is
- * not a separator.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public boolean isEnabled(int position) {
- for (ListAdapter piece : pieces) {
- int size = piece.getCount();
-
- if (position < size) {
- return (piece.isEnabled(position));
- }
-
- position -= size;
- }
-
- return (false);
- }
-
- /**
- * Get a View that displays the data at the specified
- * position in the data set.
- *
- * @param position Position of the item whose data we want
- * @param convertView View to recycle, if not null
- * @param parent ViewGroup containing the returned View
- */
- @Override
- public View getView(int position, View convertView,
- ViewGroup parent) {
- for (ListAdapter piece : pieces) {
- int size = piece.getCount();
-
- if (position < size) {
-
- return (piece.getView(position, convertView, parent));
- }
-
- position -= size;
- }
-
- return (null);
- }
-
- /**
- * Get the row id associated with the specified position
- * in the list.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public long getItemId(int position) {
- for (ListAdapter piece : pieces) {
- int size = piece.getCount();
-
- if (position < size) {
- return (piece.getItemId(position));
- }
-
- position -= size;
- }
-
- return (-1);
- }
-
- private static class EnabledSackAdapter extends SackOfViewsAdapter {
- public EnabledSackAdapter(List<View> views) {
- super(views);
- }
-
- @Override
- public boolean areAllItemsEnabled() {
- return (true);
- }
-
- @Override
- public boolean isEnabled(int position) {
- return (true);
- }
- }
-
- private class CascadeDataSetObserver extends DataSetObserver {
- @Override
- public void onChanged() {
- notifyDataSetChanged();
- }
-
- @Override
- public void onInvalidated() {
- notifyDataSetInvalidated();
- }
- }
-}
-
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ModalBackgroundTask.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ModalBackgroundTask.java
deleted file mode 100644
index 15e2add2..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ModalBackgroundTask.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.util.Log;
-import net.sourceforge.subsonic.androidapp.R;
-
-/**
- * @author Sindre Mehus
- */
-public abstract class ModalBackgroundTask<T> extends BackgroundTask<T> {
-
- private static final String TAG = ModalBackgroundTask.class.getSimpleName();
-
- private final AlertDialog progressDialog;
- private Thread thread;
- private final boolean finishActivityOnCancel;
- private boolean cancelled;
-
- public ModalBackgroundTask(Activity activity, boolean finishActivityOnCancel) {
- super(activity);
- this.finishActivityOnCancel = finishActivityOnCancel;
- progressDialog = createProgressDialog();
- }
-
- public ModalBackgroundTask(Activity activity) {
- this(activity, true);
- }
-
- private AlertDialog createProgressDialog() {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- builder.setIcon(android.R.drawable.ic_dialog_info);
- builder.setTitle(R.string.background_task_wait);
- builder.setMessage(R.string.background_task_loading);
- builder.setCancelable(true);
- builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialogInterface) {
- cancel();
- }
- });
- builder.setPositiveButton(R.string.common_cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- cancel();
- }
- });
-
- return builder.create();
- }
-
- public void execute() {
- cancelled = false;
- progressDialog.show();
-
- thread = new Thread() {
- @Override
- public void run() {
- try {
- final T result = doInBackground();
- if (cancelled) {
- progressDialog.dismiss();
- return;
- }
-
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- progressDialog.dismiss();
- done(result);
- }
- });
-
- } catch (final Throwable t) {
- if (cancelled) {
- return;
- }
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- progressDialog.dismiss();
- error(t);
- }
- });
- }
- }
- };
- thread.start();
- }
-
- protected void cancel() {
- cancelled = true;
- if (thread != null) {
- thread.interrupt();
- }
-
- if (finishActivityOnCancel) {
- getActivity().finish();
- }
- }
-
- protected boolean isCancelled() {
- return cancelled;
- }
-
- protected void error(Throwable error) {
- Log.w(TAG, "Got exception: " + error, error);
- new ErrorDialog(getActivity(), getErrorMessage(error), finishActivityOnCancel);
- }
-
- @Override
- public void updateProgress(final String message) {
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- progressDialog.setMessage(message);
- }
- });
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/MyViewFlipper.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/MyViewFlipper.java
deleted file mode 100644
index 94f217ff..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/MyViewFlipper.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.ViewFlipper;
-
-/**
- * Work-around for Android Issue 6191 (http://code.google.com/p/android/issues/detail?id=6191)
- *
- * @author Sindre Mehus
- * @version $Id$
- */
-public class MyViewFlipper extends ViewFlipper {
-
- public MyViewFlipper(Context context) {
- super(context);
- }
-
- public MyViewFlipper(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
-
- @Override
- protected void onDetachedFromWindow() {
- try {
- super.onDetachedFromWindow();
- }
- catch (IllegalArgumentException e) {
- // Call stopFlipping() in order to kick off updateRunning()
- stopFlipping();
- }
- }
-}
-
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/Pair.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/Pair.java
deleted file mode 100644
index 73dc3224..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/Pair.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import java.io.Serializable;
-
-/**
- * @author Sindre Mehus
- */
-public class Pair<S, T> implements Serializable {
-
- private S first;
- private T second;
-
- public Pair() {
- }
-
- public Pair(S first, T second) {
- this.first = first;
- this.second = second;
- }
-
- public S getFirst() {
- return first;
- }
-
- public void setFirst(S first) {
- this.first = first;
- }
-
- public T getSecond() {
- return second;
- }
-
- public void setSecond(T second) {
- this.second = second;
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/PlaylistAdapter.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/PlaylistAdapter.java
deleted file mode 100644
index 16028c12..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/PlaylistAdapter.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import android.content.Context;
-import android.widget.ArrayAdapter;
-import android.widget.SectionIndexer;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.Playlist;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
-* @author Sindre Mehus
-* @version $Id$
-*/
-public class PlaylistAdapter extends ArrayAdapter<Playlist> implements SectionIndexer {
-
- // Both arrays are indexed by section ID.
- private final Object[] sections;
- private final Integer[] positions;
-
- /**
- * Note: playlists must be sorted alphabetically.
- */
- public PlaylistAdapter(Context context, List<Playlist> playlists) {
- super(context, R.layout.playlist_list_item, playlists);
-
- Set<String> sectionSet = new LinkedHashSet<String>(30);
- List<Integer> positionList = new ArrayList<Integer>(30);
- for (int i = 0; i < playlists.size(); i++) {
- Playlist playlist = playlists.get(i);
- if (playlist.getName().length() > 0) {
- String index = playlist.getName().substring(0, 1).toUpperCase();
- if (!sectionSet.contains(index)) {
- sectionSet.add(index);
- positionList.add(i);
- }
- }
- }
- sections = sectionSet.toArray(new Object[sectionSet.size()]);
- positions = positionList.toArray(new Integer[positionList.size()]);
- }
-
- @Override
- public Object[] getSections() {
- return sections;
- }
-
- @Override
- public int getPositionForSection(int section) {
- section = Math.min(section, positions.length - 1);
- return positions[section];
- }
-
- @Override
- public int getSectionForPosition(int pos) {
- for (int i = 0; i < sections.length - 1; i++) {
- if (pos < positions[i + 1]) {
- return i;
- }
- }
- return sections.length - 1;
- }
-
- public static class PlaylistComparator implements Comparator<Playlist> {
- @Override
- public int compare(Playlist playlist1, Playlist playlist2) {
- return playlist1.getName().compareToIgnoreCase(playlist2.getName());
- }
-
- public static List<Playlist> sort(List<Playlist> playlists) {
- Collections.sort(playlists, new PlaylistComparator());
- return playlists;
- }
-
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ProgressListener.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ProgressListener.java
deleted file mode 100644
index 0d2924f7..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ProgressListener.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-/**
- * @author Sindre Mehus
- */
-public interface ProgressListener {
- void updateProgress(String message);
- void updateProgress(int messageId);
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SackOfViewsAdapter.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SackOfViewsAdapter.java
deleted file mode 100644
index ca825e55..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SackOfViewsAdapter.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/***
- Copyright (c) 2008-2009 CommonsWare, LLC
- Portions (c) 2009 Google, Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License"); you may
- not use this file except in compliance with the License. You may obtain
- a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ListView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Adapter that simply returns row views from a list.
- * <p/>
- * If you supply a size, you must implement newView(), to
- * create a required view. The adapter will then cache these
- * views.
- * <p/>
- * If you supply a list of views in the constructor, that
- * list will be used directly. If any elements in the list
- * are null, then newView() will be called just for those
- * slots.
- * <p/>
- * Subclasses may also wish to override areAllItemsEnabled()
- * (default: false) and isEnabled() (default: false), if some
- * of their rows should be selectable.
- * <p/>
- * It is assumed each view is unique, and therefore will not
- * get recycled.
- * <p/>
- * Note that this adapter is not designed for long lists. It
- * is more for screens that should behave like a list. This
- * is particularly useful if you combine this with other
- * adapters (e.g., SectionedAdapter) that might have an
- * arbitrary number of rows, so it all appears seamless.
- */
-public class SackOfViewsAdapter extends BaseAdapter {
- private List<View> views = null;
-
- /**
- * Constructor creating an empty list of views, but with
- * a specified count. Subclasses must override newView().
- */
- public SackOfViewsAdapter(int count) {
- super();
-
- views = new ArrayList<View>(count);
-
- for (int i = 0; i < count; i++) {
- views.add(null);
- }
- }
-
- /**
- * Constructor wrapping a supplied list of views.
- * Subclasses must override newView() if any of the elements
- * in the list are null.
- */
- public SackOfViewsAdapter(List<View> views) {
- for (View view : views) {
- view.setLayoutParams(new ListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
- }
- this.views = views;
- }
-
- /**
- * Get the data item associated with the specified
- * position in the data set.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public Object getItem(int position) {
- return (views.get(position));
- }
-
- /**
- * How many items are in the data set represented by this
- * Adapter.
- */
- @Override
- public int getCount() {
- return (views.size());
- }
-
- /**
- * Returns the number of types of Views that will be
- * created by getView().
- */
- @Override
- public int getViewTypeCount() {
- return (getCount());
- }
-
- /**
- * Get the type of View that will be created by getView()
- * for the specified item.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public int getItemViewType(int position) {
- return (position);
- }
-
- /**
- * Are all items in this ListAdapter enabled? If yes it
- * means all items are selectable and clickable.
- */
- @Override
- public boolean areAllItemsEnabled() {
- return (false);
- }
-
- /**
- * Returns true if the item at the specified position is
- * not a separator.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public boolean isEnabled(int position) {
- return (false);
- }
-
- /**
- * Get a View that displays the data at the specified
- * position in the data set.
- *
- * @param position Position of the item whose data we want
- * @param convertView View to recycle, if not null
- * @param parent ViewGroup containing the returned View
- */
- @Override
- public View getView(int position, View convertView,
- ViewGroup parent) {
- View result = views.get(position);
-
- if (result == null) {
- result = newView(position, parent);
- views.set(position, result);
- }
-
- return (result);
- }
-
- /**
- * Get the row id associated with the specified position
- * in the list.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public long getItemId(int position) {
- return (position);
- }
-
- /**
- * Create a new View to go into the list at the specified
- * position.
- *
- * @param position Position of the item whose data we want
- * @param parent ViewGroup containing the returned View
- */
- protected View newView(int position, ViewGroup parent) {
- throw new RuntimeException("You must override newView()!");
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ShufflePlayBuffer.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ShufflePlayBuffer.java
deleted file mode 100644
index 825fcc44..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/ShufflePlayBuffer.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import android.content.Context;
-import android.util.Log;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.service.MusicService;
-import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public class ShufflePlayBuffer {
-
- private static final String TAG = ShufflePlayBuffer.class.getSimpleName();
- private static final int CAPACITY = 50;
- private static final int REFILL_THRESHOLD = 40;
-
- private final ScheduledExecutorService executorService;
- private final List<MusicDirectory.Entry> buffer = new ArrayList<MusicDirectory.Entry>();
- private Context context;
- private int currentServer;
-
- public ShufflePlayBuffer(Context context) {
- this.context = context;
- executorService = Executors.newSingleThreadScheduledExecutor();
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- refill();
- }
- };
- executorService.scheduleWithFixedDelay(runnable, 1, 10, TimeUnit.SECONDS);
- }
-
- public List<MusicDirectory.Entry> get(int size) {
- clearBufferIfnecessary();
-
- List<MusicDirectory.Entry> result = new ArrayList<MusicDirectory.Entry>(size);
- synchronized (buffer) {
- while (!buffer.isEmpty() && result.size() < size) {
- result.add(buffer.remove(buffer.size() - 1));
- }
- }
- Log.i(TAG, "Taking " + result.size() + " songs from shuffle play buffer. " + buffer.size() + " remaining.");
- return result;
- }
-
- public void shutdown() {
- executorService.shutdown();
- }
-
- private void refill() {
-
- // Check if active server has changed.
- clearBufferIfnecessary();
-
- if (buffer.size() > REFILL_THRESHOLD || (!Util.isNetworkConnected(context) && !Util.isOffline(context))) {
- return;
- }
-
- try {
- MusicService service = MusicServiceFactory.getMusicService(context);
- int n = CAPACITY - buffer.size();
- MusicDirectory songs = service.getRandomSongs(n, context, null);
-
- synchronized (buffer) {
- buffer.addAll(songs.getChildren());
- Log.i(TAG, "Refilled shuffle play buffer with " + songs.getChildren().size() + " songs.");
- }
- } catch (Exception x) {
- Log.w(TAG, "Failed to refill shuffle play buffer.", x);
- }
- }
-
- private void clearBufferIfnecessary() {
- synchronized (buffer) {
- if (currentServer != Util.getActiveServer(context)) {
- currentServer = Util.getActiveServer(context);
- buffer.clear();
- }
- }
- }
-
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SilentBackgroundTask.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SilentBackgroundTask.java
deleted file mode 100644
index 7aa85d7c..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SilentBackgroundTask.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2010 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import android.app.Activity;
-
-/**
- * @author Sindre Mehus
- */
-public abstract class SilentBackgroundTask<T> extends BackgroundTask<T> {
-
- public SilentBackgroundTask(Activity activity) {
- super(activity);
- }
-
- @Override
- public void execute() {
- Thread thread = new Thread() {
- @Override
- public void run() {
- try {
- final T result = doInBackground();
-
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- done(result);
- }
- });
-
- } catch (final Throwable t) {
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- error(t);
- }
- });
- }
- }
- };
- thread.start();
- }
-
- @Override
- public void updateProgress(int messageId) {
- }
-
- @Override
- public void updateProgress(String message) {
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SimpleServiceBinder.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SimpleServiceBinder.java
deleted file mode 100644
index 9ddf9903..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SimpleServiceBinder.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import android.os.Binder;
-
-/**
- * @author Sindre Mehus
- */
-public class SimpleServiceBinder<S> extends Binder {
-
- private final S service;
-
- public SimpleServiceBinder(S service) {
- this.service = service;
- }
-
- public S getService() {
- return service;
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SongView.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SongView.java
deleted file mode 100644
index 22902a11..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/SongView.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import android.content.Context;
-import android.os.Handler;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.Checkable;
-import android.widget.CheckedTextView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.service.DownloadService;
-import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
-import net.sourceforge.subsonic.androidapp.service.DownloadFile;
-
-import java.io.File;
-import java.util.WeakHashMap;
-
-/**
- * Used to display songs in a {@code ListView}.
- *
- * @author Sindre Mehus
- */
-public class SongView extends LinearLayout implements Checkable {
-
- private static final String TAG = SongView.class.getSimpleName();
- private static final WeakHashMap<SongView, ?> INSTANCES = new WeakHashMap<SongView, Object>();
- private static Handler handler;
-
- private CheckedTextView checkedTextView;
- private TextView titleTextView;
- private TextView artistTextView;
- private TextView durationTextView;
- private TextView statusTextView;
- private MusicDirectory.Entry song;
-
- public SongView(Context context) {
- super(context);
- LayoutInflater.from(context).inflate(R.layout.song_list_item, this, true);
-
- checkedTextView = (CheckedTextView) findViewById(R.id.song_check);
- titleTextView = (TextView) findViewById(R.id.song_title);
- artistTextView = (TextView) findViewById(R.id.song_artist);
- durationTextView = (TextView) findViewById(R.id.song_duration);
- statusTextView = (TextView) findViewById(R.id.song_status);
-
- INSTANCES.put(this, null);
- int instanceCount = INSTANCES.size();
- if (instanceCount > 50) {
- Log.w(TAG, instanceCount + " live SongView instances");
- }
- startUpdater();
- }
-
- public void setSong(MusicDirectory.Entry song, boolean checkable) {
- this.song = song;
- StringBuilder artist = new StringBuilder(40);
-
- String bitRate = null;
- if (song.getBitRate() != null) {
- bitRate = String.format(getContext().getString(R.string.song_details_kbps), song.getBitRate());
- }
-
- String fileFormat = null;
- if (song.getTranscodedSuffix() != null && !song.getTranscodedSuffix().equals(song.getSuffix())) {
- fileFormat = String.format("%s > %s", song.getSuffix(), song.getTranscodedSuffix());
- } else {
- fileFormat = song.getSuffix();
- }
-
- artist.append(song.getArtist()).append(" (")
- .append(String.format(getContext().getString(R.string.song_details_all), bitRate == null ? "" : bitRate, fileFormat))
- .append(")");
-
- titleTextView.setText(song.getTitle());
- artistTextView.setText(artist);
- durationTextView.setText(Util.formatDuration(song.getDuration()));
- checkedTextView.setVisibility(checkable && !song.isVideo() ? View.VISIBLE : View.GONE);
-
- update();
- }
-
- private void update() {
- DownloadService downloadService = DownloadServiceImpl.getInstance();
- if (downloadService == null) {
- return;
- }
-
- DownloadFile downloadFile = downloadService.forSong(song);
- File completeFile = downloadFile.getCompleteFile();
- File partialFile = downloadFile.getPartialFile();
-
- int leftImage = 0;
- int rightImage = 0;
-
- if (completeFile.exists()) {
- leftImage = downloadFile.isSaved() ? R.drawable.saved : R.drawable.downloaded;
- }
-
- if (downloadFile.isDownloading() && !downloadFile.isDownloadCancelled() && partialFile.exists()) {
- statusTextView.setText(Util.formatLocalizedBytes(partialFile.length(), getContext()));
- rightImage = R.drawable.downloading;
- } else {
- statusTextView.setText(null);
- }
- statusTextView.setCompoundDrawablesWithIntrinsicBounds(leftImage, 0, rightImage, 0);
-
- boolean playing = downloadService.getCurrentPlaying() == downloadFile;
- if (playing) {
- titleTextView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.stat_notify_playing, 0, 0, 0);
- } else {
- titleTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
- }
- }
-
- private static synchronized void startUpdater() {
- if (handler != null) {
- return;
- }
-
- handler = new Handler();
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- updateAll();
- handler.postDelayed(this, 1000L);
- }
- };
- handler.postDelayed(runnable, 1000L);
- }
-
- private static void updateAll() {
- try {
- for (SongView view : INSTANCES.keySet()) {
- if (view.isShown()) {
- view.update();
- }
- }
- } catch (Throwable x) {
- Log.w(TAG, "Error when updating song views.", x);
- }
- }
-
- @Override
- public void setChecked(boolean b) {
- checkedTextView.setChecked(b);
- }
-
- @Override
- public boolean isChecked() {
- return checkedTextView.isChecked();
- }
-
- @Override
- public void toggle() {
- checkedTextView.toggle();
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/TabActivityBackgroundTask.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/TabActivityBackgroundTask.java
deleted file mode 100644
index 033a51ad..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/TabActivityBackgroundTask.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package net.sourceforge.subsonic.androidapp.util;
-
-import net.sourceforge.subsonic.androidapp.activity.SubsonicTabActivity;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public abstract class TabActivityBackgroundTask<T> extends BackgroundTask<T> {
-
- private final SubsonicTabActivity tabActivity;
-
- public TabActivityBackgroundTask(SubsonicTabActivity activity) {
- super(activity);
- tabActivity = activity;
- }
-
- @Override
- public void execute() {
- tabActivity.setProgressVisible(true);
-
- new Thread() {
- @Override
- public void run() {
- try {
- final T result = doInBackground();
- if (isCancelled()) {
- return;
- }
-
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- tabActivity.setProgressVisible(false);
- done(result);
- }
- });
- } catch (final Throwable t) {
- if (isCancelled()) {
- return;
- }
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- tabActivity.setProgressVisible(false);
- error(t);
- }
- });
- }
- }
- }.start();
- }
-
- private boolean isCancelled() {
- return tabActivity.isDestroyed();
- }
-
- @Override
- public void updateProgress(final String message) {
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- tabActivity.updateProgress(message);
- }
- });
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/TimeLimitedCache.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/TimeLimitedCache.java
deleted file mode 100644
index 5df5901e..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/TimeLimitedCache.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import java.lang.ref.SoftReference;
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public class TimeLimitedCache<T> {
-
- private SoftReference<T> value;
- private final long ttlMillis;
- private long expires;
-
- public TimeLimitedCache(long ttl, TimeUnit timeUnit) {
- this.ttlMillis = TimeUnit.MILLISECONDS.convert(ttl, timeUnit);
- }
-
- public T get() {
- return System.currentTimeMillis() < expires ? value.get() : null;
- }
-
- public void set(T value) {
- set(value, ttlMillis, TimeUnit.MILLISECONDS);
- }
-
- public void set(T value, long ttl, TimeUnit timeUnit) {
- this.value = new SoftReference<T>(value);
- expires = System.currentTimeMillis() + timeUnit.toMillis(ttl);
- }
-
- public void clear() {
- expires = 0L;
- value = null;
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/Util.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/Util.java
deleted file mode 100644
index 9a8c692d..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/util/Util.java
+++ /dev/null
@@ -1,829 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.util;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.os.Environment;
-import android.os.Handler;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.RemoteViews;
-import android.widget.TextView;
-import android.widget.Toast;
-import net.sourceforge.subsonic.androidapp.R;
-import net.sourceforge.subsonic.androidapp.activity.DownloadActivity;
-import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
-import net.sourceforge.subsonic.androidapp.domain.PlayerState;
-import net.sourceforge.subsonic.androidapp.domain.RepeatMode;
-import net.sourceforge.subsonic.androidapp.domain.Version;
-import net.sourceforge.subsonic.androidapp.provider.SubsonicAppWidgetProvider;
-import net.sourceforge.subsonic.androidapp.receiver.MediaButtonIntentReceiver;
-import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
-import org.apache.http.HttpEntity;
-
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.security.MessageDigest;
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * @author Sindre Mehus
- * @version $Id$
- */
-public final class Util {
-
- private static final String TAG = Util.class.getSimpleName();
-
- private static final DecimalFormat GIGA_BYTE_FORMAT = new DecimalFormat("0.00 GB");
- private static final DecimalFormat MEGA_BYTE_FORMAT = new DecimalFormat("0.00 MB");
- private static final DecimalFormat KILO_BYTE_FORMAT = new DecimalFormat("0 KB");
-
- private static DecimalFormat GIGA_BYTE_LOCALIZED_FORMAT = null;
- private static DecimalFormat MEGA_BYTE_LOCALIZED_FORMAT = null;
- private static DecimalFormat KILO_BYTE_LOCALIZED_FORMAT = null;
- private static DecimalFormat BYTE_LOCALIZED_FORMAT = null;
-
- public static final String EVENT_META_CHANGED = "net.sourceforge.subsonic.androidapp.EVENT_META_CHANGED";
- public static final String EVENT_PLAYSTATE_CHANGED = "net.sourceforge.subsonic.androidapp.EVENT_PLAYSTATE_CHANGED";
-
- private static final Map<Integer, Version> SERVER_REST_VERSIONS = new ConcurrentHashMap<Integer, Version>();
-
- // Used by hexEncode()
- private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
-
- private final static Pair<Integer, Integer> NOTIFICATION_TEXT_COLORS = new Pair<Integer, Integer>();
- private static Toast toast;
-
- private Util() {
- }
-
- public static boolean isOffline(Context context) {
- return getActiveServer(context) == 0;
- }
-
- public static boolean isScreenLitOnDownload(Context context) {
- SharedPreferences prefs = getPreferences(context);
- return prefs.getBoolean(Constants.PREFERENCES_KEY_SCREEN_LIT_ON_DOWNLOAD, false);
- }
-
- public static RepeatMode getRepeatMode(Context context) {
- SharedPreferences prefs = getPreferences(context);
- return RepeatMode.valueOf(prefs.getString(Constants.PREFERENCES_KEY_REPEAT_MODE, RepeatMode.OFF.name()));
- }
-
- public static void setRepeatMode(Context context, RepeatMode repeatMode) {
- SharedPreferences prefs = getPreferences(context);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(Constants.PREFERENCES_KEY_REPEAT_MODE, repeatMode.name());
- editor.commit();
- }
-
- public static boolean isScrobblingEnabled(Context context) {
- if (isOffline(context)) {
- return false;
- }
- SharedPreferences prefs = getPreferences(context);
- return prefs.getBoolean(Constants.PREFERENCES_KEY_SCROBBLE, false);
- }
-
- public static void setActiveServer(Context context, int instance) {
- SharedPreferences prefs = getPreferences(context);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, instance);
- editor.commit();
- }
-
- public static int getActiveServer(Context context) {
- SharedPreferences prefs = getPreferences(context);
- return prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
- }
-
- public static String getServerName(Context context, int instance) {
- if (instance == 0) {
- return context.getResources().getString(R.string.main_offline);
- }
- SharedPreferences prefs = getPreferences(context);
- return prefs.getString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, null);
- }
-
- public static void setServerRestVersion(Context context, Version version) {
- SERVER_REST_VERSIONS.put(getActiveServer(context), version);
- }
-
- public static Version getServerRestVersion(Context context) {
- return SERVER_REST_VERSIONS.get(getActiveServer(context));
- }
-
- public static void setSelectedMusicFolderId(Context context, String musicFolderId) {
- int instance = getActiveServer(context);
- SharedPreferences prefs = getPreferences(context);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(Constants.PREFERENCES_KEY_MUSIC_FOLDER_ID + instance, musicFolderId);
- editor.commit();
- }
-
- public static String getSelectedMusicFolderId(Context context) {
- SharedPreferences prefs = getPreferences(context);
- int instance = getActiveServer(context);
- return prefs.getString(Constants.PREFERENCES_KEY_MUSIC_FOLDER_ID + instance, null);
- }
-
- public static String getTheme(Context context) {
- SharedPreferences prefs = getPreferences(context);
- return prefs.getString(Constants.PREFERENCES_KEY_THEME, null);
- }
-
- public static int getMaxBitrate(Context context) {
- ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = manager.getActiveNetworkInfo();
- if (networkInfo == null) {
- return 0;
- }
-
- boolean wifi = networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
- SharedPreferences prefs = getPreferences(context);
- return Integer.parseInt(prefs.getString(wifi ? Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI : Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE, "0"));
- }
-
- public static int getPreloadCount(Context context) {
- SharedPreferences prefs = getPreferences(context);
- int preloadCount = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_PRELOAD_COUNT, "-1"));
- return preloadCount == -1 ? Integer.MAX_VALUE : preloadCount;
- }
-
- public static int getCacheSizeMB(Context context) {
- SharedPreferences prefs = getPreferences(context);
- int cacheSize = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_CACHE_SIZE, "-1"));
- return cacheSize == -1 ? Integer.MAX_VALUE : cacheSize;
- }
-
- public static String getRestUrl(Context context, String method) {
- StringBuilder builder = new StringBuilder();
-
- SharedPreferences prefs = getPreferences(context);
-
- int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
- String serverUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null);
- String username = prefs.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null);
- String password = prefs.getString(Constants.PREFERENCES_KEY_PASSWORD + instance, null);
-
- // Slightly obfuscate password
- password = "enc:" + Util.utf8HexEncode(password);
-
- builder.append(serverUrl);
- if (builder.charAt(builder.length() - 1) != '/') {
- builder.append("/");
- }
- builder.append("rest/").append(method).append(".view");
- builder.append("?u=").append(username);
- builder.append("&p=").append(password);
- builder.append("&v=").append(Constants.REST_PROTOCOL_VERSION);
- builder.append("&c=").append(Constants.REST_CLIENT_ID);
-
- return builder.toString();
- }
-
- public static SharedPreferences getPreferences(Context context) {
- return context.getSharedPreferences(Constants.PREFERENCES_FILE_NAME, 0);
- }
-
- public static String getContentType(HttpEntity entity) {
- if (entity == null || entity.getContentType() == null) {
- return null;
- }
- return entity.getContentType().getValue();
- }
-
- public static int getRemainingTrialDays(Context context) {
- SharedPreferences prefs = getPreferences(context);
- long installTime = prefs.getLong(Constants.PREFERENCES_KEY_INSTALL_TIME, 0L);
-
- if (installTime == 0L) {
- installTime = System.currentTimeMillis();
- SharedPreferences.Editor editor = prefs.edit();
- editor.putLong(Constants.PREFERENCES_KEY_INSTALL_TIME, installTime);
- editor.commit();
- }
-
- long now = System.currentTimeMillis();
- long millisPerDay = 24L * 60L * 60L * 1000L;
- int daysSinceInstall = (int) ((now - installTime) / millisPerDay);
- return Math.max(0, Constants.FREE_TRIAL_DAYS - daysSinceInstall);
- }
-
- /**
- * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
- * <p/>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedInputStream</code>.
- *
- * @param input the <code>InputStream</code> to read from
- * @return the requested byte array
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- */
- public static byte[] toByteArray(InputStream input) throws IOException {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- copy(input, output);
- return output.toByteArray();
- }
-
- public static long copy(InputStream input, OutputStream output)
- throws IOException {
- byte[] buffer = new byte[1024 * 4];
- long count = 0;
- int n;
- while (-1 != (n = input.read(buffer))) {
- output.write(buffer, 0, n);
- count += n;
- }
- return count;
- }
-
- public static void atomicCopy(File from, File to) throws IOException {
- FileInputStream in = null;
- FileOutputStream out = null;
- File tmp = null;
- try {
- tmp = new File(to.getPath() + ".tmp");
- in = new FileInputStream(from);
- out = new FileOutputStream(tmp);
- in.getChannel().transferTo(0, from.length(), out.getChannel());
- out.close();
- if (!tmp.renameTo(to)) {
- throw new IOException("Failed to rename " + tmp + " to " + to);
- }
- Log.i(TAG, "Copied " + from + " to " + to);
- } catch (IOException x) {
- close(out);
- delete(to);
- throw x;
- } finally {
- close(in);
- close(out);
- delete(tmp);
- }
- }
-
- public static void close(Closeable closeable) {
- try {
- if (closeable != null) {
- closeable.close();
- }
- } catch (Throwable x) {
- // Ignored
- }
- }
-
- public static boolean delete(File file) {
- if (file != null && file.exists()) {
- if (!file.delete()) {
- Log.w(TAG, "Failed to delete file " + file);
- return false;
- }
- Log.i(TAG, "Deleted file " + file);
- }
- return true;
- }
-
- public static void toast(Context context, int messageId) {
- toast(context, messageId, true);
- }
-
- public static void toast(Context context, int messageId, boolean shortDuration) {
- toast(context, context.getString(messageId), shortDuration);
- }
-
- public static void toast(Context context, String message) {
- toast(context, message, true);
- }
-
- public static void toast(Context context, String message, boolean shortDuration) {
- if (toast == null) {
- toast = Toast.makeText(context, message, shortDuration ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG);
- toast.setGravity(Gravity.CENTER, 0, 0);
- } else {
- toast.setText(message);
- toast.setDuration(shortDuration ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG);
- }
- toast.show();
- }
-
- /**
- * Converts a byte-count to a formatted string suitable for display to the user.
- * For instance:
- * <ul>
- * <li><code>format(918)</code> returns <em>"918 B"</em>.</li>
- * <li><code>format(98765)</code> returns <em>"96 KB"</em>.</li>
- * <li><code>format(1238476)</code> returns <em>"1.2 MB"</em>.</li>
- * </ul>
- * This method assumes that 1 KB is 1024 bytes.
- * To get a localized string, please use formatLocalizedBytes instead.
- *
- * @param byteCount The number of bytes.
- * @return The formatted string.
- */
- public static synchronized String formatBytes(long byteCount) {
-
- // More than 1 GB?
- if (byteCount >= 1024 * 1024 * 1024) {
- NumberFormat gigaByteFormat = GIGA_BYTE_FORMAT;
- return gigaByteFormat.format((double) byteCount / (1024 * 1024 * 1024));
- }
-
- // More than 1 MB?
- if (byteCount >= 1024 * 1024) {
- NumberFormat megaByteFormat = MEGA_BYTE_FORMAT;
- return megaByteFormat.format((double) byteCount / (1024 * 1024));
- }
-
- // More than 1 KB?
- if (byteCount >= 1024) {
- NumberFormat kiloByteFormat = KILO_BYTE_FORMAT;
- return kiloByteFormat.format((double) byteCount / 1024);
- }
-
- return byteCount + " B";
- }
-
- /**
- * Converts a byte-count to a formatted string suitable for display to the user.
- * For instance:
- * <ul>
- * <li><code>format(918)</code> returns <em>"918 B"</em>.</li>
- * <li><code>format(98765)</code> returns <em>"96 KB"</em>.</li>
- * <li><code>format(1238476)</code> returns <em>"1.2 MB"</em>.</li>
- * </ul>
- * This method assumes that 1 KB is 1024 bytes.
- * This version of the method returns a localized string.
- *
- * @param byteCount The number of bytes.
- * @return The formatted string.
- */
- public static synchronized String formatLocalizedBytes(long byteCount, Context context) {
-
- // More than 1 GB?
- if (byteCount >= 1024 * 1024 * 1024) {
- if (GIGA_BYTE_LOCALIZED_FORMAT == null) {
- GIGA_BYTE_LOCALIZED_FORMAT = new DecimalFormat(context.getResources().getString(R.string.util_bytes_format_gigabyte));
- }
-
- return GIGA_BYTE_LOCALIZED_FORMAT.format((double) byteCount / (1024 * 1024 * 1024));
- }
-
- // More than 1 MB?
- if (byteCount >= 1024 * 1024) {
- if (MEGA_BYTE_LOCALIZED_FORMAT == null) {
- MEGA_BYTE_LOCALIZED_FORMAT = new DecimalFormat(context.getResources().getString(R.string.util_bytes_format_megabyte));
- }
-
- return MEGA_BYTE_LOCALIZED_FORMAT.format((double) byteCount / (1024 * 1024));
- }
-
- // More than 1 KB?
- if (byteCount >= 1024) {
- if (KILO_BYTE_LOCALIZED_FORMAT == null) {
- KILO_BYTE_LOCALIZED_FORMAT = new DecimalFormat(context.getResources().getString(R.string.util_bytes_format_kilobyte));
- }
-
- return KILO_BYTE_LOCALIZED_FORMAT.format((double) byteCount / 1024);
- }
-
- if (BYTE_LOCALIZED_FORMAT == null) {
- BYTE_LOCALIZED_FORMAT = new DecimalFormat(context.getResources().getString(R.string.util_bytes_format_byte));
- }
-
- return BYTE_LOCALIZED_FORMAT.format((double) byteCount);
- }
-
- public static String formatDuration(Integer seconds) {
- if (seconds == null) {
- return null;
- }
-
- int minutes = seconds / 60;
- int secs = seconds % 60;
-
- StringBuilder builder = new StringBuilder(6);
- builder.append(minutes).append(":");
- if (secs < 10) {
- builder.append("0");
- }
- builder.append(secs);
- return builder.toString();
- }
-
- public static boolean equals(Object object1, Object object2) {
- if (object1 == object2) {
- return true;
- }
- if (object1 == null || object2 == null) {
- return false;
- }
- return object1.equals(object2);
-
- }
-
- /**
- * Encodes the given string by using the hexadecimal representation of its UTF-8 bytes.
- *
- * @param s The string to encode.
- * @return The encoded string.
- */
- public static String utf8HexEncode(String s) {
- if (s == null) {
- return null;
- }
- byte[] utf8;
- try {
- utf8 = s.getBytes(Constants.UTF_8);
- } catch (UnsupportedEncodingException x) {
- throw new RuntimeException(x);
- }
- return hexEncode(utf8);
- }
-
- /**
- * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
- * The returned array will be double the length of the passed array, as it takes two characters to represent any
- * given byte.
- *
- * @param data Bytes to convert to hexadecimal characters.
- * @return A string containing hexadecimal characters.
- */
- public static String hexEncode(byte[] data) {
- int length = data.length;
- char[] out = new char[length << 1];
- // two characters form the hex value.
- for (int i = 0, j = 0; i < length; i++) {
- out[j++] = HEX_DIGITS[(0xF0 & data[i]) >>> 4];
- out[j++] = HEX_DIGITS[0x0F & data[i]];
- }
- return new String(out);
- }
-
- /**
- * Calculates the MD5 digest and returns the value as a 32 character hex string.
- *
- * @param s Data to digest.
- * @return MD5 digest as a hex string.
- */
- public static String md5Hex(String s) {
- if (s == null) {
- return null;
- }
-
- try {
- MessageDigest md5 = MessageDigest.getInstance("MD5");
- return hexEncode(md5.digest(s.getBytes(Constants.UTF_8)));
- } catch (Exception x) {
- throw new RuntimeException(x.getMessage(), x);
- }
- }
-
- public static boolean isNetworkConnected(Context context) {
- ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = manager.getActiveNetworkInfo();
- boolean connected = networkInfo != null && networkInfo.isConnected();
-
- boolean wifiConnected = connected && networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
- boolean wifiRequired = isWifiRequiredForDownload(context);
-
- return connected && (!wifiRequired || wifiConnected);
- }
-
- public static boolean isExternalStoragePresent() {
- return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
- }
-
- private static boolean isWifiRequiredForDownload(Context context) {
- SharedPreferences prefs = getPreferences(context);
- return prefs.getBoolean(Constants.PREFERENCES_KEY_WIFI_REQUIRED_FOR_DOWNLOAD, false);
- }
-
- public static void info(Context context, int titleId, int messageId) {
- showDialog(context, android.R.drawable.ic_dialog_info, titleId, messageId);
- }
-
- private static void showDialog(Context context, int icon, int titleId, int messageId) {
- new AlertDialog.Builder(context)
- .setIcon(icon)
- .setTitle(titleId)
- .setMessage(messageId)
- .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int i) {
- dialog.dismiss();
- }
- })
- .show();
- }
-
- public static void showPlayingNotification(final Context context, final DownloadServiceImpl downloadService, Handler handler, MusicDirectory.Entry song) {
-
- // Use the same text for the ticker and the expanded notification
- String title = song.getTitle();
- String text = song.getArtist();
-
- // Set the icon, scrolling text and timestamp
- final Notification notification = new Notification(R.drawable.stat_notify_playing, title, System.currentTimeMillis());
- notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
-
- RemoteViews contentView = new RemoteViews(context.getPackageName(), R.layout.notification);
-
- // Set the album art.
- try {
- int size = context.getResources().getDrawable(R.drawable.unknown_album).getIntrinsicHeight();
- Bitmap bitmap = FileUtil.getAlbumArtBitmap(context, song, size);
- if (bitmap == null) {
- // set default album art
- contentView.setImageViewResource(R.id.notification_image, R.drawable.unknown_album);
- } else {
- contentView.setImageViewBitmap(R.id.notification_image, bitmap);
- }
- } catch (Exception x) {
- Log.w(TAG, "Failed to get notification cover art", x);
- contentView.setImageViewResource(R.id.notification_image, R.drawable.unknown_album);
- }
-
- // set the text for the notifications
- contentView.setTextViewText(R.id.notification_title, title);
- contentView.setTextViewText(R.id.notification_artist, text);
-
- Pair<Integer, Integer> colors = getNotificationTextColors(context);
- if (colors.getFirst() != null) {
- contentView.setTextColor(R.id.notification_title, colors.getFirst());
- }
- if (colors.getSecond() != null) {
- contentView.setTextColor(R.id.notification_artist, colors.getSecond());
- }
-
- notification.contentView = contentView;
-
- Intent notificationIntent = new Intent(context, DownloadActivity.class);
- notification.contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
-
- // Send the notification and put the service in the foreground.
- handler.post(new Runnable() {
- @Override
- public void run() {
- startForeground(downloadService, Constants.NOTIFICATION_ID_PLAYING, notification);
- }
- });
-
- // Update widget
- SubsonicAppWidgetProvider.getInstance().notifyChange(context, downloadService, true);
- }
-
- public static void hidePlayingNotification(final Context context, final DownloadServiceImpl downloadService, Handler handler) {
-
- // Remove notification and remove the service from the foreground
- handler.post(new Runnable() {
- @Override
- public void run() {
- stopForeground(downloadService, true);
- }
- });
-
- // Update widget
- SubsonicAppWidgetProvider.getInstance().notifyChange(context, downloadService, false);
- }
-
- public static void sleepQuietly(long millis) {
- try {
- Thread.sleep(millis);
- } catch (InterruptedException x) {
- Log.w(TAG, "Interrupted from sleep.", x);
- }
- }
-
- public static void startActivityWithoutTransition(Activity currentActivity, Class<? extends Activity> newActivitiy) {
- startActivityWithoutTransition(currentActivity, new Intent(currentActivity, newActivitiy));
- }
-
- public static void startActivityWithoutTransition(Activity currentActivity, Intent intent) {
- currentActivity.startActivity(intent);
- disablePendingTransition(currentActivity);
- }
-
- public static void disablePendingTransition(Activity activity) {
-
- // Activity.overridePendingTransition() was introduced in Android 2.0. Use reflection to maintain
- // compatibility with 1.5.
- try {
- Method method = Activity.class.getMethod("overridePendingTransition", int.class, int.class);
- method.invoke(activity, 0, 0);
- } catch (Throwable x) {
- // Ignored
- }
- }
-
- public static Drawable createDrawableFromBitmap(Context context, Bitmap bitmap) {
- // BitmapDrawable(Resources, Bitmap) was introduced in Android 1.6. Use reflection to maintain
- // compatibility with 1.5.
- try {
- Constructor<BitmapDrawable> constructor = BitmapDrawable.class.getConstructor(Resources.class, Bitmap.class);
- return constructor.newInstance(context.getResources(), bitmap);
- } catch (Throwable x) {
- return new BitmapDrawable(bitmap);
- }
- }
-
- public static void registerMediaButtonEventReceiver(Context context) {
-
- // Only do it if enabled in the settings.
- SharedPreferences prefs = getPreferences(context);
- boolean enabled = prefs.getBoolean(Constants.PREFERENCES_KEY_MEDIA_BUTTONS, true);
-
- if (enabled) {
-
- // AudioManager.registerMediaButtonEventReceiver() was introduced in Android 2.2.
- // Use reflection to maintain compatibility with 1.5.
- try {
- AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- ComponentName componentName = new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName());
- Method method = AudioManager.class.getMethod("registerMediaButtonEventReceiver", ComponentName.class);
- method.invoke(audioManager, componentName);
- } catch (Throwable x) {
- // Ignored.
- }
- }
- }
-
- public static void unregisterMediaButtonEventReceiver(Context context) {
- // AudioManager.unregisterMediaButtonEventReceiver() was introduced in Android 2.2.
- // Use reflection to maintain compatibility with 1.5.
- try {
- AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- ComponentName componentName = new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName());
- Method method = AudioManager.class.getMethod("unregisterMediaButtonEventReceiver", ComponentName.class);
- method.invoke(audioManager, componentName);
- } catch (Throwable x) {
- // Ignored.
- }
- }
-
- private static void startForeground(Service service, int notificationId, Notification notification) {
- // Service.startForeground() was introduced in Android 2.0.
- // Use reflection to maintain compatibility with 1.5.
- try {
- Method method = Service.class.getMethod("startForeground", int.class, Notification.class);
- method.invoke(service, notificationId, notification);
- Log.i(TAG, "Successfully invoked Service.startForeground()");
- } catch (Throwable x) {
- NotificationManager notificationManager = (NotificationManager) service.getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.notify(Constants.NOTIFICATION_ID_PLAYING, notification);
- Log.i(TAG, "Service.startForeground() not available. Using work-around.");
- }
- }
-
- private static void stopForeground(Service service, boolean removeNotification) {
- // Service.stopForeground() was introduced in Android 2.0.
- // Use reflection to maintain compatibility with 1.5.
- try {
- Method method = Service.class.getMethod("stopForeground", boolean.class);
- method.invoke(service, removeNotification);
- Log.i(TAG, "Successfully invoked Service.stopForeground()");
- } catch (Throwable x) {
- NotificationManager notificationManager = (NotificationManager) service.getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.cancel(Constants.NOTIFICATION_ID_PLAYING);
- Log.i(TAG, "Service.stopForeground() not available. Using work-around.");
- }
- }
-
- /**
- * <p>Broadcasts the given song info as the new song being played.</p>
- */
- public static void broadcastNewTrackInfo(Context context, MusicDirectory.Entry song) {
- Intent intent = new Intent(EVENT_META_CHANGED);
-
- if (song != null) {
- intent.putExtra("title", song.getTitle());
- intent.putExtra("artist", song.getArtist());
- intent.putExtra("album", song.getAlbum());
-
- File albumArtFile = FileUtil.getAlbumArtFile(context, song);
- intent.putExtra("coverart", albumArtFile.getAbsolutePath());
- } else {
- intent.putExtra("title", "");
- intent.putExtra("artist", "");
- intent.putExtra("album", "");
- intent.putExtra("coverart", "");
- }
-
- context.sendBroadcast(intent);
- }
-
- /**
- * <p>Broadcasts the given player state as the one being set.</p>
- */
- public static void broadcastPlaybackStatusChange(Context context, PlayerState state) {
- Intent intent = new Intent(EVENT_PLAYSTATE_CHANGED);
-
- switch (state) {
- case STARTED:
- intent.putExtra("state", "play");
- break;
- case STOPPED:
- intent.putExtra("state", "stop");
- break;
- case PAUSED:
- intent.putExtra("state", "pause");
- break;
- case COMPLETED:
- intent.putExtra("state", "complete");
- break;
- default:
- return; // No need to broadcast.
- }
-
- context.sendBroadcast(intent);
- }
-
- /**
- * Resolves the default text color for notifications.
- *
- * Based on http://stackoverflow.com/questions/4867338/custom-notification-layouts-and-text-colors/7320604#7320604
- */
- private static Pair<Integer, Integer> getNotificationTextColors(Context context) {
- if (NOTIFICATION_TEXT_COLORS.getFirst() == null && NOTIFICATION_TEXT_COLORS.getSecond() == null) {
- try {
- Notification notification = new Notification();
- String title = "title";
- String content = "content";
- notification.setLatestEventInfo(context, title, content, null);
- LinearLayout group = new LinearLayout(context);
- ViewGroup event = (ViewGroup) notification.contentView.apply(context, group);
- findNotificationTextColors(event, title, content);
- group.removeAllViews();
- } catch (Exception x) {
- Log.w(TAG, "Failed to resolve notification text colors.", x);
- }
- }
- return NOTIFICATION_TEXT_COLORS;
- }
-
- private static void findNotificationTextColors(ViewGroup group, String title, String content) {
- for (int i = 0; i < group.getChildCount(); i++) {
- if (group.getChildAt(i) instanceof TextView) {
- TextView textView = (TextView) group.getChildAt(i);
- String text = textView.getText().toString();
- if (title.equals(text)) {
- NOTIFICATION_TEXT_COLORS.setFirst(textView.getTextColors().getDefaultColor());
- }
- else if (content.equals(text)) {
- NOTIFICATION_TEXT_COLORS.setSecond(textView.getTextColors().getDefaultColor());
- }
- }
- else if (group.getChildAt(i) instanceof ViewGroup)
- findNotificationTextColors((ViewGroup) group.getChildAt(i), title, content);
- }
- }
-}
diff --git a/subsonic-android/src/net/sourceforge/subsonic/androidapp/view/VisualizerView.java b/subsonic-android/src/net/sourceforge/subsonic/androidapp/view/VisualizerView.java
deleted file mode 100644
index 76a45253..00000000
--- a/subsonic-android/src/net/sourceforge/subsonic/androidapp/view/VisualizerView.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2011 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.androidapp.view;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.media.audiofx.Visualizer;
-import android.util.AttributeSet;
-import android.view.View;
-import net.sourceforge.subsonic.androidapp.audiofx.VisualizerController;
-import net.sourceforge.subsonic.androidapp.domain.PlayerState;
-import net.sourceforge.subsonic.androidapp.service.DownloadService;
-import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
-
-/**
- * A simple class that draws waveform data received from a
- * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture}
- *
- * @author Sindre Mehus
- * @version $Id$
- */
-public class VisualizerView extends View {
-
- private static final int PREFERRED_CAPTURE_RATE_MILLIHERTZ = 20000;
-
- private final Paint paint = new Paint();
-
- private byte[] data;
- private float[] points;
- private boolean active;
-
- public VisualizerView(Context context) {
- super(context);
-
- paint.setStrokeWidth(2f);
- paint.setAntiAlias(true);
- paint.setColor(Color.rgb(129, 201, 54));
- }
-
- public boolean isActive() {
- return active;
- }
-
- public void setActive(boolean active) {
- this.active = active;
- Visualizer visualizer = getVizualiser();
- if (visualizer == null) {
- return;
- }
-
- int captureRate = Math.min(PREFERRED_CAPTURE_RATE_MILLIHERTZ, Visualizer.getMaxCaptureRate());
- if (active) {
- visualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {
- @Override
- public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate) {
- updateVisualizer(waveform);
- }
-
- @Override
- public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) {
- }
- }, captureRate, true, false);
- } else {
- visualizer.setDataCaptureListener(null, captureRate, false, false);
- }
-
- visualizer.setEnabled(active);
- invalidate();
- }
-
- private Visualizer getVizualiser() {
- DownloadService downloadService = DownloadServiceImpl.getInstance();
- VisualizerController visualizerController = downloadService == null ? null : downloadService.getVisualizerController();
- return visualizerController == null ? null : visualizerController.getVisualizer();
- }
-
- private void updateVisualizer(byte[] waveform) {
- this.data = waveform;
- invalidate();
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- if (!active) {
- return;
- }
- DownloadService downloadService = DownloadServiceImpl.getInstance();
- if (downloadService != null && downloadService.getPlayerState() != PlayerState.STARTED) {
- return;
- }
-
- if (data == null) {
- return;
- }
-
- if (points == null || points.length < data.length * 4) {
- points = new float[data.length * 4];
- }
-
- int w = getWidth();
- int h = getHeight();
-
- for (int i = 0; i < data.length - 1; i++) {
- points[i * 4] = w * i / (data.length - 1);
- points[i * 4 + 1] = h / 2 + ((byte) (data[i] + 128)) * (h / 2) / 128;
- points[i * 4 + 2] = w * (i + 1) / (data.length - 1);
- points[i * 4 + 3] = h / 2 + ((byte) (data[i + 1] + 128)) * (h / 2) / 128;
- }
-
- canvas.drawLines(points, paint);
- }
-}